2018-01-17 15:52:00 -05:00
|
|
|
/***********************************************************************************************************************************
|
|
|
|
Archive Push Command
|
|
|
|
***********************************************************************************************************************************/
|
|
|
|
#include <unistd.h>
|
|
|
|
|
2018-04-29 10:16:59 -04:00
|
|
|
#include "command/archive/common.h"
|
2018-04-12 20:42:26 -04:00
|
|
|
#include "command/command.h"
|
2018-05-18 11:57:32 -04:00
|
|
|
#include "common/debug.h"
|
2018-04-12 20:42:26 -04:00
|
|
|
#include "common/fork.h"
|
2018-01-17 15:52:00 -05:00
|
|
|
#include "common/log.h"
|
|
|
|
#include "common/memContext.h"
|
|
|
|
#include "common/wait.h"
|
|
|
|
#include "config/config.h"
|
2019-03-14 13:38:55 +04:00
|
|
|
#include "config/exec.h"
|
2018-01-17 15:52:00 -05:00
|
|
|
#include "perl/exec.h"
|
|
|
|
#include "storage/helper.h"
|
|
|
|
|
|
|
|
/***********************************************************************************************************************************
|
|
|
|
Push a WAL segment to the repository
|
|
|
|
***********************************************************************************************************************************/
|
|
|
|
void
|
2018-08-03 19:19:14 -04:00
|
|
|
cmdArchivePush(void)
|
2018-01-17 15:52:00 -05:00
|
|
|
{
|
2019-01-21 17:41:59 +02:00
|
|
|
FUNCTION_LOG_VOID(logLevelDebug);
|
2018-05-18 11:57:32 -04:00
|
|
|
|
2018-01-17 15:52:00 -05:00
|
|
|
MEM_CONTEXT_TEMP_BEGIN()
|
|
|
|
{
|
|
|
|
// Make sure there is a parameter to retrieve the WAL segment from
|
|
|
|
const StringList *commandParam = cfgCommandParam();
|
|
|
|
|
|
|
|
if (strLstSize(commandParam) != 1)
|
|
|
|
THROW(ParamRequiredError, "WAL segment to push required");
|
|
|
|
|
|
|
|
// Get the segment name
|
|
|
|
String *walSegment = strBase(strLstGet(commandParam, 0));
|
|
|
|
|
|
|
|
if (cfgOptionBool(cfgOptArchiveAsync))
|
|
|
|
{
|
|
|
|
bool pushed = false; // Has the WAL segment been pushed yet?
|
2018-04-12 20:42:26 -04:00
|
|
|
bool forked = false; // Has the async process been forked yet?
|
2018-01-17 15:52:00 -05:00
|
|
|
bool confessOnError = false; // Should we confess errors?
|
|
|
|
|
|
|
|
// Loop and wait for the WAL segment to be pushed
|
2018-11-08 08:37:57 -05:00
|
|
|
Wait *wait = waitNew((TimeMSec)(cfgOptionDbl(cfgOptArchiveTimeout) * MSEC_PER_SEC));
|
2018-01-17 15:52:00 -05:00
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
// Check if the WAL segment has been pushed. Errors will not be confessed on the first try to allow the async
|
|
|
|
// process a chance to fix them.
|
2018-04-30 17:27:39 -04:00
|
|
|
pushed = archiveAsyncStatus(archiveModePush, walSegment, confessOnError);
|
2018-01-17 15:52:00 -05:00
|
|
|
|
2018-04-12 20:42:26 -04:00
|
|
|
// If the WAL segment has not already been pushed then start the async process to push it. There's no point in
|
|
|
|
// forking the async process off more than once so track that as well. Use an archive lock to prevent more than
|
|
|
|
// one async process being launched.
|
|
|
|
if (!pushed && !forked &&
|
|
|
|
lockAcquire(cfgOptionStr(cfgOptLockPath), cfgOptionStr(cfgOptStanza), cfgLockType(), 0, false))
|
2018-01-17 15:52:00 -05:00
|
|
|
{
|
2019-03-14 13:38:55 +04:00
|
|
|
// The async process should not output on the console at all
|
|
|
|
KeyValue *optionReplace = kvNew();
|
2018-04-12 20:42:26 -04:00
|
|
|
|
2019-03-14 13:38:55 +04:00
|
|
|
kvPut(optionReplace, varNewStr(strNew(cfgOptionName(cfgOptLogLevelConsole))), varNewStrZ("off"));
|
|
|
|
kvPut(optionReplace, varNewStr(strNew(cfgOptionName(cfgOptLogLevelStderr))), varNewStrZ("off"));
|
2018-04-12 20:42:26 -04:00
|
|
|
|
2019-03-14 13:38:55 +04:00
|
|
|
// Generate command options
|
|
|
|
StringList *commandExec = cfgExecParam(cfgCmdArchivePushAsync, optionReplace);
|
|
|
|
strLstInsert(commandExec, 0, cfgExe());
|
|
|
|
strLstAdd(commandExec, strLstGet(commandParam, 0));
|
2018-04-12 20:42:26 -04:00
|
|
|
|
2019-03-14 13:38:55 +04:00
|
|
|
// Release the lock and mark the async process as forked
|
|
|
|
lockRelease(true);
|
|
|
|
forked = true;
|
2018-04-12 20:42:26 -04:00
|
|
|
|
2019-03-14 13:38:55 +04:00
|
|
|
// Fork off the async process
|
|
|
|
if (fork() == 0)
|
|
|
|
{
|
2018-04-12 20:42:26 -04:00
|
|
|
// Detach from parent process
|
|
|
|
forkDetach();
|
|
|
|
|
2019-03-14 13:38:55 +04:00
|
|
|
// Execute the binary. This statement will not return if it is successful.
|
|
|
|
THROW_ON_SYS_ERROR_FMT(
|
|
|
|
execvp(strPtr(cfgExe()), (char ** const)strLstPtr(commandExec)) == -1,
|
|
|
|
ExecuteError, "unable to execute '%s'", cfgCommandName(cfgCmdArchiveGetAsync));
|
2018-01-17 15:52:00 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now that the async process has been launched, confess any errors that are found
|
|
|
|
confessOnError = true;
|
|
|
|
}
|
2019-03-14 13:38:55 +04:00
|
|
|
while (!pushed && waitMore(wait));
|
2018-01-17 15:52:00 -05:00
|
|
|
|
2019-03-14 13:38:55 +04:00
|
|
|
// If the WAL segment was not pushed then error
|
|
|
|
if (!pushed)
|
2018-01-17 15:52:00 -05:00
|
|
|
{
|
2019-03-14 13:38:55 +04:00
|
|
|
THROW_FMT(
|
|
|
|
ArchiveTimeoutError, "unable to push WAL segment '%s' asynchronously after %lg second(s)",
|
|
|
|
strPtr(walSegment), cfgOptionDbl(cfgOptArchiveTimeout));
|
2018-04-12 20:42:26 -04:00
|
|
|
}
|
2019-03-14 13:38:55 +04:00
|
|
|
|
|
|
|
// Log success
|
|
|
|
LOG_INFO("pushed WAL segment %s asynchronously", strPtr(walSegment));
|
2018-01-17 15:52:00 -05:00
|
|
|
}
|
|
|
|
else
|
2019-03-14 13:38:55 +04:00
|
|
|
perlExec();
|
2018-01-17 15:52:00 -05:00
|
|
|
}
|
|
|
|
MEM_CONTEXT_TEMP_END();
|
2018-05-18 11:57:32 -04:00
|
|
|
|
2019-01-21 17:41:59 +02:00
|
|
|
FUNCTION_LOG_RETURN_VOID();
|
2018-01-17 15:52:00 -05:00
|
|
|
}
|