Add generational caching

Contributor: Jay Nelson (jaynel)
Branch: gcache

Generational caching is an ets-backed form of caching
which avoids setting expiration times for individual
objects in the cache, but instead uses generational
expiration of objects en masse for higher performance.

A generational cache is maintained using ets tables.
One ets table (named 'cxy_cache') is used to hold the
meta-data about all generational caches. The meta
table holds references to 2 generations of ets table
caches for each Cache_Name that is registered to
managed cached items. Cache lookups occur against
the most recent generation, then the older generation.
If an item is found in the older generation, it is
automatically copied to the newer generation ets
table before returning the Value corresponding to
the Key lookup.

When a generation expires, a third empty ets table
is created to hold the yet to come generation of
requests. The current generation is moved to the
2nd generation slot and the old 2nd generation ets
table is deleted. Any items with references being
held only in the old 2nd generation should be
garbage collected soon after the deletion of the
ets table.

The following benefits are expected when using
generational caching:

  1) Concurrent access to ets cached values
  2) Fast response from ets caches
  3) Efficient garbage collection of expired items

The module cxy_cache is built directly on raw ets
calls. It does not use ets_buffers, and all API
calls run in the same process as the caller.

New generations are created either using a periodic
polling time in milliseconds, when the number of
accesses to a generation exceeds a threshold, or
using an arbitrary anonymous function which takes
the Cache_Name, Access_Count, and Current_Time as
arguments to decide whether a new generation is
warranted. Currently, new generations are computed
using cxy_cache_fsm to poll and test, rather than
on each cache item access, to ensure performance
when accessing the caches is as fast as possible.

The module cxy_cache_sup is essential to the proper
operation of generational caches. It creates the
ets meta-table which manages all registered caches.
This supervisor is needed to ensure that the owner
of the ets meta-table begins before and survives
after any specific cache ets tables, because if the
owner of an ets table terminates, the ets table is
automatically deleted by the Erlang VM.

The cxy_cache_sup supervisor should be started in
an applications normal supervisor hierarchy and
then calls to cxy_cache_sup:start_cache/2,3,4 can
be used to register specific generational caches
for each type of cached item. A cxy_cache_fsm
instance will be automatically started each time
start_cache is called.