cgul_cache.h File Reference

cache objects so they can be reused without thrashing malloc() More...

#include "cgul_common.h"
#include "cgul_exception.h"
Include dependency graph for cgul_cache.h:
This graph shows which files directly or indirectly include this file:

Typedefs

typedef typedefCGUL_BEGIN_C struct cgul_cache * cgul_cache_t
 
typedef void *(* cgul_cache__constructor_t) (cgul_exception_t *cex)
 
typedef void(* cgul_cache__destructor_t) (void *obj)
 
typedef void(* cgul_cache__restructor_t) (void *obj)
 

Functions

CGUL_EXPORT cgul_cache_t cgul_cache__get_freer ()
 
CGUL_EXPORT cgul_cache_t cgul_cache__new (cgul_exception_t *cex, cgul_cache__constructor_t constructor, cgul_cache__destructor_t destructor, cgul_cache__restructor_t restructor)
 
CGUL_EXPORT void cgul_cache__delete (cgul_cache_t cache)
 
CGUL_EXPORT unsigned long int cgul_cache__get_size (cgul_exception_t *cex, cgul_cache_t cache)
 
CGUL_EXPORT void cgul_cache__set_size (cgul_exception_t *cex, cgul_cache_t cache, unsigned long int size)
 
CGUL_EXPORT unsigned long int cgul_cache__get_reserve (cgul_exception_t *cex, cgul_cache_t cache)
 
CGUL_EXPORT void cgul_cache__set_reserve (cgul_exception_t *cex, cgul_cache_t cache, unsigned long int reserve)
 
CGUL_EXPORT void * cgul_cache__get (cgul_exception_t *cex, cgul_cache_t cache)
 
CGUL_EXPORT void cgul_cache__put (cgul_exception_t *cex, cgul_cache_t cache, void *obj)
 

Detailed Description

This class allows you to cache objects so that they can be reused without have to reallocate and free the memory. This improves performance because malloc() and free() are relatively expensive. It should also help reduce memory fragmentation.

This class can also be used to reserve objects for future use. This can be used to allow synchronous error reporting in classes like cgul_event_router which keep a pending event queue. Without reserving an object when cgul_event_router__add_listener() has to put an event on the pending event queue, that object would have to be allocated later which could cause an asynchronous out-of-memory exception, but by allocating and reserving that object immediately, the client gets synchronous notification of out-of-memory exceptions.

Lastly, this class can be used as an abstraction layer for creating objects. For example, the constructors for cgul_rbtree set up a cgul_cache to return different nodes depending on whether the user wants to enable the indexing feature of cgul_rbtree. This allows the user to save two unsigned int values per node which can lead to a substantial savings for a large tree. Most of the rest of the code in cgul_rbtree is written without having to know the exact type of node that is being used and simply calls cgul_cache__get() and cgul_cache__put() when appropriate.

This class is used internally by cgul_list and cgul_rbtree to cache their nodes. You can use these classes to test this class by, for example, creating a cgul_list and playing with cgul_list_set_cache_size().

Author
Paul Serice

Typedef Documentation

§ cgul_cache_t

typedef typedefCGUL_BEGIN_C struct cgul_cache* cgul_cache_t

Opaque pointer to a cgul_cache instance.

§ cgul_cache__constructor_t

typedef void*(* cgul_cache__constructor_t) (cgul_exception_t *cex)

This function pointer typedef is needed so that the cgul_cache knows how to create new default instances of the objects you want to cache.

§ cgul_cache__destructor_t

typedef void(* cgul_cache__destructor_t) (void *obj)

This function pointer typedef is needed so that the cgul_cache knows how to delete instances of the objects you want to cache. The client's implementation of this function should not throw an exception.

§ cgul_cache__restructor_t

typedef void(* cgul_cache__restructor_t) (void *obj)

This function pointer typedef is needed so that the cgul_cache knows how take a fully constructed object and return it to its initial default state. This callback is invoked when objects are put back on the cache to minimize the memory footprint of objects on the cache. If the restructor is set to NULL, the client is responsible for resetting the object before putting it back on the cgul_cache.

Function Documentation

§ cgul_cache__get_freer()

CGUL_EXPORT cgul_cache_t cgul_cache__get_freer ( )

Static method used to return the cgul_cache instance that is an adapter for free(). Because the object returned is statically allocated, the client should not attempt to call cgul_cache__delete() on the pointer returned. If the client forgets, cgul_cache__delete() will ignore the request.

The purpose of this static method is to allow clients to use methods (like cgul_rbtree__remove_range()) that accept cgul_cache objects for cleaning up keys or values even though the objects are allocated directly using one of the malloc() family of function calls (instead of through the cgul_cache interface).

The cgul_cache object returned only implements the cgul_cache__destructor_t part of the cgul_cache interface. Thus, any attempt to use the object returned to construct a new object will result in NULL being returned.

Because the cgul_cache object returned is only used in the destruction context, the conventional cgul_exception object required of most methods is not required of this method.

Returns
cgul_cache adapter for free()

Referenced by cgul_cache_cxx::get_freer().

§ cgul_cache__new()

