PostgreSQL Source Code: src/bin/pg_rewind/filemap.c Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

25

26#include <sys/stat.h>

28

30#include "catalog/pg_tablespace_d.h"

37

38

39

40

41

42#define SH_PREFIX filehash

43#define SH_ELEMENT_TYPE file_entry_t

44#define SH_KEY_TYPE const char *

45#define SH_KEY path

46#define SH_HASH_KEY(tb, key) hash_string(key)

47#define SH_EQUAL(tb, a, b) (strcmp(a, b) == 0)

48#define SH_SCOPE static inline

49#define SH_RAW_ALLOCATOR pg_malloc0

50#define SH_DECLARE

51#define SH_DEFINE

53

54#define FILEHASH_INITIAL_SIZE 1000

55

57

61

64

65

66

67

69{

73

74#define SH_PREFIX keepwal

75#define SH_ELEMENT_TYPE keepwal_entry

76#define SH_KEY_TYPE const char *

77#define SH_KEY path

78#define SH_HASH_KEY(tb, key) hash_string(key)

79#define SH_EQUAL(tb, a, b) (strcmp(a, b) == 0)

80#define SH_SCOPE static inline

81#define SH_RAW_ALLOCATOR pg_malloc0

82#define SH_DECLARE

83#define SH_DEFINE

85

86#define KEEPWAL_INITIAL_SIZE 1000

87

88

89static keepwal_hash *keepwal = NULL;

91

93

95

96

97

98

99

100

101

103{

104 const char *name;

106};

107

108

109

110

111

112

113

114

115

116

118{

119

120

121

122

123 "pg_stat_tmp",

124

125

126

127

128

129

130 "pg_replslot",

131

132

133 "pg_dynshmem",

134

135

136 "pg_notify",

137

138

139

140

141

142 "pg_serial",

143

144

145 "pg_snapshots",

146

147

148 "pg_subtrans",

149

150

151 NULL

152};

153

154

155

156

157

159{

160

161 {"postgresql.auto.conf.tmp", false},

162

163

164 {"current_logfiles.tmp", false},

165

166

167

168 {"pg_internal.init", true},

169

170

171

172

173

174

175 {"backup_label", false},

176 {"tablespace_map", false},

177

178

179

180

181

182

183

184 {"backup_manifest", false},

185

186 {"postmaster.pid", false},

187 {"postmaster.opts", false},

188

189

190 {NULL, false}

191};

192

193

194

195

196void

198{

200}

201

202

205{

207 bool found;

208

209 entry = filehash_insert(filehash, path, &found);

210 if (!found)

211 {

214

221

226

228 }

229

230 return entry;

231}

232

235{

236 return filehash_lookup(filehash, path);

237}

238

239

240

241

242void

244{

245

247}

248

249

250void

252{

254 bool found;

255

256

258

259 entry = keepwal_insert(keepwal, path, &found);

260

261 if (!found)

263}

264

265

266static bool

268{

269 return keepwal_lookup(keepwal, path) != NULL;

270}

271

272

273

274

275

276

277

278

279void

281 const char *link_target)

282{

284

285

286

287

288

289

292

293

294

295

296

298 pg_fatal("data file \"%s\" in source is not a regular file", path);

299

300

303 pg_fatal("duplicate source file \"%s\"", path);

308}

309

310

311

312

313

314

315void

317 const char *link_target)

318{

320

321

322

323

324

325

326

327

328

329

332

333

336 pg_fatal("duplicate source file \"%s\"", path);

341}

342

343

344

345

346

347

348

349

350

351

352void

355{

356 char *path;

359 int segno;

360

361 segno = blkno / RELSEG_SIZE;

362 blkno_inseg = blkno % RELSEG_SIZE;

363

364 path = datasegpath(rlocator, forknum, segno);

367

368

369

370

371

372

373

374

375

376

377

378

379

380

381

382

383

384 if (entry)

385 {

387

389 {

391 pg_fatal("unexpected page modification for non-regular file \"%s\"",

392 entry->path);

393

395 {

396 off_t end_offset;

397

398 end_offset = (blkno_inseg + 1) * BLCKSZ;

399 if (end_offset <= entry->source_size && end_offset <= entry->target_size)

401 }

402 }

403 }

404}

