diff options
Diffstat (limited to 'libparc/parc/memory')
-rw-r--r-- | libparc/parc/memory/parc_BufferPool.c | 236 | ||||
-rw-r--r-- | libparc/parc/memory/parc_BufferPool.h | 344 | ||||
-rw-r--r-- | libparc/parc/memory/test/CMakeLists.txt | 13 | ||||
-rw-r--r-- | libparc/parc/memory/test/test_parc_BufferPool.c | 370 |
4 files changed, 963 insertions, 0 deletions
diff --git a/libparc/parc/memory/parc_BufferPool.c b/libparc/parc/memory/parc_BufferPool.c new file mode 100644 index 00000000..d6695fdf --- /dev/null +++ b/libparc/parc/memory/parc_BufferPool.c @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ +#include <config.h> + +#include <parc/algol/parc_Object.h> +#include <parc/algol/parc_DisplayIndented.h> +#include <parc/algol/parc_Memory.h> + +#include <parc/algol/parc_LinkedList.h> + +#include "parc_BufferPool.h" + +struct PARCBufferPool { + size_t bufferSize; + size_t limit; + size_t largestPoolSize; + size_t totalInstances; + size_t cacheHits; + PARCLinkedList *freeList; + PARCObjectDescriptor *descriptor; + const PARCObjectDescriptor *originalDescriptor; +}; + +static bool +_parcBufferPool_Destructor(PARCBufferPool **instancePtr) +{ + assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCBufferPool pointer."); + + PARCBufferPool *pool = *instancePtr; + + parcLinkedList_Apply(pool->freeList, (void (*))parcObject_SetDescriptor, (const void *) &PARCBuffer_Descriptor); + + parcLinkedList_Release(&pool->freeList); + parcObjectDescriptor_Destroy(&pool->descriptor); + + return true; +} + +static bool +_parcBufferPool_ObjectDestructor(PARCBuffer **bufferPtr) +{ + PARCBuffer *buffer = *bufferPtr; + + PARCBufferPool *bufferPool = parcObjectDescriptor_GetTypeState(parcObject_GetDescriptor(buffer)); + + parcObject_Synchronize(bufferPool->freeList) + { + size_t freeListSize = parcLinkedList_Size(bufferPool->freeList); + + if (bufferPool->limit > freeListSize) { + parcLinkedList_Append(bufferPool->freeList, buffer); + freeListSize++; + if (bufferPool->largestPoolSize < freeListSize) { + bufferPool->largestPoolSize = freeListSize; + } + } else { + parcBuffer_Acquire(buffer); + parcObject_SetDescriptor(buffer, &PARCBuffer_Descriptor); + parcBuffer_Release(&buffer); + } + } + + *bufferPtr = 0; + return false; +} + +parcObject_ImplementAcquire(parcBufferPool, PARCBufferPool); + +parcObject_ImplementRelease(parcBufferPool, PARCBufferPool); + +parcObject_Override(PARCBufferPool, PARCObject, + .destructor = (PARCObjectDestructor *) _parcBufferPool_Destructor, + .isLockable = true); + + +void +parcBufferPool_AssertValid(const PARCBufferPool *instance) +{ + assertTrue(parcBufferPool_IsValid(instance), + "PARCBufferPool is not valid."); +} + +PARCBufferPool * +parcBufferPool_CreateExtending(const PARCObjectDescriptor *originalDescriptor, size_t limit, size_t bufferSize) +{ + PARCBufferPool *result = parcObject_CreateInstance(PARCBufferPool); + + if (result != NULL) { + result->limit = limit; + result->totalInstances = 0; + result->cacheHits = 0; + result->largestPoolSize = 0; + result->bufferSize = bufferSize; + result->freeList = parcLinkedList_Create(); + + result->originalDescriptor = originalDescriptor; + + char *string = parcMemory_Format("PARCBufferPool=%zu", bufferSize); + result->descriptor = parcObjectDescriptor_CreateExtension(result->originalDescriptor, string); + result->descriptor->destructor = (PARCObjectDestructor *) _parcBufferPool_ObjectDestructor; + result->descriptor->typeState = (PARCObjectTypeState *) result; + parcMemory_Deallocate(&string); + } + + return result; +} + +PARCBufferPool * +parcBufferPool_Create(size_t limit, size_t bufferSize) +{ + PARCBufferPool *result = parcBufferPool_CreateExtending(&parcObject_DescriptorName(PARCBuffer), limit, bufferSize); + + return result; +} + +void +parcBufferPool_Display(const PARCBufferPool *instance, int indentation) +{ + parcDisplayIndented_PrintLine(indentation, "PARCBufferPool@%p {", instance); + /* Call Display() functions for the fields here. */ + parcDisplayIndented_PrintLine(indentation, "}"); +} + +bool +parcBufferPool_IsValid(const PARCBufferPool *bufferPool) +{ + bool result = false; + + if (bufferPool != NULL) { + result = parcLinkedList_IsValid(bufferPool->freeList); + } + + return result; +} + +PARCBuffer * +parcBufferPool_GetInstance(PARCBufferPool *bufferPool) +{ + PARCBuffer *result = NULL; + + parcObject_Synchronize(bufferPool->freeList) + { + if (parcLinkedList_Size(bufferPool->freeList) > 0) { + result = parcLinkedList_RemoveFirst(bufferPool->freeList); + bufferPool->cacheHits++; + } else { + result = parcBuffer_Allocate(bufferPool->bufferSize); + parcObject_SetDescriptor(result, bufferPool->descriptor); + } + bufferPool->totalInstances++; + } + + return result; +} + +size_t +parcBufferPool_Drain(PARCBufferPool *bufferPool) +{ + size_t result = 0; + + parcObject_Synchronize(bufferPool->freeList) + { + size_t freeListSize = parcLinkedList_Size(bufferPool->freeList); + if (freeListSize > bufferPool->limit) { + result = freeListSize - bufferPool->limit; + for (size_t i = bufferPool->limit; i < freeListSize; i++) { + PARCObject *object = parcLinkedList_RemoveLast(bufferPool->freeList); + parcObject_SetDescriptor(object, &PARCBuffer_Descriptor); + parcObject_Release(&object); + } + } + } + + return result; +} + +size_t +parcBufferPool_SetLimit(PARCBufferPool *bufferPool, size_t limit) +{ + size_t oldLimit = bufferPool->limit; + + if (limit < bufferPool->limit) { + bufferPool->largestPoolSize = bufferPool->limit; + } + + bufferPool->limit = limit; + + return oldLimit; +} + +size_t +parcBufferPool_GetLimit(const PARCBufferPool *bufferPool) +{ + return bufferPool->limit; +} + +size_t +parcBufferPool_GetCurrentPoolSize(const PARCBufferPool *bufferPool) +{ + size_t result = parcLinkedList_Size(bufferPool->freeList); + + return result; +} + +size_t +parcBufferPool_GetLargestPoolSize(const PARCBufferPool *bufferPool) +{ + return bufferPool->largestPoolSize; +} + +size_t +parcBufferPool_GetTotalInstances(const PARCBufferPool *bufferPool) +{ + return bufferPool->totalInstances; +} + +size_t +parcBufferPool_GetCacheHits(const PARCBufferPool *bufferPool) +{ + return bufferPool->cacheHits; +} diff --git a/libparc/parc/memory/parc_BufferPool.h b/libparc/parc/memory/parc_BufferPool.h new file mode 100644 index 00000000..33028920 --- /dev/null +++ b/libparc/parc/memory/parc_BufferPool.h @@ -0,0 +1,344 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file parc_BufferPool.h + * @ingroup memory + * @brief A simple pool of uniformly sized PARCBuffer instances. + * + * The client uses `parcBufferPool_GetInstance` to obtain instances which are placed attempted to be placed + * into the pool when the `PARCBuffer_Release` function is called. + * The pool has a maxmimum number of instances that it will cache. + * + */ +#ifndef PARCLibrary_parc_BufferPool +#define PARCLibrary_parc_BufferPool +#include <stdbool.h> + +#include <parc/algol/parc_Object.h> + +parcObject_Declare(PARCBufferPool); + +/** + * Increase the number of references to a `PARCBufferPool` instance. + * + * Note that new `PARCBufferPool` is not created, + * only that the given `PARCBufferPool` reference count is incremented. + * Discard the reference by invoking `parcBufferPool_Release`. + * + * @param [in] instance A pointer to a valid PARCBufferPool instance. + * + * @return The same value as the parameter @p instance. + * + * Example: + * @code + * { + * PARCBufferPool *a = parcBufferPool_Create(5, 10); + * + * PARCBufferPool *b = parcBufferPool_Acquire(a); + * + * parcBufferPool_Release(&a); + * parcBufferPool_Release(&b); + * } + * @endcode + */ +PARCBufferPool *parcBufferPool_Acquire(const PARCBufferPool *instance); + +#ifdef PARCLibrary_DISABLE_VALIDATION +# define parcBufferPool_OptionalAssertValid(_instance_) +#else +# define parcBufferPool_OptionalAssertValid(_instance_) parcBufferPool_AssertValid(_instance_) +#endif + +/** + * Assert that the given `PARCBufferPool` instance is valid. + * + * @param [in] instance A pointer to a valid PARCBufferPool instance. + * + * Example: + * @code + * { + * PARCBufferPool *a = parcBufferPool_Create(5, 10); + * + * parcBufferPool_AssertValid(a); + * + * parcBufferPool_Release(&a); + * } + * @endcode + */ +void parcBufferPool_AssertValid(const PARCBufferPool *instance); + +/** + * Create an instance of PARCBufferPool containing instances of `PARCBuffer`. + * + * This function is equivalent to invoking + * @code + * PARCBufferPool *a = parcBufferPool_CreateExtending(&parcObject_DescriptorName(PARCBuffer), 5, 10); + * @endcode + * + * The value of @p limit is the maximum number of instances that the pool will cache, + * and @p bufferSize is the size of the `PARCBuffer` instances cached. + * + * @return non-NULL A pointer to a valid PARCBufferPool instance. + * @return NULL An error occurred. + * + * Example: + * @code + * { + * PARCBufferPool *a = parcBufferPool_Create(5, 10); + * + * parcBufferPool_Release(&a); + * } + * @endcode + */ +PARCBufferPool *parcBufferPool_Create(size_t limit, size_t bufferSize); + +/** + * Create an instance of PARCBufferPool containing instances of object specified by the given `PARCObjectDescriptor`. + * + * The value of @p limit is the maximum number of instances that the pool will cache, + * and @p bufferSize is the size of the `PARCBuffer` instances cached. + * + * This function creates a PARCBufferPool that creates and manages instances of PARCBuffer which may have been extended. + * + * @return non-NULL A pointer to a valid PARCBufferPool instance. + * @return NULL An error occurred. + * + * Example: + * @code + * { + * PARCBufferPool *a = parcBufferPool_CreateExtending(&parcObject_DescriptorName(MyPARCBuffer), 5, 10); + * + * parcBufferPool_Release(&a); + * } + * @endcode + */ +PARCBufferPool *parcBufferPool_CreateExtending(const PARCObjectDescriptor *originalDescriptor, size_t limit, size_t bufferSize); + +/** + * Print a human readable representation of the given `PARCBufferPool`. + * + * @param [in] instance A pointer to a valid PARCBufferPool instance. + * @param [in] indentation The indentation level to use for printing. + * + * Example: + * @code + * { + * PARCBufferPool *a = parcBufferPool_Create(5, 10); + * + * parcBufferPool_Display(a, 0); + * + * parcBufferPool_Release(&a); + * } + * @endcode + */ +void parcBufferPool_Display(const PARCBufferPool *instance, int indentation); + +/** + * Determine if an instance of `PARCBufferPool` is valid. + * + * Valid means the internal state of the type is consistent with its required current or future behaviour. + * This may include the validation of internal instances of types. + * + * @param [in] instance A pointer to a valid PARCBufferPool instance. + * + * @return true The instance is valid. + * @return false The instance is not valid. + * + * Example: + * @code + * { + * PARCBufferPool *a = parcBufferPool_Create(5, 10); + * + * if (parcBufferPool_IsValid(a)) { + * printf("Instance is valid.\n"); + * } + * + * parcBufferPool_Release(&a); + * } + * @endcode + * + */ +bool parcBufferPool_IsValid(const PARCBufferPool *instance); + +/** + * Release a previously acquired reference to the given `PARCBufferPool` instance, + * decrementing the reference count for the instance. + * + * The pointer to the instance is set to NULL as a side-effect of this function. + * + * If the invocation causes the last reference to the instance to be released, + * the instance is deallocated and the instance's implementation will perform + * additional cleanup and release other privately held references. + * + * @param [in,out] instancePtr A pointer to a pointer to the instance to release. + * + * Example: + * @code + * { + * PARCBufferPool *a = parcBufferPool_Create(5, 10); + * + * parcBufferPool_Release(&a); + * } + * @endcode + */ +void parcBufferPool_Release(PARCBufferPool **instancePtr); + +/** + * Get an instance of a `PARCBuffer`. + * + * If the PARCBufferPool contains a cached instance, it will be returned. + * Otherwise a new instance will be created. + * + * Any `PARCBuffer` instance which is later released, will be a candidate for caching by the given `PARCBufferPool`. + * + * @param [in] bufferPool A pointer to a valid PARCBufferPool instance. + * + * @return non-NULL A pointer to a valid `PARCBuffer`. + * @return NULL An error occurred. + * + * Example: + * @code + * { + * + * PARCBufferPool *pool = parcBufferPool_Create(5, 10); + * ... + * + * parcBufferPool_Release(&pool); + * } + * @endcode + */ +PARCBuffer *parcBufferPool_GetInstance(PARCBufferPool *bufferPool); + +/** + * Set the largest number of buffers the pool will cache. + * + * If the new limit is less than the current limit, and the current pool size is greater than the new limit, + * the number of buffers the pool will cache will decay as they are obtained and released from the pool during use. + * + * @param [in] bufferPool A pointer to a valid PARCBufferPool instance. + * @param [in] limit the largest number of buffers the pool will cache. + * + * @return The previous value of the largest number of buffers the pool cached. + * + * Example: + * @code + * { + * + * PARCBufferPool *pool = parcBufferPool_Create(5, 10); + * ... + * + * size_t limit = parcBufferPool_SetLimit(pool, 3); + * + * parcBufferPool_Release(&pool); + * } + * @endcode + */ +size_t parcBufferPool_SetLimit(PARCBufferPool *bufferPool, size_t limit); + +/** + * Get the largest number of buffers the pool will cache. + * + * @param [in] bufferPool A pointer to a valid PARCBufferPool instance. + * + * @return The value of the largest number of buffers the pool will cache. + * + * Example: + * @code + * { + * + * PARCBufferPool *pool = parcBufferPool_Create(5, 10); + * ... + * + * size_t limit = parcBufferPool_GetLimit(pool); + * + * parcBufferPool_Release(&pool); + * } + * @endcode + */ +size_t parcBufferPool_GetLimit(const PARCBufferPool *bufferPool); + +/** + * Get the current number of buffers the pool has cached. + * + * The value is always greater than or equal to 0 and less than or equal to the limit. + * + * @param [in] bufferPool A pointer to a valid PARCBufferPool instance. + * + * @return the largest number of buffers the pool has ever cached. + * + * Example: + * @code + * { + * PARCBufferPool *pool = parcBufferPool_Create(5, 10); + * ... + * + * size_t poolSize = parcBufferPool_GetCurrentPoolSize(pool); + * + * parcBufferPool_Release(&pool); + * } + * @endcode + */ +size_t parcBufferPool_GetCurrentPoolSize(const PARCBufferPool *bufferPool); + +/** + * Get the largest number of buffers the pool has ever cached. + * + * The value is always greater than or equal to 0 and less than or equal to the limit. + * + * @param [in] bufferPool A pointer to a valid PARCBufferPool instance. + * + * @return the largest number of buffers the pool has ever cached. + * + * Example: + * @code + * { + * PARCBufferPool *pool = parcBufferPool_Create(5, 10); + * ... + * + * size_t allTimeHigh = parcBufferPool_GetLargestPoolSize(pool); + * + * parcBufferPool_Release(&pool); + * } + * @endcode + */ +size_t parcBufferPool_GetLargestPoolSize(const PARCBufferPool *bufferPool); + +/** + * Forcibly drain the PARCBufferPool of an excess (more than the pool's limit) `PARCBuffer` instances. + * + * The number of PARCBuffer instances can exceed the PARCBufferPool's limit if `parcBufferPool_SetLimit` is used to set the limit + * to less than Pool's current pool size. + * + * @param [in] bufferPool A pointer to a valid PARCBufferPool instance. + * + * @return the largest number of buffers released from the Pool's cache. + * + * Example: + * @code + * { + * + * PARCBufferPool *pool = parcBufferPool_Create(5, 10); + * ... + * + * size_t limit = parcBufferPool_SetLimit(pool, 3); + * size_t drained = parcBufferPool_Drain(pool); + * + * parcBufferPool_Release(&pool); + * } + * @endcode + */ +size_t parcBufferPool_Drain(PARCBufferPool *bufferPool); +#endif diff --git a/libparc/parc/memory/test/CMakeLists.txt b/libparc/parc/memory/test/CMakeLists.txt new file mode 100644 index 00000000..61a5608b --- /dev/null +++ b/libparc/parc/memory/test/CMakeLists.txt @@ -0,0 +1,13 @@ +set(TestsExpectedToPass + test_parc_BufferPool + ) + +# Enable gcov output for the tests +add_definitions(--coverage) +set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage") + +foreach(test ${TestsExpectedToPass}) + AddTest(${test}) +endforeach() + + diff --git a/libparc/parc/memory/test/test_parc_BufferPool.c b/libparc/parc/memory/test/test_parc_BufferPool.c new file mode 100644 index 00000000..b7c18d08 --- /dev/null +++ b/libparc/parc/memory/test/test_parc_BufferPool.c @@ -0,0 +1,370 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ +#include "../parc_BufferPool.c" + +#include <LongBow/testing.h> +#include <LongBow/debugging.h> +#include <parc/algol/parc_Memory.h> +#include <parc/algol/parc_SafeMemory.h> +#include <parc/algol/parc_DisplayIndented.h> + +#include <parc/testing/parc_MemoryTesting.h> +#include <parc/testing/parc_ObjectTesting.h> + +LONGBOW_TEST_RUNNER(parc_BufferPool) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(CreateAcquireRelease); + LONGBOW_RUN_TEST_FIXTURE(Object); + LONGBOW_RUN_TEST_FIXTURE(Specialization); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(parc_BufferPool) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(parc_BufferPool) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(CreateAcquireRelease) +{ + LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease); +} + +LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease) +{ + if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) { + parcSafeMemory_ReportAllocation(1); + return LONGBOW_STATUS_MEMORYLEAK; + } + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease) +{ + PARCBufferPool *instance = parcBufferPool_Create(3, 10); + assertNotNull(instance, "Expected non-null result from parcBufferPool_Create();"); + + parcObjectTesting_AssertAcquireReleaseContract(parcBufferPool_Acquire, instance); + + parcBufferPool_Release(&instance); + assertNull(instance, "Expected null result from parcBufferPool_Release();"); +} + +LONGBOW_TEST_FIXTURE(Object) +{ + LONGBOW_RUN_TEST_CASE(Object, parcBufferPool_Display); + LONGBOW_RUN_TEST_CASE(Object, parcBufferPool_IsValid); + LONGBOW_RUN_TEST_CASE(Object, parcBufferPool_AssertValid); +} + +LONGBOW_TEST_FIXTURE_SETUP(Object) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Object) +{ + if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) { + return LONGBOW_STATUS_MEMORYLEAK; + } + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Object, parcBufferPool_Display) +{ + PARCBufferPool *instance = parcBufferPool_Create(3, 10); + parcBufferPool_Display(instance, 0); + parcBufferPool_Release(&instance); +} + +LONGBOW_TEST_CASE(Object, parcBufferPool_IsValid) +{ + PARCBufferPool *instance = parcBufferPool_Create(3, 10); + assertTrue(parcBufferPool_IsValid(instance), "Expected parcBufferPool_Create to result in a valid instance."); + + parcBufferPool_Release(&instance); + assertFalse(parcBufferPool_IsValid(instance), "Expected parcBufferPool_Release to result in an invalid instance."); +} + +LONGBOW_TEST_CASE(Object, parcBufferPool_AssertValid) +{ + PARCBufferPool *instance = parcBufferPool_Create(3, 10); + parcBufferPool_AssertValid(instance); + + parcBufferPool_Release(&instance); + assertFalse(parcBufferPool_IsValid(instance), "Expected parcBufferPool_Release to result in an invalid instance."); +} + +LONGBOW_TEST_FIXTURE(Specialization) +{ + LONGBOW_RUN_TEST_CASE(Specialization, parcBufferPool_GetInstance); + LONGBOW_RUN_TEST_CASE(Specialization, parcBufferPool_GetLargestPoolSize); + LONGBOW_RUN_TEST_CASE(Specialization, parcBufferPool_GetCurrentPoolSize); + LONGBOW_RUN_TEST_CASE(Specialization, parcBufferPool_GetTotalInstances); + LONGBOW_RUN_TEST_CASE(Specialization, parcBufferPool_GetCacheHits); + LONGBOW_RUN_TEST_CASE(Specialization, parcBufferPool_GetLimit); + LONGBOW_RUN_TEST_CASE(Specialization, parcBufferPool_SetLimit_Increasing); + LONGBOW_RUN_TEST_CASE(Specialization, parcBufferPool_SetLimit_Decreasing); + LONGBOW_RUN_TEST_CASE(Specialization, parcBufferPool_Drain); +} + +LONGBOW_TEST_FIXTURE_SETUP(Specialization) +{ + longBowTestCase_SetInt(testCase, "initialAllocations", parcMemory_Outstanding()); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Specialization) +{ + int initialAllocations = longBowTestCase_GetInt(testCase, "initialAllocations"); + + if (parcMemory_Outstanding() > initialAllocations) { + parcSafeMemory_ReportAllocation(1); + return LONGBOW_STATUS_MEMORYLEAK; + } + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Specialization, parcBufferPool_GetInstance) +{ + PARCBufferPool *pool = parcBufferPool_Create(3, 10); + + PARCBuffer *buffer = parcBufferPool_GetInstance(pool); + + parcBuffer_AssertValid(buffer); + parcBuffer_Release(&buffer); + + size_t largestPoolSize = parcBufferPool_GetLargestPoolSize(pool); + + assertTrue(largestPoolSize == 1, "Expected the largestPoolSize to be 1, actual %zu", largestPoolSize); + + parcBufferPool_Release(&pool); +} + +LONGBOW_TEST_CASE(Specialization, parcBufferPool_GetLargestPoolSize) +{ + PARCBufferPool *pool = parcBufferPool_Create(3, 10); + size_t largestPoolSize = parcBufferPool_GetLargestPoolSize(pool); + + assertTrue(largestPoolSize == 0, "Expected the largestPoolSize to be 0, actual %zu", largestPoolSize); + + PARCBuffer *buffer = parcBufferPool_GetInstance(pool); + + parcBuffer_AssertValid(buffer); + parcBuffer_Release(&buffer); + + largestPoolSize = parcBufferPool_GetLargestPoolSize(pool); + + assertTrue(largestPoolSize == 1, "Expected the largestPoolSize to be 1, actual %zu", largestPoolSize); + + parcBufferPool_Release(&pool); +} + +LONGBOW_TEST_CASE(Specialization, parcBufferPool_GetTotalInstances) +{ + PARCBufferPool *pool = parcBufferPool_Create(3, 10); + size_t totalInstances = parcBufferPool_GetTotalInstances(pool); + + assertTrue(totalInstances == 0, "Expected the totalInstances to be 0, actual %zu", totalInstances); + + PARCBuffer *buffer = parcBufferPool_GetInstance(pool); + + parcBuffer_AssertValid(buffer); + parcBuffer_Release(&buffer); + + totalInstances = parcBufferPool_GetTotalInstances(pool); + + assertTrue(totalInstances == 1, "Expected the totalInstances to be 1, actual %zu", totalInstances); + + parcBufferPool_Release(&pool); +} + +LONGBOW_TEST_CASE(Specialization, parcBufferPool_GetCacheHits) +{ + PARCBufferPool *pool = parcBufferPool_Create(3, 10); + size_t cacheHits = parcBufferPool_GetCacheHits(pool); + + assertTrue(cacheHits == 0, "Expected the cacheHits to be 0, actual %zu", cacheHits); + + PARCBuffer *buffer = parcBufferPool_GetInstance(pool); + parcBuffer_AssertValid(buffer); + parcBuffer_Release(&buffer); + + cacheHits = parcBufferPool_GetCacheHits(pool); + assertTrue(cacheHits == 0, "Expected the cacheHits to be 0, actual %zu", cacheHits); + + buffer = parcBufferPool_GetInstance(pool); + parcBuffer_AssertValid(buffer); + parcBuffer_Release(&buffer); + + cacheHits = parcBufferPool_GetCacheHits(pool); + assertTrue(cacheHits == 1, "Expected the cacheHits to be 1, actual %zu", cacheHits); + + parcBufferPool_Release(&pool); +} + +LONGBOW_TEST_CASE(Specialization, parcBufferPool_GetLimit) +{ + size_t expected = 20; + + PARCBufferPool *pool = parcBufferPool_Create(expected, 10); + size_t limit = parcBufferPool_GetLimit(pool); + + assertTrue(limit == expected, "Expected the limit to be %zu, actual %zu", expected, limit); + parcBufferPool_Release(&pool); +} + +LONGBOW_TEST_CASE(Specialization, parcBufferPool_GetCurrentPoolSize) +{ + size_t expectedLimit = 3; + + PARCBufferPool *pool = parcBufferPool_Create(expectedLimit, 10); + size_t poolSize = parcBufferPool_GetCurrentPoolSize(pool); + + assertTrue(poolSize == 0, "Expected the poolSize to be 0, actual %zu", poolSize); + + PARCBuffer *buffer1 = parcBufferPool_GetInstance(pool); + PARCBuffer *buffer2 = parcBufferPool_GetInstance(pool); + PARCBuffer *buffer3 = parcBufferPool_GetInstance(pool); + PARCBuffer *buffer4 = parcBufferPool_GetInstance(pool); + PARCBuffer *buffer5 = parcBufferPool_GetInstance(pool); + + parcBuffer_Release(&buffer1); + parcBuffer_Release(&buffer2); + parcBuffer_Release(&buffer3); + parcBuffer_Release(&buffer4); + parcBuffer_Release(&buffer5); + + poolSize = parcBufferPool_GetCurrentPoolSize(pool); + + assertTrue(poolSize == expectedLimit, "Expected the poolSize to be %zu, actual %zu", expectedLimit, poolSize); + + parcBufferPool_Release(&pool); +} + +LONGBOW_TEST_CASE(Specialization, parcBufferPool_SetLimit_Increasing) +{ + size_t oldLimit = 3; + size_t newLimit = 5; + + PARCBufferPool *pool = parcBufferPool_Create(oldLimit, 10); + size_t limit = parcBufferPool_GetLimit(pool); + + assertTrue(limit == oldLimit, "Expected the limit to be %zu, actual %zu", oldLimit, limit); + + PARCBuffer *buffer1 = parcBufferPool_GetInstance(pool); + PARCBuffer *buffer2 = parcBufferPool_GetInstance(pool); + PARCBuffer *buffer3 = parcBufferPool_GetInstance(pool); + parcBuffer_AssertValid(buffer1); + parcBuffer_AssertValid(buffer2); + parcBuffer_AssertValid(buffer3); + parcBuffer_Release(&buffer1); + parcBuffer_Release(&buffer2); + parcBuffer_Release(&buffer3); + + limit = parcBufferPool_SetLimit(pool, newLimit); + assertTrue(limit == 3, "Expected the old limit to be %zu, actual %zu", oldLimit, limit); + + size_t largestPoolSize = parcBufferPool_GetLargestPoolSize(pool); + assertTrue(largestPoolSize == oldLimit, "Expected largest pool size to be %zu, actual %zu", oldLimit, largestPoolSize); + + + parcBufferPool_Release(&pool); +} + +LONGBOW_TEST_CASE(Specialization, parcBufferPool_SetLimit_Decreasing) +{ + size_t oldLimit = 3; + size_t newLimit = 2; + + PARCBufferPool *pool = parcBufferPool_Create(oldLimit, 10); + size_t limit = parcBufferPool_GetLimit(pool); + + assertTrue(limit == oldLimit, "Expected the limit to be %zu, actual %zu", oldLimit, limit); + + PARCBuffer *buffer1 = parcBufferPool_GetInstance(pool); + PARCBuffer *buffer2 = parcBufferPool_GetInstance(pool); + PARCBuffer *buffer3 = parcBufferPool_GetInstance(pool); + parcBuffer_AssertValid(buffer1); + parcBuffer_AssertValid(buffer2); + parcBuffer_AssertValid(buffer3); + parcBuffer_Release(&buffer1); + parcBuffer_Release(&buffer2); + parcBuffer_Release(&buffer3); + + limit = parcBufferPool_SetLimit(pool, newLimit); + assertTrue(limit == 3, "Expected the old limit to be %zu, actual %zu", oldLimit, limit); + + size_t largestPoolSize = parcBufferPool_GetLargestPoolSize(pool); + assertTrue(largestPoolSize == oldLimit, "Expected largest pool size to be %zu, actual %zu", oldLimit, largestPoolSize); + + + parcBufferPool_Release(&pool); +} + +LONGBOW_TEST_CASE(Specialization, parcBufferPool_Drain) +{ + size_t oldLimit = 3; + size_t newLimit = 2; + + PARCBufferPool *pool = parcBufferPool_Create(oldLimit, 10); + + PARCBuffer *buffer1 = parcBufferPool_GetInstance(pool); + PARCBuffer *buffer2 = parcBufferPool_GetInstance(pool); + PARCBuffer *buffer3 = parcBufferPool_GetInstance(pool); + parcBuffer_AssertValid(buffer1); + parcBuffer_AssertValid(buffer2); + parcBuffer_AssertValid(buffer3); + parcBuffer_Release(&buffer1); + parcBuffer_Release(&buffer2); + parcBuffer_Release(&buffer3); + + size_t limit = parcBufferPool_SetLimit(pool, newLimit); + assertTrue(limit == oldLimit, "Expected the limit to be %zu, actual %zu", oldLimit, limit); + + size_t drained = parcBufferPool_Drain(pool); + assertTrue(drained == 1, "Expected the drained to be 1, actual %zu", drained); + + parcBufferPool_Release(&pool); +} + +int +main(int argc, char *argv[argc]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_BufferPool); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} |