4 * Copyright (C) 1989, 1990 by the Massachusetts Institute of Technology
5 * For copying and distribution information, please see the file
10 static char *rcsid_cache_dc = "$Header$";
13 #include <mit-copyright.h>
15 #include "mr_server.h"
17 EXEC SQL INCLUDE sqlca;
19 EXEC SQL WHENEVER SQLERROR DO dbmserr();
23 /* Cache parameters: */
24 #define CACHESIZE 101 /* number of cache slots */
25 #define NAMESZ 257 /* max size of a name */
34 struct item *trans; /* keep track of transactions */
37 static struct item cachehead;
40 /* statistics counters */
41 int cachehits = 0, cachemisses = 0;
44 /* Name hash function. */
46 int hashname(char *name, enum tables type)
51 val = (val << 5) - val + *name++ - '`';
56 /* Initialize the cache, flushing any old data, and report the statistics
57 * if the cache was previously in use.
60 void flush_cache(void)
64 if (cachehits + cachemisses != 0)
66 com_err(whoami, 0, "Flushing cache; %d hits, %d misses, %d%% hit rate",
67 cachehits, cachemisses,
68 (100 * cachehits) / (cachehits + cachemisses));
71 cachehead.next = cachehead.prev = &cachehead;
72 cachehits = cachemisses = cachesize = 0;
73 for (i = cachehead.next; i != &cachehead; i = i->next)
75 if (i->prev != &cachehead)
78 if (cachehead.prev != &cachehead)
80 cachehead.next = cachehead.prev = &cachehead;
81 cachehead.trans = NULL;
85 /* Do a name to ID translation. id will be updated with the answer if
86 * it is available, and as a side effect the cache is updated.
89 int name_to_id(char *name, enum tables type, int *id)
92 EXEC SQL BEGIN DECLARE SECTION;
95 EXEC SQL END DECLARE SECTION;
97 h = hashname(name, type);
98 for (i = cachehead.next; i != &cachehead; i = i->next)
100 if (i->nhash != h || strcmp(name, i->name) || type != i->type)
104 i->next->prev = i->prev;
105 i->prev->next = i->next;
106 i->next = cachehead.next;
107 i->prev = &cachehead;
108 cachehead.next->prev = i;
119 if (strchr(iname, '@') || (strlen(iname) > 8))
121 sqlca.sqlcode = SQL_NO_MATCH;
124 EXEC SQL SELECT users_id INTO :j FROM users WHERE login = :iname;
127 EXEC SQL SELECT list_id INTO :j FROM list WHERE name = :iname;
130 EXEC SQL SELECT mach_id INTO :j FROM machine WHERE name = UPPER(:iname);
133 EXEC SQL SELECT snet_id INTO :j FROM subnet WHERE name = UPPER(:iname);
136 EXEC SQL SELECT clu_id INTO :j FROM clusters WHERE name = :iname;
139 EXEC SQL SELECT filsys_id INTO :j FROM filesys WHERE label = :iname;
142 if (!iname[0]) /* special-case empty string */
147 EXEC SQL SELECT string_id INTO :j FROM strings WHERE string = :iname;
152 if (sqlca.sqlcode == SQL_NO_MATCH)
154 if (sqlca.sqlerrd[2] > 1)
155 return MR_NOT_UNIQUE;
159 if (name[0] == '#' && type != USERS_TABLE)
161 if (cachesize < CACHESIZE)
163 i = malloc(sizeof(struct item));
169 cachehead.prev = i->prev;
170 i->prev->next = &cachehead;
172 strcpy(i->name, name);
176 i->next = cachehead.next;
177 i->prev = &cachehead;
179 cachehead.next->prev = i;
181 /* find the end of the transaction chain & add this item */
182 for (t = &cachehead; t->trans && t != i; t = t->trans)
190 /* Perform an ID to name mapping. name should be a pointer to a pointer to
191 * malloc'ed data. The buffer it refers to will be freed, and a new buffer
192 * allocated with the answer.
195 int id_to_name(int id, enum tables type, char **name)
198 EXEC SQL BEGIN DECLARE SECTION;
201 EXEC SQL END DECLARE SECTION;
203 for (i = cachehead.next; i != &cachehead; i = i->next)
205 if (i->id != id || type != i->type)
208 *name = strsave(i->name);
210 i->next->prev = i->prev;
211 i->prev->next = i->next;
212 i->next = cachehead.next;
213 i->prev = &cachehead;
214 cachehead.next->prev = i;
225 EXEC SQL SELECT login INTO :iname FROM users WHERE users_id = :j;
228 EXEC SQL SELECT name INTO :iname FROM list WHERE list_id = :j;
231 EXEC SQL SELECT name INTO :iname FROM machine WHERE mach_id = :j;
234 EXEC SQL SELECT name INTO :iname FROM subnet WHERE snet_id = :j;
237 EXEC SQL SELECT name INTO :iname FROM clusters WHERE clu_id = :j;
240 EXEC SQL SELECT label INTO :iname FROM filesys WHERE filsys_id = :j;
243 EXEC SQL SELECT string INTO :iname FROM strings WHERE string_id = :j;
248 if (sqlca.sqlcode == SQL_NO_MATCH)
251 sprintf(iname, "#%d", j);
252 *name = strsave(iname);
255 if (sqlca.sqlerrd[2] > 1)
260 *name = strsave(strtrim(iname));
261 if (**name == '#' && type != USERS_TABLE)
263 if (cachesize < CACHESIZE)
265 i = malloc(sizeof(struct item));
271 cachehead.prev = i->prev;
272 i->prev->next = &cachehead;
274 strcpy(i->name, *name);
276 i->nhash = hashname(*name, type);
278 i->next = cachehead.next;
279 i->prev = &cachehead;
281 cachehead.next->prev = i;
283 /* find the end of the transaction chain & add this item */
284 for (t = &cachehead; t->trans && t != i; t = t->trans)
292 /* Explicitly add something to the cache without doing a lookup in the
296 int cache_entry(char *name, enum tables type, int id)
300 for (i = cachehead.next; i != &cachehead; i = i->next)
302 if (i->id == id && i->type == type)
304 if (strcmp(i->name, name))
306 strcpy(i->name, name);
307 i->nhash = hashname(name, type);
312 if (cachesize < CACHESIZE)
314 i = malloc(sizeof(struct item));
320 cachehead.prev = i->prev;
321 i->prev->next = &cachehead;
323 strcpy(i->name, name);
325 i->nhash = hashname(name, type);
327 i->next = cachehead.next;
328 i->prev = &cachehead;
330 cachehead.next->prev = i;
332 /* find the end of the transaction chain & add this item */
333 for (t = &cachehead; t->trans && t != i; t = t->trans)
341 /* Flush something that may or may not already be in the cache. */
343 void flush_name(char *name, enum tables type)
347 /* first clear it out of the transaction chain */
348 for (i = &cachehead; i && i->trans; i = i->trans)
350 if (!strcmp(name, i->trans->name) && type == i->trans->type)
351 i->trans = i->trans->trans;
355 for (i = cachehead.next; i != &cachehead; i = i->next)
357 if (!strcmp(name, i->name) && type == i->type)
360 i->next->prev = i->prev;
361 i->prev->next = i->next;
368 /* Called when a transaction is committed to also commit any cache changes.
369 * Just throws away the list of cache changes for this transaction.
372 void cache_commit(void)
374 cachehead.trans = NULL;
378 /* Called whan a transaction is aborted to throw away any cache changes
379 * from that transaction.
382 void cache_abort(void)
386 for (i = cachehead.trans; i; i = t)
389 flush_name(i->name, i->type);
391 cachehead.trans = NULL;