From: genoa Date: Mon, 22 Jun 1992 23:05:25 +0000 (+0000) Subject: *** empty log message *** X-Git-Tag: release77~519 X-Git-Url: http://andersk.mit.edu/gitweb/moira.git/commitdiff_plain/7de0249436aef39bba1b9fc0b58e078b7bf1fd14 *** empty log message *** --- diff --git a/server/cache.dc b/server/cache.dc new file mode 100644 index 00000000..23087adb --- /dev/null +++ b/server/cache.dc @@ -0,0 +1,342 @@ +/* + * $Header$ + * + * Copyright (C) 1989, 1990 by the Massachusetts Institute of Technology + * For copying and distribution information, please see the file + * . + */ + +#ifndef lint +static char *rcsid_cache_dc = "$Header$"; +#endif lint + +#include +#include "query.h" +#include "mr_server.h" +EXEC SQL INCLUDE sqlca; + +extern char *whoami, *strsave(); +extern int ingres_errno, mr_errcode; + + +/*** NOTE ************************************************************** + * + * This code depends on each type starting with a unique letter. If + * any new types are added to the system that begin with the same + * letter as one of the existing types: + * User + * List + * String + * Machine + * Cluster + * Filesystem + * then we will have to rework the code that only looks at the first + * letter of the types. + * + *********************************************************************** + */ + +/* Cache parameters: */ +#define CACHESIZE 101 /* number of cache slots */ +#define NAMESZ 257 /* max size of a name */ + +struct item { + char name[NAMESZ]; + char type[9]; + int nhash; + int id; + struct item *next; + struct item *prev; +}; + +static struct item cachehead; +static int cachesize; + +/* statistics counters */ +int cachehits = 0, cachemisses = 0; + + +/* Name hash function. */ + +int hashname(name, type) +register char *name; +char *type; +{ + register int val = *type; + + while (*name) + val = val<<5 - val + *name++ - '`'; + return(val); +} + + +/* Initialize the cache, flushing any old data, and report the statistics + * if the cache was previously in use. + */ + +flush_cache() +{ + register struct item *i; + + if (cachehits + cachemisses != 0) + com_err(whoami, 0, "Flushing cache; %d hits, %d misses, %d%% hit rate", + cachehits, cachemisses, + (100 * cachehits) / (cachehits + cachemisses)); + else + cachehead.next = cachehead.prev = &cachehead; + cachehits = cachemisses = cachesize = 0; + for (i = cachehead.next; i != &cachehead; i = i->next) { + if (i->prev != &cachehead) + free(i->prev); + } + if (cachehead.prev != &cachehead) + free(cachehead.prev); + cachehead.next = cachehead.prev = &cachehead; +} + + +/* Do a name to ID translation. id will be updated with the answer if + * it is available, and as a side effect the cache is updated. + */ + +int name_to_id(name, type, id) +char *name; +char *type; +int *id; +{ + register struct item *i; + EXEC SQL BEGIN DECLARE SECTION; + char *iname; + int j, rowcount; + EXEC SQL END DECLARE SECTION; + int h, ctr; + + h = hashname(name, type); + for (i = cachehead.next; i != &cachehead; i = i->next) { + if (i->nhash != h || + strcmp(name, i->name) || + strcasecmp(type, i->type)) + continue; + *id = i->id; + cachehits++; + i->next->prev = i->prev; + i->prev->next = i->next; + i->next = cachehead.next; + i->prev = &cachehead; + cachehead.next->prev = i; + cachehead.next = i; + return(MR_SUCCESS); + } + + cachemisses++; + iname = name; + + switch (*type) { + case 'U': + case 'u': + EXEC SQL SELECT users_id INTO :j FROM users WHERE login=:iname; + break; + case 'L': + case 'l': + EXEC SQL SELECT list_id INTO :j FROM list WHERE name=:iname; + break; + case 'M': + case 'm': + uppercase(iname); + EXEC SQL SELECT mach_id INTO :j FROM machine WHERE name=:iname; + break; + case 'C': + case 'c': + EXEC SQL SELECT clu_id INTO :j FROM cluster WHERE name=:iname; + break; + case 'F': + case 'f': + EXEC SQL SELECT filsys_id INTO :j FROM filesys WHERE label=:iname; + break; + case 'S': + case 's': + EXEC SQL SELECT string_id INTO :j FROM strings WHERE string=:iname; + break; + default: + return(MR_INTERNAL); + } + if (sqlca.sqlcode == 100) + return(MR_NO_MATCH); + if (sqlca.sqlerrd[2] > 1) + return(MR_NOT_UNIQUE); + if (sqlca.sqlcode != 0) + return(MR_INGRES_ERR); + *id = j; + if (name[0] == '#' && !strcasecmp(type, "USER")) + return(MR_SUCCESS); + if (cachesize < CACHESIZE) { + i = (struct item *) malloc(sizeof(struct item)); + cachesize++; + } else { + i = cachehead.prev; + cachehead.prev = i->prev; + i->prev->next = &cachehead; + } + strcpy(i->name, name); + strcpy(i->type, type); + i->nhash = h; + i->id = j; + i->next = cachehead.next; + i->prev = &cachehead; + cachehead.next->prev = i; + cachehead.next = i; + return(MR_SUCCESS); +} + + +/* Perform an ID to name mapping. name should be a pointer to a pointer to + * malloc'ed data. The buffer it refers to will be freed, and a new buffer + * allocated with the answer. + */ + +int id_to_name(id, type, name) +int id; +char *type; +char **name; +{ + register struct item *i; + EXEC SQL BEGIN DECLARE SECTION; + char iname[NAMESZ]; + int j, rowcount; + EXEC SQL END DECLARE SECTION; + int ctr; + + for (i = cachehead.next; i != &cachehead; i = i->next) { + if (i->id != id || strcasecmp(type, i->type)) continue; + free(*name); + *name = strsave(i->name); + cachehits++; + i->next->prev = i->prev; + i->prev->next = i->next; + i->next = cachehead.next; + i->prev = &cachehead; + cachehead.next->prev = i; + cachehead.next = i; + return(MR_SUCCESS); + } + + cachemisses++; + j = id; + + switch (*type) { + case 'U': + case 'u': + EXEC SQL SELECT login INTO :iname FROM users WHERE users_id=:j; + break; + case 'L': + case 'l': + EXEC SQL SELECT name INTO :iname FROM list WHERE list_id=:j; + break; + case 'M': + case 'm': + EXEC SQL SELECT name INTO :iname FROM machine WHERE mach_id=:j; + break; + case 'C': + case 'c': + EXEC SQL SELECT name INTO :iname FROM cluster WHERE clu_id=:j; + break; + case 'F': + case 'f': + EXEC SQL SELECT label INTO :iname FROM filesys WHERE filsys_id=:j; + break; + case 'S': + case 's': + EXEC SQL SELECT string INTO :iname FROM strings WHERE string_id=:j; + break; + default: + return(MR_INTERNAL); + } + if (sqlca.sqlcode == 100) { + free(*name); + sprintf(iname, "#%d", j); + *name = strsave(iname); + return(MR_NO_MATCH); + } + if (sqlca.sqlerrd[2] > 1) + return(MR_INTERNAL); + if (sqlca.sqlcode != 0) + return(MR_INGRES_ERR); + free(*name); + *name = strsave(strtrim(iname)); + if (**name == '#' && !strcasecmp(type, "USER")) + return(MR_SUCCESS); + if (cachesize < CACHESIZE) { + i = (struct item *) malloc(sizeof(struct item)); + cachesize++; + } else { + i = cachehead.prev; + cachehead.prev = i->prev; + i->prev->next = &cachehead; + } + strcpy(i->name, *name); + strcpy(i->type, type); + i->nhash = hashname(*name, type); + i->id = id; + i->next = cachehead.next; + i->prev = &cachehead; + cachehead.next->prev = i; + cachehead.next = i; + return(MR_SUCCESS); +} + + +/* Explicitly add something to the cache without doing a lookup in the + * database. + */ + +cache_entry(name, type, id) +char *name; +char *type; +int id; +{ + register struct item *i; + + for (i = cachehead.next; i != &cachehead; i = i->next) + if (i->id == id && !strcmp(i->type, type)) + return(MR_SUCCESS); + if (cachesize < CACHESIZE) { + i = (struct item *) malloc(sizeof(struct item)); + cachesize++; + } else { + i = cachehead.prev; + cachehead.prev = i->prev; + i->prev->next = &cachehead; + } + strcpy(i->name, name); + strcpy(i->type, type); + i->nhash = hashname(name, type); + i->id = id; + i->next = cachehead.next; + i->prev = &cachehead; + cachehead.next->prev = i; + cachehead.next = i; + return(MR_SUCCESS); +} + + +/* Flush something that may or may not already be in the cache. */ + +flush_name(name, type) +char *name; +char *type; +{ + int h; + register struct item *i; + + h = hashname(name, type); + + for (i = cachehead.next; i != &cachehead; i = i->next) { + if (!strcmp(name, i->name) && !strcasecmp(type, i->type)) { + cachesize--; + i->next->prev = i->prev; + i->prev->next = i->next; + free(i); + return(MR_SUCCESS); + } + } +}