CGUL_EXPORT cgul_cache_t cgul_cache__new ( cgul_exception_t cex,
cgul_cache__constructor_t  constructor,
cgul_cache__destructor_t  destructor,
cgul_cache__restructor_t  restructor 
)

Create a new cgul_cache instance. If restructor is set to NULL, the client is responsible for resetting the object before putting it back on the cgul_cache. If memory cannot be allocated, NULL is returned and an exception is thrown.

By default, the maximum cache size is set to 0. This means no objects are cached by default. When you want to enable caching, you can change the maximum cache size by calling cgul_cache__set_size().

Parameters
[in,out]cexc-style exception
[in]constructorconstructor for the cached objects
[in]destructordestructor for the cached objects
[in]restructorrestructor for the cached objects
Returns
new cgul_cache instance

Referenced by cgul_cache_cxx::cgul_cache_cxx().

§ cgul_cache__delete()

CGUL_EXPORT void cgul_cache__delete ( cgul_cache_t  cache)

This method first calls the destructor for each object that is still cached. It then frees all of its internally allocated resources. The client should not use the cache instance after calling this method.

Parameters
[in]cachecgul_cache instance

Referenced by cgul_cache_cxx::set_obj(), and cgul_cache_cxx::~cgul_cache_cxx().

§ cgul_cache__get_size()

CGUL_EXPORT unsigned long int cgul_cache__get_size ( cgul_exception_t cex,
cgul_cache_t  cache 
)

Get the maximum number of objects the cache can hold when the reserve is zero. To get the total number of elements the cache can hold, you must add the reserve to the size.

Parameters
[in]cexc-style exception
[in]cachecgul_cache instance
Returns
maximum size of the cache

Referenced by cgul_cache_cxx::get_size().

§ cgul_cache__set_size()

CGUL_EXPORT void cgul_cache__set_size ( cgul_exception_t cex,
cgul_cache_t  cache,
unsigned long int  size 
)

Set the maximum number of objects the cache can hold when the reserve is zero.

Calling this method with size less than the reserve does not free any of the reserved objects; however, it may free objects that have recently been "moved" from the reserve to the main cache. (See cgul_cache__set_reserve().)

You can release all the cached objects and disable caching of objects by setting the cache reserve to 0 and the cache size to 0 (in that order). This is the default.

If an error occurs (while enlarging the cache), an exception is thrown.

Parameters
[in,out]cexc-style exception
[in]cachecgul_cache instance
[in]sizemaximum size of the cache

Referenced by cgul_cache_cxx::set_size().

§ cgul_cache__get_reserve()

CGUL_EXPORT unsigned long int cgul_cache__get_reserve ( cgul_exception_t cex,
cgul_cache_t  cache 
)

Get the reserve limit. This is the number of objects that are guaranteed to be held in reserve by the cache. These objects will not be returned by the cache until the reserve is reduced. The reserve is independent of the size of the cache.

Parameters
[in]cexc-style exception
[in]cachecgul_cache instance
Returns
reserve

Referenced by cgul_cache_cxx::get_reserve().

§ cgul_cache__set_reserve()

CGUL_EXPORT void cgul_cache__set_reserve ( cgul_exception_t cex,
cgul_cache_t  cache,
unsigned long int  reserve 
)

Set the reserve limit. This method causes cache to reserve objects. The reserved objects are held indefinitely until the reserve is reduced. The reserve is independent of the size of the cache.

It is important to understand that if these reserved objects are not already being held by the cache, the cache will instantiate them. This allows the client to immediately instantiate objects without having to worry about out-of-memory exceptions when the objects are used later.

Note that if you want to get a pointer to one of the reserved object, you first call cgul_cache__set_reserve() to reduce the number of the reserved objects. This simply "moves" the now unreserved objects to the main cache of objects. You then immediately call cgul_cache__get() to get an object from the main cache.

It is done like this so that you can code strictly in terms of cgul_cache__get(). You can then reserve an object now and trigger when it is used later just by calling this method. The code that uses cgul_cache__get() does not need to know anything about reserved objects. It will just naturally use them.

Objects that are "moved" from the reserve to the main cache are not guaranteed to be available if cgul_cache__set_size() has since been called.

Parameters
[in,out]cexc-style exception
[in]cachecgul_cache instance
[in]reservereserve

Referenced by cgul_cache_cxx::set_reserve().

§ cgul_cache__get()

CGUL_EXPORT void* cgul_cache__get ( cgul_exception_t cex,
cgul_cache_t  cache 
)

Try to return a re-initialized object from the cache; if the cache is empty, a newly instantiated object will be returned instead. If an error occurs, NULL is returned and an exception is thrown.

Parameters
[in,out]cexc-style exception
[in]cachecgul_cache instance
Returns
cached or new object

Referenced by cgul_cache_cxx::get().

§ cgul_cache__put()

CGUL_EXPORT void cgul_cache__put ( cgul_exception_t cex,
cgul_cache_t  cache,
void *  obj 
)

Try to put obj on the cache. If the cache is full, obj will be delete instead.

Parameters
[in]cexc-style exception
[in]cachecgul_cache instance
[in]objobject to cache or delete

Referenced by cgul_cache_cxx::put().