00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "postgres.h"
00016
00017 #include <sys/types.h>
00018 #include <sys/stat.h>
00019 #include <sys/wait.h>
00020 #include <signal.h>
00021 #include <unistd.h>
00022
00023 #include "access/xlog.h"
00024 #include "access/xlog_internal.h"
00025 #include "miscadmin.h"
00026 #include "postmaster/startup.h"
00027 #include "replication/walsender.h"
00028 #include "storage/fd.h"
00029 #include "storage/ipc.h"
00030 #include "storage/lwlock.h"
00031 #include "storage/pmsignal.h"
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051 bool
00052 RestoreArchivedFile(char *path, const char *xlogfname,
00053 const char *recovername, off_t expectedSize,
00054 bool cleanupEnabled)
00055 {
00056 char xlogpath[MAXPGPATH];
00057 char xlogRestoreCmd[MAXPGPATH];
00058 char lastRestartPointFname[MAXPGPATH];
00059 char *dp;
00060 char *endp;
00061 const char *sp;
00062 int rc;
00063 bool signaled;
00064 struct stat stat_buf;
00065 XLogSegNo restartSegNo;
00066 XLogRecPtr restartRedoPtr;
00067 TimeLineID restartTli;
00068
00069
00070 if (recoveryRestoreCommand == NULL)
00071 goto not_available;
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096 snprintf(xlogpath, MAXPGPATH, XLOGDIR "/%s", recovername);
00097
00098
00099
00100
00101 if (stat(xlogpath, &stat_buf) != 0)
00102 {
00103 if (errno != ENOENT)
00104 ereport(FATAL,
00105 (errcode_for_file_access(),
00106 errmsg("could not stat file \"%s\": %m",
00107 xlogpath)));
00108 }
00109 else
00110 {
00111 if (unlink(xlogpath) != 0)
00112 ereport(FATAL,
00113 (errcode_for_file_access(),
00114 errmsg("could not remove file \"%s\": %m",
00115 xlogpath)));
00116 }
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135 if (cleanupEnabled)
00136 {
00137 GetOldestRestartPoint(&restartRedoPtr, &restartTli);
00138 XLByteToSeg(restartRedoPtr, restartSegNo);
00139 XLogFileName(lastRestartPointFname, restartTli, restartSegNo);
00140
00141 Assert(strcmp(lastRestartPointFname, xlogfname) <= 0);
00142 }
00143 else
00144 XLogFileName(lastRestartPointFname, 0, 0L);
00145
00146
00147
00148
00149 dp = xlogRestoreCmd;
00150 endp = xlogRestoreCmd + MAXPGPATH - 1;
00151 *endp = '\0';
00152
00153 for (sp = recoveryRestoreCommand; *sp; sp++)
00154 {
00155 if (*sp == '%')
00156 {
00157 switch (sp[1])
00158 {
00159 case 'p':
00160
00161 sp++;
00162 StrNCpy(dp, xlogpath, endp - dp);
00163 make_native_path(dp);
00164 dp += strlen(dp);
00165 break;
00166 case 'f':
00167
00168 sp++;
00169 StrNCpy(dp, xlogfname, endp - dp);
00170 dp += strlen(dp);
00171 break;
00172 case 'r':
00173
00174 sp++;
00175 StrNCpy(dp, lastRestartPointFname, endp - dp);
00176 dp += strlen(dp);
00177 break;
00178 case '%':
00179
00180 sp++;
00181 if (dp < endp)
00182 *dp++ = *sp;
00183 break;
00184 default:
00185
00186 if (dp < endp)
00187 *dp++ = *sp;
00188 break;
00189 }
00190 }
00191 else
00192 {
00193 if (dp < endp)
00194 *dp++ = *sp;
00195 }
00196 }
00197 *dp = '\0';
00198
00199 ereport(DEBUG3,
00200 (errmsg_internal("executing restore command \"%s\"",
00201 xlogRestoreCmd)));
00202
00203
00204
00205
00206 PreRestoreCommand();
00207
00208
00209
00210
00211 rc = system(xlogRestoreCmd);
00212
00213 PostRestoreCommand();
00214
00215 if (rc == 0)
00216 {
00217
00218
00219
00220
00221 if (stat(xlogpath, &stat_buf) == 0)
00222 {
00223 if (expectedSize > 0 && stat_buf.st_size != expectedSize)
00224 {
00225 int elevel;
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239 if (StandbyMode && stat_buf.st_size < expectedSize)
00240 elevel = DEBUG1;
00241 else
00242 elevel = FATAL;
00243 ereport(elevel,
00244 (errmsg("archive file \"%s\" has wrong size: %lu instead of %lu",
00245 xlogfname,
00246 (unsigned long) stat_buf.st_size,
00247 (unsigned long) expectedSize)));
00248 return false;
00249 }
00250 else
00251 {
00252 ereport(LOG,
00253 (errmsg("restored log file \"%s\" from archive",
00254 xlogfname)));
00255 strcpy(path, xlogpath);
00256 return true;
00257 }
00258 }
00259 else
00260 {
00261
00262 if (errno != ENOENT)
00263 ereport(FATAL,
00264 (errcode_for_file_access(),
00265 errmsg("could not stat file \"%s\": %m",
00266 xlogpath)));
00267 }
00268 }
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297 if (WIFSIGNALED(rc) && WTERMSIG(rc) == SIGTERM)
00298 proc_exit(1);
00299
00300 signaled = WIFSIGNALED(rc) || WEXITSTATUS(rc) > 125;
00301
00302 ereport(signaled ? FATAL : DEBUG2,
00303 (errmsg("could not restore file \"%s\" from archive: return code %d",
00304 xlogfname, rc)));
00305
00306 not_available:
00307
00308
00309
00310
00311
00312
00313
00314
00315 snprintf(path, MAXPGPATH, XLOGDIR "/%s", xlogfname);
00316 return false;
00317 }
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329 void
00330 ExecuteRecoveryCommand(char *command, char *commandName, bool failOnSignal)
00331 {
00332 char xlogRecoveryCmd[MAXPGPATH];
00333 char lastRestartPointFname[MAXPGPATH];
00334 char *dp;
00335 char *endp;
00336 const char *sp;
00337 int rc;
00338 bool signaled;
00339 XLogSegNo restartSegNo;
00340 XLogRecPtr restartRedoPtr;
00341 TimeLineID restartTli;
00342
00343 Assert(command && commandName);
00344
00345
00346
00347
00348
00349
00350 GetOldestRestartPoint(&restartRedoPtr, &restartTli);
00351 XLByteToSeg(restartRedoPtr, restartSegNo);
00352 XLogFileName(lastRestartPointFname, restartTli, restartSegNo);
00353
00354
00355
00356
00357 dp = xlogRecoveryCmd;
00358 endp = xlogRecoveryCmd + MAXPGPATH - 1;
00359 *endp = '\0';
00360
00361 for (sp = command; *sp; sp++)
00362 {
00363 if (*sp == '%')
00364 {
00365 switch (sp[1])
00366 {
00367 case 'r':
00368
00369 sp++;
00370 StrNCpy(dp, lastRestartPointFname, endp - dp);
00371 dp += strlen(dp);
00372 break;
00373 case '%':
00374
00375 sp++;
00376 if (dp < endp)
00377 *dp++ = *sp;
00378 break;
00379 default:
00380
00381 if (dp < endp)
00382 *dp++ = *sp;
00383 break;
00384 }
00385 }
00386 else
00387 {
00388 if (dp < endp)
00389 *dp++ = *sp;
00390 }
00391 }
00392 *dp = '\0';
00393
00394 ereport(DEBUG3,
00395 (errmsg_internal("executing %s \"%s\"", commandName, command)));
00396
00397
00398
00399
00400 rc = system(xlogRecoveryCmd);
00401 if (rc != 0)
00402 {
00403
00404
00405
00406
00407
00408 signaled = WIFSIGNALED(rc) || WEXITSTATUS(rc) > 125;
00409
00410 ereport((signaled && failOnSignal) ? FATAL : WARNING,
00411
00412
00413
00414 (errmsg("%s \"%s\": return code %d", commandName,
00415 command, rc)));
00416 }
00417 }
00418
00419
00420
00421
00422
00423
00424
00425 void
00426 KeepFileRestoredFromArchive(char *path, char *xlogfname)
00427 {
00428 char xlogfpath[MAXPGPATH];
00429 bool reload = false;
00430 struct stat statbuf;
00431
00432 snprintf(xlogfpath, MAXPGPATH, XLOGDIR "/%s", xlogfname);
00433
00434 if (stat(xlogfpath, &statbuf) == 0)
00435 {
00436 char oldpath[MAXPGPATH];
00437 #ifdef WIN32
00438 static unsigned int deletedcounter = 1;
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450 snprintf(oldpath, MAXPGPATH, "%s.deleted%u",
00451 xlogfpath, deletedcounter++);
00452 if (rename(xlogfpath, oldpath) != 0)
00453 {
00454 ereport(ERROR,
00455 (errcode_for_file_access(),
00456 errmsg("could not rename file \"%s\" to \"%s\": %m",
00457 xlogfpath, oldpath)));
00458 }
00459 #else
00460 strncpy(oldpath, xlogfpath, MAXPGPATH);
00461 #endif
00462 if (unlink(oldpath) != 0)
00463 ereport(FATAL,
00464 (errcode_for_file_access(),
00465 errmsg("could not remove file \"%s\": %m",
00466 xlogfpath)));
00467 reload = true;
00468 }
00469
00470 if (rename(path, xlogfpath) < 0)
00471 ereport(ERROR,
00472 (errcode_for_file_access(),
00473 errmsg("could not rename file \"%s\" to \"%s\": %m",
00474 path, xlogfpath)));
00475
00476
00477
00478
00479
00480 XLogArchiveForceDone(xlogfname);
00481
00482
00483
00484
00485
00486
00487
00488
00489 if (reload)
00490 WalSndRqstFileReload();
00491
00492
00493
00494
00495
00496
00497 WalSndWakeup();
00498 }
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510 void
00511 XLogArchiveNotify(const char *xlog)
00512 {
00513 char archiveStatusPath[MAXPGPATH];
00514 FILE *fd;
00515
00516
00517 StatusFilePath(archiveStatusPath, xlog, ".ready");
00518 fd = AllocateFile(archiveStatusPath, "w");
00519 if (fd == NULL)
00520 {
00521 ereport(LOG,
00522 (errcode_for_file_access(),
00523 errmsg("could not create archive status file \"%s\": %m",
00524 archiveStatusPath)));
00525 return;
00526 }
00527 if (FreeFile(fd))
00528 {
00529 ereport(LOG,
00530 (errcode_for_file_access(),
00531 errmsg("could not write archive status file \"%s\": %m",
00532 archiveStatusPath)));
00533 return;
00534 }
00535
00536
00537 if (IsUnderPostmaster)
00538 SendPostmasterSignal(PMSIGNAL_WAKEN_ARCHIVER);
00539 }
00540
00541
00542
00543
00544 void
00545 XLogArchiveNotifySeg(XLogSegNo segno)
00546 {
00547 char xlog[MAXFNAMELEN];
00548
00549 XLogFileName(xlog, ThisTimeLineID, segno);
00550 XLogArchiveNotify(xlog);
00551 }
00552
00553
00554
00555
00556
00557
00558
00559
00560 void
00561 XLogArchiveForceDone(const char *xlog)
00562 {
00563 char archiveReady[MAXPGPATH];
00564 char archiveDone[MAXPGPATH];
00565 struct stat stat_buf;
00566 FILE *fd;
00567
00568
00569 StatusFilePath(archiveDone, xlog, ".done");
00570 if (stat(archiveDone, &stat_buf) == 0)
00571 return;
00572
00573
00574 StatusFilePath(archiveReady, xlog, ".ready");
00575 if (stat(archiveReady, &stat_buf) == 0)
00576 {
00577 if (rename(archiveReady, archiveDone) < 0)
00578 ereport(WARNING,
00579 (errcode_for_file_access(),
00580 errmsg("could not rename file \"%s\" to \"%s\": %m",
00581 archiveReady, archiveDone)));
00582
00583 return;
00584 }
00585
00586
00587 fd = AllocateFile(archiveDone, "w");
00588 if (fd == NULL)
00589 {
00590 ereport(LOG,
00591 (errcode_for_file_access(),
00592 errmsg("could not create archive status file \"%s\": %m",
00593 archiveDone)));
00594 return;
00595 }
00596 if (FreeFile(fd))
00597 {
00598 ereport(LOG,
00599 (errcode_for_file_access(),
00600 errmsg("could not write archive status file \"%s\": %m",
00601 archiveDone)));
00602 return;
00603 }
00604 }
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620 bool
00621 XLogArchiveCheckDone(const char *xlog)
00622 {
00623 char archiveStatusPath[MAXPGPATH];
00624 struct stat stat_buf;
00625
00626
00627 if (!XLogArchivingActive())
00628 return true;
00629
00630
00631 StatusFilePath(archiveStatusPath, xlog, ".done");
00632 if (stat(archiveStatusPath, &stat_buf) == 0)
00633 return true;
00634
00635
00636 StatusFilePath(archiveStatusPath, xlog, ".ready");
00637 if (stat(archiveStatusPath, &stat_buf) == 0)
00638 return false;
00639
00640
00641 StatusFilePath(archiveStatusPath, xlog, ".done");
00642 if (stat(archiveStatusPath, &stat_buf) == 0)
00643 return true;
00644
00645
00646 XLogArchiveNotify(xlog);
00647 return false;
00648 }
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660 bool
00661 XLogArchiveIsBusy(const char *xlog)
00662 {
00663 char archiveStatusPath[MAXPGPATH];
00664 struct stat stat_buf;
00665
00666
00667 StatusFilePath(archiveStatusPath, xlog, ".done");
00668 if (stat(archiveStatusPath, &stat_buf) == 0)
00669 return false;
00670
00671
00672 StatusFilePath(archiveStatusPath, xlog, ".ready");
00673 if (stat(archiveStatusPath, &stat_buf) == 0)
00674 return true;
00675
00676
00677 StatusFilePath(archiveStatusPath, xlog, ".done");
00678 if (stat(archiveStatusPath, &stat_buf) == 0)
00679 return false;
00680
00681
00682
00683
00684
00685
00686 snprintf(archiveStatusPath, MAXPGPATH, XLOGDIR "/%s", xlog);
00687 if (stat(archiveStatusPath, &stat_buf) != 0 &&
00688 errno == ENOENT)
00689 return false;
00690
00691 return true;
00692 }
00693
00694
00695
00696
00697
00698
00699 void
00700 XLogArchiveCleanup(const char *xlog)
00701 {
00702 char archiveStatusPath[MAXPGPATH];
00703
00704
00705 StatusFilePath(archiveStatusPath, xlog, ".done");
00706 unlink(archiveStatusPath);
00707
00708
00709
00710 StatusFilePath(archiveStatusPath, xlog, ".ready");
00711 unlink(archiveStatusPath);
00712
00713 }