1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2026-05-22 10:15:16 +02:00

Allow MemContext objects to be copied to a new parent.

This makes it easier to create objects and then copy them to another context when they are complete without having to worry about freeing them on error. Update List, StringList, and Buffer to allow moves. Update Ini and Storage to take advantage of moves.
This commit is contained in:
David Steele
2018-04-06 17:04:52 -04:00
parent b9f636cab4
commit f3b56cf8f3
17 changed files with 443 additions and 240 deletions
+4
View File
@@ -39,6 +39,10 @@
<p>Storage object improvements. Convert all functions to variadic functions. Enforce read-only storage. Add <code>storageLocalWrite()</code> helper function. Add <code>storageExists()</code>, <code>storagePathCreate()</code>, and <code>storageRemove()</code>. Add <code>StorageFile</code> object and <code>storageOpenRead()</code>/<code>storageOpenWrite()</code>. Abstract Posix driver code into a separate module.</p> <p>Storage object improvements. Convert all functions to variadic functions. Enforce read-only storage. Add <code>storageLocalWrite()</code> helper function. Add <code>storageExists()</code>, <code>storagePathCreate()</code>, and <code>storageRemove()</code>. Add <code>StorageFile</code> object and <code>storageOpenRead()</code>/<code>storageOpenWrite()</code>. Abstract Posix driver code into a separate module.</p>
</release-item> </release-item>
<release-item>
<p>Allow <code>MemContext</code> objects to be copied to a new parent. This makes it easier to create objects and then copy them to another context when they are complete without having to worry about freeing them on error. Update <code>List</code>, <code>StringList</code>, and <code>Buffer</code> to allow moves. Update <code>Ini</code> and <code>Storage</code> to take advantage of moves.</p>
</release-item>
<release-item> <release-item>
<p>Improve branch coverage in C code.</p> <p>Improve branch coverage in C code.</p>
</release-item> </release-item>
+1 -3
View File
@@ -110,8 +110,6 @@ iniSectionKeyList(const Ini *this, const String *section)
// Get the section // Get the section
KeyValue *sectionKv = varKv(kvGet(this->store, varNewStr(section))); KeyValue *sectionKv = varKv(kvGet(this->store, varNewStr(section)));
memContextSwitch(MEM_CONTEXT_OLD());
// Return key list of the section exists // Return key list of the section exists
if (sectionKv != NULL) if (sectionKv != NULL)
result = strLstNewVarLst(kvKeyList(sectionKv)); result = strLstNewVarLst(kvKeyList(sectionKv));
@@ -119,7 +117,7 @@ iniSectionKeyList(const Ini *this, const String *section)
else else
result = strLstNew(); result = strLstNew();
memContextSwitch(MEM_CONTEXT_TEMP()); strLstMove(result, MEM_CONTEXT_OLD());
} }
MEM_CONTEXT_TEMP_END(); MEM_CONTEXT_TEMP_END();
+91 -37
View File
@@ -4,6 +4,7 @@ Memory Context Manager
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "common/debug.h"
#include "common/error.h" #include "common/error.h"
#include "common/memContext.h" #include "common/memContext.h"
@@ -113,6 +114,55 @@ memFreeInternal(void *buffer)
free(buffer); free(buffer);
} }
/***********************************************************************************************************************************
Find space for a new mem context
***********************************************************************************************************************************/
static unsigned int
memContextNewIndex(MemContext *memContext, bool allowFree)
{
// Try to find space for the new context
unsigned int contextIdx;
for (contextIdx = 0; contextIdx < memContext->contextChildListSize; contextIdx++)
{
if (!memContext->contextChildList[contextIdx] ||
(allowFree && memContext->contextChildList[contextIdx]->state == memContextStateFree))
{
break;
}
}
// If no space was found then allocate more
if (contextIdx == memContext->contextChildListSize)
{
// If no space has been allocated to the list
if (memContext->contextChildListSize == 0)
{
// Allocate memory before modifying anything else in case there is an error
memContext->contextChildList = memAllocInternal(sizeof(MemContext *) * MEM_CONTEXT_INITIAL_SIZE, true);
// Set new list size
memContext->contextChildListSize = MEM_CONTEXT_INITIAL_SIZE;
}
// Else grow the list
else
{
// Calculate new list size
unsigned int contextChildListSizeNew = memContext->contextChildListSize * 2;
// ReAllocate memory before modifying anything else in case there is an error
memContext->contextChildList = memReAllocInternal(
memContext->contextChildList, sizeof(MemContext *) * memContext->contextChildListSize,
sizeof(MemContext *) * contextChildListSizeNew, true);
// Set new list size
memContext->contextChildListSize = contextChildListSizeNew;
}
}
return contextIdx;
}
/*********************************************************************************************************************************** /***********************************************************************************************************************************
Create a new memory context Create a new memory context
***********************************************************************************************************************************/ ***********************************************************************************************************************************/
@@ -123,43 +173,8 @@ memContextNew(const char *name)
if (strlen(name) == 0 || strlen(name) > MEM_CONTEXT_NAME_SIZE) if (strlen(name) == 0 || strlen(name) > MEM_CONTEXT_NAME_SIZE)
THROW(AssertError, "context name length must be > 0 and <= %d", MEM_CONTEXT_NAME_SIZE); THROW(AssertError, "context name length must be > 0 and <= %d", MEM_CONTEXT_NAME_SIZE);
// Try to find space for the new context // Find space for the new context
unsigned int contextIdx; unsigned int contextIdx = memContextNewIndex(memContextCurrent(), true);
for (contextIdx = 0; contextIdx < memContextCurrent()->contextChildListSize; contextIdx++)
if (!memContextCurrent()->contextChildList[contextIdx] ||
memContextCurrent()->contextChildList[contextIdx]->state == memContextStateFree)
{
break;
}
// If no space was found then allocate more
if (contextIdx == memContextCurrent()->contextChildListSize)
{
// If no space has been allocated to the list
if (memContextCurrent()->contextChildListSize == 0)
{
// Allocate memory before modifying anything else in case there is an error
memContextCurrent()->contextChildList = memAllocInternal(sizeof(MemContext *) * MEM_CONTEXT_INITIAL_SIZE, true);
// Set new list size
memContextCurrent()->contextChildListSize = MEM_CONTEXT_INITIAL_SIZE;
}
// Else grow the list
else
{
// Calculate new list size
unsigned int contextChildListSizeNew = memContextCurrent()->contextChildListSize * 2;
// ReAllocate memory before modifying anything else in case there is an error
memContextCurrent()->contextChildList = memReAllocInternal(
memContextCurrent()->contextChildList, sizeof(MemContext *) * memContextCurrent()->contextChildListSize,
sizeof(MemContext *) * contextChildListSizeNew, true);
// Set new list size
memContextCurrent()->contextChildListSize = contextChildListSizeNew;
}
}
// If the context has not been allocated yet // If the context has not been allocated yet
if (!memContextCurrent()->contextChildList[contextIdx]) if (!memContextCurrent()->contextChildList[contextIdx])
@@ -330,6 +345,45 @@ memFree(void *buffer)
alloc->active = false; alloc->active = false;
} }
/***********************************************************************************************************************************
Move a context to a new parent context
This is generally used to move objects to a new context once they have been successfully created.
***********************************************************************************************************************************/
void
memContextMove(MemContext *this, MemContext *parentNew)
{
// Only move if a valid mem context is provided
if (this != NULL)
{
// Find context in the old parent and NULL it out
MemContext *parentOld = this->contextParent;
unsigned int contextIdx;
for (contextIdx = 0; contextIdx < parentOld->contextChildListSize; contextIdx++)
{
if (parentOld->contextChildList[contextIdx] == this)
{
parentOld->contextChildList[contextIdx] = NULL;
break;
}
}
// The memory must be found
if (contextIdx == parentOld->contextChildListSize)
THROW(AssertError, "unable to find mem context in old parent");
// Find a place in the new parent context and assign it. The child list may be moved while finding a new index so store the
// index and use it with (what might be) the new pointer.
contextIdx = memContextNewIndex(parentNew, false);
ASSERT_DEBUG(parentNew->contextChildList[contextIdx] == NULL);
parentNew->contextChildList[contextIdx] = this;
// Assign new parent
this->contextParent = parentNew;
}
}
/*********************************************************************************************************************************** /***********************************************************************************************************************************
Switch to the specified context and return the old context Switch to the specified context and return the old context
***********************************************************************************************************************************/ ***********************************************************************************************************************************/
+1
View File
@@ -63,6 +63,7 @@ TRY_END();
Use the MEM_CONTEXT*() macros when possible rather than implement error-handling for every memory context block. Use the MEM_CONTEXT*() macros when possible rather than implement error-handling for every memory context block.
***********************************************************************************************************************************/ ***********************************************************************************************************************************/
MemContext *memContextNew(const char *name); MemContext *memContextNew(const char *name);
void memContextMove(MemContext *this, MemContext *parentNew);
void memContextCallback(MemContext *this, void (*callbackFunction)(void *), void *callbackArgument); void memContextCallback(MemContext *this, void (*callbackFunction)(void *), void *callbackArgument);
MemContext *memContextSwitch(MemContext *this); MemContext *memContextSwitch(MemContext *this);
void memContextFree(MemContext *this); void memContextFree(MemContext *this);
+26 -18
View File
@@ -3,7 +3,6 @@ String Handler
***********************************************************************************************************************************/ ***********************************************************************************************************************************/
#include <string.h> #include <string.h>
#include "common/memContext.h"
#include "common/type/buffer.h" #include "common/type/buffer.h"
/*********************************************************************************************************************************** /***********************************************************************************************************************************
@@ -22,14 +21,20 @@ Create a new buffer
Buffer * Buffer *
bufNew(size_t size) bufNew(size_t size)
{ {
// Create object Buffer *this = NULL;
Buffer *this = memNew(sizeof(Buffer));
this->memContext = memContextCurrent();
this->size = size;
// Allocate buffer MEM_CONTEXT_NEW_BEGIN("Buffer")
if (size > 0) {
this->buffer = memNewRaw(this->size); // Create object
this = memNew(sizeof(Buffer));
this->memContext = MEM_CONTEXT_NEW();
this->size = size;
// Allocate buffer
if (size > 0)
this->buffer = memNewRaw(this->size);
}
MEM_CONTEXT_NEW_END();
return this; return this;
} }
@@ -49,6 +54,18 @@ bufNewStr(const String *string)
return this; return this;
} }
/***********************************************************************************************************************************
Move buffer to a new mem context
***********************************************************************************************************************************/
Buffer *
bufMove(Buffer *this, MemContext *parentNew)
{
if (this != NULL)
memContextMove(this->memContext, parentNew);
return this;
}
/*********************************************************************************************************************************** /***********************************************************************************************************************************
Return buffer ptr Return buffer ptr
***********************************************************************************************************************************/ ***********************************************************************************************************************************/
@@ -113,14 +130,5 @@ void
bufFree(Buffer *this) bufFree(Buffer *this)
{ {
if (this != NULL) if (this != NULL)
{ memContextFree(this->memContext);
MEM_CONTEXT_BEGIN(this->memContext)
{
if (this->buffer != NULL)
memFree(this->buffer);
memFree(this);
}
MEM_CONTEXT_END();
}
} }
+4 -4
View File
@@ -4,20 +4,20 @@ Buffer Handler
#ifndef COMMON_TYPE_BUFFER_H #ifndef COMMON_TYPE_BUFFER_H
#define COMMON_TYPE_BUFFER_H #define COMMON_TYPE_BUFFER_H
#include "common/typec.h"
/*********************************************************************************************************************************** /***********************************************************************************************************************************
Buffer object Buffer object
***********************************************************************************************************************************/ ***********************************************************************************************************************************/
typedef struct Buffer Buffer; typedef struct Buffer Buffer;
#include "common/memContext.h"
#include "common/type/string.h"
/*********************************************************************************************************************************** /***********************************************************************************************************************************
Functions Functions
***********************************************************************************************************************************/ ***********************************************************************************************************************************/
#include "common/type/string.h"
Buffer *bufNew(size_t size); Buffer *bufNew(size_t size);
Buffer *bufNewStr(const String *string); Buffer *bufNewStr(const String *string);
Buffer *bufMove(Buffer *this, MemContext *parentNew);
Buffer *bufResize(Buffer *this, size_t size); Buffer *bufResize(Buffer *this, size_t size);
size_t bufSize(const Buffer *this); size_t bufSize(const Buffer *this);
unsigned char *bufPtr(const Buffer *this); unsigned char *bufPtr(const Buffer *this);
+48 -18
View File
@@ -5,7 +5,6 @@ List Handler
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "common/memContext.h"
#include "common/type/list.h" #include "common/type/list.h"
/*********************************************************************************************************************************** /***********************************************************************************************************************************
@@ -13,6 +12,7 @@ Contains information about the list
***********************************************************************************************************************************/ ***********************************************************************************************************************************/
struct List struct List
{ {
MemContext *memContext;
size_t itemSize; size_t itemSize;
unsigned int listSize; unsigned int listSize;
unsigned int listSizeMax; unsigned int listSizeMax;
@@ -25,9 +25,16 @@ Create a new list
List * List *
lstNew(size_t itemSize) lstNew(size_t itemSize)
{ {
// Create object List *this = NULL;
List *this = memNew(sizeof(List));
this->itemSize = itemSize; MEM_CONTEXT_NEW_BEGIN("List")
{
// Create object
this = memNew(sizeof(List));
this->memContext = MEM_CONTEXT_NEW();
this->itemSize = itemSize;
}
MEM_CONTEXT_NEW_END();
// Return buffer // Return buffer
return this; return this;
@@ -42,18 +49,22 @@ lstAdd(List *this, const void *item)
// If list size = max then allocate more space // If list size = max then allocate more space
if (this->listSize == this->listSizeMax) if (this->listSize == this->listSizeMax)
{ {
// If nothing has been allocated yet MEM_CONTEXT_BEGIN(this->memContext)
if (this->listSizeMax == 0)
{ {
this->listSizeMax = LIST_INITIAL_SIZE; // If nothing has been allocated yet
this->list = memNewRaw(this->listSizeMax * this->itemSize); if (this->listSizeMax == 0)
} {
// Else the list needs to be extended this->listSizeMax = LIST_INITIAL_SIZE;
else this->list = memNewRaw(this->listSizeMax * this->itemSize);
{ }
this->listSizeMax *= 2; // Else the list needs to be extended
this->list = memGrowRaw(this->list, this->listSizeMax * this->itemSize); else
{
this->listSizeMax *= 2;
this->list = memGrowRaw(this->list, this->listSizeMax * this->itemSize);
}
} }
MEM_CONTEXT_END();
} }
memcpy(this->list + (this->listSize * this->itemSize), item, this->itemSize); memcpy(this->list + (this->listSize * this->itemSize), item, this->itemSize);
@@ -77,6 +88,27 @@ lstGet(const List *this, unsigned int listIdx)
return this->list + (listIdx * this->itemSize); return this->list + (listIdx * this->itemSize);
} }
/***********************************************************************************************************************************
Return the memory context for this list
***********************************************************************************************************************************/
MemContext *
lstMemContext(const List *this)
{
return this->memContext;
}
/***********************************************************************************************************************************
Move the string list
***********************************************************************************************************************************/
List *
lstMove(List *this, MemContext *parentNew)
{
if (this != NULL)
memContextMove(this->memContext, parentNew);
return this;
}
/*********************************************************************************************************************************** /***********************************************************************************************************************************
Return list size Return list size
***********************************************************************************************************************************/ ***********************************************************************************************************************************/
@@ -103,8 +135,6 @@ Free the string
void void
lstFree(List *this) lstFree(List *this)
{ {
if (this->list != NULL) if (this != NULL)
memFree(this->list); memContextFree(this->memContext);
memFree(this);
} }
+3
View File
@@ -4,6 +4,7 @@ List Handler
#ifndef COMMON_TYPE_LIST_H #ifndef COMMON_TYPE_LIST_H
#define COMMON_TYPE_LIST_H #define COMMON_TYPE_LIST_H
#include "common/memContext.h"
#include "common/type/string.h" #include "common/type/string.h"
/*********************************************************************************************************************************** /***********************************************************************************************************************************
@@ -22,6 +23,8 @@ Functions
List *lstNew(size_t itemSize); List *lstNew(size_t itemSize);
List *lstAdd(List *this, const void *item); List *lstAdd(List *this, const void *item);
void *lstGet(const List *this, unsigned int listIdx); void *lstGet(const List *this, unsigned int listIdx);
MemContext *lstMemContext(const List *this);
List *lstMove(List *this, MemContext *parentNew);
unsigned int lstSize(const List *this); unsigned int lstSize(const List *this);
List *lstSort(List *this, int (*comparator)(const void *, const void*)); List *lstSort(List *this, int (*comparator)(const void *, const void*));
void lstFree(List *this); void lstFree(List *this);
+95 -46
View File
@@ -18,6 +18,15 @@ strLstNew()
return (StringList *)lstNew(sizeof(String *)); return (StringList *)lstNew(sizeof(String *));
} }
/***********************************************************************************************************************************
Internal add -- the string must have been created in the list's mem context before being passed
***********************************************************************************************************************************/
static StringList *
strLstAddInternal(StringList *this, String *string)
{
return (StringList *)lstAdd((List *)this, &string);
}
/*********************************************************************************************************************************** /***********************************************************************************************************************************
Split a string into a string list based on a delimiter Split a string into a string list based on a delimiter
***********************************************************************************************************************************/ ***********************************************************************************************************************************/
@@ -39,22 +48,26 @@ strLstNewSplitZ(const String *string, const char *delimiter)
// Match points to the next delimiter match that has been found // Match points to the next delimiter match that has been found
const char *stringMatch = NULL; const char *stringMatch = NULL;
do MEM_CONTEXT_BEGIN(lstMemContext((List *)this))
{ {
// Find a delimiter match do
stringMatch = strstr(stringBase, delimiter);
// If a match was found then add the string
if (stringMatch != NULL)
{ {
strLstAdd(this, strNewN(stringBase, (size_t)(stringMatch - stringBase))); // Find a delimiter match
stringBase = stringMatch + strlen(delimiter); stringMatch = strstr(stringBase, delimiter);
// If a match was found then add the string
if (stringMatch != NULL)
{
strLstAddInternal(this, strNewN(stringBase, (size_t)(stringMatch - stringBase)));
stringBase = stringMatch + strlen(delimiter);
}
// Else make whatever is left the last string
else
strLstAddInternal(this, strNew(stringBase));
} }
// Else make whatever is left the last string while(stringMatch != NULL);
else
strLstAdd(this, strNew(stringBase));
} }
while(stringMatch != NULL); MEM_CONTEXT_END();
return this; return this;
} }
@@ -84,39 +97,43 @@ strLstNewSplitSizeZ(const String *string, const char *delimiter, size_t size)
const char *stringMatchLast = NULL; const char *stringMatchLast = NULL;
const char *stringMatch = NULL; const char *stringMatch = NULL;
do MEM_CONTEXT_BEGIN(lstMemContext((List *)this))
{ {
// Find a delimiter match do
stringMatch = strstr(stringMatchLast == NULL ? stringBase : stringMatchLast, delimiter);
// If a match was found then add the string
if (stringMatch != NULL)
{ {
if ((size_t)(stringMatch - stringBase) >= size) // Find a delimiter match
{ stringMatch = strstr(stringMatchLast == NULL ? stringBase : stringMatchLast, delimiter);
if (stringMatchLast != NULL)
stringMatch = stringMatchLast - strlen(delimiter);
strLstAdd(this, strNewN(stringBase, (size_t)(stringMatch - stringBase))); // If a match was found then add the string
stringBase = stringMatch + strlen(delimiter); if (stringMatch != NULL)
stringMatchLast = NULL; {
if ((size_t)(stringMatch - stringBase) >= size)
{
if (stringMatchLast != NULL)
stringMatch = stringMatchLast - strlen(delimiter);
strLstAddInternal(this, strNewN(stringBase, (size_t)(stringMatch - stringBase)));
stringBase = stringMatch + strlen(delimiter);
stringMatchLast = NULL;
}
else
stringMatchLast = stringMatch + strlen(delimiter);
} }
// Else make whatever is left the last string
else else
stringMatchLast = stringMatch + strlen(delimiter);
}
// Else make whatever is left the last string
else
{
if (stringMatchLast != NULL && strlen(stringBase) - strlen(delimiter) >= size)
{ {
strLstAdd(this, strNewN(stringBase, (size_t)((stringMatchLast - strlen(delimiter)) - stringBase))); if (stringMatchLast != NULL && strlen(stringBase) - strlen(delimiter) >= size)
stringBase = stringMatchLast; {
} strLstAddInternal(this, strNewN(stringBase, (size_t)((stringMatchLast - strlen(delimiter)) - stringBase)));
stringBase = stringMatchLast;
}
strLstAdd(this, strNew(stringBase)); strLstAddInternal(this, strNew(stringBase));
}
} }
while(stringMatch != NULL);
} }
while(stringMatch != NULL); MEM_CONTEXT_END();
return this; return this;
} }
@@ -131,8 +148,12 @@ strLstNewVarLst(const VariantList *sourceList)
StringList *this = strLstNew(); StringList *this = strLstNew();
// Copy variants // Copy variants
for (unsigned int listIdx = 0; listIdx < varLstSize(sourceList); listIdx++) MEM_CONTEXT_BEGIN(lstMemContext((List *)this))
strLstAdd(this, varStr(varLstGet(sourceList, listIdx))); {
for (unsigned int listIdx = 0; listIdx < varLstSize(sourceList); listIdx++)
strLstAddInternal(this, strDup(varStr(varLstGet(sourceList, listIdx))));
}
MEM_CONTEXT_END();
return this; return this;
} }
@@ -146,9 +167,13 @@ strLstDup(const StringList *sourceList)
// Create the list // Create the list
StringList *this = strLstNew(); StringList *this = strLstNew();
// Copy variants // Copy strings
for (unsigned int listIdx = 0; listIdx < strLstSize(sourceList); listIdx++) MEM_CONTEXT_BEGIN(lstMemContext((List *)this))
strLstAdd(this, strLstGet(sourceList, listIdx)); {
for (unsigned int listIdx = 0; listIdx < strLstSize(sourceList); listIdx++)
strLstAddInternal(this, strDup(strLstGet(sourceList, listIdx)));
}
MEM_CONTEXT_END();
return this; return this;
} }
@@ -159,8 +184,15 @@ Wrapper for lstAdd()
StringList * StringList *
strLstAdd(StringList *this, const String *string) strLstAdd(StringList *this, const String *string)
{ {
String *stringCopy = strDup(string); StringList *result = NULL;
return (StringList *)lstAdd((List *)this, &stringCopy);
MEM_CONTEXT_BEGIN(lstMemContext((List *)this))
{
result = strLstAddInternal(this, strDup(string));
}
MEM_CONTEXT_END();
return result;
} }
/*********************************************************************************************************************************** /***********************************************************************************************************************************
@@ -169,7 +201,15 @@ Add a zero-terminated string to the list
StringList * StringList *
strLstAddZ(StringList *this, const char *string) strLstAddZ(StringList *this, const char *string)
{ {
return strLstAdd(this, strNew(string)); StringList *result = NULL;
MEM_CONTEXT_BEGIN(lstMemContext((List *)this))
{
result = strLstAddInternal(this, strNew(string));
}
MEM_CONTEXT_END();
return result;
} }
/*********************************************************************************************************************************** /***********************************************************************************************************************************
@@ -203,6 +243,16 @@ strLstJoin(const StringList *this, const char *separator)
return join; return join;
} }
/***********************************************************************************************************************************
Move the string list
***********************************************************************************************************************************/
StringList *
strLstMove(StringList *this, MemContext *parentNew)
{
lstMove((List *)this, parentNew);
return this;
}
/*********************************************************************************************************************************** /***********************************************************************************************************************************
Return an array of pointers to the zero-terminated strings in this list. DO NOT override const and modify any of the strings in Return an array of pointers to the zero-terminated strings in this list. DO NOT override const and modify any of the strings in
this array, though it is OK to modify the array itself. this array, though it is OK to modify the array itself.
@@ -273,6 +323,5 @@ Wrapper for lstFree()
void void
strLstFree(StringList *this) strLstFree(StringList *this)
{ {
if (this != NULL) lstFree((List *)this);
lstFree((List *)this);
} }
+8 -7
View File
@@ -4,7 +4,10 @@ String List Handler
#ifndef COMMON_TYPE_STRINGLIST_H #ifndef COMMON_TYPE_STRINGLIST_H
#define COMMON_TYPE_STRINGLIST_H #define COMMON_TYPE_STRINGLIST_H
#include "common/type/string.h" /***********************************************************************************************************************************
String list type
***********************************************************************************************************************************/
typedef struct StringList StringList;
/*********************************************************************************************************************************** /***********************************************************************************************************************************
Sort orders Sort orders
@@ -15,16 +18,13 @@ typedef enum
sortOrderDesc, sortOrderDesc,
} SortOrder; } SortOrder;
/*********************************************************************************************************************************** #include "common/memContext.h"
String list type #include "common/type/string.h"
***********************************************************************************************************************************/ #include "common/type/variantList.h"
typedef struct StringList StringList;
/*********************************************************************************************************************************** /***********************************************************************************************************************************
Functions Functions
***********************************************************************************************************************************/ ***********************************************************************************************************************************/
#include "common/type/variantList.h"
StringList *strLstNew(); StringList *strLstNew();
StringList *strLstNewSplit(const String *string, const String *delimiter); StringList *strLstNewSplit(const String *string, const String *delimiter);
StringList *strLstNewSplitZ(const String *string, const char *delimiter); StringList *strLstNewSplitZ(const String *string, const char *delimiter);
@@ -37,6 +37,7 @@ StringList *strLstAdd(StringList *this, const String *string);
StringList *strLstAddZ(StringList *this, const char *string); StringList *strLstAddZ(StringList *this, const char *string);
String *strLstGet(const StringList *this, unsigned int listIdx); String *strLstGet(const StringList *this, unsigned int listIdx);
String *strLstJoin(const StringList *this, const char *separator); String *strLstJoin(const StringList *this, const char *separator);
StringList * strLstMove(StringList *this, MemContext *parentNew);
const char **strLstPtr(const StringList *this); const char **strLstPtr(const StringList *this);
unsigned int strLstSize(const StringList *this); unsigned int strLstSize(const StringList *this);
StringList *strLstSort(StringList *this, SortOrder sortOrder); StringList *strLstSort(StringList *this, SortOrder sortOrder);
+59 -68
View File
@@ -54,56 +54,53 @@ Read from storage into a buffer
Buffer * Buffer *
storageDriverPosixGet(const StorageFile *file) storageDriverPosixGet(const StorageFile *file)
{ {
Buffer volatile *result = NULL; Buffer *result = NULL;
TRY_BEGIN() MEM_CONTEXT_TEMP_BEGIN()
{ {
// Create result buffer with buffer size TRY_BEGIN()
ssize_t actualBytes = 0;
size_t totalBytes = 0;
do
{ {
size_t bufferSize = storageBufferSize(storageFileStorage(file)); size_t bufferSize = storageBufferSize(storageFileStorage(file));
result = bufNew(bufferSize);
// Allocate the buffer before first read // Create result buffer with buffer size
if (result == NULL) ssize_t actualBytes = 0;
result = bufNew(bufferSize); size_t totalBytes = 0;
// Grow the buffer on subsequent reads
else
bufResize((Buffer *)result, bufSize((Buffer *)result) + bufferSize);
// Read and handle errors do
actualBytes = read( {
STORAGE_DATA(file)->handle, bufPtr((Buffer *)result) + totalBytes, bufferSize); // Grow the buffer on subsequent reads
if (totalBytes != 0)
bufResize(result, bufSize(result) + bufferSize);
// Error occurred during write // Read and handle errors
if (actualBytes == -1) actualBytes = read(
THROW_SYS_ERROR(FileReadError, "unable to read '%s'", strPtr(storageFileName(file))); STORAGE_DATA(file)->handle, bufPtr(result) + totalBytes, bufferSize);
// Track total bytes read // Error occurred during write
totalBytes += (size_t)actualBytes; if (actualBytes == -1)
THROW_SYS_ERROR(FileReadError, "unable to read '%s'", strPtr(storageFileName(file)));
// Track total bytes read
totalBytes += (size_t)actualBytes;
}
while (actualBytes != 0);
// Resize buffer to total bytes read
bufResize(result, totalBytes);
} }
while (actualBytes != 0); FINALLY()
{
close(STORAGE_DATA(file)->handle);
storageFileFree(file);
}
TRY_END();
// Resize buffer to total bytes read bufMove(result, MEM_CONTEXT_OLD());
bufResize((Buffer *)result, totalBytes);
} }
CATCH_ANY() MEM_CONTEXT_TEMP_END();
{
// Free buffer on error if it was allocated
bufFree((Buffer *)result);
RETHROW(); return result;
}
FINALLY()
{
close(STORAGE_DATA(file)->handle);
storageFileFree(file);
}
TRY_END();
return (Buffer *)result;
} }
/*********************************************************************************************************************************** /***********************************************************************************************************************************
@@ -113,9 +110,7 @@ StringList *
storageDriverPosixList(const String *path, bool errorOnMissing, const String *expression) storageDriverPosixList(const String *path, bool errorOnMissing, const String *expression)
{ {
StringList *result = NULL; StringList *result = NULL;
DIR *dir = NULL; DIR *dir = NULL;
RegExp *regExp = NULL;
TRY_BEGIN() TRY_BEGIN()
{ {
@@ -130,44 +125,40 @@ storageDriverPosixList(const String *path, bool errorOnMissing, const String *ex
} }
else else
{ {
// Prepare regexp if an expression was passed MEM_CONTEXT_TEMP_BEGIN()
if (expression != NULL)
regExp = regExpNew(expression);
// Create the string list now that we know the directory is valid
result = strLstNew();
// Read the directory entries
struct dirent *dirEntry = readdir(dir);
while (dirEntry != NULL)
{ {
String *entry = strNew(dirEntry->d_name); // Prepare regexp if an expression was passed
RegExp *regExp = (expression == NULL) ? NULL : regExpNew(expression);
// Create the string list now that we know the directory is valid
result = strLstNew();
// Read the directory entries
struct dirent *dirEntry = readdir(dir);
while (dirEntry != NULL)
{
String *entry = strNew(dirEntry->d_name);
// Exclude current/parent directory and apply the expression if specified
if (!strEqZ(entry, ".") && !strEqZ(entry, "..") && (regExp == NULL || regExpMatch(regExp, entry)))
strLstAdd(result, entry);
// Exclude current/parent directory and apply the expression if specified
if (!strEqZ(entry, ".") && !strEqZ(entry, "..") && (regExp == NULL || regExpMatch(regExp, entry)))
strLstAdd(result, entry);
else
strFree(entry); strFree(entry);
dirEntry = readdir(dir); dirEntry = readdir(dir);
} }
}
}
CATCH_ANY()
{
// Free list on error
strLstFree(result);
RETHROW(); // Move finished list up to the old context
strLstMove(result, MEM_CONTEXT_OLD());
}
MEM_CONTEXT_TEMP_END();
}
} }
FINALLY() FINALLY()
{ {
if (dir != NULL) if (dir != NULL)
closedir(dir); closedir(dir);
if (regExp != NULL)
regExpFree(regExp);
} }
TRY_END(); TRY_END();
+8 -20
View File
@@ -123,21 +123,15 @@ storageList(const Storage *this, const String *pathExp, StorageListParam param)
{ {
StringList *result = NULL; StringList *result = NULL;
String *path = NULL; MEM_CONTEXT_TEMP_BEGIN()
TRY_BEGIN()
{ {
// Build the path // Build the path
path = storagePathNP(this, pathExp); String *path = storagePathNP(this, pathExp);
// Call driver function // Move list up to the old context
result = storageDriverPosixList(path, param.errorOnMissing, param.expression); result = strLstMove(storageDriverPosixList(path, param.errorOnMissing, param.expression), MEM_CONTEXT_OLD());
} }
FINALLY() MEM_CONTEXT_TEMP_END();
{
strFree(path);
}
TRY_END();
return result; return result;
} }
@@ -151,7 +145,7 @@ storageOpenRead(const Storage *this, const String *fileExp, StorageOpenReadParam
{ {
StorageFile *result = NULL; StorageFile *result = NULL;
MEM_CONTEXT_NEW_BEGIN("StorageFileRead") MEM_CONTEXT_NEW_BEGIN("StorageFile")
{ {
String *fileName = storagePathNP(this, fileExp); String *fileName = storagePathNP(this, fileExp);
@@ -159,13 +153,7 @@ storageOpenRead(const Storage *this, const String *fileExp, StorageOpenReadParam
void *data = storageDriverPosixOpenRead(fileName, param.ignoreMissing); void *data = storageDriverPosixOpenRead(fileName, param.ignoreMissing);
// Free mem contexts if missing files are ignored // Free mem contexts if missing files are ignored
if (data == NULL) if (data != NULL)
{
memContextSwitch(MEM_CONTEXT_OLD());
memContextFree(MEM_CONTEXT_NEW());
}
// Else create the storage file
else
result = storageFileNew(this, fileName, storageFileTypeRead, data); result = storageFileNew(this, fileName, storageFileTypeRead, data);
} }
MEM_CONTEXT_NEW_END(); MEM_CONTEXT_NEW_END();
@@ -183,7 +171,7 @@ storageOpenWrite(const Storage *this, const String *fileExp, StorageOpenWritePar
StorageFile *result = NULL; StorageFile *result = NULL;
MEM_CONTEXT_NEW_BEGIN("StorageFileWrite") MEM_CONTEXT_NEW_BEGIN("StorageFile")
{ {
String *fileName = storagePathNP(this, fileExp); String *fileName = storagePathNP(this, fileExp);
+1 -1
View File
@@ -135,7 +135,7 @@ my $oTestDef =
}, },
{ {
&TESTDEF_NAME => 'mem-context', &TESTDEF_NAME => 'mem-context',
&TESTDEF_TOTAL => 6, &TESTDEF_TOTAL => 7,
&TESTDEF_C => true, &TESTDEF_C => true,
&TESTDEF_CDEF => '-DNO_MEM_CONTEXT -DNO_LOG', &TESTDEF_CDEF => '-DNO_MEM_CONTEXT -DNO_LOG',
+51 -2
View File
@@ -91,8 +91,6 @@ testRun()
TEST_RESULT_INT(memContextTop()->contextChildListSize, 0, "top context should init with zero children"); TEST_RESULT_INT(memContextTop()->contextChildListSize, 0, "top context should init with zero children");
TEST_RESULT_PTR(memContextTop()->contextChildList, NULL, "top context child list empty"); TEST_RESULT_PTR(memContextTop()->contextChildList, NULL, "top context child list empty");
// TEST_ERROR(memContextFree(memContextTop()), AssertError, "cannot free top context");
// Current context should equal top context // Current context should equal top context
TEST_RESULT_PTR(memContextCurrent(), memContextTop(), "top context == current context"); TEST_RESULT_PTR(memContextCurrent(), memContextTop(), "top context == current context");
@@ -156,6 +154,11 @@ testRun()
TEST_ERROR( TEST_ERROR(
memContextFree(memContextTop()->contextChildList[MEM_CONTEXT_INITIAL_SIZE]), memContextFree(memContextTop()->contextChildList[MEM_CONTEXT_INITIAL_SIZE]),
AssertError, "cannot free inactive context"); AssertError, "cannot free inactive context");
MemContext *noAllocation = memContextNew("empty");
noAllocation->allocListSize = 0;
free(noAllocation->allocList);
TEST_RESULT_VOID(memContextFree(noAllocation), "free context with no allocations");
} }
// ----------------------------------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------------------------------
@@ -201,6 +204,11 @@ testRun()
TEST_RESULT_INT(expectedTotal, sizeof(size_t), "all bytes are 0xFE in original portion"); TEST_RESULT_INT(expectedTotal, sizeof(size_t), "all bytes are 0xFE in original portion");
// Free memory // Free memory
TEST_RESULT_VOID(memFree(memContextCurrent()->allocList[MEM_CONTEXT_ALLOC_INITIAL_SIZE].buffer), "free allocation");
TEST_ERROR(
memFree(memContextCurrent()->allocList[MEM_CONTEXT_ALLOC_INITIAL_SIZE].buffer), AssertError,
"unable to find allocation");
TEST_ERROR(memFree(NULL), AssertError, "unable to find null allocation"); TEST_ERROR(memFree(NULL), AssertError, "unable to find null allocation");
TEST_ERROR(memFree((void *)0x01), AssertError, "unable to find allocation"); TEST_ERROR(memFree((void *)0x01), AssertError, "unable to find allocation");
memFree(buffer); memFree(buffer);
@@ -298,5 +306,46 @@ testRun()
TEST_RESULT_BOOL(memContext->state == memContextStateFree, true, "new mem context is not active"); TEST_RESULT_BOOL(memContext->state == memContextStateFree, true, "new mem context is not active");
} }
// -----------------------------------------------------------------------------------------------------------------------------
if (testBegin("memContextMove()"))
{
TEST_RESULT_VOID(memContextMove(NULL, NULL), "move NULL context");
// -------------------------------------------------------------------------------------------------------------------------
MemContext *memContext = NULL;
void *mem = NULL;
MEM_CONTEXT_NEW_BEGIN("outer")
{
MEM_CONTEXT_TEMP_BEGIN()
{
memContextNew("not-to-be-moved");
MEM_CONTEXT_NEW_BEGIN("inner")
{
memContext = MEM_CONTEXT_NEW();
mem = memNew(sizeof(int));
}
MEM_CONTEXT_NEW_END();
TEST_RESULT_PTR(memContext->allocList[0].buffer, mem, "check memory allocation");
TEST_RESULT_PTR(memContextCurrent()->contextChildList[1], memContext, "check memory context");
// Null out the mem context in the parent so the move will fail
memContextCurrent()->contextChildList[1] = NULL;
TEST_ERROR(memContextMove(memContext, MEM_CONTEXT_OLD()), AssertError, "unable to find mem context in old parent");
// Set it back so the move will fail
memContextCurrent()->contextChildList[1] = memContext;
TEST_RESULT_VOID(memContextMove(memContext, MEM_CONTEXT_OLD()), "move context");
}
MEM_CONTEXT_TEMP_END();
TEST_RESULT_PTR(memContext->allocList[0].buffer, mem, "check memory allocation");
TEST_RESULT_PTR(memContextCurrent()->contextChildList[1], memContext, "check memory context");
}
MEM_CONTEXT_NEW_END();
}
memContextFree(memContextTop()); memContextFree(memContextTop());
} }
+10 -2
View File
@@ -9,11 +9,17 @@ void
testRun() testRun()
{ {
// ***************************************************************************************************************************** // *****************************************************************************************************************************
if (testBegin("bufNew(), bufNewStr(), bufSize(), bufPtr(), and bufFree()")) if (testBegin("bufNew(), bufNewStr(), bufMove(), bufSize(), bufPtr(), and bufFree()"))
{ {
Buffer *buffer = NULL; Buffer *buffer = NULL;
TEST_ASSIGN(buffer, bufNew(256), "new buffer"); MEM_CONTEXT_TEMP_BEGIN()
{
TEST_ASSIGN(buffer, bufNew(256), "new buffer");
bufMove(buffer, MEM_CONTEXT_OLD());
}
MEM_CONTEXT_TEMP_END();
TEST_RESULT_PTR(bufPtr(buffer), buffer->buffer, "buffer pointer"); TEST_RESULT_PTR(bufPtr(buffer), buffer->buffer, "buffer pointer");
TEST_RESULT_INT(bufSize(buffer), 256, "buffer size"); TEST_RESULT_INT(bufSize(buffer), 256, "buffer size");
@@ -23,6 +29,8 @@ testRun()
TEST_RESULT_VOID(bufFree(buffer), "free buffer"); TEST_RESULT_VOID(bufFree(buffer), "free buffer");
TEST_RESULT_VOID(bufFree(bufNew(0)), "free empty buffer"); TEST_RESULT_VOID(bufFree(bufNew(0)), "free empty buffer");
TEST_RESULT_VOID(bufFree(NULL), "free null buffer"); TEST_RESULT_VOID(bufFree(NULL), "free null buffer");
TEST_RESULT_VOID(bufMove(NULL, NULL), "move null buffer");
} }
// ***************************************************************************************************************************** // *****************************************************************************************************************************
+17 -6
View File
@@ -27,29 +27,39 @@ void
testRun() testRun()
{ {
// ***************************************************************************************************************************** // *****************************************************************************************************************************
if (testBegin("lstNew() and lstFree()")) if (testBegin("lstNew(), lstMemContext(), and lstFree()"))
{ {
List *list = lstNew(sizeof(void *)); List *list = lstNew(sizeof(void *));
TEST_RESULT_INT(list->itemSize, sizeof(void *), "item size"); TEST_RESULT_INT(list->itemSize, sizeof(void *), "item size");
TEST_RESULT_INT(list->listSize, 0, "list size"); TEST_RESULT_INT(list->listSize, 0, "list size");
TEST_RESULT_INT(list->listSizeMax, 0, "list size max"); TEST_RESULT_INT(list->listSizeMax, 0, "list size max");
TEST_RESULT_PTR(lstMemContext(list), list->memContext, "list mem context");
void *ptr = NULL; void *ptr = NULL;
TEST_RESULT_PTR(lstAdd(list, &ptr), list, "add item"); TEST_RESULT_PTR(lstAdd(list, &ptr), list, "add item");
TEST_RESULT_VOID(lstFree(list), "free list"); TEST_RESULT_VOID(lstFree(list), "free list");
TEST_RESULT_VOID(lstFree(lstNew(1)), "free empty list"); TEST_RESULT_VOID(lstFree(lstNew(1)), "free empty list");
TEST_RESULT_VOID(lstFree(NULL), "free null list");
} }
// ***************************************************************************************************************************** // *****************************************************************************************************************************
if (testBegin("lstAdd() and lstSize()")) if (testBegin("lstAdd(), lstMove(), and lstSize()"))
{ {
List *list = lstNew(sizeof(int)); List *list = NULL;
// Add ints to the list MEM_CONTEXT_TEMP_BEGIN()
for (int listIdx = 0; listIdx <= LIST_INITIAL_SIZE; listIdx++) {
TEST_RESULT_PTR(lstAdd(list, &listIdx), list, "add item %d", listIdx); list = lstNew(sizeof(int));
// Add ints to the list
for (int listIdx = 0; listIdx <= LIST_INITIAL_SIZE; listIdx++)
TEST_RESULT_PTR(lstAdd(list, &listIdx), list, "add item %d", listIdx);
lstMove(list, MEM_CONTEXT_OLD());
}
MEM_CONTEXT_TEMP_END();
TEST_RESULT_INT(lstSize(list), 9, "list size"); TEST_RESULT_INT(lstSize(list), 9, "list size");
@@ -61,6 +71,7 @@ testRun()
} }
TEST_ERROR(lstGet(list, lstSize(list)), AssertError, "cannot get index 9 from list with 9 value(s)"); TEST_ERROR(lstGet(list, lstSize(list)), AssertError, "cannot get index 9 from list with 9 value(s)");
TEST_RESULT_VOID(lstMove(NULL, NULL), "move null list");
} }
// ***************************************************************************************************************************** // *****************************************************************************************************************************
+16 -8
View File
@@ -9,21 +9,29 @@ void
testRun() testRun()
{ {
// ***************************************************************************************************************************** // *****************************************************************************************************************************
if (testBegin("strLstNew(), strLstAdd, strLstGet(), strLstSize(), and strLstFree()")) if (testBegin("strLstNew(), strLstAdd, strLstGet(), strLstMove(), strLstSize(), and strLstFree()"))
{ {
StringList *list = strLstNew();
// Add strings to the list // Add strings to the list
// ------------------------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------------------------
for (int listIdx = 0; listIdx <= LIST_INITIAL_SIZE; listIdx++) StringList *list = NULL;
MEM_CONTEXT_TEMP_BEGIN()
{ {
if (listIdx == 0) list = strLstNew();
for (int listIdx = 0; listIdx <= LIST_INITIAL_SIZE; listIdx++)
{ {
TEST_RESULT_PTR(strLstAdd(list, NULL), list, "add null item"); if (listIdx == 0)
{
TEST_RESULT_PTR(strLstAdd(list, NULL), list, "add null item");
}
else
TEST_RESULT_PTR(strLstAdd(list, strNewFmt("STR%02d", listIdx)), list, "add item %d", listIdx);
} }
else
TEST_RESULT_PTR(strLstAdd(list, strNewFmt("STR%02d", listIdx)), list, "add item %d", listIdx); strLstMove(list, MEM_CONTEXT_OLD());
} }
MEM_CONTEXT_TEMP_END();
TEST_RESULT_INT(strLstSize(list), 9, "list size"); TEST_RESULT_INT(strLstSize(list), 9, "list size");