You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-06-18 23:57:33 +02:00
Prior to this the Perl remote was used to satisfy C requests. This worked fine but since the remote needed to be migrated to C anyway there was no reason to wait. Add the ProtocolServer object and tweak ProtocolClient to work with it. It was also necessary to add a mechanism to get option values from the remote so that encryption settings could be read and used in the storage object. Update the remote storage objects to comply with the protocol changes and add the storage protocol handler. Ideally this commit would have been broken up into smaller chunks but there are cross-dependencies in the protocol layer and it didn't seem worth the extra effort.
289 lines
11 KiB
C
289 lines
11 KiB
C
/***********************************************************************************************************************************
|
|
Remote Storage File Read Driver
|
|
***********************************************************************************************************************************/
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
|
|
#include "common/debug.h"
|
|
#include "common/io/read.intern.h"
|
|
#include "common/log.h"
|
|
#include "common/memContext.h"
|
|
#include "common/regExp.h"
|
|
#include "common/type/convert.h"
|
|
#include "storage/driver/remote/fileRead.h"
|
|
#include "storage/driver/remote/protocol.h"
|
|
#include "storage/fileRead.intern.h"
|
|
|
|
/***********************************************************************************************************************************
|
|
Regular expressions
|
|
***********************************************************************************************************************************/
|
|
STRING_STATIC(BLOCK_REG_EXP_STR, PROTOCOL_BLOCK_HEADER "[0-9]+");
|
|
|
|
/***********************************************************************************************************************************
|
|
Object type
|
|
***********************************************************************************************************************************/
|
|
struct StorageDriverRemoteFileRead
|
|
{
|
|
MemContext *memContext;
|
|
StorageDriverRemote *storage;
|
|
StorageFileRead *interface;
|
|
IoRead *io;
|
|
String *name;
|
|
bool ignoreMissing;
|
|
|
|
ProtocolClient *client; // Protocol client for requests
|
|
size_t remaining; // Bytes remaining to be read
|
|
bool eof; // Has the file reached eof?
|
|
};
|
|
|
|
/***********************************************************************************************************************************
|
|
Local variables
|
|
***********************************************************************************************************************************/
|
|
static struct
|
|
{
|
|
MemContext *memContext; // Mem context for protocol helper
|
|
RegExp *blockRegExp; // Regular expression to check block messages
|
|
} storageDriverRemoteFileReadLocal;
|
|
|
|
/***********************************************************************************************************************************
|
|
Create a new file
|
|
***********************************************************************************************************************************/
|
|
StorageDriverRemoteFileRead *
|
|
storageDriverRemoteFileReadNew(StorageDriverRemote *storage, ProtocolClient *client, const String *name, bool ignoreMissing)
|
|
{
|
|
FUNCTION_LOG_BEGIN(logLevelTrace);
|
|
FUNCTION_LOG_PARAM(STORAGE_DRIVER_REMOTE, storage);
|
|
FUNCTION_LOG_PARAM(PROTOCOL_CLIENT, client);
|
|
FUNCTION_LOG_PARAM(STRING, name);
|
|
FUNCTION_LOG_PARAM(BOOL, ignoreMissing);
|
|
FUNCTION_LOG_END();
|
|
|
|
ASSERT(storage != NULL);
|
|
ASSERT(client != NULL);
|
|
ASSERT(name != NULL);
|
|
|
|
StorageDriverRemoteFileRead *this = NULL;
|
|
|
|
// Create the file object
|
|
MEM_CONTEXT_NEW_BEGIN("StorageDriverRemoteFileRead")
|
|
{
|
|
this = memNew(sizeof(StorageDriverRemoteFileRead));
|
|
this->memContext = MEM_CONTEXT_NEW();
|
|
this->storage = storage;
|
|
this->name = strDup(name);
|
|
this->ignoreMissing = ignoreMissing;
|
|
|
|
this->client = client;
|
|
|
|
// Create block regular expression if it has not been created yet
|
|
if (storageDriverRemoteFileReadLocal.memContext == NULL)
|
|
{
|
|
MEM_CONTEXT_BEGIN(memContextTop())
|
|
{
|
|
MEM_CONTEXT_NEW_BEGIN("StorageDriverRemoteFileReadLocal")
|
|
{
|
|
storageDriverRemoteFileReadLocal.memContext = memContextCurrent();
|
|
storageDriverRemoteFileReadLocal.blockRegExp = regExpNew(BLOCK_REG_EXP_STR);
|
|
}
|
|
MEM_CONTEXT_NEW_END();
|
|
}
|
|
MEM_CONTEXT_END();
|
|
}
|
|
|
|
this->interface = storageFileReadNewP(
|
|
strNew(STORAGE_DRIVER_REMOTE_TYPE), this,
|
|
.ignoreMissing = (StorageFileReadInterfaceIgnoreMissing)storageDriverRemoteFileReadIgnoreMissing,
|
|
.io = (StorageFileReadInterfaceIo)storageDriverRemoteFileReadIo,
|
|
.name = (StorageFileReadInterfaceName)storageDriverRemoteFileReadName);
|
|
|
|
this->io = ioReadNewP(
|
|
this, .eof = (IoReadInterfaceEof)storageDriverRemoteFileReadEof,
|
|
.open = (IoReadInterfaceOpen)storageDriverRemoteFileReadOpen, .read = (IoReadInterfaceRead)storageDriverRemoteFileRead);
|
|
}
|
|
MEM_CONTEXT_NEW_END();
|
|
|
|
FUNCTION_LOG_RETURN(STORAGE_DRIVER_REMOTE_FILE_READ, this);
|
|
}
|
|
|
|
/***********************************************************************************************************************************
|
|
Open the file
|
|
***********************************************************************************************************************************/
|
|
bool
|
|
storageDriverRemoteFileReadOpen(StorageDriverRemoteFileRead *this)
|
|
{
|
|
FUNCTION_LOG_BEGIN(logLevelTrace);
|
|
FUNCTION_LOG_PARAM(STORAGE_DRIVER_REMOTE_FILE_READ, this);
|
|
FUNCTION_LOG_END();
|
|
|
|
ASSERT(this != NULL);
|
|
|
|
bool result = false;
|
|
|
|
MEM_CONTEXT_TEMP_BEGIN()
|
|
{
|
|
// Add parameters
|
|
Variant *param = varNewVarLst(varLstNew());
|
|
varLstAdd(varVarLst(param), varNewStr(this->name));
|
|
varLstAdd(varVarLst(param), varNewBool(this->ignoreMissing));
|
|
|
|
// Construct command
|
|
KeyValue *command = kvPut(kvNew(), varNewStr(PROTOCOL_COMMAND_STR), varNewStr(PROTOCOL_COMMAND_STORAGE_OPEN_READ_STR));
|
|
kvPut(command, varNewStr(PROTOCOL_PARAMETER_STR), param);
|
|
|
|
result = varBool(protocolClientExecute(this->client, command, true));
|
|
}
|
|
MEM_CONTEXT_TEMP_END();
|
|
|
|
FUNCTION_LOG_RETURN(BOOL, result);
|
|
}
|
|
|
|
/***********************************************************************************************************************************
|
|
Get size of the next transfer block
|
|
***********************************************************************************************************************************/
|
|
static size_t
|
|
storageDriverRemoteFileReadBlockSize(const String *message)
|
|
{
|
|
FUNCTION_LOG_BEGIN(logLevelTrace);
|
|
FUNCTION_LOG_PARAM(STRING, message);
|
|
FUNCTION_LOG_END();
|
|
|
|
ASSERT(message != NULL);
|
|
|
|
if (!regExpMatch(storageDriverRemoteFileReadLocal.blockRegExp, message))
|
|
THROW_FMT(ProtocolError, "'%s' is not a valid block size message", strPtr(message));
|
|
|
|
FUNCTION_LOG_RETURN(SIZE, (size_t)cvtZToUInt64(strPtr(message) + sizeof(PROTOCOL_BLOCK_HEADER) - 1));
|
|
}
|
|
|
|
/***********************************************************************************************************************************
|
|
Read from a file
|
|
***********************************************************************************************************************************/
|
|
size_t
|
|
storageDriverRemoteFileRead(StorageDriverRemoteFileRead *this, Buffer *buffer, bool block)
|
|
{
|
|
FUNCTION_LOG_BEGIN(logLevelTrace);
|
|
FUNCTION_LOG_PARAM(STORAGE_DRIVER_REMOTE_FILE_READ, this);
|
|
FUNCTION_LOG_PARAM(BUFFER, buffer);
|
|
FUNCTION_LOG_PARAM(BOOL, block);
|
|
FUNCTION_LOG_END();
|
|
|
|
ASSERT(this != NULL);
|
|
ASSERT(buffer != NULL && !bufFull(buffer));
|
|
|
|
size_t result = 0;
|
|
|
|
// Read if eof has not been reached
|
|
if (!this->eof)
|
|
{
|
|
do
|
|
{
|
|
// If no bytes remaining then read a new block
|
|
if (this->remaining == 0)
|
|
{
|
|
MEM_CONTEXT_TEMP_BEGIN()
|
|
{
|
|
this->remaining = storageDriverRemoteFileReadBlockSize(ioReadLine(protocolClientIoRead(this->client)));
|
|
|
|
if (this->remaining == 0)
|
|
this->eof = true;
|
|
}
|
|
MEM_CONTEXT_TEMP_END();
|
|
}
|
|
|
|
// Read if not eof
|
|
if (!this->eof)
|
|
{
|
|
// If the buffer can contain all remaining bytes
|
|
if (bufRemains(buffer) >= this->remaining)
|
|
{
|
|
bufLimitSet(buffer, bufUsed(buffer) + this->remaining);
|
|
ioRead(protocolClientIoRead(this->client), buffer);
|
|
bufLimitClear(buffer);
|
|
this->remaining = 0;
|
|
}
|
|
// Else read what we can
|
|
else
|
|
this->remaining -= ioRead(protocolClientIoRead(this->client), buffer);
|
|
}
|
|
}
|
|
while (!this->eof && !bufFull(buffer));
|
|
}
|
|
|
|
FUNCTION_LOG_RETURN(SIZE, result);
|
|
}
|
|
|
|
/***********************************************************************************************************************************
|
|
Has file reached EOF?
|
|
***********************************************************************************************************************************/
|
|
bool
|
|
storageDriverRemoteFileReadEof(const StorageDriverRemoteFileRead *this)
|
|
{
|
|
FUNCTION_TEST_BEGIN();
|
|
FUNCTION_TEST_PARAM(STORAGE_DRIVER_REMOTE_FILE_READ, this);
|
|
FUNCTION_TEST_END();
|
|
|
|
ASSERT(this != NULL);
|
|
|
|
FUNCTION_TEST_RETURN(this->eof);
|
|
}
|
|
|
|
/***********************************************************************************************************************************
|
|
Should a missing file be ignored?
|
|
***********************************************************************************************************************************/
|
|
bool
|
|
storageDriverRemoteFileReadIgnoreMissing(const StorageDriverRemoteFileRead *this)
|
|
{
|
|
FUNCTION_TEST_BEGIN();
|
|
FUNCTION_TEST_PARAM(STORAGE_DRIVER_REMOTE_FILE_READ, this);
|
|
FUNCTION_TEST_END();
|
|
|
|
ASSERT(this != NULL);
|
|
|
|
FUNCTION_TEST_RETURN(this->ignoreMissing);
|
|
}
|
|
|
|
/***********************************************************************************************************************************
|
|
Get the interface
|
|
***********************************************************************************************************************************/
|
|
StorageFileRead *
|
|
storageDriverRemoteFileReadInterface(const StorageDriverRemoteFileRead *this)
|
|
{
|
|
FUNCTION_TEST_BEGIN();
|
|
FUNCTION_TEST_PARAM(STORAGE_DRIVER_REMOTE_FILE_READ, this);
|
|
FUNCTION_TEST_END();
|
|
|
|
ASSERT(this != NULL);
|
|
|
|
FUNCTION_TEST_RETURN(this->interface);
|
|
}
|
|
|
|
/***********************************************************************************************************************************
|
|
Get the I/O interface
|
|
***********************************************************************************************************************************/
|
|
IoRead *
|
|
storageDriverRemoteFileReadIo(const StorageDriverRemoteFileRead *this)
|
|
{
|
|
FUNCTION_TEST_BEGIN();
|
|
FUNCTION_TEST_PARAM(STORAGE_DRIVER_REMOTE_FILE_READ, this);
|
|
FUNCTION_TEST_END();
|
|
|
|
ASSERT(this != NULL);
|
|
|
|
FUNCTION_TEST_RETURN(this->io);
|
|
}
|
|
|
|
/***********************************************************************************************************************************
|
|
File name
|
|
***********************************************************************************************************************************/
|
|
const String *
|
|
storageDriverRemoteFileReadName(const StorageDriverRemoteFileRead *this)
|
|
{
|
|
FUNCTION_TEST_BEGIN();
|
|
FUNCTION_TEST_PARAM(STORAGE_DRIVER_REMOTE_FILE_READ, this);
|
|
FUNCTION_TEST_END();
|
|
|
|
ASSERT(this != NULL);
|
|
|
|
FUNCTION_TEST_RETURN(this->name);
|
|
}
|