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"
16 EXEC SQL INCLUDE sqlca;
18 EXEC SQL WHENEVER SQLERROR CALL ingerr;
20 extern char *whoami, *strsave();
21 extern int ingres_errno, mr_errcode;
24 /*** NOTE **************************************************************
26 * This code depends on each type starting with a unique letter. If
27 * any new types are added to the system that begin with the same
28 * letter as one of the existing types:
36 * then we will have to rework the code that only looks at the first
37 * letter of the types.
39 ***********************************************************************
42 /* Cache parameters: */
43 #define CACHESIZE 101 /* number of cache slots */
44 #define NAMESZ 257 /* max size of a name */
53 struct item *trans; /* keep track of transactions */
56 static struct item cachehead;
59 /* statistics counters */
60 int cachehits = 0, cachemisses = 0;
63 /* Name hash function. */
65 int hashname(name, type)
69 register int val = *type;
72 val = val<<5 - val + *name++ - '`';
77 /* Initialize the cache, flushing any old data, and report the statistics
78 * if the cache was previously in use.
83 register struct item *i;
85 if (cachehits + cachemisses != 0)
86 com_err(whoami, 0, "Flushing cache; %d hits, %d misses, %d%% hit rate",
87 cachehits, cachemisses,
88 (100 * cachehits) / (cachehits + cachemisses));
90 cachehead.next = cachehead.prev = &cachehead;
91 cachehits = cachemisses = cachesize = 0;
92 for (i = cachehead.next; i != &cachehead; i = i->next) {
93 if (i->prev != &cachehead)
96 if (cachehead.prev != &cachehead)
98 cachehead.next = cachehead.prev = &cachehead;
99 cachehead.trans = (struct item *)NULL;
103 /* Do a name to ID translation. id will be updated with the answer if
104 * it is available, and as a side effect the cache is updated.
107 int name_to_id(name, type, id)
112 register struct item *i, *t;
113 EXEC SQL BEGIN DECLARE SECTION;
116 EXEC SQL END DECLARE SECTION;
120 h = hashname(name, type);
121 for (i = cachehead.next; i != &cachehead; i = i->next) {
123 strcmp(name, i->name) ||
124 strcasecmp(type, i->type))
128 i->next->prev = i->prev;
129 i->prev->next = i->next;
130 i->next = cachehead.next;
131 i->prev = &cachehead;
132 cachehead.next->prev = i;
141 if (!strcasecmp(type, "subnet"))
147 if (index(iname, '@') || (strlen(iname) > 8)) {
151 EXEC SQL SELECT users_id INTO :j FROM users WHERE login=:iname;
155 EXEC SQL SELECT list_id INTO :j FROM list WHERE name=:iname;
159 EXEC SQL SELECT mach_id INTO :j FROM machine WHERE name=UPPERCASE(:iname);
163 EXEC SQL SELECT snet_id INTO :j FROM subnet WHERE name=UPPERCASE(:iname);
167 EXEC SQL SELECT clu_id INTO :j FROM cluster WHERE name=:iname;
171 EXEC SQL SELECT filsys_id INTO :j FROM filesys WHERE label=:iname;
175 EXEC SQL SELECT string_id INTO :j FROM strings WHERE string=:iname;
180 if (sqlca.sqlcode == 100)
182 if (sqlca.sqlerrd[2] > 1)
183 return(MR_NOT_UNIQUE);
184 if (sqlca.sqlcode != 0)
185 return(MR_INGRES_ERR);
187 if (name[0] == '#' && !strcasecmp(type, "USER"))
189 if (cachesize < CACHESIZE) {
190 i = (struct item *) malloc(sizeof(struct item));
194 cachehead.prev = i->prev;
195 i->prev->next = &cachehead;
197 strcpy(i->name, name);
198 strcpy(i->type, type);
201 i->next = cachehead.next;
202 i->prev = &cachehead;
203 cachehead.next->prev = i;
205 /* find the end of the transaction chain & add this item */
206 for (t = &cachehead; t->trans && t != i; t = t->trans);
209 i->trans = (struct item *)NULL;
215 /* Perform an ID to name mapping. name should be a pointer to a pointer to
216 * malloc'ed data. The buffer it refers to will be freed, and a new buffer
217 * allocated with the answer.
220 int id_to_name(id, type, name)
225 register struct item *i, *t;
226 EXEC SQL BEGIN DECLARE SECTION;
229 EXEC SQL END DECLARE SECTION;
233 for (i = cachehead.next; i != &cachehead; i = i->next) {
234 if (i->id != id || strcasecmp(type, i->type)) continue;
236 *name = strsave(i->name);
238 i->next->prev = i->prev;
239 i->prev->next = i->next;
240 i->next = cachehead.next;
241 i->prev = &cachehead;
242 cachehead.next->prev = i;
250 if (!strcasecmp(type, "subnet"))
256 EXEC SQL SELECT CHAR(login) INTO :iname FROM users WHERE users_id=:j;
260 EXEC SQL SELECT CHAR(name) INTO :iname FROM list WHERE list_id=:j;
264 EXEC SQL SELECT CHAR(name) INTO :iname FROM machine WHERE mach_id=:j;
268 EXEC SQL SELECT CHAR(name) INTO :iname FROM subnet WHERE snet_id=:j;
272 EXEC SQL SELECT CHAR(name) INTO :iname FROM cluster WHERE clu_id=:j;
276 EXEC SQL SELECT CHAR(label) INTO :iname FROM filesys WHERE filsys_id=:j;
280 EXEC SQL SELECT CHAR(string) INTO :iname FROM strings WHERE string_id=:j;
285 if (sqlca.sqlcode == 100) {
287 sprintf(iname, "#%d", j);
288 *name = strsave(iname);
291 if (sqlca.sqlerrd[2] > 1)
293 if (sqlca.sqlcode != 0)
294 return(MR_INGRES_ERR);
296 *name = strsave(strtrim(iname));
297 if (**name == '#' && !strcasecmp(type, "USER"))
299 if (cachesize < CACHESIZE) {
300 i = (struct item *) malloc(sizeof(struct item));
304 cachehead.prev = i->prev;
305 i->prev->next = &cachehead;
307 strcpy(i->name, *name);
308 strcpy(i->type, type);
309 i->nhash = hashname(*name, type);
311 i->next = cachehead.next;
312 i->prev = &cachehead;
313 cachehead.next->prev = i;
315 /* find the end of the transaction chain & add this item */
316 for (t = &cachehead; t->trans && t != i; t = t->trans);
319 i->trans = (struct item *)NULL;
325 /* Explicitly add something to the cache without doing a lookup in the
329 cache_entry(name, type, id)
334 register struct item *i, *t;
336 for (i = cachehead.next; i != &cachehead; i = i->next)
337 if (i->id == id && !strcmp(i->type, type)) {
338 if (strcmp(i->name, name)) {
339 strcpy(i->name, name);
340 i->nhash = hashname(name, type);
344 if (cachesize < CACHESIZE) {
345 i = (struct item *) malloc(sizeof(struct item));
349 cachehead.prev = i->prev;
350 i->prev->next = &cachehead;
352 strcpy(i->name, name);
353 strcpy(i->type, type);
354 i->nhash = hashname(name, type);
356 i->next = cachehead.next;
357 i->prev = &cachehead;
358 cachehead.next->prev = i;
360 /* find the end of the transaction chain & add this item */
361 for (t = &cachehead; t->trans && t != i; t = t->trans);
364 i->trans = (struct item *)NULL;
370 /* Flush something that may or may not already be in the cache. */
372 flush_name(name, type)
377 register struct item *i;
379 h = hashname(name, type);
381 for (i = cachehead.next; i != &cachehead; i = i->next) {
382 if (!strcmp(name, i->name) && !strcasecmp(type, i->type)) {
384 i->next->prev = i->prev;
385 i->prev->next = i->next;
393 /* Called when a transaction is committed to also commit any cache changes.
394 * Just throws away the list of cache changes for this transaction.
399 cachehead.trans = (struct item *)NULL;
403 /* Called whan a transaction is aborted to throw away any cache changes
404 * from that transaction.
409 register struct item *i, *t;
411 for (i = cachehead.trans; i; i = t) {
413 flush_name(i->name, i->type);
415 cachehead.trans = (struct item *)NULL;