home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
drdobbs
/
1987
/
12
/
deikman
/
cache.c
next >
Wrap
Text File
|
1987-12-21
|
6KB
|
254 lines
/* cache.c - memory cache
alan deikman 12/86
These routines handle a memory cache of fixed sized records.
All memory is allocated through the standard library routine
malloc().
Each routine other than cacallo() takes as the first parameter
a character pointer that is originally returned by the cacallo()
routine.
cacallo() Allocate cache
cacold() Get oldest record
cacnum() Number oldest record and make it the newest
cacflsh() Process all marked records
cacfind() Find record n and make it newest
cacproc() Mark record for processing when freed
cacunpc() Unmark record for processing when freed
cacstat() Get cache statistics
cacfree() Free cache
*/
#include <stdio.h>
#include <malloc.h>
#include "cache.h"
/* cacallo() - Allocate cache */
CACDS *cacallo(num, recl, extf, idnt)
int num; /* number of records to allocate */
int recl; /* length of each record */
int (*extf)(); /* pointer to external processing function */
long idnt; /* parameter passed to external function */
{
CACDS *cac;
char *cacmem();
int i = 0;
/* set up cac structure with initial values */
if (num < 2) num = 2;
cac = (CACDS *) cacmem(sizeof(CACDS));
cac->recl = recl;
cac->maxr = num;
cac->proc = extf;
cac->idnt = idnt;
cac->hits =
cac->miss =
cac->adds = 0L;
cac->nums = (long *) cacmem(num * sizeof(long));
cac->next = (short *) cacmem(num * sizeof(short));
cac->prio = (short *) cacmem(num * sizeof(short));
cac->mark = cacmem(num);
cac->recs = cacmem(num * recl);
/* initial lru/mru chain */
while (i < num) {
cac->next[i] = i + 1;
cac->prio[i] = i - 1;
cac->nums[i] = -1;
cac->mark[i] = 0;
i++; }
cac->next[num - 1] = cac->prio[0] = -1;
cac->mru = 0;
cac->lru = num - 1;
/* return cache pointer */
return cac; }
/* allocate memory with error checking */
char *cacmem(siz)
int siz;
{
char *c;
c = malloc(siz);
if (c == (char *) 0) {
fprintf(stderr, "cacallo: Can't allocate memory.\n");
fprintf(stderr, "Tried to get %d bytes on top of %ld bytes already\n",
siz, cacamem);
exit(1); }
cacamem += siz;
return c; }
/* number oldest record and make it the newest. if the record was
marked for exit procesing, call external processing function.
return pointer to record */
char *cacnum(cac, num)
CACDS *cac; /* cache header */
long num; /* number new MRU record */
{
char *rec = cac->recs + (cac->lru * cac->recl);
/* call external function */
if (cac->mark[cac->lru] && cac->proc)
(*(cac->proc))(cac->idnt, cac->nums[cac->lru], rec);
/* unmark record and make it newest */
cac->mark[cac->lru] = 0;
cac->adds++;
cac->nums[cac->lru] = num;
cacnew(cac, cac->lru);
/* return record; ready for usage */
return rec; }
/* get pointer to oldest record without altering age */
char *cacold(cac)
CACDS *cac; /* cache header */
{
return cac->recs + (cac->lru * cac->recl); }
/* if an exit processing routine has been defined, process all marked
records */
cacflsh(cac)
CACDS *cac; /* cache header */
{
int i;
char *rec;
if (!(cac->proc)) return;
for (i = 0; i < cac->maxr; i++) if (cac->mark[i]) {
rec = cac->recs + (i * cac->recl);
(*(cac->proc))(cac->idnt, cac->nums[i], rec);
cac->mark[i] = 0; }
return; }
/* make record newest */
cacnew(cac, rec)
CACDS *cac; /* cache header */
short rec; /* record to make newest */
{
/* if this record is already the newest, just return */
if (rec == cac->mru) return;
/* change prior's next */
cac->next[cac->prio[rec]] = cac->next[rec];
/* change next's prior - if there was no next that means this was the
lru record. change lru */
if (cac->next[rec] != -1)
cac->prio[cac->next[rec]] = cac->prio[rec];
else {
if (rec != cac->lru) {
fprintf(stderr, "cacnew: panic\n");
exit(1); }
cac->lru = cac->prio[rec]; }
/* now the record is out of the chain. stick it back in at the mru end. */
cac->prio[cac->mru] = rec;
cac->next[rec] = cac->mru;
cac->prio[rec] = -1;
cac->mru = rec;
/* done */
return; }
/* find record and make it newest */
char *cacfind(cac, num)
CACDS *cac; /* cache header */
long num; /* record number to look for */
{
int i;
for (i = 0; i < cac->maxr; i++) if (cac->nums[i] == num) {
cac->hits++;
cacnew(cac, i);
return cac->recs + (i * cac->recl); }
cac->miss++;
return (char *) 0; }
/* mark record for external processing */
cacproc(cac, num)
CACDS *cac; /* cache header */
long num; /* record to mark */
{
int i;
for (i = 0; i < cac->maxr; i++) if (cac->nums[i] == num) {
cac->mark[i] = 1;
return; }
return; }
/* un-mark record for external processing */
cacunpc(cac, num)
CACDS *cac; /* cache header */
long num; /* record to unmark */
{
int i;
for (i = 0; i < cac->maxr; i++) if (cac->nums[i] == num) {
cac->mark[i] = 0;
return; }
return; }
/* get statistics of the cache */
cacstat(cac, hit, mis, add)
CACDS *cac; /* cache header */
long *hit, *mis, *add; /* values to return */
{
*hit = cac->hits;
*mis = cac->miss;
*add = cac->adds;
return; }
/* free cache */
cacfree(cac)
CACDS *cac; /* cache header */
{
cacflsh(cac);
cacamem -= sizeof(CACDS) + (cac->maxr * sizeof(long)) +
(cac->maxr * 2 * sizeof(short)) + (cac->maxr) +
(cac->maxr * cac->recl);
free(cac->recs);
free(cac->prio);
free(cac->next);
free(cac->nums);
free(cac);
return; }