Mod_cachem, an Apache 2.X only DSO module, creates, maintains, and manages a shared memory cache (either named or anonymous) usable by other DSO modules from within their ap_hook_method_handler. The cache is not designed for numerous inserts/ deletes, and/or numerous records, and/or lengthy access of cache data and/or critical module private data. It is designed for a module to create one or a few data records for maintaining state information and for sharing some information among processes. The rationale for the above is that modules requiring extensive shared memory or process communication will incorporate their own robust solutions. Not intended, at this time, for use by Apache 2 filters. Intended to reduce the complexity and increase the reliability of supported modules. REQUIREMENTS ============ Apache2 shared memory support (APR_HAS_SHARED_MEMORY defined.) INFORMATION =========== Website: http://countm.sourceforge.net/ Website: http://sourceforge.net/projects/countm/ Release: 0.2 Supports: Fedora Core 5 i386 Supports: Fedora Core 4 i386 Supports: FreeBSD i386 6.0-RELEASE Supports: OpenSolaris i386 Build 28 Development Environment: Fedora Core 4 i386 FILE RELEASES ============= apache2-mod_cachem-0.2.tar.gz (Platform Independent) apache2-mod_cachem-0.2-1.fc4.src.rpm (Fedora Core 4 i386) apache2-mod_cachem-0.2-1.fc4.i386.rpm (Fedora Core 4 i386) apache2-mod_cachem-debuginfo-0.2-1.fc4.i386.rpm (Fedora Core 4 i386) apache2-mod_cachem-0.2-1.fc5.src.rpm (Fedora Core 5 i386) apache2-mod_cachem-0.2-1.fc5.i386.rpm (Fedora Core 5 i386) apache2-mod_cachem-debuginfo-0.2-1.fc5.i386.rpm (Fedora Core 5 i386) apache2-mod_cachem-0.2_1.tbz (FreeBSD i386 6.0-RELEASE) apache2-mod_cachem-0.2-solaris-i86pc.tar.gz (OpenSolaris i386 Build 28) INSTALLATION - Generic ====================== Download the apache2-mod_cachem-0.2.tar.gz distribution tarball. Create a cachem module project using apxs (from the Apache2 package), and, after verifying proper compilation, installation, and operation, copy the mod_cachem* files from the distribution into the project directory. [bkyoung@flood tmp]$ ls apache2-mod_cachem-0.2.tar.gz [bkyoung@flood tmp]$ tar -xzpf apache2-mod_cachem-0.2.tar.gz [bkyoung@flood tmp]$ /usr/sbin/apxs -g -n cachem Creating [DIR] cachem Creating [FILE] cachem/Makefile Creating [FILE] cachem/modules.mk Creating [FILE] cachem/mod_cachem.c Creating [FILE] cachem/.deps [bkyoung@flood tmp]$ cd cachem [bkyoung@flood cachem]$ make /usr/lib/apr/build/libtool --silent --mode=compile gcc -pthread -O2 -g -pipe -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -DAP_HAVE_DESIGNATED_INITIALIZER -DSSL_EXPERIMENTAL_ENGINE -I/usr/include/httpd -I/usr/include/apr-0 -I/usr/include/openssl -DAP_FNAME=\"mod_cachem.c\" -prefer-pic -c mod_cachem.c && touch mod_cachem.slo /usr/lib/apr/build/libtool --silent --mode=link gcc -pthread -O2 -g -pipe -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o mod_cachem.la -rpath /usr/lib/httpd/modules -module -avoid-version mod_cachem.lo [bkyoung@flood cachem]$ cp -pf ../apache2-mod_cachem-0.2/mod_cachem* . [bkyoung@flood cachem]$ make clean make[1]: Entering directory `/home/bkyoung/tmp/tmp/cachem' rm -f *.o *.lo *.slo *.obj *.a *.la rm -rf .libs make[1]: Leaving directory `/home/bkyoung/tmp/tmp/cachem' rm -f mod_cachem.o mod_cachem.lo mod_cachem.slo mod_cachem.la [bkyoung@flood cachem]$ make /usr/lib/apr/build/libtool --silent --mode=compile gcc -pthread -O2 -g -pipe -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -DAP_HAVE_DESIGNATED_INITIALIZER -DSSL_EXPERIMENTAL_ENGINE -I/usr/include/httpd -I/usr/include/apr-0 -I/usr/include/openssl -DAP_FNAME=\"mod_cachem.c\" -prefer-pic -c mod_cachem.c && touch mod_cachem.slo /usr/lib/apr/build/libtool --silent --mode=link gcc -pthread -O2 -g -pipe -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -m32 -march=i386 -mtune=pentium4 -fasynchronous-unwind-tables -o mod_cachem.la -rpath /usr/lib/httpd/modules -module -avoid-version mod_cachem.lo [bkyoung@flood cachem]$ make DESTDIR=`pwd`/dest install make[1]: Entering directory `/home/bkyoung/tmp/tmp/cachem' /usr/lib/apr/build/libtool --silent --mode=install cp mod_cachem.la /home/bkyoung/tmp/tmp/cachem/dest/usr/lib/httpd/modules/ libtool: install: warning: remember to run `libtool --finish /usr/lib/httpd/modules' make[1]: Leaving directory `/home/bkyoung/tmp/tmp/cachem' /usr/lib/apr/build/libtool --silent --mode=install cp mod_cachem.la /home/bkyoung/tmp/tmp/cachem/dest/usr/lib/httpd/modules/ libtool: install: warning: remember to run `libtool --finish /usr/lib/httpd/modules' For install into the system, run the make install target as root, and do not use DESTDIR prepackaging variable. INSTALLATION FAILS TO BUILD GENERATED SAMPLE MODULE =================================================== Determine the package installation prefix. This is the configure --prefix setting. Find the "build" directory, which contains the supporting build files (instdso.sh etc.) Create a symbolic link within prefix directory to the "build" directory. EX: Prefix is /usr/local "build" directory is /usr/local/share/apache2/build cd /usr/local ln -s /usr/local/share/apache2/build build INSTALLATION - Fedora Core 4 ============================ Use RPM to install the apache2-mod_cachem-0.2-1.fc4.i386.rpm package. rpm -i apache2-mod_cachem-0.2-1.fc4.i386.rpm The configuration file is installed into: /etc/httpd/conf.d/mod_cachem.conf INSTALLATION - FreeBSD ====================== Install the apache2-mod_cachem-0.2_1.tbz binary package using: pkg_add apache2-mod_cachem-0.2_1.tbz The configuration file is installed into: /usr/local/etc/apache2/Includes Verify, and add if necessary, that the /usr/local/etc/apache2/httpd.conf file contains: Include /usr/local/etc/apache2/Includes/*.conf INSTALLATION - OpenSolaris ========================== Install the apache2-mod_cachem-0.2-solaris-i86pc.tar.gz packages using: gzcat apache2-mod_cachem-0.2-solaris-i86pc.tar.gz | tar -xfp - pkgadd -d `pwd` SFWmodcachem The configuration file is installed into: /etc/apache2/conf.d Verify, and add if necessary, that the /etc/apache2/httpd.conf file contains: Include /etc/apache2/conf.d/*.conf CONFIGURATION DIRECTIVES ======================== Description: Runtime shared memory. Syntax: CACHEM /named_shared_memory/file-path shared_memory_size Default: NULL NULL Context: Global Server Status: Extension Module: mod_cachem The CACHEM directive takes two arguments and is only valid in the global server configuration. The first argument may be an absolute file path or "NULL". "NULL" implies anonymous shared memory, and a valid absolute file path implies named shared memory. The second argument may be a valid unsigned integer or "NULL". If "NULL", internal defaults are used, guaranteeing inadequate storage space size for any application. A valid unsigned integer determines the size of the memory cache, and must be a multiple of 8. Modules using the shared memory area probably have their requirements documented. Description: Supporting lockfile. Syntax: CACHEMlockFile /absolute/file-path Default: None Context: Global Server Status: Extension Module: mod_cachem The CACHEMlockFile directive determines the location of the supporting lockfile, if required. It must be defined correctly, or server may freeze. Description: Supporting DBM file. Syntax: CACHEMDBM /absolute/file-path Default: None Context: Global Server Status: Extension Module: mod_cachem Mod_cachem uses DBM to store module identification. The CACHEMDBM directive is the absolute file-path used for the DBM. USAGE ===== Mod_cachem is designed as a support module. Set the CACHEM, CACHEMlockfile, and CACHEMDBM directives in the mod_cachem.conf file. USAGE - Development =================== Modules, within the module method handler, as a first rule of business, initialize their instance of the cache with cachem_handler_init. Modules, within the module method handler, acquire an id, if desired, via cachem_id. All calls with equal s parameters will return the same id during a httpd server run (IE all detached/ non detached processes of httpd will always returned the same id for a given s parameter, which may be saved as a global). If s is NULL, then a generic unique id is returned. Applications insert records into the cache via the cachem_add function. All future access to the records are via the returned indexes. When a record is inserted into the cache, the pid of the inserting process and the user supplied id are attached to the record. Applications delete records using the cachem_delete function. Applications may access the record using the cachem_lock, cachem_get, and cachem_unlock functions. Within the lock, the actual data may be accessed via the returned pointer. Once the lock is released, the pointer state is undefined. Copy the mod_cachem.h file into the httpd include directory, or add the path to the directory containing mod_cachem.h using -I. During detached process termination, the cachem_delete_pid function may be used to delete all records matching a specific id and the current pid from the cache. Ideal for a cleanup function. ACQUIRE AN MODULE SPECIFIC ID ============================= #include cachem_id_t id; apr_pool_t * p=r->pool; cachem_lock(); id = cachem_id(__FILE__, p); cachem_unlock(); INSERTING A RECORD INTO CACHE ============================= m_index_t index; some_record_t rec; cachem_lock(); index=cachem_add(&rec, sizeof(rec), id); cachem_unlock(); ACCESSING ALL RECORDS WITH A SPECIFIC ID ======================================== m_index_t index=CACHEM_INVALID_INDEX; cachem_id_t id; void * ptr=NULL; cachem_lock(); while( (index=cachem_get_id(id, index))!=CACHEM_INVALID_INDEX) { ptr = cachem_get(index); } cachem_unlock(); DELETING ALL RECORDS WITH A SPECIFIC ID ======================================= cachem_id_t id; m_index_t index=CACHEM_INVALID_INDEX; cachem_lock(); while( (index=cachem_get_id(id, CACHEM_INVALID_INDEX))!=CACHEM_INVALID_INDEX) { cachem_delete(index, CACHEM_NOLOCKING); } cachem_unlock(); DELETING A SPECIFIC RECORD ========================== m_index_t index; cachem_lock(); cachem_delete(index); cachem_unlock(); DELETING ALL RECORDS WITH CURRENT PID AND SPECIFIC ID ===================================================== m_index_t index; cachem_id_t id; cachem_lock(); while( (index=cachem_get_pid(id, CACHEM_INVALID_INDEX))!=CACHEM_INVALID_INDEX) { cachem_delete(index); } cachem_unlock(); MOD_STATUS INTEGRATION ====================== A server-status request will print out some information about the current state of the cache. NOTES ===== Process are constantly being created and destroyed. When a process terminates, all blocks within the cache with the pid of the terminating process and id of CACHEM_INVALID_ID are automatically deleted. Each server startup, but not each server process startup, erases any DBM information. Determining the CACHEM size requires knowing the requirements of the modules using the cache. Normally this is a sizeof(some_structure) plus some additional number. Defining DEBUG at build time will activate the method handler for debugging. All data storage within the memory cache are aligned(4). Aligned (8) is easily doable, but not implemented at this time. The cache is split into one static and three dynamic sections. The first section (the static section) is the cache header, containing cachem data. The second section (first dynamic section) is the block storage area. The third section (second dynamic section) is the free area. The last section (the third dynamic section) contains the block pointers. The cache is compacted/krunched at all times. Inserts and deletes may cause block relocations within the block storage area. CACHE MEMORY MODEL ================== BLOCK FORMAT |======================| | Record Data | <- Aligned (4) o_beg |----------------------| | Possible Padding | |======================| HEADER FORMAT |======================| | cachem_header | <- Aligned (8) pData |----------------------| | Possible Padding | <- sizeof(cachem_header) |======================| BLOCK POINTER SECTION FORMAT |======================| | cachem_bptr[M] N | <- o_bptop / / | cachem_bptr[2] X | | cachem_bptr[1] 1 | | cachem_bptr[0] 0 | |======================| M = the number of allocated block pointers. X = An unused block pointer. N = u_blks The Mth block pointer must be used. CACHE FORMAT |======================| (header section static) | HEADER SECTION | <- pData |======================| (block section dynamic) | BLOCK 0 | <- o_st |----------------------| | BLOCK 1 | |----------------------| / / |----------------------| | BLOCK N | |======================| (free area dynamic) / FREE SECTION / <- o_fr |======================| (block pointer section dynamic) | BLOCK PTR SECTION | <- o_bptop |======================| <- uSize/nSize (first byte after the cache, (in)valid) N = u_blks NOTES: u_blks: The number of used block within the cache. A cachem_bptr may or may not be used to point to a block. Unused cachem_bptr have the o_beg value set to zero (0). The number of valid block pointers is equal to the number of blocks. Each valid block pointer points to the next block, in sequence. When the index cachem_bptr is deleted, o_bptop is adjusted to the last used cachem_bptr in the array. When a cachem_bptr is added, o_bptop is adjusted to point to it. When a block is added and a unused block pointer is available, the block area is opened. When a block is added and a block pointer is allocated, o_bptop is adjusted, and the block is allocated from the free area. When a block is deleted, then the bptr is deleted, and the subsequent blocks are relocated. EMPTY CACHE |======================| (header section static) | HEADER SECTION | <- pData |======================| (block section/ free area dynamic) / BLOCK/FREE SECTION / <- o_fr, o_st |======================|(block pointer section dynamic) <- uSize/nSize (first byte after the cache, (in)valid) <- o_bptop INSERT ONE RECORD |======================| (header section static) | HEADER SECTION | <- pData |======================| (block section dynamic) | BLOCK 0 | <- o_st |======================| (free area dynamic) / FREE SECTION / <- o_fr |======================| (block pointer section dynamic) | BLOCK PTR 0 | <- o_bptop |======================| <- uSize/nSize (first byte after the cache, (in)valid) BUILDING THE DISTRIBUTION - Developer ===================================== The bootstrap bs.sh script will build the distribution tarball for supported systems. The files withing the dist/OS/OS_REL directory contain the necessary control scripts. Most important is the setvars.inc.sh script. The setvars.inc.sh script is designed to be included within the bs.sh script, and sets various build parameters and build functions. The pkg_configure functions controls the configure settings. /bin/sh bs.sh d Fedora 4 Will build and place the distribution package within PKGDISTDIR. After the distribution package is built, build the package with: (set ~/.rpmmacros correctly) /bin/sh bs.sh p Fedora 4 REPLACE STRINGS (A manual maintenance convenience.) ================================================= These strings are designed to be replaced within this manual using sed(P). Replacement order is important. apache2-mod_cachem-0.2-1.fc4.src.rpm apache2-mod_cachem-0.2-1.fc4.i386.rpm apache2-mod_cachem-debuginfo-0.2-1.fc4.i386.rpm apache2-mod_cachem-0.2-1.fc5.src.rpm apache2-mod_cachem-0.2-1.fc5.i386.rpm apache2-mod_cachem-debuginfo-0.2-1.fc5.i386.rpm apache2-mod_cachem-0.2_1.tbz Fedora Core 5 i386 Fedora Core 4 i386 FreeBSD i386 6.0-RELEASE OpenSolaris i386 Build 28 apache2-mod_cachem-0.2.tar.gz apache2-mod_cachem-0.2 apache2-mod_cachem 0.2 RELEASE CHECKLIST (maintainer section) ====================================== Adjust version in configure.ac (AC_INIT). Adjust usage function in bs.sh. Adjust VERSION and RELEASE in Fedora/fcpkg.sh (adjust case statement). Adjust VERSION and RELEASE in Fedora/*/cachem.spec. Adjust %description in Fedora/*/cachem.spec to first paragraph of cachem.txt. Adjust FreeBSD/*/pkg-descr to first paragraph of cachem.txt. Adjust Solaris/*/pkginfo NAME= to first paragraph of cachem.txt. Adjust Solaris/*/prototype to reflect new version, pkginfo, depend. Adjust VERSION in Solaris/sub.sh Adjust PORTVERSION and PORTREVISION in FreeBSD/*/Makefile Replace strings in cachem.txt. Adjust NEWS, README, AUTHORS as necessary. Fixup the ChangeLog. Add the new dist/*/* files to CVS. Use aspell as much as possible.