00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include "postgres.h"
00033
00034 #include <sys/stat.h>
00035 #include <stdio.h>
00036 #include <unistd.h>
00037
00038 #include "access/timeline.h"
00039 #include "access/xlog_internal.h"
00040 #include "access/xlogdefs.h"
00041 #include "storage/fd.h"
00042
00043
00044
00045
00046
00047 void
00048 restoreTimeLineHistoryFiles(TimeLineID begin, TimeLineID end)
00049 {
00050 char path[MAXPGPATH];
00051 char histfname[MAXFNAMELEN];
00052 TimeLineID tli;
00053
00054 for (tli = begin; tli < end; tli++)
00055 {
00056 if (tli == 1)
00057 continue;
00058
00059 TLHistoryFileName(histfname, tli);
00060 if (RestoreArchivedFile(path, histfname, "RECOVERYHISTORY", 0, false))
00061 KeepFileRestoredFromArchive(path, histfname);
00062 }
00063 }
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073 List *
00074 readTimeLineHistory(TimeLineID targetTLI)
00075 {
00076 List *result;
00077 char path[MAXPGPATH];
00078 char histfname[MAXFNAMELEN];
00079 char fline[MAXPGPATH];
00080 FILE *fd;
00081 TimeLineHistoryEntry *entry;
00082 TimeLineID lasttli = 0;
00083 XLogRecPtr prevend;
00084 bool fromArchive = false;
00085
00086
00087 if (targetTLI == 1)
00088 {
00089 entry = (TimeLineHistoryEntry *) palloc(sizeof(TimeLineHistoryEntry));
00090 entry->tli = targetTLI;
00091 entry->begin = entry->end = InvalidXLogRecPtr;
00092 return list_make1(entry);
00093 }
00094
00095 if (ArchiveRecoveryRequested)
00096 {
00097 TLHistoryFileName(histfname, targetTLI);
00098 fromArchive =
00099 RestoreArchivedFile(path, histfname, "RECOVERYHISTORY", 0, false);
00100 }
00101 else
00102 TLHistoryFilePath(path, targetTLI);
00103
00104 fd = AllocateFile(path, "r");
00105 if (fd == NULL)
00106 {
00107 if (errno != ENOENT)
00108 ereport(FATAL,
00109 (errcode_for_file_access(),
00110 errmsg("could not open file \"%s\": %m", path)));
00111
00112 entry = (TimeLineHistoryEntry *) palloc(sizeof(TimeLineHistoryEntry));
00113 entry->tli = targetTLI;
00114 entry->begin = entry->end = InvalidXLogRecPtr;
00115 return list_make1(entry);
00116 }
00117
00118 result = NIL;
00119
00120
00121
00122
00123 prevend = InvalidXLogRecPtr;
00124 while (fgets(fline, sizeof(fline), fd) != NULL)
00125 {
00126
00127 char *ptr;
00128 TimeLineID tli;
00129 uint32 switchpoint_hi;
00130 uint32 switchpoint_lo;
00131 int nfields;
00132
00133 for (ptr = fline; *ptr; ptr++)
00134 {
00135 if (!isspace((unsigned char) *ptr))
00136 break;
00137 }
00138 if (*ptr == '\0' || *ptr == '#')
00139 continue;
00140
00141 nfields = sscanf(fline, "%u\t%X/%X", &tli, &switchpoint_hi, &switchpoint_lo);
00142
00143 if (nfields < 1)
00144 {
00145
00146 ereport(FATAL,
00147 (errmsg("syntax error in history file: %s", fline),
00148 errhint("Expected a numeric timeline ID.")));
00149 }
00150 if (nfields != 3)
00151 ereport(FATAL,
00152 (errmsg("syntax error in history file: %s", fline),
00153 errhint("Expected an XLOG switchpoint location.")));
00154
00155 if (result && tli <= lasttli)
00156 ereport(FATAL,
00157 (errmsg("invalid data in history file: %s", fline),
00158 errhint("Timeline IDs must be in increasing sequence.")));
00159
00160 lasttli = tli;
00161
00162 entry = (TimeLineHistoryEntry *) palloc(sizeof(TimeLineHistoryEntry));
00163 entry->tli = tli;
00164 entry->begin = prevend;
00165 entry->end = ((uint64) (switchpoint_hi)) << 32 | (uint64) switchpoint_lo;
00166 prevend = entry->end;
00167
00168
00169 result = lcons(entry, result);
00170
00171
00172 }
00173
00174 FreeFile(fd);
00175
00176 if (result && targetTLI <= lasttli)
00177 ereport(FATAL,
00178 (errmsg("invalid data in history file \"%s\"", path),
00179 errhint("Timeline IDs must be less than child timeline's ID.")));
00180
00181
00182
00183
00184
00185 entry = (TimeLineHistoryEntry *) palloc(sizeof(TimeLineHistoryEntry));
00186 entry->tli = targetTLI;
00187 entry->begin = prevend;
00188 entry->end = InvalidXLogRecPtr;
00189
00190 result = lcons(entry, result);
00191
00192
00193
00194
00195
00196 if (fromArchive)
00197 KeepFileRestoredFromArchive(path, histfname);
00198
00199 return result;
00200 }
00201
00202
00203
00204
00205 bool
00206 existsTimeLineHistory(TimeLineID probeTLI)
00207 {
00208 char path[MAXPGPATH];
00209 char histfname[MAXFNAMELEN];
00210 FILE *fd;
00211
00212
00213 if (probeTLI == 1)
00214 return false;
00215
00216 if (ArchiveRecoveryRequested)
00217 {
00218 TLHistoryFileName(histfname, probeTLI);
00219 RestoreArchivedFile(path, histfname, "RECOVERYHISTORY", 0, false);
00220 }
00221 else
00222 TLHistoryFilePath(path, probeTLI);
00223
00224 fd = AllocateFile(path, "r");
00225 if (fd != NULL)
00226 {
00227 FreeFile(fd);
00228 return true;
00229 }
00230 else
00231 {
00232 if (errno != ENOENT)
00233 ereport(FATAL,
00234 (errcode_for_file_access(),
00235 errmsg("could not open file \"%s\": %m", path)));
00236 return false;
00237 }
00238 }
00239
00240
00241
00242
00243
00244
00245
00246
00247 TimeLineID
00248 findNewestTimeLine(TimeLineID startTLI)
00249 {
00250 TimeLineID newestTLI;
00251 TimeLineID probeTLI;
00252
00253
00254
00255
00256
00257 newestTLI = startTLI;
00258
00259 for (probeTLI = startTLI + 1;; probeTLI++)
00260 {
00261 if (existsTimeLineHistory(probeTLI))
00262 {
00263 newestTLI = probeTLI;
00264 }
00265 else
00266 {
00267
00268 break;
00269 }
00270 }
00271
00272 return newestTLI;
00273 }
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287 void
00288 writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI,
00289 XLogRecPtr switchpoint, char *reason)
00290 {
00291 char path[MAXPGPATH];
00292 char tmppath[MAXPGPATH];
00293 char histfname[MAXFNAMELEN];
00294 char buffer[BLCKSZ];
00295 int srcfd;
00296 int fd;
00297 int nbytes;
00298
00299 Assert(newTLI > parentTLI);
00300
00301
00302
00303
00304 snprintf(tmppath, MAXPGPATH, XLOGDIR "/xlogtemp.%d", (int) getpid());
00305
00306 unlink(tmppath);
00307
00308
00309 fd = OpenTransientFile(tmppath, O_RDWR | O_CREAT | O_EXCL,
00310 S_IRUSR | S_IWUSR);
00311 if (fd < 0)
00312 ereport(ERROR,
00313 (errcode_for_file_access(),
00314 errmsg("could not create file \"%s\": %m", tmppath)));
00315
00316
00317
00318
00319 if (ArchiveRecoveryRequested)
00320 {
00321 TLHistoryFileName(histfname, parentTLI);
00322 RestoreArchivedFile(path, histfname, "RECOVERYHISTORY", 0, false);
00323 }
00324 else
00325 TLHistoryFilePath(path, parentTLI);
00326
00327 srcfd = OpenTransientFile(path, O_RDONLY, 0);
00328 if (srcfd < 0)
00329 {
00330 if (errno != ENOENT)
00331 ereport(ERROR,
00332 (errcode_for_file_access(),
00333 errmsg("could not open file \"%s\": %m", path)));
00334
00335 }
00336 else
00337 {
00338 for (;;)
00339 {
00340 errno = 0;
00341 nbytes = (int) read(srcfd, buffer, sizeof(buffer));
00342 if (nbytes < 0 || errno != 0)
00343 ereport(ERROR,
00344 (errcode_for_file_access(),
00345 errmsg("could not read file \"%s\": %m", path)));
00346 if (nbytes == 0)
00347 break;
00348 errno = 0;
00349 if ((int) write(fd, buffer, nbytes) != nbytes)
00350 {
00351 int save_errno = errno;
00352
00353
00354
00355
00356
00357 unlink(tmppath);
00358
00359
00360
00361
00362 errno = save_errno ? save_errno : ENOSPC;
00363
00364 ereport(ERROR,
00365 (errcode_for_file_access(),
00366 errmsg("could not write to file \"%s\": %m", tmppath)));
00367 }
00368 }
00369 CloseTransientFile(srcfd);
00370 }
00371
00372
00373
00374
00375
00376
00377
00378 snprintf(buffer, sizeof(buffer),
00379 "%s%u\t%X/%X\t%s\n",
00380 (srcfd < 0) ? "" : "\n",
00381 parentTLI,
00382 (uint32) (switchpoint >> 32), (uint32) (switchpoint),
00383 reason);
00384
00385 nbytes = strlen(buffer);
00386 errno = 0;
00387 if ((int) write(fd, buffer, nbytes) != nbytes)
00388 {
00389 int save_errno = errno;
00390
00391
00392
00393
00394 unlink(tmppath);
00395
00396 errno = save_errno ? save_errno : ENOSPC;
00397
00398 ereport(ERROR,
00399 (errcode_for_file_access(),
00400 errmsg("could not write to file \"%s\": %m", tmppath)));
00401 }
00402
00403 if (pg_fsync(fd) != 0)
00404 ereport(ERROR,
00405 (errcode_for_file_access(),
00406 errmsg("could not fsync file \"%s\": %m", tmppath)));
00407
00408 if (CloseTransientFile(fd))
00409 ereport(ERROR,
00410 (errcode_for_file_access(),
00411 errmsg("could not close file \"%s\": %m", tmppath)));
00412
00413
00414
00415
00416
00417 TLHistoryFilePath(path, newTLI);
00418
00419
00420
00421
00422
00423
00424 #if HAVE_WORKING_LINK
00425 if (link(tmppath, path) < 0)
00426 ereport(ERROR,
00427 (errcode_for_file_access(),
00428 errmsg("could not link file \"%s\" to \"%s\": %m",
00429 tmppath, path)));
00430 unlink(tmppath);
00431 #else
00432 if (rename(tmppath, path) < 0)
00433 ereport(ERROR,
00434 (errcode_for_file_access(),
00435 errmsg("could not rename file \"%s\" to \"%s\": %m",
00436 tmppath, path)));
00437 #endif
00438
00439
00440 TLHistoryFileName(histfname, newTLI);
00441 XLogArchiveNotify(histfname);
00442 }
00443
00444
00445
00446
00447
00448
00449
00450
00451 void
00452 writeTimeLineHistoryFile(TimeLineID tli, char *content, int size)
00453 {
00454 char path[MAXPGPATH];
00455 char tmppath[MAXPGPATH];
00456 int fd;
00457
00458
00459
00460
00461 snprintf(tmppath, MAXPGPATH, XLOGDIR "/xlogtemp.%d", (int) getpid());
00462
00463 unlink(tmppath);
00464
00465
00466 fd = OpenTransientFile(tmppath, O_RDWR | O_CREAT | O_EXCL,
00467 S_IRUSR | S_IWUSR);
00468 if (fd < 0)
00469 ereport(ERROR,
00470 (errcode_for_file_access(),
00471 errmsg("could not create file \"%s\": %m", tmppath)));
00472
00473 errno = 0;
00474 if ((int) write(fd, content, size) != size)
00475 {
00476 int save_errno = errno;
00477
00478
00479
00480
00481 unlink(tmppath);
00482
00483 errno = save_errno ? save_errno : ENOSPC;
00484
00485 ereport(ERROR,
00486 (errcode_for_file_access(),
00487 errmsg("could not write to file \"%s\": %m", tmppath)));
00488 }
00489
00490 if (pg_fsync(fd) != 0)
00491 ereport(ERROR,
00492 (errcode_for_file_access(),
00493 errmsg("could not fsync file \"%s\": %m", tmppath)));
00494
00495 if (CloseTransientFile(fd))
00496 ereport(ERROR,
00497 (errcode_for_file_access(),
00498 errmsg("could not close file \"%s\": %m", tmppath)));
00499
00500
00501
00502
00503
00504 TLHistoryFilePath(path, tli);
00505
00506
00507
00508
00509
00510
00511 #if HAVE_WORKING_LINK
00512 if (link(tmppath, path) < 0)
00513 ereport(ERROR,
00514 (errcode_for_file_access(),
00515 errmsg("could not link file \"%s\" to \"%s\": %m",
00516 tmppath, path)));
00517 unlink(tmppath);
00518 #else
00519 if (rename(tmppath, path) < 0)
00520 ereport(ERROR,
00521 (errcode_for_file_access(),
00522 errmsg("could not rename file \"%s\" to \"%s\": %m",
00523 tmppath, path)));
00524 #endif
00525 }
00526
00527
00528
00529
00530 bool
00531 tliInHistory(TimeLineID tli, List *expectedTLEs)
00532 {
00533 ListCell *cell;
00534
00535 foreach(cell, expectedTLEs)
00536 {
00537 if (((TimeLineHistoryEntry *) lfirst(cell))->tli == tli)
00538 return true;
00539 }
00540
00541 return false;
00542 }
00543
00544
00545
00546
00547
00548 TimeLineID
00549 tliOfPointInHistory(XLogRecPtr ptr, List *history)
00550 {
00551 ListCell *cell;
00552
00553 foreach(cell, history)
00554 {
00555 TimeLineHistoryEntry *tle = (TimeLineHistoryEntry *) lfirst(cell);
00556 if ((XLogRecPtrIsInvalid(tle->begin) || tle->begin <= ptr) &&
00557 (XLogRecPtrIsInvalid(tle->end) || ptr < tle->end))
00558 {
00559
00560 return tle->tli;
00561 }
00562 }
00563
00564
00565 elog(ERROR, "timeline history was not contiguous");
00566 return 0;
00567 }
00568
00569
00570
00571
00572
00573
00574
00575 XLogRecPtr
00576 tliSwitchPoint(TimeLineID tli, List *history, TimeLineID *nextTLI)
00577 {
00578 ListCell *cell;
00579
00580 if (nextTLI)
00581 *nextTLI = 0;
00582 foreach (cell, history)
00583 {
00584 TimeLineHistoryEntry *tle = (TimeLineHistoryEntry *) lfirst(cell);
00585
00586 if (tle->tli == tli)
00587 return tle->end;
00588 if (nextTLI)
00589 *nextTLI = tle->tli;
00590 }
00591
00592 ereport(ERROR,
00593 (errmsg("requested timeline %u is not in this server's history",
00594 tli)));
00595 return InvalidXLogRecPtr;
00596 }