f = stream->walmethod->ops->open_for_write(stream->walmethod, tmppath,
NULL, 0); if (f == NULL)
{
pg_log_error("could not create archive status file \"%s\": %s",
tmppath, GetLastWalMethodError(stream->walmethod)); returnfalse;
}
if (stream->walmethod->ops->close(f, CLOSE_NORMAL) != 0)
{
pg_log_error("could not close archive status file \"%s\": %s",
tmppath, GetLastWalMethodError(stream->walmethod)); returnfalse;
}
/* Note that this considers the compression used if necessary */
fn = stream->walmethod->ops->get_file_name(stream->walmethod,
walfile_name,
stream->partial_suffix);
/* *Whenstreamingtofiles,ifanexistingfileexistsweverifythatit's *eitherempty(justcreated),oracompleteWalSegSzsegment(inwhich *caseithasbeencreatedandpadded).Anythingelseindicatesacorrupt *file.Compressedfileshavenoneedforpadding,sojustignorethis *case. * *Whenstreamingtotar,nofilewiththisnamewillexistbefore,sowe *neverhavetoverifyasize.
*/ if (stream->walmethod->compression_algorithm == PG_COMPRESSION_NONE &&
stream->walmethod->ops->existsfile(stream->walmethod, fn))
{
size = stream->walmethod->ops->get_file_size(stream->walmethod, fn); if (size < 0)
{
pg_log_error("could not get size of write-ahead log file \"%s\": %s",
fn, GetLastWalMethodError(stream->walmethod));
pg_free(fn); returnfalse;
} if (size == WalSegSz)
{ /* Already padded file. Open it for use */
f = stream->walmethod->ops->open_for_write(stream->walmethod, walfile_name, stream->partial_suffix, 0); if (f == NULL)
{
pg_log_error("could not open existing write-ahead log file \"%s\": %s",
fn, GetLastWalMethodError(stream->walmethod));
pg_free(fn); returnfalse;
}
/* fsync file in case of a previous crash */ if (stream->walmethod->ops->sync(f) != 0)
{
pg_log_error("could not fsync existing write-ahead log file \"%s\": %s",
fn, GetLastWalMethodError(stream->walmethod));
stream->walmethod->ops->close(f, CLOSE_UNLINK); exit(1);
}
walfile = f;
pg_free(fn); returntrue;
} if (size != 0)
{ /* if write didn't set errno, assume problem is no disk space */ if (errno == 0)
errno = ENOSPC;
pg_log_error(ngettext("write-ahead log file \"%s\" has %zd byte, should be 0 or %d", "write-ahead log file \"%s\" has %zd bytes, should be 0 or %d",
size),
fn, size, WalSegSz);
pg_free(fn); returnfalse;
} /* File existed and was empty, so fall through and open */
}
/* No file existed, so create one */
f = stream->walmethod->ops->open_for_write(stream->walmethod,
walfile_name,
stream->partial_suffix,
WalSegSz); if (f == NULL)
{
pg_log_error("could not open write-ahead log file \"%s\": %s",
fn, GetLastWalMethodError(stream->walmethod));
pg_free(fn); returnfalse;
}
/* Note that this considers the compression used if necessary */
fn = stream->walmethod->ops->get_file_name(stream->walmethod,
walfile_name,
stream->partial_suffix);
if (stream->partial_suffix)
{ if (currpos == WalSegSz)
r = stream->walmethod->ops->close(walfile, CLOSE_NORMAL); else
{
pg_log_info("not renaming \"%s\", segment is not complete", fn);
r = stream->walmethod->ops->close(walfile, CLOSE_NO_RENAME);
}
} else
r = stream->walmethod->ops->close(walfile, CLOSE_NORMAL);
walfile = NULL;
if (r != 0)
{
pg_log_error("could not close file \"%s\": %s",
fn, GetLastWalMethodError(stream->walmethod));
pg_free(fn); returnfalse;
}
pg_free(fn);
/* *Markfileasarchivedifrequestedbythecaller-pg_basebackupneeds *todosoasfilescanotherwisegetarchivedagainafterpromotionofa *newnode.Thisisinlinewithwalreceiver.calwaysdoinga *XLogArchiveForceDone()afteracompletesegment.
*/ if (currpos == WalSegSz && stream->mark_done)
{ /* writes error message if failed */ if (!mark_file_as_archived(stream, walfile_name)) returnfalse;
}
pg_log_error("incompatible server version %s; client does not support streaming from server versions older than %s",
serverver ? serverver : "'unknown'", "9.3"); returnfalse;
} elseif (serverMajor > maxServerMajor)
{ constchar *serverver = PQparameterStatus(conn, "server_version");
pg_log_error("incompatible server version %s; client does not support streaming from server versions newer than %s",
serverver ? serverver : "'unknown'",
PG_VERSION); returnfalse;
} returntrue;
}
if (strcmp(stream->sysidentifier, sysidentifier) != 0)
{
pg_log_error("system identifier does not match between base backup and streaming connection");
pg_free(sysidentifier); returnfalse;
}
pg_free(sysidentifier);
if (stream->timeline > servertli)
{
pg_log_error("starting timeline %u is not present in the server",
stream->timeline); returnfalse;
}
}
while (1)
{ /* *Fetchthetimelinehistoryfileforthistimeline,ifwedon'thave *italready.Whenstreaminglogtotar,thiswillalwaysreturn *false,asweareneverstreamingintoanexistingfileand *thereforetherecanbenopre-existingtimelinehistoryfile.
*/ if (!existsTimeLineHistoryFile(stream))
{
snprintf(query, sizeof(query), "TIMELINE_HISTORY %u", stream->timeline);
res = PQexec(conn, query); if (PQresultStatus(res) != PGRES_TUPLES_OK)
{ /* FIXME: we might send it ok, but get an error */
pg_log_error("could not send replication command \"%s\": %s", "TIMELINE_HISTORY", PQresultErrorMessage(res));
PQclear(res); returnfalse;
}
/* *TheresponsetoTIMELINE_HISTORYisasinglerowresultset *withtwofields:filenameandcontent
*/ if (PQnfields(res) != 2 || PQntuples(res) != 1)
{
pg_log_warning("unexpected response to TIMELINE_HISTORY command: got %d rows and %d fields, expected %d rows and %d fields",
PQntuples(res), PQnfields(res), 1, 2);
}
/* Write the history file to disk */
writeTimeLineHistoryFile(stream,
PQgetvalue(res, 0, 0),
PQgetvalue(res, 0, 1));
PQclear(res);
}
/* *Beforewestartstreamingfromtherequestedlocation,checkifthe *callbacktellsustostophere.
*/ if (stream->stream_stop(stream->startpos, stream->timeline, false)) returntrue;
/* Initiate the replication stream at specified location */
snprintf(query, sizeof(query), "START_REPLICATION %s%X/%X TIMELINE %u",
slotcmd,
LSN_FORMAT_ARGS(stream->startpos),
stream->timeline);
res = PQexec(conn, query); if (PQresultStatus(res) != PGRES_COPY_BOTH)
{
pg_log_error("could not send replication command \"%s\": %s", "START_REPLICATION", PQresultErrorMessage(res));
PQclear(res); returnfalse;
}
PQclear(res);
/* Stream the WAL */
res = HandleCopyStream(conn, stream, &stoppos); if (res == NULL) goto error;
parsed = ReadEndOfStreamingResult(res, &stream->startpos, &newtimeline);
PQclear(res); if (!parsed) goto error;
/* Sanity check the values the server gave us */ if (newtimeline <= stream->timeline)
{
pg_log_error("server reported unexpected next timeline %u, following timeline %u",
newtimeline, stream->timeline); goto error;
} if (stream->startpos > stoppos)
{
pg_log_error("server stopped streaming timeline %u at %X/%X, but reported next timeline %u to begin at %X/%X",
stream->timeline, LSN_FORMAT_ARGS(stoppos),
newtimeline, LSN_FORMAT_ARGS(stream->startpos)); goto error;
}
/* Read the final result, which should be CommandComplete. */
res = PQgetResult(conn); if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
pg_log_error("unexpected termination of replication stream: %s",
PQresultErrorMessage(res));
PQclear(res); goto error;
}
PQclear(res);
/* *Nodataavailable.Waitforsometoappear,butnotlongerthan *thespecifiedtimeout,sothatwecanpingtheserver.Alsostop *waitingifinputappearsonstop_socket.
*/
ret = CopyStreamPoll(conn, timeout, stop_socket); if (ret <= 0) return ret;
/* Now there is actually data on the socket */ if (PQconsumeInput(conn) == 0)
{
pg_log_error("could not receive data from WAL stream: %s",
PQerrorMessage(conn)); return -1;
}
if (len < pos + 1)
{
pg_log_error("streaming header too small: %d", len); returnfalse;
}
replyRequested = copybuf[pos];
/* If the server requested an immediate reply, send one. */ if (replyRequested && still_sending)
{ if (reportFlushPosition && lastFlushPosition < blockpos &&
walfile != NULL)
{ /* *Ifavalidflushlocationneedstobereported,flushthe *currentWALfilesothatthelatestflushlocationissentback *totheserver.ThisisnecessarytoseewhetherthelastWAL *datahasbeensuccessfullyreplicatedornot,atthenormal *shutdownoftheserver.
*/ if (stream->walmethod->ops->sync(walfile) != 0)
pg_fatal("could not fsync file \"%s\": %s",
walfile->pathname, GetLastWalMethodError(stream->walmethod));
lastFlushPosition = blockpos;
}
now = feGetCurrentTimestamp(); if (!sendFeedback(conn, blockpos, now, false)) returnfalse;
*last_status = now;
}
returntrue;
}
/* *ProcessXLogDatamessage.
*/ staticbool
ProcessXLogDataMsg(PGconn *conn, StreamCtl *stream, char *copybuf, int len,
XLogRecPtr *blockpos)
{ int xlogoff; int bytes_left; int bytes_written; int hdr_len;
/* *Oncewe'vedecidedwedon'twanttoreceiveanymore,justignoreany *subsequentXLogDatamessages.
*/ if (!(still_sending)) returntrue;
/* Extract WAL location for this block */
xlogoff = XLogSegmentOffset(*blockpos, WalSegSz);
/* *Verifythattheinitiallocationinthestreammatcheswherewethink *weare.
*/ if (walfile == NULL)
{ /* No file open yet */ if (xlogoff != 0)
{
pg_log_error("received write-ahead log record for offset %u with no file open",
xlogoff); returnfalse;
}
} else
{ /* More data in existing segment */ if (walfile->currpos != xlogoff)
{
pg_log_error("got WAL data offset %08x, expected %08x",
xlogoff, (int) walfile->currpos); returnfalse;
}
}
if (walfile == NULL)
{ if (!open_walfile(stream, *blockpos))
{ /* Error logged by open_walfile */ returnfalse;
}
}
if (stream->walmethod->ops->write(walfile,
copybuf + hdr_len + bytes_written,
bytes_to_write) != bytes_to_write)
{
pg_log_error("could not write %d bytes to WAL file \"%s\": %s",
bytes_to_write, walfile->pathname,
GetLastWalMethodError(stream->walmethod)); returnfalse;
}
/* Write was successful, advance our position */
bytes_written += bytes_to_write;
bytes_left -= bytes_to_write;
*blockpos += bytes_to_write;
xlogoff += bytes_to_write;
/* Did we reach the end of a WAL segment? */ if (XLogSegmentOffset(*blockpos, WalSegSz) == 0)
{ if (!close_walfile(stream, *blockpos)) /* Error message written in close_walfile() */ returnfalse;
xlogoff = 0;
if (still_sending && stream->stream_stop(*blockpos, stream->timeline, true))
{ if (PQputCopyEnd(conn, NULL) <= 0 || PQflush(conn))
{
pg_log_error("could not send copy-end packet: %s",
PQerrorMessage(conn)); returnfalse;
}
still_sending = false; returntrue; /* ignore the rest of this XLogData packet */
}
}
} /* No more data left to write, receive next copy packet */
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.