405

406

407

408

409static bool

411{

413 int excludeIdx;

415

416

417

418

421 {

422 return true;

423 }

424

425

426 for (excludeIdx = 0; excludeFiles[excludeIdx].name != NULL; excludeIdx++)

427 {

429

433 else

435

437 cmplen++;

439 {

440 if (is_source)

441 pg_log_debug("entry \"%s\" excluded from source file list",

442 path);

443 else

444 pg_log_debug("entry \"%s\" excluded from target file list",

445 path);

446 return true;

447 }

448 }

449

450

451

452

453

454 for (excludeIdx = 0; excludeDirContents[excludeIdx] != NULL; excludeIdx++)

455 {

456 snprintf(localpath, sizeof(localpath), "%s/",

458 if (strstr(path, localpath) == path)

459 {

460 if (is_source)

461 pg_log_debug("entry \"%s\" excluded from source file list",

462 path);

463 else

464 pg_log_debug("entry \"%s\" excluded from target file list",

465 path);

466 return true;

467 }

468 }

469

470 return false;

471}

472

473static const char *

475{

477 {

479 return "NONE";

481 return "COPY";

483 return "TRUNCATE";

485 return "COPY_TAIL";

487 return "CREATE";

489 return "REMOVE";

490

491 default:

492 return "unknown";

493 }

494}

495

496

497

498

499void

501{

503 int i;

504

507

509 {

511

513 continue;

514

516

518 {

520 continue;

521 }

522

525

527 {

530

534

536 }

537 }

538}

539

540void

542{

544 int i;

545

547 {

549

553 {

556

559 }

560 }

562}

563

564

565

566

569{

571 unsigned int segNo;

572 int nmatch;

574

575

576 if (strncmp("pg_wal/", path, 7) == 0)

577 {

578 const char *filename = path + 7;

579

582 else

584 }

585

586

587

588

589

590

591

592

593

594

595

596

597

598

599

600

601

602

603

604

605

606

607

608

609

610

611

615 segNo = 0;

617

618 nmatch = sscanf(path, "global/%u.%u", &rlocator.relNumber, &segNo);

619 if (nmatch == 1 || nmatch == 2)

620 {

621 rlocator.spcOid = GLOBALTABLESPACE_OID;

622 rlocator.dbOid = 0;

624 }

625 else

626 {

627 nmatch = sscanf(path, "base/%u/%u.%u",

629 if (nmatch == 2 || nmatch == 3)

630 {

631 rlocator.spcOid = DEFAULTTABLESPACE_OID;

633 }

634 else

635 {

638 &segNo);

639 if (nmatch == 3 || nmatch == 4)

641 }

642 }

643

644

645

646

647

648

649

651 {

653

654 if (strcmp(check_path, path) != 0)

656

657 pfree(check_path);

658 }

659

660 return result;

661}

662

663

664

665

666

667

668static char *

670{

672 char *segpath;

673

675 if (segno > 0)

676 {

677 segpath = psprintf("%s.%u", path.str, segno);

678 return segpath;

679 }

680 else

682}

683

684

685

686

687

688

689

690

691

692

693

694static int

696{

699

700 if (fa->action > fb->action)

701 return 1;

702 if (fa->action < fb->action)

703 return -1;

704

706 return strcmp(fb->path, fa->path);

707 else

708 return strcmp(fa->path, fb->path);

709}

710

711

712

713

714

715

716

717

720 size_t source_size, size_t target_size)

721{

724

725

727

728

729

730

731

732

733

734

735

736

737

738 if (file_segno < last_common_segno &&

739 source_size == target_size)

741

743}

744

745

746

747

750{

751 const char *path = entry->path;

752

753

754

755

756

759

760

761 if (strstr(path, ".DS_Store") != NULL)

763

764

765

766

768 {

771 else

773 }

774

775

776

777

779 {

780

781

782

783

784

786 {

793 pg_fatal("unknown file type for \"%s\"", entry->path);

794 break;

795 }

796 }

798 {

799

800

801

802

804 {

805 pg_log_debug("Not removing file \"%s\" because it is required for recovery", path);

807 }

809 }

811 {

812

813

814

815

818 }

819

820

821

822

824

826 {

827

828 pg_fatal("file \"%s\" is of different type in source and target", entry->path);

829 }

830

831

832

833

834

837

839 {

842

844

845

846

847

849

852 {

853

855

858 else

859 filename++;

860

864 }

866 {

867

868

869

870

872 }

873 else

874 {

875

876

877

878

879

880

881

882

883

884

885

886

887

888

889

890

891

892

893

894

895

896

897

898

903 else

905 }

906 break;

907

909 pg_fatal("unknown file type for \"%s\"", path);

910 break;

911 }

912

913

914 pg_fatal("could not decide what to do with file \"%s\"", path);

915}

916

917

918

919

920

921

922

925{

926 int i;

927 filehash_iterator it;

930

931 filehash_start_iterate(filehash, &it);

932 while ((entry = filehash_iterate(filehash, &it)) != NULL)

933 {

935 }

936

937

938

939

940

944 filehash_start_iterate(filehash, &it);

945 i = 0;

946 while ((entry = filehash_iterate(filehash, &it)) != NULL)

947 {

948 filemap->entries[i++] = entry;

949 }

950

953

954 return filemap;

955}

bool datapagemap_next(datapagemap_iterator_t *iter, BlockNumber *blkno)

void datapagemap_print(datapagemap_t *map)

datapagemap_iterator_t * datapagemap_iterate(datapagemap_t *map)

void datapagemap_add(datapagemap_t *map, BlockNumber blkno)

void * pg_malloc(size_t size)

char * pg_strdup(const char *in)

#define PG_TEMP_FILES_DIR

#define PG_TEMP_FILE_PREFIX

static const struct exclude_list_item excludeFiles[]

struct keepwal_entry keepwal_entry

static bool keepwal_entry_exists(const char *path)

static const char * action_to_str(file_action_t action)

void process_source_file(const char *path, file_type_t type, size_t size, const char *link_target)

static const char *const excludeDirContents[]

void print_filemap(filemap_t *filemap)

static char * datasegpath(RelFileLocator rlocator, ForkNumber forknum, BlockNumber segno)

static file_action_t decide_file_action(file_entry_t *entry, XLogSegNo last_common_segno)

static filehash_hash * filehash

void process_target_file(const char *path, file_type_t type, size_t size, const char *link_target)

void process_target_wal_block_change(ForkNumber forknum, RelFileLocator rlocator, BlockNumber blkno)

void keepwal_add_entry(const char *path)

static file_action_t decide_wal_file_action(const char *fname, XLogSegNo last_common_segno, size_t source_size, size_t target_size)

static keepwal_hash * keepwal

static file_entry_t * lookup_filehash_entry(const char *path)

#define KEEPWAL_INITIAL_SIZE

static file_entry_t * insert_filehash_entry(const char *path)

static bool check_file_excluded(const char *path, bool is_source)

#define FILEHASH_INITIAL_SIZE

static int final_filemap_cmp(const void *a, const void *b)

void calculate_totals(filemap_t *filemap)

filemap_t * decide_file_actions(XLogSegNo last_common_segno)

static file_content_type_t getFileContentType(const char *path)

@ FILE_CONTENT_TYPE_OTHER

@ FILE_CONTENT_TYPE_RELATION

Assert(PointerIsAligned(start, uint64))

#define pg_log_debug(...)

char * pstrdup(const char *in)

void pfree(void *pointer)

char * last_dir_separator(const char *filename)

#define qsort(a, b, c, d)

char * psprintf(const char *fmt,...)

#define InvalidRelFileNumber

#define relpathperm(rlocator, forknum)

#define TABLESPACE_VERSION_DIRECTORY

bool pg_str_endswith(const char *str, const char *end)

char str[REL_PATH_STR_MAXLEN+1]

datapagemap_t target_pages_to_overwrite

char * source_link_target

file_content_type_t content_type

char * target_link_target

file_entry_t * entries[FLEXIBLE_ARRAY_MEMBER]

#define XLOG_CONTROL_FILE

static bool IsXLogFileName(const char *fname)

static void XLogFromFileName(const char *fname, TimeLineID *tli, XLogSegNo *logSegNo, int wal_segsz_bytes)