You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-06-18 23:57:33 +02:00
Migrate local command to C.
The C local is only used for C commands in the main process. Some tweaking of the existing protocolGet() command was required. Originally the idea was to share the function for local and remote requests but the differences (as in Perl) were too great to make that practical.
This commit is contained in:
@ -1825,6 +1825,7 @@ my %hConfigDefine =
|
||||
},
|
||||
},
|
||||
&CFGCMD_ARCHIVE_GET_ASYNC => {},
|
||||
&CFGCMD_LOCAL => {},
|
||||
&CFGCMD_ARCHIVE_PUSH =>
|
||||
{
|
||||
&CFGDEF_DEPEND =>
|
||||
|
@ -52,7 +52,7 @@
|
||||
|
||||
<release-development-list>
|
||||
<release-item>
|
||||
<p>Migrate <cmd>remote</cmd> command to C.</p>
|
||||
<p>Migrate <cmd>local</cmd> and <cmd>remote</cmd> commands to C.</p>
|
||||
</release-item>
|
||||
|
||||
<release-item>
|
||||
|
@ -65,6 +65,7 @@ SRCS = \
|
||||
command/info/info.c \
|
||||
command/command.c \
|
||||
command/control/control.c \
|
||||
command/local/local.c \
|
||||
command/remote/remote.c \
|
||||
common/debug.c \
|
||||
common/encode.c \
|
||||
@ -203,6 +204,9 @@ command/help/help.o: command/help/help.c common/assert.h common/debug.h common/e
|
||||
command/info/info.o: command/info/info.c command/archive/common.h command/info/info.h common/assert.h common/debug.h common/error.auto.h common/error.h common/ini.h common/io/filter/filter.h common/io/filter/group.h common/io/handleWrite.h common/io/read.h common/io/write.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/json.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h config/config.auto.h config/config.h config/define.auto.h config/define.h crypto/crypto.h crypto/hash.h info/info.h info/infoArchive.h info/infoBackup.h info/infoPg.h perl/exec.h postgres/interface.h storage/fileRead.h storage/fileWrite.h storage/helper.h storage/info.h storage/storage.h
|
||||
$(CC) $(CFLAGS) -c command/info/info.c -o command/info/info.o
|
||||
|
||||
command/local/local.o: command/local/local.c common/assert.h common/debug.h common/error.auto.h common/error.h common/io/filter/filter.h common/io/filter/group.h common/io/handleRead.h common/io/handleWrite.h common/io/read.h common/io/write.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h config/config.auto.h config/config.h config/define.auto.h config/define.h config/protocol.h protocol/client.h protocol/command.h protocol/helper.h protocol/server.h
|
||||
$(CC) $(CFLAGS) -c command/local/local.c -o command/local/local.o
|
||||
|
||||
command/remote/remote.o: command/remote/remote.c common/assert.h common/debug.h common/error.auto.h common/error.h common/io/filter/filter.h common/io/filter/group.h common/io/handleRead.h common/io/handleWrite.h common/io/read.h common/io/write.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h config/config.auto.h config/config.h config/define.auto.h config/define.h config/protocol.h protocol/client.h protocol/command.h protocol/helper.h protocol/server.h storage/driver/remote/protocol.h
|
||||
$(CC) $(CFLAGS) -c command/remote/remote.c -o command/remote/remote.o
|
||||
|
||||
@ -380,7 +384,7 @@ info/infoManifest.o: info/infoManifest.c common/error.auto.h common/error.h comm
|
||||
info/infoPg.o: info/infoPg.c common/assert.h common/debug.h common/error.auto.h common/error.h common/ini.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/json.h common/type/keyValue.h common/type/list.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h crypto/crypto.h crypto/hash.h info/info.h info/infoPg.h postgres/interface.h postgres/version.h storage/fileRead.h storage/fileWrite.h storage/helper.h storage/info.h storage/storage.h
|
||||
$(CC) $(CFLAGS) -c info/infoPg.c -o info/infoPg.o
|
||||
|
||||
main.o: main.c command/archive/get/get.h command/archive/push/push.h command/command.h command/help/help.h command/info/info.h command/remote/remote.h common/assert.h common/debug.h common/error.auto.h common/error.h common/exit.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h config/config.auto.h config/config.h config/define.auto.h config/define.h config/load.h perl/exec.h postgres/interface.h version.h
|
||||
main.o: main.c command/archive/get/get.h command/archive/push/push.h command/command.h command/help/help.h command/info/info.h command/local/local.h command/remote/remote.h common/assert.h common/debug.h common/error.auto.h common/error.h common/exit.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h config/config.auto.h config/config.h config/define.auto.h config/define.h config/load.h perl/exec.h postgres/interface.h version.h
|
||||
$(CC) $(CFLAGS) -c main.c -o main.o
|
||||
|
||||
perl/config.o: perl/config.c common/assert.h common/debug.h common/error.auto.h common/error.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/json.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h config/config.auto.h config/config.h config/define.auto.h config/define.h
|
||||
|
35
src/command/local/local.c
Normal file
35
src/command/local/local.c
Normal file
@ -0,0 +1,35 @@
|
||||
/***********************************************************************************************************************************
|
||||
Local Command
|
||||
***********************************************************************************************************************************/
|
||||
#include "common/debug.h"
|
||||
#include "common/io/handleRead.h"
|
||||
#include "common/io/handleWrite.h"
|
||||
#include "common/log.h"
|
||||
#include "config/config.h"
|
||||
#include "config/protocol.h"
|
||||
#include "protocol/helper.h"
|
||||
#include "protocol/server.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Remote command
|
||||
***********************************************************************************************************************************/
|
||||
void
|
||||
cmdLocal(int handleRead, int handleWrite)
|
||||
{
|
||||
FUNCTION_LOG_VOID(logLevelDebug);
|
||||
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
String *name = strNewFmt(PROTOCOL_SERVICE_LOCAL "-%d", cfgOptionInt(cfgOptProcess));
|
||||
IoRead *read = ioHandleReadIo(ioHandleReadNew(name, handleRead, (TimeMSec)(cfgOptionDbl(cfgOptProtocolTimeout) * 1000)));
|
||||
ioReadOpen(read);
|
||||
IoWrite *write = ioHandleWriteIo(ioHandleWriteNew(name, handleWrite));
|
||||
ioWriteOpen(write);
|
||||
|
||||
ProtocolServer *server = protocolServerNew(name, PROTOCOL_SERVICE_LOCAL_STR, read, write);
|
||||
protocolServerProcess(server);
|
||||
}
|
||||
MEM_CONTEXT_TEMP_END();
|
||||
|
||||
FUNCTION_LOG_RETURN_VOID();
|
||||
}
|
12
src/command/local/local.h
Normal file
12
src/command/local/local.h
Normal file
@ -0,0 +1,12 @@
|
||||
/***********************************************************************************************************************************
|
||||
Local Command
|
||||
***********************************************************************************************************************************/
|
||||
#ifndef COMMAND_LOCAL_LOCAL_H
|
||||
#define COMMAND_LOCAL_LOCAL_H
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Functions
|
||||
***********************************************************************************************************************************/
|
||||
void cmdLocal(int handleRead, int handleWrite);
|
||||
|
||||
#endif
|
@ -3877,6 +3877,7 @@ static ConfigDefineOptionData configDefineOptionData[] = CFGDEFDATA_OPTION_LIST
|
||||
CFGDEFDATA_OPTION_COMMAND(cfgDefCmdArchiveGet)
|
||||
CFGDEFDATA_OPTION_COMMAND(cfgDefCmdArchiveGetAsync)
|
||||
CFGDEFDATA_OPTION_COMMAND(cfgDefCmdArchivePush)
|
||||
CFGDEFDATA_OPTION_COMMAND(cfgDefCmdLocal)
|
||||
)
|
||||
|
||||
CFGDEFDATA_OPTION_OPTIONAL_LIST
|
||||
|
14
src/main.c
14
src/main.c
@ -7,9 +7,10 @@ Main
|
||||
|
||||
#include "command/archive/get/get.h"
|
||||
#include "command/archive/push/push.h"
|
||||
#include "command/command.h"
|
||||
#include "command/help/help.h"
|
||||
#include "command/info/info.h"
|
||||
#include "command/command.h"
|
||||
#include "command/local/local.h"
|
||||
#include "command/remote/remote.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/error.h"
|
||||
@ -62,11 +63,18 @@ main(int argListSize, const char *argList[])
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
// Local command. Currently only implements a subset.
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
else if (cfgCommand() == cfgCmdLocal && strEqZ(cfgOptionStr(cfgOptCommand), cfgCommandName(cfgCmdArchiveGet)))
|
||||
{
|
||||
cmdLocal(STDIN_FILENO, STDOUT_FILENO);
|
||||
}
|
||||
|
||||
// Remote command. Currently only implements a subset.
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
else if (cfgCommand() == cfgCmdRemote &&
|
||||
(strEqZ(cfgOptionStr(cfgOptCommand), cfgCommandName(cfgCmdInfo)) ||
|
||||
strEqZ(cfgOptionStr(cfgOptCommand), cfgCommandName(cfgCmdArchiveGet))))
|
||||
(strEqZ(cfgOptionStr(cfgOptCommand), cfgCommandName(cfgCmdArchiveGet)) ||
|
||||
strEqZ(cfgOptionStr(cfgOptCommand), cfgCommandName(cfgCmdInfo))))
|
||||
{
|
||||
cmdRemote(STDIN_FILENO, STDOUT_FILENO);
|
||||
}
|
||||
|
@ -9,15 +9,6 @@ Object type
|
||||
***********************************************************************************************************************************/
|
||||
typedef struct ProtocolClient ProtocolClient;
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Remote tyoe enum
|
||||
***********************************************************************************************************************************/
|
||||
typedef enum
|
||||
{
|
||||
remoteTypeRepo,
|
||||
remoteTypeDb,
|
||||
} RemoteType;
|
||||
|
||||
#include "common/io/read.h"
|
||||
#include "common/io/write.h"
|
||||
#include "protocol/command.h"
|
||||
|
@ -13,19 +13,47 @@ Protocol Helper
|
||||
/***********************************************************************************************************************************
|
||||
Constants
|
||||
***********************************************************************************************************************************/
|
||||
STRING_EXTERN(PROTOCOL_SERVICE_LOCAL_STR, PROTOCOL_SERVICE_LOCAL);
|
||||
STRING_EXTERN(PROTOCOL_SERVICE_REMOTE_STR, PROTOCOL_SERVICE_REMOTE);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Local variables
|
||||
***********************************************************************************************************************************/
|
||||
typedef struct ProtocolHelperClient
|
||||
{
|
||||
Exec *exec; // Executed client
|
||||
ProtocolClient *client; // Protocol client
|
||||
} ProtocolHelperClient;
|
||||
|
||||
static struct
|
||||
{
|
||||
MemContext *memContext; // Mem context for protocol helper
|
||||
|
||||
Exec *remoteExec; // Executed remote
|
||||
ProtocolClient *remote; // Remote protocol client
|
||||
unsigned int clientRemoteSize; // Remote clients
|
||||
ProtocolHelperClient *clientRemote;
|
||||
|
||||
unsigned int clientLocalSize; // Local clients
|
||||
ProtocolHelperClient *clientLocal;
|
||||
} protocolHelper;
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Init local mem context and data structure
|
||||
***********************************************************************************************************************************/
|
||||
static void
|
||||
protocolHelperInit(void)
|
||||
{
|
||||
// In the protocol helper has not been initialized
|
||||
if (protocolHelper.memContext == NULL)
|
||||
{
|
||||
// Create a mem context to store protocol objects
|
||||
MEM_CONTEXT_BEGIN(memContextTop())
|
||||
{
|
||||
protocolHelper.memContext = memContextNew("ProtocolHelper");
|
||||
}
|
||||
MEM_CONTEXT_END();
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Is the repository local?
|
||||
***********************************************************************************************************************************/
|
||||
@ -37,18 +65,110 @@ repoIsLocal(void)
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Get the command line required for protocol execution
|
||||
Get the command line required for local protocol execution
|
||||
***********************************************************************************************************************************/
|
||||
static StringList *
|
||||
protocolParam(RemoteType remoteType, unsigned int remoteId)
|
||||
protocolLocalParam(ProtocolStorageType protocolStorageType, unsigned int protocolId)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(ENUM, remoteType);
|
||||
FUNCTION_LOG_PARAM(UINT, remoteId);
|
||||
FUNCTION_LOG_PARAM(ENUM, protocolStorageType);
|
||||
FUNCTION_LOG_PARAM(UINT, protocolId);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
ASSERT(remoteType == remoteTypeRepo); // ??? Hard-coded until the function supports db remotes
|
||||
ASSERT(remoteId == 1); // ??? Hard-coded until the function supports db remotes
|
||||
ASSERT(protocolStorageType == protocolStorageTypeRepo); // ??? Hard-coded until the function supports pg remotes
|
||||
|
||||
StringList *result = NULL;
|
||||
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
// Option replacements
|
||||
KeyValue *optionReplace = kvNew();
|
||||
|
||||
// Add the command option
|
||||
kvPut(optionReplace, varNewStr(strNew(cfgOptionName(cfgOptCommand))), varNewStr(strNew(cfgCommandName(cfgCommand()))));
|
||||
|
||||
// Add the process id -- used when more than one process will be called
|
||||
kvPut(optionReplace, varNewStr(strNew(cfgOptionName(cfgOptProcess))), varNewInt(0));
|
||||
|
||||
// Add the host id -- for now this is hard-coded to 1
|
||||
kvPut(optionReplace, varNewStr(strNew(cfgOptionName(cfgOptHostId))), varNewInt(1));
|
||||
|
||||
// Add the type
|
||||
kvPut(optionReplace, varNewStr(strNew(cfgOptionName(cfgOptType))), varNewStr(strNew("backup")));
|
||||
|
||||
result = strLstMove(cfgExecParam(cfgCmdLocal, optionReplace), MEM_CONTEXT_OLD());
|
||||
}
|
||||
MEM_CONTEXT_TEMP_END();
|
||||
|
||||
FUNCTION_LOG_RETURN(STRING_LIST, result);
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Get the local protocol client
|
||||
***********************************************************************************************************************************/
|
||||
ProtocolClient *
|
||||
protocolLocalGet(ProtocolStorageType protocolStorageType, unsigned int protocolId)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(ENUM, protocolStorageType);
|
||||
FUNCTION_LOG_PARAM(UINT, protocolId);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
protocolHelperInit();
|
||||
|
||||
// Allocate the client cache
|
||||
if (protocolHelper.clientLocalSize == 0)
|
||||
{
|
||||
MEM_CONTEXT_BEGIN(protocolHelper.memContext)
|
||||
{
|
||||
protocolHelper.clientLocalSize = (unsigned int)cfgOptionInt(cfgOptProcessMax);
|
||||
protocolHelper.clientLocal = (ProtocolHelperClient *)memNew(
|
||||
protocolHelper.clientLocalSize * sizeof(ProtocolHelperClient));
|
||||
}
|
||||
MEM_CONTEXT_END();
|
||||
}
|
||||
|
||||
ASSERT(protocolId <= protocolHelper.clientLocalSize);
|
||||
|
||||
// Create protocol object
|
||||
ProtocolHelperClient *protocolHelperClient = &protocolHelper.clientLocal[protocolId - 1];
|
||||
|
||||
if (protocolHelperClient->client == NULL)
|
||||
{
|
||||
MEM_CONTEXT_BEGIN(protocolHelper.memContext)
|
||||
{
|
||||
// Execute the protocol command
|
||||
protocolHelperClient->exec = execNew(
|
||||
cfgExe(), protocolLocalParam(protocolStorageType, protocolId),
|
||||
strNewFmt(PROTOCOL_SERVICE_LOCAL "-%u process", protocolId),
|
||||
(TimeMSec)(cfgOptionDbl(cfgOptProtocolTimeout) * 1000));
|
||||
execOpen(protocolHelperClient->exec);
|
||||
|
||||
// Create protocol object
|
||||
protocolHelperClient->client = protocolClientNew(
|
||||
strNewFmt(PROTOCOL_SERVICE_LOCAL "-%u protocol", protocolId),
|
||||
PROTOCOL_SERVICE_LOCAL_STR, execIoRead(protocolHelperClient->exec), execIoWrite(protocolHelperClient->exec));
|
||||
|
||||
protocolClientMove(protocolHelperClient->client, execMemContext(protocolHelperClient->exec));
|
||||
}
|
||||
MEM_CONTEXT_END();
|
||||
}
|
||||
|
||||
FUNCTION_LOG_RETURN(PROTOCOL_CLIENT, protocolHelperClient->client);
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Get the command line required for remote protocol execution
|
||||
***********************************************************************************************************************************/
|
||||
static StringList *
|
||||
protocolRemoteParam(ProtocolStorageType protocolStorageType, unsigned int protocolId)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(ENUM, protocolStorageType);
|
||||
FUNCTION_LOG_PARAM(UINT, protocolId);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
ASSERT(protocolStorageType == protocolStorageTypeRepo); // ??? Hard-coded until the function supports pg remotes
|
||||
|
||||
// Fixed parameters for ssh command
|
||||
StringList *result = strLstNew();
|
||||
@ -69,7 +189,7 @@ protocolParam(RemoteType remoteType, unsigned int remoteId)
|
||||
// Append user/host
|
||||
strLstAdd(result, strNewFmt("%s@%s", strPtr(cfgOptionStr(cfgOptRepoHostUser)), strPtr(cfgOptionStr(cfgOptRepoHost))));
|
||||
|
||||
// Append pgbackrest command
|
||||
// Option replacements
|
||||
KeyValue *optionReplace = kvNew();
|
||||
|
||||
// Replace config options with the host versions
|
||||
@ -82,7 +202,7 @@ protocolParam(RemoteType remoteType, unsigned int remoteId)
|
||||
if (cfgOptionSource(cfgOptRepoHostConfigPath) != cfgSourceDefault)
|
||||
kvPut(optionReplace, varNewStr(strNew(cfgOptionName(cfgOptConfigPath))), cfgOption(cfgOptRepoHostConfigPath));
|
||||
|
||||
// If this is the local or remote command then we need to add the command option
|
||||
// Add the command option
|
||||
kvPut(optionReplace, varNewStr(strNew(cfgOptionName(cfgOptCommand))), varNewStr(strNew(cfgCommandName(cfgCommand()))));
|
||||
|
||||
// Add the process id -- used when more than one process will be called
|
||||
@ -104,42 +224,55 @@ protocolParam(RemoteType remoteType, unsigned int remoteId)
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Get the protocol client
|
||||
Get the remote protocol client
|
||||
***********************************************************************************************************************************/
|
||||
ProtocolClient *
|
||||
protocolGet(RemoteType remoteType, unsigned int remoteId)
|
||||
protocolRemoteGet(ProtocolStorageType protocolStorageType, unsigned int protocolId)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(ENUM, remoteType);
|
||||
FUNCTION_LOG_PARAM(UINT, remoteId);
|
||||
FUNCTION_LOG_PARAM(ENUM, protocolStorageType);
|
||||
FUNCTION_LOG_PARAM(UINT, protocolId);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
// Create a mem context to store protocol objects
|
||||
if (protocolHelper.memContext == NULL)
|
||||
protocolHelperInit();
|
||||
|
||||
// Allocate the client cache
|
||||
if (protocolHelper.clientRemoteSize == 0)
|
||||
{
|
||||
MEM_CONTEXT_BEGIN(memContextTop())
|
||||
MEM_CONTEXT_BEGIN(protocolHelper.memContext)
|
||||
{
|
||||
protocolHelper.memContext = memContextNew("ProtocolHelper");
|
||||
// The number of remotes allowed is the greater of allowed repo or db configs + 1 (0 is reserved for connections from
|
||||
// the main process). Since these are static and only one will be true it presents a problem for coverage. We think
|
||||
// that pg remotes will always be greater but we'll protect that assumption with an assertion.
|
||||
ASSERT(cfgDefOptionIndexTotal(cfgDefOptPgPath) >= cfgDefOptionIndexTotal(cfgDefOptRepoPath));
|
||||
|
||||
protocolHelper.clientRemoteSize = cfgDefOptionIndexTotal(cfgDefOptPgPath) +1;
|
||||
protocolHelper.clientRemote = (ProtocolHelperClient *)memNew(
|
||||
protocolHelper.clientRemoteSize * sizeof(ProtocolHelperClient));
|
||||
}
|
||||
MEM_CONTEXT_END();
|
||||
}
|
||||
|
||||
ASSERT(protocolId < protocolHelper.clientRemoteSize);
|
||||
|
||||
// Create protocol object
|
||||
if (protocolHelper.remote == NULL)
|
||||
ProtocolHelperClient *protocolHelperClient = &protocolHelper.clientRemote[protocolId];
|
||||
|
||||
if (protocolHelperClient->client == NULL)
|
||||
{
|
||||
MEM_CONTEXT_BEGIN(protocolHelper.memContext)
|
||||
{
|
||||
// Execute the protocol command
|
||||
protocolHelper.remoteExec = execNew(
|
||||
cfgOptionStr(cfgOptCmdSsh), protocolParam(remoteType, remoteId),
|
||||
strNewFmt("remote-%u process on '%s'", remoteId, strPtr(cfgOptionStr(cfgOptRepoHost))),
|
||||
protocolHelperClient->exec = execNew(
|
||||
cfgOptionStr(cfgOptCmdSsh), protocolRemoteParam(protocolStorageType, protocolId),
|
||||
strNewFmt(PROTOCOL_SERVICE_REMOTE "-%u process on '%s'", protocolId, strPtr(cfgOptionStr(cfgOptRepoHost))),
|
||||
(TimeMSec)(cfgOptionDbl(cfgOptProtocolTimeout) * 1000));
|
||||
execOpen(protocolHelper.remoteExec);
|
||||
execOpen(protocolHelperClient->exec);
|
||||
|
||||
// Create protocol object
|
||||
protocolHelper.remote = protocolClientNew(
|
||||
strNewFmt("remote-%u protocol on '%s'", remoteId, strPtr(cfgOptionStr(cfgOptRepoHost))),
|
||||
PROTOCOL_SERVICE_REMOTE_STR, execIoRead(protocolHelper.remoteExec), execIoWrite(protocolHelper.remoteExec));
|
||||
protocolHelperClient->client = protocolClientNew(
|
||||
strNewFmt(PROTOCOL_SERVICE_REMOTE "-%u protocol on '%s'", protocolId, strPtr(cfgOptionStr(cfgOptRepoHost))),
|
||||
PROTOCOL_SERVICE_REMOTE_STR, execIoRead(protocolHelperClient->exec), execIoWrite(protocolHelperClient->exec));
|
||||
|
||||
// Get cipher options from the remote if none are locally configured
|
||||
if (strEq(cfgOptionStr(cfgOptRepoCipherType), CIPHER_TYPE_NONE_STR))
|
||||
@ -149,7 +282,7 @@ protocolGet(RemoteType remoteType, unsigned int remoteId)
|
||||
varLstAdd(param, varNewStr(strNew(cfgOptionName(cfgOptRepoCipherType))));
|
||||
varLstAdd(param, varNewStr(strNew(cfgOptionName(cfgOptRepoCipherPass))));
|
||||
|
||||
VariantList *optionList = configProtocolOption(protocolHelper.remote, param);
|
||||
VariantList *optionList = configProtocolOption(protocolHelperClient->client, param);
|
||||
|
||||
if (!strEq(varStr(varLstGet(optionList, 0)), CIPHER_TYPE_NONE_STR))
|
||||
{
|
||||
@ -158,12 +291,12 @@ protocolGet(RemoteType remoteType, unsigned int remoteId)
|
||||
}
|
||||
}
|
||||
|
||||
protocolClientMove(protocolHelper.remote, execMemContext(protocolHelper.remoteExec));
|
||||
protocolClientMove(protocolHelperClient->client, execMemContext(protocolHelperClient->exec));
|
||||
}
|
||||
MEM_CONTEXT_END();
|
||||
}
|
||||
|
||||
FUNCTION_LOG_RETURN(PROTOCOL_CLIENT, protocolHelper.remote);
|
||||
FUNCTION_LOG_RETURN(PROTOCOL_CLIENT, protocolHelperClient->client);
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
@ -174,12 +307,37 @@ protocolFree(void)
|
||||
{
|
||||
FUNCTION_LOG_VOID(logLevelTrace);
|
||||
|
||||
if (protocolHelper.remote != NULL)
|
||||
if (protocolHelper.memContext != NULL)
|
||||
{
|
||||
protocolClientFree(protocolHelper.remote);
|
||||
execFree(protocolHelper.remoteExec);
|
||||
// Free remotes
|
||||
for (unsigned int clientIdx = 0; clientIdx < protocolHelper.clientRemoteSize; clientIdx++)
|
||||
{
|
||||
ProtocolHelperClient *protocolHelperClient = &protocolHelper.clientRemote[clientIdx];
|
||||
|
||||
protocolHelper.remote = NULL;
|
||||
if (protocolHelperClient->client != NULL)
|
||||
{
|
||||
protocolClientFree(protocolHelperClient->client);
|
||||
execFree(protocolHelperClient->exec);
|
||||
|
||||
protocolHelperClient->client = NULL;
|
||||
protocolHelperClient->exec = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Free locals
|
||||
for (unsigned int clientIdx = 0; clientIdx < protocolHelper.clientLocalSize; clientIdx++)
|
||||
{
|
||||
ProtocolHelperClient *protocolHelperClient = &protocolHelper.clientLocal[clientIdx];
|
||||
|
||||
if (protocolHelperClient->client != NULL)
|
||||
{
|
||||
protocolClientFree(protocolHelperClient->client);
|
||||
execFree(protocolHelperClient->exec);
|
||||
|
||||
protocolHelperClient->client = NULL;
|
||||
protocolHelperClient->exec = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FUNCTION_LOG_RETURN_VOID();
|
||||
|
@ -4,19 +4,39 @@ Protocol Helper
|
||||
#ifndef PROTOCOL_HELPER_H
|
||||
#define PROTOCOL_HELPER_H
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Protocol storage type enum
|
||||
***********************************************************************************************************************************/
|
||||
typedef enum
|
||||
{
|
||||
protocolStorageTypeRepo,
|
||||
protocolStorageTypePg,
|
||||
} ProtocolStorageType;
|
||||
|
||||
#include "protocol/client.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Constants
|
||||
***********************************************************************************************************************************/
|
||||
#define PROTOCOL_SERVICE_LOCAL "local"
|
||||
STRING_DECLARE(PROTOCOL_SERVICE_LOCAL_STR);
|
||||
#define PROTOCOL_SERVICE_REMOTE "remote"
|
||||
STRING_DECLARE(PROTOCOL_SERVICE_REMOTE_STR);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Functions
|
||||
***********************************************************************************************************************************/
|
||||
ProtocolClient *protocolLocalGet(ProtocolStorageType protocolStorageType, unsigned int protocolId);
|
||||
ProtocolClient *protocolRemoteGet(ProtocolStorageType protocolStorageType, unsigned int protocolId);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Getters
|
||||
***********************************************************************************************************************************/
|
||||
bool repoIsLocal(void);
|
||||
ProtocolClient *protocolGet(RemoteType remoteType, unsigned int remoteId);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Destructor
|
||||
***********************************************************************************************************************************/
|
||||
void protocolFree(void);
|
||||
|
||||
#endif
|
||||
|
@ -30,14 +30,14 @@ New object
|
||||
***********************************************************************************************************************************/
|
||||
StorageDriverRemote *
|
||||
storageDriverRemoteNew(
|
||||
mode_t modeFile, mode_t modePath, bool write, StoragePathExpressionCallback pathExpressionFunction, RemoteType remoteType,
|
||||
unsigned int remoteId)
|
||||
mode_t modeFile, mode_t modePath, bool write, StoragePathExpressionCallback pathExpressionFunction, ProtocolClient *client)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(MODE, modeFile);
|
||||
FUNCTION_LOG_PARAM(MODE, modePath);
|
||||
FUNCTION_LOG_PARAM(BOOL, write);
|
||||
FUNCTION_LOG_PARAM(FUNCTIONP, pathExpressionFunction);
|
||||
FUNCTION_LOG_PARAM(PROTOCOL_CLIENT, client);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
ASSERT(modeFile != 0);
|
||||
@ -51,7 +51,7 @@ storageDriverRemoteNew(
|
||||
this = memNew(sizeof(StorageDriverRemote));
|
||||
this->memContext = MEM_CONTEXT_NEW();
|
||||
|
||||
this->client = protocolGet(remoteType, remoteId);
|
||||
this->client = client;
|
||||
|
||||
// Create the storage interface
|
||||
this->interface = storageNewP(
|
||||
|
@ -23,8 +23,7 @@ Driver type constant
|
||||
Constructor
|
||||
***********************************************************************************************************************************/
|
||||
StorageDriverRemote *storageDriverRemoteNew(
|
||||
mode_t modeFile, mode_t modePath, bool write, StoragePathExpressionCallback pathExpressionFunction, RemoteType remoteType,
|
||||
unsigned int remoteId);
|
||||
mode_t modeFile, mode_t modePath, bool write, StoragePathExpressionCallback pathExpressionFunction, ProtocolClient *client);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Functions
|
||||
|
@ -209,7 +209,8 @@ storageRepoGet(const String *type, bool write)
|
||||
{
|
||||
result = storageDriverRemoteInterface(
|
||||
storageDriverRemoteNew(
|
||||
STORAGE_MODE_FILE_DEFAULT, STORAGE_MODE_PATH_DEFAULT, write, storageRepoPathExpression, remoteTypeRepo, 1));
|
||||
STORAGE_MODE_FILE_DEFAULT, STORAGE_MODE_PATH_DEFAULT, write, storageRepoPathExpression,
|
||||
protocolRemoteGet(protocolStorageTypeRepo, 1)));
|
||||
}
|
||||
// For now treat posix and cifs drivers as if they are the same. This won't be true once the repository storage becomes
|
||||
// writable but for now it's OK. The assertion above should pop if we try to create writable repo storage.
|
||||
|
@ -724,6 +724,13 @@ unit:
|
||||
coverage:
|
||||
command/info/info: full
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------------------------------
|
||||
- name: local
|
||||
total: 1
|
||||
|
||||
coverage:
|
||||
command/local/local: full
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------------------------------
|
||||
- name: remote
|
||||
total: 1
|
||||
|
@ -298,9 +298,8 @@ sub run
|
||||
my $oGetAsync = new pgBackRest::Archive::Get::Async(
|
||||
$self->{strSpoolPath}, $self->backrestExe(), \@stryWal);
|
||||
|
||||
$self->optionTestSetBool(CFGOPT_ARCHIVE_ASYNC, true);
|
||||
$self->optionTestSet(CFGOPT_SPOOL_PATH, $self->{strRepoPath});
|
||||
$self->configTestLoad(CFGCMD_ARCHIVE_GET);
|
||||
$self->configTestLoad(CFGCMD_ARCHIVE_GET_ASYNC);
|
||||
|
||||
$oGetAsync->process();
|
||||
|
||||
@ -372,7 +371,7 @@ sub run
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->optionTestSet(CFGOPT_PROTOCOL_TIMEOUT, 30);
|
||||
$self->optionTestSet(CFGOPT_DB_TIMEOUT, 29);
|
||||
$self->configTestLoad(CFGCMD_ARCHIVE_GET);
|
||||
$self->configTestLoad(CFGCMD_ARCHIVE_GET_ASYNC);
|
||||
|
||||
$oGetAsync->process();
|
||||
}
|
||||
|
64
test/src/module/command/localTest.c
Normal file
64
test/src/module/command/localTest.c
Normal file
@ -0,0 +1,64 @@
|
||||
/***********************************************************************************************************************************
|
||||
Test Local Command
|
||||
***********************************************************************************************************************************/
|
||||
#include "common/io/handleRead.h"
|
||||
#include "common/io/handleWrite.h"
|
||||
#include "protocol/client.h"
|
||||
#include "protocol/server.h"
|
||||
|
||||
#include "common/harnessConfig.h"
|
||||
#include "common/harnessFork.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Test Run
|
||||
***********************************************************************************************************************************/
|
||||
void
|
||||
testRun(void)
|
||||
{
|
||||
FUNCTION_HARNESS_VOID();
|
||||
|
||||
// *****************************************************************************************************************************
|
||||
if (testBegin("cmdLocal()"))
|
||||
{
|
||||
// Create pipes for testing. Read/write is from the perspective of the client.
|
||||
int pipeRead[2];
|
||||
int pipeWrite[2];
|
||||
THROW_ON_SYS_ERROR(pipe(pipeRead) == -1, KernelError, "unable to read test pipe");
|
||||
THROW_ON_SYS_ERROR(pipe(pipeWrite) == -1, KernelError, "unable to write test pipe");
|
||||
|
||||
HARNESS_FORK_BEGIN()
|
||||
{
|
||||
HARNESS_FORK_CHILD_BEGIN(0, true)
|
||||
{
|
||||
StringList *argList = strLstNew();
|
||||
strLstAddZ(argList, "pgbackrest");
|
||||
strLstAddZ(argList, "--stanza=test1");
|
||||
strLstAddZ(argList, "--command=archive-get-async");
|
||||
strLstAddZ(argList, "--process=1");
|
||||
strLstAddZ(argList, "--type=backup");
|
||||
strLstAddZ(argList, "--host-id=1");
|
||||
strLstAddZ(argList, "local");
|
||||
harnessCfgLoad(strLstSize(argList), strLstPtr(argList));
|
||||
|
||||
cmdLocal(HARNESS_FORK_CHILD_READ(), HARNESS_FORK_CHILD_WRITE());
|
||||
}
|
||||
HARNESS_FORK_CHILD_END();
|
||||
|
||||
HARNESS_FORK_PARENT_BEGIN()
|
||||
{
|
||||
IoRead *read = ioHandleReadIo(ioHandleReadNew(strNew("server read"), HARNESS_FORK_PARENT_READ_PROCESS(0), 2000));
|
||||
ioReadOpen(read);
|
||||
IoWrite *write = ioHandleWriteIo(ioHandleWriteNew(strNew("server write"), HARNESS_FORK_PARENT_WRITE_PROCESS(0)));
|
||||
ioWriteOpen(write);
|
||||
|
||||
ProtocolClient *client = protocolClientNew(strNew("test"), PROTOCOL_SERVICE_LOCAL_STR, read, write);
|
||||
protocolClientNoOp(client);
|
||||
protocolClientFree(client);
|
||||
}
|
||||
HARNESS_FORK_PARENT_END();
|
||||
}
|
||||
HARNESS_FORK_END();
|
||||
}
|
||||
|
||||
FUNCTION_HARNESS_RESULT_VOID();
|
||||
}
|
@ -98,7 +98,7 @@ testRun(void)
|
||||
harnessCfgLoad(strLstSize(argList), strLstPtr(argList));
|
||||
|
||||
TEST_RESULT_STR(
|
||||
strPtr(strLstJoin(protocolParam(remoteTypeRepo, 1), "|")),
|
||||
strPtr(strLstJoin(protocolRemoteParam(protocolStorageTypeRepo, 1), "|")),
|
||||
strPtr(
|
||||
strNew(
|
||||
"-o|LogLevel=error|-o|Compression=no|-o|PasswordAuthentication=no|repo-host-user@repo-host"
|
||||
@ -119,7 +119,7 @@ testRun(void)
|
||||
harnessCfgLoad(strLstSize(argList), strLstPtr(argList));
|
||||
|
||||
TEST_RESULT_STR(
|
||||
strPtr(strLstJoin(protocolParam(remoteTypeRepo, 1), "|")),
|
||||
strPtr(strLstJoin(protocolRemoteParam(protocolStorageTypeRepo, 1), "|")),
|
||||
strPtr(
|
||||
strNew(
|
||||
"-o|LogLevel=error|-o|Compression=no|-o|PasswordAuthentication=no|-p|444|repo-host-user@repo-host"
|
||||
@ -161,12 +161,6 @@ testRun(void)
|
||||
// *****************************************************************************************************************************
|
||||
if (testBegin("ProtocolClient"))
|
||||
{
|
||||
// Create pipes for testing. Read/write is from the perspective of the client.
|
||||
int pipeRead[2];
|
||||
int pipeWrite[2];
|
||||
THROW_ON_SYS_ERROR(pipe(pipeRead) == -1, KernelError, "unable to read test pipe");
|
||||
THROW_ON_SYS_ERROR(pipe(pipeWrite) == -1, KernelError, "unable to write test pipe");
|
||||
|
||||
HARNESS_FORK_BEGIN()
|
||||
{
|
||||
HARNESS_FORK_CHILD_BEGIN(0, true)
|
||||
@ -590,10 +584,12 @@ testRun(void)
|
||||
|
||||
ProtocolClient *client = NULL;
|
||||
|
||||
TEST_ASSIGN(client, protocolGet(remoteTypeRepo, 1), "get protocol");
|
||||
TEST_RESULT_PTR(protocolGet(remoteTypeRepo, 1), client, "get cached protocol");
|
||||
TEST_RESULT_VOID(protocolFree(), "free protocol objects");
|
||||
TEST_RESULT_VOID(protocolFree(), "free protocol objects again");
|
||||
TEST_RESULT_VOID(protocolFree(), "free protocol objects before anything has been created");
|
||||
|
||||
TEST_ASSIGN(client, protocolRemoteGet(protocolStorageTypeRepo, 1), "get remote protocol");
|
||||
TEST_RESULT_PTR(protocolRemoteGet(protocolStorageTypeRepo, 1), client, "get remote cached protocol");
|
||||
TEST_RESULT_VOID(protocolFree(), "free remote protocol objects");
|
||||
TEST_RESULT_VOID(protocolFree(), "free remote protocol objects again");
|
||||
|
||||
// Start protocol with local encryption settings
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
@ -616,10 +612,10 @@ testRun(void)
|
||||
harnessCfgLoad(strLstSize(argList), strLstPtr(argList));
|
||||
|
||||
TEST_RESULT_STR(strPtr(cfgOptionStr(cfgOptRepoCipherPass)), "acbd", "check cipher pass before");
|
||||
TEST_ASSIGN(client, protocolGet(remoteTypeRepo, 1), "get protocol");
|
||||
TEST_ASSIGN(client, protocolRemoteGet(protocolStorageTypeRepo, 1), "get remote protocol");
|
||||
TEST_RESULT_STR(strPtr(cfgOptionStr(cfgOptRepoCipherPass)), "acbd", "check cipher pass after");
|
||||
|
||||
TEST_RESULT_VOID(protocolFree(), "free protocol objects");
|
||||
TEST_RESULT_VOID(protocolFree(), "free remote protocol objects");
|
||||
|
||||
// Start protocol with remote encryption settings
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
@ -642,10 +638,24 @@ testRun(void)
|
||||
harnessCfgLoad(strLstSize(argList), strLstPtr(argList));
|
||||
|
||||
TEST_RESULT_PTR(cfgOptionStr(cfgOptRepoCipherPass), NULL, "check cipher pass before");
|
||||
TEST_ASSIGN(client, protocolGet(remoteTypeRepo, 1), "get protocol");
|
||||
TEST_ASSIGN(client, protocolRemoteGet(protocolStorageTypeRepo, 1), "get remote protocol");
|
||||
TEST_RESULT_STR(strPtr(cfgOptionStr(cfgOptRepoCipherPass)), "dcba", "check cipher pass after");
|
||||
|
||||
TEST_RESULT_VOID(protocolFree(), "free protocol objects");
|
||||
// Start local protocol
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
argList = strLstNew();
|
||||
strLstAddZ(argList, "/usr/bin/pgbackrest");
|
||||
strLstAddZ(argList, "--stanza=db");
|
||||
strLstAddZ(argList, "--protocol-timeout=10");
|
||||
strLstAddZ(argList, "archive-get");
|
||||
harnessCfgLoad(strLstSize(argList), strLstPtr(argList));
|
||||
|
||||
TEST_ASSIGN(client, protocolLocalGet(protocolStorageTypeRepo, 1), "get local protocol");
|
||||
TEST_RESULT_PTR(protocolLocalGet(protocolStorageTypeRepo, 1), client, "get local cached protocol");
|
||||
TEST_RESULT_PTR(protocolHelper.clientLocal[0].client, client, "check location in cache");
|
||||
|
||||
TEST_RESULT_VOID(protocolFree(), "free local and remote protocol objects");
|
||||
TEST_RESULT_VOID(protocolFree(), "free local and remote protocol objects again");
|
||||
}
|
||||
|
||||
FUNCTION_HARNESS_RESULT_VOID();
|
||||
|
Reference in New Issue
Block a user