NAME
Cache::RamDisk
Sharing of Perl Objects Between Processes on Several RAM Drives
VERSION
0.1.6
SYNOPSYS
Application start phase:
cache_install( {
'Base'
=>
'/tmp/rd'
,
'Size'
=> 16,
'INodes'
=> 1024,
'SIndex'
=> {
'fie'
=> 8,
'foe'
=> 64,
'fum'
=> 512 },
'ShMem'
=>
'RdLk'
,
'Keys'
=> {
'fie'
=> 50,
'foe'
=> 200,
'fum'
=> 4000 },
'User'
=>
'apache'
,
'Group'
=>
'apache'
} );
Content handler code:
Object code:
package
MyApp::Fie;
use
Cache::RamDisk;
sub
new {
my
(
$class
,
$id
) =
@_
;
my
$c
= Cache::RamDisk->new (
'/tmp/rd'
, CACHE_LRU);
my
$self
=
$c
->get({
'fie'
=>
$id
})->{
'fie'
}->{
$id
} ||
do
{
# perform some db logics
$self
=
$sth
->fetchrow_hashref;
bless
$self
,
$class
;
$c
->put({
'fie'
=> {
$id
=>
$self
} });
}
$self
;
}
Later on in a cgi script:
[...]
my
$s
= cache_status (
'/tmp/rd'
);
[...]
"Number of items for 'fie': "
.
$s
->key_stat(
'fie'
), br;
On application shutdown:
cache_remove (
'/tmp/rd'
);
DESCRIPTION
Note: 'rd' is from now on in this document an abbreviation for 'ramdisk' or 'RAM Disk' or however you prefer to write or exclaim that herewith specified thing.
Cache::RamDisk provides multi-process applications with a means of sharing Perl objects between the processes while trying to avoid the inconveniences inherent to other IPC tools:
1. Message queues are extremely fast, but extremely limited too.
2. Shared memory is perhaps even faster, but it came out for me to be an at least hairy problem trying to store several references all in one segment.
3. Sockets are reliable, but require a second communication endpoint and yet another server process.
But a file is a file is a file.
The package collects as much ramdisks to a bundle as possible and necessary to hold the required user space, depending on the respective parameters under which the system's individual kernel had been compiled. The system user and group who owns the cache can be specified for the whole rd bunch, say cache.
Cache Types
The package provides three ways of cacheing policy. The desired type can be submitted to the individual object constructor with one of the following values:
CACHE_LRU
Forces the accessing object methods to treat the cache under Last Recently Used aspects: an existent object will be delivered, and the respective index entry moves to the top. Values from the 'Keys' reference in the latest call to install()
define the maximum number of objects for the respective key. If the index list is full, its last line will be pop()
ped and the new entry unshift()
ed.
CACHE_TIMED
All accesses from this object to the cache treat the value for each cache key as maximum age in seconds that cache objects belonging to the key are allowed to reach. "Stale" objects will not be delivered, but removed instead. (The decision whether to deliver or remove happens on every get()
request. There may a thread be born some day.)
CACHE_DEFAULT
A fallback policy by which you may use parts of your cache as a convenient substitute for SysV shared memory. Values set for the cache keys are ignored - which means that you will have to invalidate objects on this type of cache "by hand". Indexes are being kept up to date by simple unshift()
s and splice()
s. Note: the invalidate() method is not part of v0.1.2!
REQUIRES
Perl 5.6.1 on a Linux/ Unix System containing the following binaries:
chown
,
mkdir
, mke2fs, mount, umount
The package uses these Perl modules available from CPAN:
IPC::Shareable
IPC::SysV
Filesys::Df
Filesys::Statvfs
File::
stat
Fcntl
Symbol
Class::Struct
POSIX
EXPORTS
CACHE_DEFAULT, CACHE_LRU, CACHE_TIMED
METHODS
Class Methods
Cache::RamDisk->new ( $basepath [, $type [, $shmemkey]])
Creates a new class instance that will act on the cache denoted by $basepath
. If no $type
has been requested, CACHE_DEFAULT
is assumed. Please note that, although it is possible to access one cache with several types of instances at the same time, it is not intended to create one instance of several types. Do not try to perform bitwise operations on $type
, as their results will all lead to a CACHE_DEFAULT
cache. Returns undef when called as a class method, or when the 'Base' parameter is missing. The $shmemkey
argument is optional, but it becomes a vital necessity, if you want to access a cache that has been created with another than the default key. See Cache::RamDisk::Functions for details.
From this and from what can be read under "CACHE TYPES" follows: it is up to the programmer's responsibility how the cache will act. You will always have to have in mind which keys on the cache you want to be treated like what in one application. If you don't always stick to the same type of cache for one key, you will most likely mostly never get a predictable result, but see far below.
Object Methods
All of the following methods return the undef
value when called with faulty arguments, unless no runtime error prevents them from returning at all. ("faulty" means that they return the undef value also when called as class methods.)
$c->errstr
If an error has ocurred in the current instance, holds the message.
$c->get ( $href )
Get one or more objects from the current cache. The values in $href
may be scalars or arrayrefs. There may obviously be more than one key in the argument hash. Thus get()
is a means to retrieve a bunch of objects at one request. Returns a reference to a hash of hashrefs.
Examples:
$c
->get( {
'fie'
=> 12345 } ) returns {
'fie'
=> {
'12345'
=>
$a_reference
}}
$c
->get( {
'fie'
=> [12345, 67890],
'fum'
=> 54321 } )
returns {
'fie'
=> {
'12345'
=>
$a_reference
,
'67890'
=>
$another_reference
},
'fum'
=> {
'54321'
=>
$something_blessed
} }
If an object could not be found on the cache the respective value will be 0. If a non-existing key has been submitted, the respective value will be undef
. Returns undef
and sets errstr
if no argument can be found, or the argument isn't a hashref, or an OS error occurs.
$c->put ( $href )
Puts objects on the cache. The hashref it requires has to look like what get()
returns. How put()
behaves depends on which type of cache you chose. Returns 1 on success, or undef else and sets the by errstr
accessible field. Requests for keys which do not exist on the cache are ignored. Values being no hashrefs are ignored.
$c->invalidate ( $href )
Invalidates cache entries. With CACHE_LRU and CACHE_TIMED instances the put()
method will automatically perform the necessary steps, and mostly you will not need to invalidate()
something by hand. On a CACHE_DEFAULT cache, however, you will have to remove objects from time to time. Awaits a hashref like get()
. Returns 1 on success, else sets errstr
and returns undef
.
LOCKING
put()
operations lock the whole cache by locking the 'ShMem' segment exclusively. invalidate()
and get()
operations apply a shared lock to this segment for every input key, except the moments when they have to write back eventually changed data. Whenever a get()
accesses a key, it locks "its" respective shmem segment exclusively, because every access alters the index order. This means that put()s are egoistic, whereas get()s and invalidations try to be fair.
SOME NOTES
If running under Apache all filehandles will be created by &Apache::gensym
, else &Symbol::gensym
gets called.
There is a means of controlling the size of a running cache: it lies in performing a LRU put on a key that elsewhere in your application is being used as TIMED - because a LRU put trims the number of items to the limit a key has to obey.
A cache can serve more than one application - as long as they all stick to the same 'ShMem' segment.
Attempts to store anything else than a Perl reference will be ignored.
KNOWN BUGS
Something seems to go wrong in connection with TIMED gets: getting 10000 objects that have to be declared stale after 4000 seconds resulted even after just under 1000 seconds in a minimization of used disk spaces to 51% (!?) each. And I simply cannot figure out why: the respective codeline looks proper to me.
TODO
Implement some sort of debug mode?
Signal handling?
SEE ALSO
html link: Cache::RamDisk::FunctionsAUTHOR
Martin Haase-Thomas <njarl@punkass.com>
HISTORY
0.1.6 Nothing here, see Functions.pm
0.1.5 Some smaller changes due to my newly achieved respect for initrd's.
0.1.4 added invalidate method, published on thcsoft.de 07/26/02.
0.1.3 altered 'SIndex' logics, published on thcsoft.de 07/25/02.
0.1.2 rewrote them again, published on thcsoft.de 07/24/02.
0.1.1 rewrote object methods to fulfill the locking policy
0.1 Jul. 02, first approach, runnable under certain conditions