You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2026-05-22 10:15:16 +02:00
a474ba54c5
Not all storage types support paths as a physical thing that must be created/destroyed. Add a feature to determine which drivers use paths and simplify the driver API as much as possible given that knowledge and by implementing as much path logic as possible in the Storage object. Remove the ignoreMissing parameter from pathSync() since it is not used and makes little sense. Create a standard list of error messages for the drivers to use and apply them where the code was modified -- there is plenty of work still to be done here.
235 lines
8.5 KiB
C
235 lines
8.5 KiB
C
/***********************************************************************************************************************************
|
|
Posix Storage Read
|
|
***********************************************************************************************************************************/
|
|
#include "build.auto.h"
|
|
|
|
#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/object.h"
|
|
#include "storage/posix/read.h"
|
|
#include "storage/posix/storage.intern.h"
|
|
#include "storage/read.intern.h"
|
|
|
|
/***********************************************************************************************************************************
|
|
Object types
|
|
***********************************************************************************************************************************/
|
|
#define STORAGE_READ_POSIX_TYPE StorageReadPosix
|
|
#define STORAGE_READ_POSIX_PREFIX storageReadPosix
|
|
|
|
typedef struct StorageReadPosix
|
|
{
|
|
MemContext *memContext; // Object mem context
|
|
StorageReadInterface interface; // Interface
|
|
StoragePosix *storage; // Storage that created this object
|
|
|
|
int handle;
|
|
bool eof;
|
|
} StorageReadPosix;
|
|
|
|
/***********************************************************************************************************************************
|
|
Macros for function logging
|
|
***********************************************************************************************************************************/
|
|
#define FUNCTION_LOG_STORAGE_READ_POSIX_TYPE \
|
|
StorageReadPosix *
|
|
#define FUNCTION_LOG_STORAGE_READ_POSIX_FORMAT(value, buffer, bufferSize) \
|
|
objToLog(value, "StorageReadPosix", buffer, bufferSize)
|
|
|
|
/***********************************************************************************************************************************
|
|
Close the file handle
|
|
***********************************************************************************************************************************/
|
|
OBJECT_DEFINE_FREE_RESOURCE_BEGIN(STORAGE_READ_POSIX, LOG, logLevelTrace)
|
|
{
|
|
if (this->handle != -1)
|
|
THROW_ON_SYS_ERROR_FMT(close(this->handle) == -1, FileCloseError, STORAGE_ERROR_READ_CLOSE, strPtr(this->interface.name));
|
|
}
|
|
OBJECT_DEFINE_FREE_RESOURCE_END(LOG);
|
|
|
|
/***********************************************************************************************************************************
|
|
Open the file
|
|
***********************************************************************************************************************************/
|
|
static bool
|
|
storageReadPosixOpen(THIS_VOID)
|
|
{
|
|
THIS(StorageReadPosix);
|
|
|
|
FUNCTION_LOG_BEGIN(logLevelTrace);
|
|
FUNCTION_LOG_PARAM(STORAGE_READ_POSIX, this);
|
|
FUNCTION_LOG_END();
|
|
|
|
ASSERT(this != NULL);
|
|
ASSERT(this->handle == -1);
|
|
|
|
bool result = false;
|
|
|
|
// Open the file
|
|
this->handle = open(strPtr(this->interface.name), O_RDONLY, 0);
|
|
|
|
// Handle errors
|
|
if (this->handle == -1)
|
|
{
|
|
if (errno == ENOENT)
|
|
{
|
|
if (!this->interface.ignoreMissing)
|
|
THROW_FMT(FileMissingError, STORAGE_ERROR_READ_MISSING, strPtr(this->interface.name));
|
|
}
|
|
else
|
|
THROW_SYS_ERROR_FMT(FileOpenError, STORAGE_ERROR_READ_OPEN, strPtr(this->interface.name));
|
|
}
|
|
// On success set free callback to ensure file handle is freed
|
|
if (this->handle != -1)
|
|
{
|
|
memContextCallbackSet(this->memContext, storageReadPosixFreeResource, this);
|
|
result = true;
|
|
}
|
|
|
|
FUNCTION_LOG_RETURN(BOOL, result);
|
|
}
|
|
|
|
/***********************************************************************************************************************************
|
|
Read from a file
|
|
***********************************************************************************************************************************/
|
|
static size_t
|
|
storageReadPosix(THIS_VOID, Buffer *buffer, bool block)
|
|
{
|
|
THIS(StorageReadPosix);
|
|
|
|
FUNCTION_LOG_BEGIN(logLevelTrace);
|
|
FUNCTION_LOG_PARAM(STORAGE_READ_POSIX, this);
|
|
FUNCTION_LOG_PARAM(BUFFER, buffer);
|
|
FUNCTION_LOG_PARAM(BOOL, block);
|
|
FUNCTION_LOG_END();
|
|
|
|
ASSERT(this != NULL && this->handle != -1);
|
|
ASSERT(buffer != NULL && !bufFull(buffer));
|
|
|
|
// Read if EOF has not been reached
|
|
ssize_t actualBytes = 0;
|
|
|
|
if (!this->eof)
|
|
{
|
|
// Read and handle errors
|
|
size_t expectedBytes = bufRemains(buffer);
|
|
actualBytes = read(this->handle, bufRemainsPtr(buffer), expectedBytes);
|
|
|
|
// Error occurred during read
|
|
if (actualBytes == -1)
|
|
THROW_SYS_ERROR_FMT(FileReadError, "unable to read '%s'", strPtr(this->interface.name));
|
|
|
|
// Update amount of buffer used
|
|
bufUsedInc(buffer, (size_t)actualBytes);
|
|
|
|
// If less data than expected was read then EOF. The file may not actually be EOF but we are not concerned with files that
|
|
// are growing. Just read up to the point where the file is being extended.
|
|
if ((size_t)actualBytes != expectedBytes)
|
|
this->eof = true;
|
|
}
|
|
|
|
FUNCTION_LOG_RETURN(SIZE, (size_t)actualBytes);
|
|
}
|
|
|
|
/***********************************************************************************************************************************
|
|
Close the file
|
|
***********************************************************************************************************************************/
|
|
static void
|
|
storageReadPosixClose(THIS_VOID)
|
|
{
|
|
THIS(StorageReadPosix);
|
|
|
|
FUNCTION_LOG_BEGIN(logLevelTrace);
|
|
FUNCTION_LOG_PARAM(STORAGE_READ_POSIX, this);
|
|
FUNCTION_LOG_END();
|
|
|
|
ASSERT(this != NULL);
|
|
|
|
storageReadPosixFreeResource(this);
|
|
memContextCallbackClear(this->memContext);
|
|
this->handle = -1;
|
|
|
|
FUNCTION_LOG_RETURN_VOID();
|
|
}
|
|
|
|
/***********************************************************************************************************************************
|
|
Has file reached EOF?
|
|
***********************************************************************************************************************************/
|
|
static bool
|
|
storageReadPosixEof(THIS_VOID)
|
|
{
|
|
THIS(StorageReadPosix);
|
|
|
|
FUNCTION_TEST_BEGIN();
|
|
FUNCTION_TEST_PARAM(STORAGE_READ_POSIX, this);
|
|
FUNCTION_TEST_END();
|
|
|
|
ASSERT(this != NULL);
|
|
|
|
FUNCTION_TEST_RETURN(this->eof);
|
|
}
|
|
|
|
/***********************************************************************************************************************************
|
|
Get handle (file descriptor)
|
|
***********************************************************************************************************************************/
|
|
static int
|
|
storageReadPosixHandle(const THIS_VOID)
|
|
{
|
|
THIS(const StorageReadPosix);
|
|
|
|
FUNCTION_TEST_BEGIN();
|
|
FUNCTION_TEST_PARAM(STORAGE_READ_POSIX, this);
|
|
FUNCTION_TEST_END();
|
|
|
|
ASSERT(this != NULL);
|
|
|
|
FUNCTION_TEST_RETURN(this->handle);
|
|
}
|
|
|
|
/***********************************************************************************************************************************
|
|
New object
|
|
***********************************************************************************************************************************/
|
|
StorageRead *
|
|
storageReadPosixNew(StoragePosix *storage, const String *name, bool ignoreMissing)
|
|
{
|
|
FUNCTION_LOG_BEGIN(logLevelTrace);
|
|
FUNCTION_LOG_PARAM(STRING, name);
|
|
FUNCTION_LOG_PARAM(BOOL, ignoreMissing);
|
|
FUNCTION_LOG_END();
|
|
|
|
ASSERT(name != NULL);
|
|
|
|
StorageRead *this = NULL;
|
|
|
|
MEM_CONTEXT_NEW_BEGIN("StorageReadPosix")
|
|
{
|
|
StorageReadPosix *driver = memNew(sizeof(StorageReadPosix));
|
|
driver->memContext = MEM_CONTEXT_NEW();
|
|
|
|
driver->interface = (StorageReadInterface)
|
|
{
|
|
.type = STORAGE_POSIX_TYPE_STR,
|
|
.name = strDup(name),
|
|
.ignoreMissing = ignoreMissing,
|
|
|
|
.ioInterface = (IoReadInterface)
|
|
{
|
|
.close = storageReadPosixClose,
|
|
.eof = storageReadPosixEof,
|
|
.handle = storageReadPosixHandle,
|
|
.open = storageReadPosixOpen,
|
|
.read = storageReadPosix,
|
|
},
|
|
};
|
|
|
|
driver->storage = storage;
|
|
driver->handle = -1;
|
|
|
|
this = storageReadNew(driver, &driver->interface);
|
|
}
|
|
MEM_CONTEXT_NEW_END();
|
|
|
|
FUNCTION_LOG_RETURN(STORAGE_READ, this);
|
|
}
|