1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-01-18 04:58:51 +02:00

Add const buffer functions to Pack type.

These allow packs to be created without allocating a buffer in the case that the buffer already exists or the data is in a global constant.

Also fix a rendering issue in hrnPackReadToStr().
This commit is contained in:
David Steele 2021-10-15 15:50:55 -04:00
parent 66bfd1327e
commit 144469b977
4 changed files with 136 additions and 3 deletions

View File

@ -391,9 +391,22 @@ pckReadNew(const Pack *const pack)
if (pack == NULL)
FUNCTION_TEST_RETURN(NULL);
FUNCTION_TEST_RETURN(pckReadNewC(bufPtrConst((const Buffer *)pack), bufUsed((const Buffer *)pack)));
}
PackRead *
pckReadNewC(const unsigned char *const buffer, size_t size)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM_P(VOID, buffer);
FUNCTION_TEST_PARAM(SIZE, size);
FUNCTION_TEST_END();
ASSERT(buffer != NULL);
PackRead *this = pckReadNewInternal();
this->bufferPtr = bufPtrConst((const Buffer *)pack);
this->bufferUsed = bufUsed((const Buffer *)pack);
this->bufferPtr = buffer;
this->bufferUsed = size;
FUNCTION_TEST_RETURN(this);
}
@ -720,6 +733,54 @@ pckReadId(PackRead *this)
FUNCTION_TEST_RETURN(this->tagNextId);
}
/**********************************************************************************************************************************/
size_t
pckReadSize(PackRead *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(PACK_READ, this);
FUNCTION_TEST_END();
ASSERT(this != NULL);
ASSERT(packTypeMapData[this->tagNextTypeMap].size);
FUNCTION_TEST_RETURN(this->tagNextSize);
}
/**********************************************************************************************************************************/
void
pckReadConsume(PackRead *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(PACK_READ, this);
FUNCTION_TEST_END();
ASSERT(this != NULL);
unsigned int id = 0;
pckReadTag(this, &id, pckTypeMapUnknown, true);
pckReadTag(this, &id, this->tagNextTypeMap, false);
pckReadConsumeBuffer(this);
FUNCTION_TEST_RETURN_VOID();
}
/**********************************************************************************************************************************/
const unsigned char *
pckReadBufPtr(PackRead *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(PACK_READ, this);
FUNCTION_TEST_END();
ASSERT(this != NULL);
ASSERT(packTypeMapData[this->tagNextTypeMap].size);
ASSERT(this->buffer == NULL);
FUNCTION_TEST_RETURN(this->bufferPtr + this->bufferPos);
}
/**********************************************************************************************************************************/
// Internal version of pckReadNull() that does not require a PackIdParam struct. Some functions already have an id variable so
// assigning that to a PackIdParam struct and then copying it back is wasteful.
@ -991,6 +1052,27 @@ pckReadPackRead(PackRead *this, PckReadPackParam param)
FUNCTION_TEST_RETURN(result);
}
PackRead *
pckReadPackReadConst(PackRead *this, PckReadPackParam param)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(PACK_READ, this);
FUNCTION_TEST_PARAM(UINT, param.id);
FUNCTION_TEST_END();
if (pckReadNullInternal(this, &param.id))
FUNCTION_TEST_RETURN(NULL);
// Read the tag
pckReadTag(this, &param.id, pckTypeMapPack, false);
PackRead *const result = pckReadNewC(pckReadBufPtr(this), pckReadSize(this));
pckReadConsumeBuffer(this);
FUNCTION_TEST_RETURN(result);
}
Pack *
pckReadPack(PackRead *const this, PckReadPackParam param)
{

View File

@ -167,6 +167,7 @@ Read Constructors
***********************************************************************************************************************************/
// Note that the pack is not moved into the PackRead mem context and must be moved explicitly if the PackRead object is moved.
PackRead *pckReadNew(const Pack *pack);
PackRead *pckReadNewC(const unsigned char *const buffer, size_t size);
PackRead *pckReadNewIo(IoRead *read);
@ -183,9 +184,19 @@ typedef struct PackIdParam
// debugging. If you just need to know if the field exists or not, then use pckReadNullP().
bool pckReadNext(PackRead *this);
// Current field buffer for fields that have a size, e.g. bin. Can only be used when the pack was created with pckReadNew(). Note
// that this pointer is tied to the buffer the pack was created with so be careful not to free it too soon.
const unsigned char *pckReadBufPtr(PackRead *this);
// Consume the next field regardless of type.
void pckReadConsume(PackRead *this);
// Current field id. Set after a call to pckReadNext().
unsigned int pckReadId(PackRead *this);
// Current field size for fields that have a size, e.g. bin
size_t pckReadSize(PackRead *this);
// Current field type. Set after a call to pckReadNext().
PackType pckReadType(PackRead *this);
@ -301,6 +312,13 @@ typedef struct PckReadPackParam
PackRead *pckReadPackRead(PackRead *this, PckReadPackParam param);
// Read pack using the same buffer passed to pckReadNew(). Note that this pointer is tied to the buffer the pack was created with so
// be careful not to free it too soon.
#define pckReadPackReadConstP(this, ...) \
pckReadPackReadConst(this, (PckReadPackParam){VAR_PARAM_INIT, __VA_ARGS__})
PackRead *pckReadPackReadConst(PackRead *this, PckReadPackParam param);
// Read pack buffer
#define pckReadPackP(this, ...) \
pckReadPack(this, (PckReadPackParam){VAR_PARAM_INIT, __VA_ARGS__})

View File

@ -77,7 +77,7 @@ String *hrnPackReadToStr(PackRead *read)
case pckTypePack:
{
strCatFmt(result, "<%s>", strZ(hrnPackReadToStr(pckReadPackReadP(read))));
strCatFmt(result, "<%s>", strZ(hrnPackReadToStr(pckReadPackReadP(read, .id = id))));
break;
}

View File

@ -350,6 +350,39 @@ testRun(void)
TEST_RESULT_PTR(pckWriteResult(NULL), NULL, "null pack result");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("read const packs");
TEST_ASSIGN(packWrite, pckWriteNewP(), "new write");
// Write pack to read as ptr/size
packSub = pckWriteNewP();
pckWriteU64P(packSub, 777);
pckWriteEndP(packSub);
TEST_RESULT_VOID(pckWritePackP(packWrite, pckWriteResult(packSub)), "write pack");
// Write pack to read as const
TEST_RESULT_VOID(pckWritePackP(packWrite, NULL), "write pack");
packSub = pckWriteNewP();
pckWriteU64P(packSub, 99);
pckWriteEndP(packSub);
TEST_RESULT_VOID(pckWritePackP(packWrite, pckWriteResult(packSub)), "write pack");
TEST_RESULT_VOID(pckWriteEndP(packWrite), "write pack end");
TEST_ASSIGN(packRead, pckReadNew(pckWriteResult(packWrite)), "new read");
TEST_RESULT_BOOL(pckReadNext(packRead), true, "next pack");
TEST_RESULT_UINT(pckReadSize(packRead), 4, "pack size");
TEST_RESULT_STR_Z(bufHex(BUF(pckReadBufPtr(packRead), pckReadSize(packRead))), "98890600", "pack hex");
TEST_RESULT_UINT(pckReadU64P(pckReadNewC(pckReadBufPtr(packRead), pckReadSize(packRead))), 777, "u64 value");
TEST_RESULT_VOID(pckReadConsume(packRead), "consume pack");
TEST_RESULT_PTR(pckReadPackReadConstP(packRead), NULL, "const null pack");
TEST_RESULT_UINT(pckReadU64P(pckReadPackReadConstP(packRead)), 99, "const pack");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("pack/unpack write internal buffer empty");