On 24.01.2011 22:31, Magnus Hagander wrote:
On Mon, Jan 24, 2011 at 21:14, Heikki Linnakangas
<heikki.linnakan...@enterprisedb.com> wrote:
On 24.01.2011 20:22, Magnus Hagander wrote:
I can't see an explicit check for the user ttempting to do
pg_stop_backup() when there is a nonexclusive backup running? Maybe
I'm reading it wrong? The case being when a user has started a backup
with pg_basebackup but then connects and manually does a
pg_stop_backup. ISTM it drops us ina codepath that just doesn't do the
decrement, but also doesn't throw an error?
It throws an error later when it won't find backup_label. For better or
worse, it's always been like that.
Isn't that going to leave us in a broken state though? As in a
mistaken pg_stop_backup() will decrement the counter both breaking the
streaming base backup, and also possibly throwing an assert when that
one eventually wants to do it's do_pg_stop_backup()?
Umm, no. pg_stop_backup() won't decrement the counter unless there's an
exclusive backup in operation according to the exclusiveBackup flag.
Hmm, perhaps the code would be more readable if instead of the
forcePageWrites counter that counts exclusive and non-exclusive backups,
and an exclusiveBackup boolean indicating if one of the in-progress
backups is an exclusive one, we had a counter that only counts
non-exclusive backups, plus a boolean indicating if an exclusive backup
is in progress in addition to them.
Attached is a patch for that (against master branch, including only xlog.c).
--
Heikki Linnakangas
EnterpriseDB http://www.enterprisedb.com
*** a/src/backend/access/transam/xlog.c
--- b/src/backend/access/transam/xlog.c
***************
*** 60,67 ****
/* File path names (all relative to $PGDATA) */
- #define BACKUP_LABEL_FILE "backup_label"
- #define BACKUP_LABEL_OLD "backup_label.old"
#define RECOVERY_COMMAND_FILE "recovery.conf"
#define RECOVERY_COMMAND_DONE "recovery.done"
--- 60,65 ----
***************
*** 339,344 **** typedef struct XLogCtlInsert
--- 337,351 ----
char *currpos; /* current insertion point in cache */
XLogRecPtr RedoRecPtr; /* current redo point for insertions */
bool forcePageWrites; /* forcing full-page writes for PITR? */
+
+ /*
+ * exclusiveBackup is true if a backup started with pg_start_backup() is
+ * in progress, and nonExclusiveBackups is a counter indicating the number
+ * of streaming base backups currently in progress. forcePageWrites is
+ * set to true, when either of these is non-zero.
+ */
+ bool exclusiveBackup;
+ int nonExclusiveBackups;
} XLogCtlInsert;
/*
***************
*** 8352,8367 **** pg_start_backup(PG_FUNCTION_ARGS)
backupidstr = text_to_cstring(backupid);
! startpoint = do_pg_start_backup(backupidstr, fast);
snprintf(startxlogstr, sizeof(startxlogstr), "%X/%X",
startpoint.xlogid, startpoint.xrecoff);
PG_RETURN_TEXT_P(cstring_to_text(startxlogstr));
}
XLogRecPtr
! do_pg_start_backup(const char *backupidstr, bool fast)
{
XLogRecPtr checkpointloc;
XLogRecPtr startpoint;
pg_time_t stamp_time;
--- 8359,8396 ----
backupidstr = text_to_cstring(backupid);
! startpoint = do_pg_start_backup(backupidstr, fast, NULL);
snprintf(startxlogstr, sizeof(startxlogstr), "%X/%X",
startpoint.xlogid, startpoint.xrecoff);
PG_RETURN_TEXT_P(cstring_to_text(startxlogstr));
}
+ /*
+ * do_pg_start_backup is the workhorse of the user-visible pg_start_backup()
+ * function. It creates the necessary starting checkpoint and constructs the
+ * backup label file.
+ *
+ * There are two kind of backups: exclusive and non-exclusive. An exclusive
+ * backup is started with pg_start_backup(), and there can be only one active
+ * at a time. The backup label file of an exclusive backup is written to
+ * $PGDATA/backup_label, and it is removed by pg_stop_backup().
+ *
+ * A non-exclusive backup is used for the streaming base backups (see
+ * src/backend/replication/basebackup.c). The difference to exclusive backups
+ * is that the backup label file is not written to disk. Instead, its would-be
+ * contents are returned in *labelfile, and the caller is responsible for
+ * including it in the backup archive as 'backup_label'. There can be many
+ * non-exclusive backups active at the same time, and they don't conflict
+ * with an exclusive backup either.
+ *
+ * Every successfully started non-exclusive backup must be stopped by calling
+ * do_pg_stop_backup() or do_pg_abort_backup().
+ */
XLogRecPtr
! do_pg_start_backup(const char *backupidstr, bool fast, char **labelfile)
{
+ bool exclusive = (labelfile == NULL);
XLogRecPtr checkpointloc;
XLogRecPtr startpoint;
pg_time_t stamp_time;
***************
*** 8371,8381 **** do_pg_start_backup(const char *backupidstr, bool fast)
uint32 _logSeg;
struct stat stat_buf;
FILE *fp;
! if (!superuser() && !is_authenticated_user_replication_role())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! errmsg("must be superuser or replication role to run a backup")));
if (RecoveryInProgress())
ereport(ERROR,
--- 8400,8411 ----
uint32 _logSeg;
struct stat stat_buf;
FILE *fp;
+ StringInfoData labelfbuf;
! if (exclusive && !superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! errmsg("must be superuser to run a backup")));
if (RecoveryInProgress())
ereport(ERROR,
***************
*** 8389,8394 **** do_pg_start_backup(const char *backupidstr, bool fast)
--- 8419,8430 ----
errmsg("WAL level not sufficient for making an online backup"),
errhint("wal_level must be set to \"archive\" or \"hot_standby\" at server start.")));
+ if (strlen(backupidstr) > MAXPGPATH)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("backup label too long (max %d bytes)",
+ MAXPGPATH)));
+
/*
* Mark backup active in shared memory. We must do full-page WAL writes
* during an on-line backup even if not doing so at other times, because
***************
*** 8407,8420 **** do_pg_start_backup(const char *backupidstr, bool fast)
* ensure adequate interlocking against XLogInsert().
*/
LWLockAcquire(WALInsertLock, LW_EXCLUSIVE);
! if (XLogCtl->Insert.forcePageWrites)
{
! LWLockRelease(WALInsertLock);
! ereport(ERROR,
! (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
! errmsg("a backup is already in progress"),
! errhint("Run pg_stop_backup() and try again.")));
}
XLogCtl->Insert.forcePageWrites = true;
LWLockRelease(WALInsertLock);
--- 8443,8462 ----
* ensure adequate interlocking against XLogInsert().
*/
LWLockAcquire(WALInsertLock, LW_EXCLUSIVE);
! if (exclusive)
{
! if (XLogCtl->Insert.exclusiveBackup)
! {
! LWLockRelease(WALInsertLock);
! ereport(ERROR,
! (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
! errmsg("a backup is already in progress"),
! errhint("Run pg_stop_backup() and try again.")));
! }
! XLogCtl->Insert.exclusiveBackup = true;
}
+ else
+ XLogCtl->Insert.nonExclusiveBackups++;
XLogCtl->Insert.forcePageWrites = true;
LWLockRelease(WALInsertLock);
***************
*** 8432,8438 **** do_pg_start_backup(const char *backupidstr, bool fast)
RequestXLogSwitch();
/* Ensure we release forcePageWrites if fail below */
! PG_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) 0);
{
/*
* Force a CHECKPOINT. Aside from being necessary to prevent torn
--- 8474,8480 ----
RequestXLogSwitch();
/* Ensure we release forcePageWrites if fail below */
! PG_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
{
/*
* Force a CHECKPOINT. Aside from being necessary to prevent torn
***************
*** 8459,8512 **** do_pg_start_backup(const char *backupidstr, bool fast)
XLByteToSeg(startpoint, _logId, _logSeg);
XLogFileName(xlogfilename, ThisTimeLineID, _logId, _logSeg);
/* Use the log timezone here, not the session timezone */
stamp_time = (pg_time_t) time(NULL);
pg_strftime(strfbuf, sizeof(strfbuf),
"%Y-%m-%d %H:%M:%S %Z",
pg_localtime(&stamp_time, log_timezone));
/*
! * Check for existing backup label --- implies a backup is already
! * running. (XXX given that we checked forcePageWrites above, maybe
! * it would be OK to just unlink any such label file?)
*/
! if (stat(BACKUP_LABEL_FILE, &stat_buf) != 0)
{
! if (errno != ENOENT)
ereport(ERROR,
(errcode_for_file_access(),
! errmsg("could not stat file \"%s\": %m",
BACKUP_LABEL_FILE)));
}
else
! ereport(ERROR,
! (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
! errmsg("a backup is already in progress"),
! errhint("If you're sure there is no backup in progress, remove file \"%s\" and try again.",
! BACKUP_LABEL_FILE)));
!
! /*
! * Okay, write the file
! */
! fp = AllocateFile(BACKUP_LABEL_FILE, "w");
! if (!fp)
! ereport(ERROR,
! (errcode_for_file_access(),
! errmsg("could not create file \"%s\": %m",
! BACKUP_LABEL_FILE)));
! fprintf(fp, "START WAL LOCATION: %X/%X (file %s)\n",
! startpoint.xlogid, startpoint.xrecoff, xlogfilename);
! fprintf(fp, "CHECKPOINT LOCATION: %X/%X\n",
! checkpointloc.xlogid, checkpointloc.xrecoff);
! fprintf(fp, "START TIME: %s\n", strfbuf);
! fprintf(fp, "LABEL: %s\n", backupidstr);
! if (fflush(fp) || ferror(fp) || FreeFile(fp))
! ereport(ERROR,
! (errcode_for_file_access(),
! errmsg("could not write file \"%s\": %m",
! BACKUP_LABEL_FILE)));
}
! PG_END_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) 0);
/*
* We're done. As a convenience, return the starting WAL location.
--- 8501,8567 ----
XLByteToSeg(startpoint, _logId, _logSeg);
XLogFileName(xlogfilename, ThisTimeLineID, _logId, _logSeg);
+ /*
+ * Construct backup label file
+ */
+ initStringInfo(&labelfbuf);
+
/* Use the log timezone here, not the session timezone */
stamp_time = (pg_time_t) time(NULL);
pg_strftime(strfbuf, sizeof(strfbuf),
"%Y-%m-%d %H:%M:%S %Z",
pg_localtime(&stamp_time, log_timezone));
+ appendStringInfo(&labelfbuf, "START WAL LOCATION: %X/%X (file %s)\n",
+ startpoint.xlogid, startpoint.xrecoff, xlogfilename);
+ appendStringInfo(&labelfbuf, "CHECKPOINT LOCATION: %X/%X\n",
+ checkpointloc.xlogid, checkpointloc.xrecoff);
+ appendStringInfo(&labelfbuf, "START TIME: %s\n", strfbuf);
+ appendStringInfo(&labelfbuf, "LABEL: %s\n", backupidstr);
/*
! * Okay, write the file, or return its contents to caller.
*/
! if (exclusive)
{
! /*
! * Check for existing backup label --- implies a backup is already
! * running. (XXX given that we checked exclusiveBackup above, maybe
! * it would be OK to just unlink any such label file?)
! */
! if (stat(BACKUP_LABEL_FILE, &stat_buf) != 0)
! {
! if (errno != ENOENT)
! ereport(ERROR,
! (errcode_for_file_access(),
! errmsg("could not stat file \"%s\": %m",
! BACKUP_LABEL_FILE)));
! }
! else
! ereport(ERROR,
! (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
! errmsg("a backup is already in progress"),
! errhint("If you're sure there is no backup in progress, remove file \"%s\" and try again.",
! BACKUP_LABEL_FILE)));
!
! fp = AllocateFile(BACKUP_LABEL_FILE, "w");
!
! if (!fp)
ereport(ERROR,
(errcode_for_file_access(),
! errmsg("could not create file \"%s\": %m",
BACKUP_LABEL_FILE)));
+ fwrite(labelfbuf.data, labelfbuf.len, 1, fp);
+ if (fflush(fp) || ferror(fp) || FreeFile(fp))
+ ereport(ERROR,
+ (errcode_for_file_access(),
+ errmsg("could not write file \"%s\": %m",
+ BACKUP_LABEL_FILE)));
+ pfree(labelfbuf.data);
}
else
! *labelfile = labelfbuf.data;
}
! PG_END_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
/*
* We're done. As a convenience, return the starting WAL location.
***************
*** 8518,8526 **** do_pg_start_backup(const char *backupidstr, bool fast)
static void
pg_start_backup_callback(int code, Datum arg)
{
! /* Turn off forcePageWrites on failure */
LWLockAcquire(WALInsertLock, LW_EXCLUSIVE);
! XLogCtl->Insert.forcePageWrites = false;
LWLockRelease(WALInsertLock);
}
--- 8573,8592 ----
static void
pg_start_backup_callback(int code, Datum arg)
{
! bool exclusive = DatumGetBool(arg);
!
! /* Update backup counters and forcePageWrites on failure */
LWLockAcquire(WALInsertLock, LW_EXCLUSIVE);
! if (exclusive)
! {
! Assert(XLogCtl->Insert.exclusiveBackup);
! XLogCtl->Insert.exclusiveBackup = false;
! }
! else
! XLogCtl->Insert.nonExclusiveBackups--;
!
! if (!XLogCtl->Insert.exclusiveBackup && XLogCtl->Insert.nonExclusiveBackups == 0)
! XLogCtl->Insert.forcePageWrites = false;
LWLockRelease(WALInsertLock);
}
***************
*** 8543,8558 **** pg_stop_backup(PG_FUNCTION_ARGS)
XLogRecPtr stoppoint;
char stopxlogstr[MAXFNAMELEN];
! stoppoint = do_pg_stop_backup();
snprintf(stopxlogstr, sizeof(stopxlogstr), "%X/%X",
stoppoint.xlogid, stoppoint.xrecoff);
PG_RETURN_TEXT_P(cstring_to_text(stopxlogstr));
}
XLogRecPtr
! do_pg_stop_backup(void)
{
XLogRecPtr startpoint;
XLogRecPtr stoppoint;
XLogRecData rdata;
--- 8609,8632 ----
XLogRecPtr stoppoint;
char stopxlogstr[MAXFNAMELEN];
! stoppoint = do_pg_stop_backup(NULL);
snprintf(stopxlogstr, sizeof(stopxlogstr), "%X/%X",
stoppoint.xlogid, stoppoint.xrecoff);
PG_RETURN_TEXT_P(cstring_to_text(stopxlogstr));
}
+ /*
+ * do_pg_start_backup is the workhorse of the user-visible pg_stop_backup()
+ * function.
+
+ * If labelfile is NULL, this stops an exclusive backup. Otherwise this stops
+ * the non-exclusive backup specified by 'labelfile'.
+ */
XLogRecPtr
! do_pg_stop_backup(char *labelfile)
{
+ bool exclusive = (labelfile == NULL);
XLogRecPtr startpoint;
XLogRecPtr stoppoint;
XLogRecData rdata;
***************
*** 8568,8582 **** do_pg_stop_backup(void)
FILE *lfp;
FILE *fp;
char ch;
- int ich;
int seconds_before_warning;
int waits = 0;
bool reported_waiting = false;
! if (!superuser() && !is_authenticated_user_replication_role())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! (errmsg("must be superuser or replication role to run a backup"))));
if (RecoveryInProgress())
ereport(ERROR,
--- 8642,8656 ----
FILE *lfp;
FILE *fp;
char ch;
int seconds_before_warning;
int waits = 0;
bool reported_waiting = false;
+ char *remaining;
! if (exclusive && !superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! errmsg("must be superuser to run a backup")));
if (RecoveryInProgress())
ereport(ERROR,
***************
*** 8591,8628 **** do_pg_stop_backup(void)
errhint("wal_level must be set to \"archive\" or \"hot_standby\" at server start.")));
/*
! * OK to clear forcePageWrites
*/
LWLockAcquire(WALInsertLock, LW_EXCLUSIVE);
! XLogCtl->Insert.forcePageWrites = false;
LWLockRelease(WALInsertLock);
! /*
! * Open the existing label file
! */
! lfp = AllocateFile(BACKUP_LABEL_FILE, "r");
! if (!lfp)
{
! if (errno != ENOENT)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not read file \"%s\": %m",
BACKUP_LABEL_FILE)));
! ereport(ERROR,
! (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
! errmsg("a backup is not in progress")));
}
/*
* Read and parse the START WAL LOCATION line (this code is pretty crude,
* but we are not expecting any variability in the file format).
*/
! if (fscanf(lfp, "START WAL LOCATION: %X/%X (file %24s)%c",
&startpoint.xlogid, &startpoint.xrecoff, startxlogfilename,
&ch) != 4 || ch != '\n')
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("invalid data in file \"%s\"", BACKUP_LABEL_FILE)));
/*
* Write the backup-end xlog record
--- 8665,8749 ----
errhint("wal_level must be set to \"archive\" or \"hot_standby\" at server start.")));
/*
! * OK to update backup counters and forcePageWrites
*/
LWLockAcquire(WALInsertLock, LW_EXCLUSIVE);
! if (exclusive)
! XLogCtl->Insert.exclusiveBackup = false;
! else
! {
! /*
! * The user-visible pg_start/stop_backup() functions that operate on
! * exclusive backups can be called at any time, but for non-exclusive
! * backups, it is expected that each do_pg_start_backup() call is
! * matched by exactly one do_pg_stop_backup() call.
! */
! Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
! XLogCtl->Insert.nonExclusiveBackups--;
! }
!
! if (!XLogCtl->Insert.exclusiveBackup && XLogCtl->Insert.nonExclusiveBackups == 0)
! XLogCtl->Insert.forcePageWrites = false;
LWLockRelease(WALInsertLock);
! if (exclusive)
{
! /*
! * Read the existing label file into memory.
! */
! struct stat statbuf;
! int r;
!
! if (stat(BACKUP_LABEL_FILE, &statbuf))
! {
! if (errno != ENOENT)
! ereport(ERROR,
! (errcode_for_file_access(),
! errmsg("could not stat file \"%s\": %m",
! BACKUP_LABEL_FILE)));
! ereport(ERROR,
! (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
! errmsg("a backup is not in progress")));
! }
!
! lfp = AllocateFile(BACKUP_LABEL_FILE, "r");
! if (!lfp)
! {
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not read file \"%s\": %m",
BACKUP_LABEL_FILE)));
! }
! labelfile = palloc(statbuf.st_size + 1);
! r = fread(labelfile, statbuf.st_size, 1, lfp);
! labelfile[statbuf.st_size] = '\0';
!
! /*
! * Close and remove the backup label file
! */
! if (r != 1 || ferror(lfp) || FreeFile(lfp))
! ereport(ERROR,
! (errcode_for_file_access(),
! errmsg("could not read file \"%s\": %m",
! BACKUP_LABEL_FILE)));
! if (unlink(BACKUP_LABEL_FILE) != 0)
! ereport(ERROR,
! (errcode_for_file_access(),
! errmsg("could not remove file \"%s\": %m",
! BACKUP_LABEL_FILE)));
}
/*
* Read and parse the START WAL LOCATION line (this code is pretty crude,
* but we are not expecting any variability in the file format).
*/
! if (sscanf(labelfile, "START WAL LOCATION: %X/%X (file %24s)%c",
&startpoint.xlogid, &startpoint.xrecoff, startxlogfilename,
&ch) != 4 || ch != '\n')
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("invalid data in file \"%s\"", BACKUP_LABEL_FILE)));
+ remaining = strchr(labelfile, '\n') + 1; /* %n is not portable enough */
/*
* Write the backup-end xlog record
***************
*** 8665,8672 **** do_pg_stop_backup(void)
fprintf(fp, "STOP WAL LOCATION: %X/%X (file %s)\n",
stoppoint.xlogid, stoppoint.xrecoff, stopxlogfilename);
/* transfer remaining lines from label to history file */
! while ((ich = fgetc(lfp)) != EOF)
! fputc(ich, fp);
fprintf(fp, "STOP TIME: %s\n", strfbuf);
if (fflush(fp) || ferror(fp) || FreeFile(fp))
ereport(ERROR,
--- 8786,8792 ----
fprintf(fp, "STOP WAL LOCATION: %X/%X (file %s)\n",
stoppoint.xlogid, stoppoint.xrecoff, stopxlogfilename);
/* transfer remaining lines from label to history file */
! fprintf(fp, "%s", remaining);
fprintf(fp, "STOP TIME: %s\n", strfbuf);
if (fflush(fp) || ferror(fp) || FreeFile(fp))
ereport(ERROR,
***************
*** 8675,8694 **** do_pg_stop_backup(void)
histfilepath)));
/*
- * Close and remove the backup label file
- */
- if (ferror(lfp) || FreeFile(lfp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- if (unlink(BACKUP_LABEL_FILE) != 0)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not remove file \"%s\": %m",
- BACKUP_LABEL_FILE)));
-
- /*
* Clean out any no-longer-needed history files. As a side effect, this
* will post a .ready file for the newly created history file, notifying
* the archiver that history file may be archived immediately.
--- 8795,8800 ----
***************
*** 8769,8796 **** do_pg_stop_backup(void)
/*
* do_pg_abort_backup: abort a running backup
*
! * This does just the most basic steps of pg_stop_backup(), by taking the
* system out of backup mode, thus making it a lot more safe to call from
* an error handler.
*/
void
do_pg_abort_backup(void)
{
- /*
- * OK to clear forcePageWrites
- */
LWLockAcquire(WALInsertLock, LW_EXCLUSIVE);
! XLogCtl->Insert.forcePageWrites = false;
! LWLockRelease(WALInsertLock);
! /*
! * Remove backup label file
! */
! if (unlink(BACKUP_LABEL_FILE) != 0)
! ereport(ERROR,
! (errcode_for_file_access(),
! errmsg("could not remove file \"%s\": %m",
! BACKUP_LABEL_FILE)));
}
/*
--- 8875,8899 ----
/*
* do_pg_abort_backup: abort a running backup
*
! * This does just the most basic steps of do_pg_stop_backup(), by taking the
* system out of backup mode, thus making it a lot more safe to call from
* an error handler.
+ *
+ * NB: This is only for aborting a non-exclusive backup that doesn't write
+ * backup_label. A backup started with pg_stop_backup() needs to be finished
+ * with pg_stop_backup().
*/
void
do_pg_abort_backup(void)
{
LWLockAcquire(WALInsertLock, LW_EXCLUSIVE);
! Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
! XLogCtl->Insert.nonExclusiveBackups--;
! if (!XLogCtl->Insert.exclusiveBackup && XLogCtl->Insert.nonExclusiveBackups == 0)
! XLogCtl->Insert.forcePageWrites = false;
!
! LWLockRelease(WALInsertLock);
}
/*
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers