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(name, type)
50 register int val = type;
53 val = (val<<5) - val + *name++ - '`';
58 /* Initialize the cache, flushing any old data, and report the statistics
59 * if the cache was previously in use.
62 void flush_cache(void)
64 register struct item *i;
66 if (cachehits + cachemisses != 0)
67 com_err(whoami, 0, "Flushing cache; %d hits, %d misses, %d%% hit rate",
68 cachehits, cachemisses,
69 (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) {
74 if (i->prev != &cachehead)
77 if (cachehead.prev != &cachehead)
79 cachehead.next = cachehead.prev = &cachehead;
80 cachehead.trans = (struct item *)NULL;
84 /* Do a name to ID translation. id will be updated with the answer if
85 * it is available, and as a side effect the cache is updated.
88 int name_to_id(name, type, id)
93 register struct item *i, *t;
94 EXEC SQL BEGIN DECLARE SECTION;
97 EXEC SQL END DECLARE SECTION;
99 h = hashname(name, type);
100 for (i = cachehead.next; i != &cachehead; i = i->next) {
102 strcmp(name, i->name) ||
107 i->next->prev = i->prev;
108 i->prev->next = i->next;
109 i->next = cachehead.next;
110 i->prev = &cachehead;
111 cachehead.next->prev = i;
122 if (strchr(iname, '@') || (strlen(iname) > 8)) {
123 sqlca.sqlcode = SQL_NO_MATCH;
126 EXEC SQL SELECT users_id INTO :j FROM users WHERE login=:iname;
129 EXEC SQL SELECT list_id INTO :j FROM list WHERE name=:iname;
132 EXEC SQL SELECT mach_id INTO :j FROM machine WHERE name=UPPER(:iname);
135 EXEC SQL SELECT snet_id INTO :j FROM subnet WHERE name=UPPER(:iname);
138 EXEC SQL SELECT clu_id INTO :j FROM clusters WHERE name=:iname;
141 EXEC SQL SELECT filsys_id INTO :j FROM filesys WHERE label=:iname;
144 if (!iname[0]) { /* special-case empty string */
148 EXEC SQL SELECT string_id INTO :j FROM strings WHERE string=:iname;
153 if (sqlca.sqlcode == SQL_NO_MATCH)
155 if (sqlca.sqlerrd[2] > 1)
156 return(MR_NOT_UNIQUE);
157 if (sqlca.sqlcode != 0)
160 if (name[0] == '#' && type!=USERS_TABLE)
162 if (cachesize < CACHESIZE) {
163 i = (struct item *) malloc(sizeof(struct item));
167 cachehead.prev = i->prev;
168 i->prev->next = &cachehead;
170 strcpy(i->name, name);
174 i->next = cachehead.next;
175 i->prev = &cachehead;
177 cachehead.next->prev = i;
179 /* find the end of the transaction chain & add this item */
180 for (t = &cachehead; t->trans && t != i; t = t->trans);
181 if (t != i) t->trans = i;
186 /* Perform an ID to name mapping. name should be a pointer to a pointer to
187 * malloc'ed data. The buffer it refers to will be freed, and a new buffer
188 * allocated with the answer.
191 int id_to_name(id, type, name)
196 register struct item *i, *t;
197 EXEC SQL BEGIN DECLARE SECTION;
200 EXEC SQL END DECLARE SECTION;
202 for (i = cachehead.next; i != &cachehead; i = i->next) {
203 if (i->id != id || type!=i->type) continue;
205 *name = strsave(i->name);
207 i->next->prev = i->prev;
208 i->prev->next = i->next;
209 i->next = cachehead.next;
210 i->prev = &cachehead;
211 cachehead.next->prev = i;
222 EXEC SQL SELECT login INTO :iname FROM users WHERE users_id=:j;
225 EXEC SQL SELECT name INTO :iname FROM list WHERE list_id=:j;
228 EXEC SQL SELECT name INTO :iname FROM machine WHERE mach_id=:j;
231 EXEC SQL SELECT name INTO :iname FROM subnet WHERE snet_id=:j;
234 EXEC SQL SELECT name INTO :iname FROM clusters WHERE clu_id=:j;
237 EXEC SQL SELECT label INTO :iname FROM filesys WHERE filsys_id=:j;
240 EXEC SQL SELECT string INTO :iname FROM strings WHERE string_id=:j;
245 if (sqlca.sqlcode == SQL_NO_MATCH) {
247 sprintf(iname, "#%d", j);
248 *name = strsave(iname);
251 if (sqlca.sqlerrd[2] > 1)
253 if (sqlca.sqlcode != 0)
256 *name = strsave(strtrim(iname));
257 if (**name == '#' && type!=USERS_TABLE)
259 if (cachesize < CACHESIZE) {
260 i = (struct item *) malloc(sizeof(struct item));
264 cachehead.prev = i->prev;
265 i->prev->next = &cachehead;
267 strcpy(i->name, *name);
269 i->nhash = hashname(*name, type);
271 i->next = cachehead.next;
272 i->prev = &cachehead;
274 cachehead.next->prev = i;
276 /* find the end of the transaction chain & add this item */
277 for (t = &cachehead; t->trans && t != i; t = t->trans);
278 if (t != i) t->trans = i;
283 /* Explicitly add something to the cache without doing a lookup in the
287 int cache_entry(name, type, id)
292 register struct item *i, *t;
294 for (i = cachehead.next; i != &cachehead; i = i->next)
295 if (i->id == id && i->type==type) {
296 if (strcmp(i->name, name)) {
297 strcpy(i->name, name);
298 i->nhash = hashname(name, type);
302 if (cachesize < CACHESIZE) {
303 i = (struct item *) malloc(sizeof(struct item));
307 cachehead.prev = i->prev;
308 i->prev->next = &cachehead;
310 strcpy(i->name, name);
312 i->nhash = hashname(name, type);
314 i->next = cachehead.next;
315 i->prev = &cachehead;
317 cachehead.next->prev = i;
319 /* find the end of the transaction chain & add this item */
320 for (t = &cachehead; t->trans && t != i; t = t->trans);
321 if (t != i) t->trans = i;
326 /* Flush something that may or may not already be in the cache. */
328 void flush_name(name, type)
333 register struct item *i;
335 h = hashname(name, type);
337 for (i = cachehead.next; i != &cachehead; i = i->next) {
338 if (!strcmp(name, i->name) && type==i->type) {
340 i->next->prev = i->prev;
341 i->prev->next = i->next;
348 /* Called when a transaction is committed to also commit any cache changes.
349 * Just throws away the list of cache changes for this transaction.
352 void cache_commit(void)
354 cachehead.trans = (struct item *)NULL;
358 /* Called whan a transaction is aborted to throw away any cache changes
359 * from that transaction.
362 void cache_abort(void)
364 register struct item *i, *t;
366 for (i = cachehead.trans; i; i = t) {
368 flush_name(i->name, i->type);
370 cachehead.trans = (struct item *)NULL;