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;
19 extern char *whoami, *strsave();
20 extern int ingres_errno, mr_errcode;
23 /*** NOTE **************************************************************
25 * This code depends on each type starting with a unique letter. If
26 * any new types are added to the system that begin with the same
27 * letter as one of the existing types:
34 * then we will have to rework the code that only looks at the first
35 * letter of the types.
37 ***********************************************************************
40 /* Cache parameters: */
41 #define CACHESIZE 101 /* number of cache slots */
42 #define NAMESZ 257 /* max size of a name */
51 struct item *trans; /* keep track of transactions */
54 static struct item cachehead;
57 /* statistics counters */
58 int cachehits = 0, cachemisses = 0;
61 /* Name hash function. */
63 int hashname(name, type)
67 register int val = *type;
70 val = val<<5 - val + *name++ - '`';
75 /* Initialize the cache, flushing any old data, and report the statistics
76 * if the cache was previously in use.
81 register struct item *i;
83 if (cachehits + cachemisses != 0)
84 com_err(whoami, 0, "Flushing cache; %d hits, %d misses, %d%% hit rate",
85 cachehits, cachemisses,
86 (100 * cachehits) / (cachehits + cachemisses));
88 cachehead.next = cachehead.prev = &cachehead;
89 cachehits = cachemisses = cachesize = 0;
90 for (i = cachehead.next; i != &cachehead; i = i->next) {
91 if (i->prev != &cachehead)
94 if (cachehead.prev != &cachehead)
96 cachehead.next = cachehead.prev = &cachehead;
97 cachehead.trans = (struct item *)NULL;
101 /* Do a name to ID translation. id will be updated with the answer if
102 * it is available, and as a side effect the cache is updated.
105 int name_to_id(name, type, id)
110 register struct item *i, *t;
111 EXEC SQL BEGIN DECLARE SECTION;
114 EXEC SQL END DECLARE SECTION;
117 h = hashname(name, type);
118 for (i = cachehead.next; i != &cachehead; i = i->next) {
120 strcmp(name, i->name) ||
121 strcasecmp(type, i->type))
125 i->next->prev = i->prev;
126 i->prev->next = i->next;
127 i->next = cachehead.next;
128 i->prev = &cachehead;
129 cachehead.next->prev = i;
140 EXEC SQL SELECT users_id INTO :j FROM users WHERE login=:iname;
144 EXEC SQL SELECT list_id INTO :j FROM list WHERE name=:iname;
148 EXEC SQL SELECT mach_id INTO :j FROM machine WHERE name=uppercase(:iname);
152 EXEC SQL SELECT clu_id INTO :j FROM cluster WHERE name=:iname;
156 EXEC SQL SELECT filsys_id INTO :j FROM filesys WHERE label=:iname;
160 EXEC SQL SELECT string_id INTO :j FROM strings WHERE string=:iname;
165 if (sqlca.sqlcode == 100)
167 if (sqlca.sqlerrd[2] > 1)
168 return(MR_NOT_UNIQUE);
169 if (sqlca.sqlcode != 0)
170 return(MR_INGRES_ERR);
172 if (name[0] == '#' && !strcasecmp(type, "USER"))
174 if (cachesize < CACHESIZE) {
175 i = (struct item *) malloc(sizeof(struct item));
179 cachehead.prev = i->prev;
180 i->prev->next = &cachehead;
182 strcpy(i->name, name);
183 strcpy(i->type, type);
186 i->next = cachehead.next;
187 i->prev = &cachehead;
188 cachehead.next->prev = i;
190 /* find the end of the transaction chain & add this item */
191 for (t = &cachehead; t->trans && t != i; t = t->trans);
194 i->trans = (struct item *)NULL;
200 /* Perform an ID to name mapping. name should be a pointer to a pointer to
201 * malloc'ed data. The buffer it refers to will be freed, and a new buffer
202 * allocated with the answer.
205 int id_to_name(id, type, name)
210 register struct item *i;
211 EXEC SQL BEGIN DECLARE SECTION;
214 EXEC SQL END DECLARE SECTION;
217 for (i = cachehead.next; i != &cachehead; i = i->next) {
218 if (i->id != id || strcasecmp(type, i->type)) continue;
220 *name = strsave(i->name);
222 i->next->prev = i->prev;
223 i->prev->next = i->next;
224 i->next = cachehead.next;
225 i->prev = &cachehead;
226 cachehead.next->prev = i;
237 EXEC SQL SELECT login INTO :iname FROM users WHERE users_id=:j;
241 EXEC SQL SELECT name INTO :iname FROM list WHERE list_id=:j;
245 EXEC SQL SELECT name INTO :iname FROM machine WHERE mach_id=:j;
249 EXEC SQL SELECT name INTO :iname FROM cluster WHERE clu_id=:j;
253 EXEC SQL SELECT label INTO :iname FROM filesys WHERE filsys_id=:j;
257 EXEC SQL SELECT string INTO :iname FROM strings WHERE string_id=:j;
262 if (sqlca.sqlcode == 100) {
264 sprintf(iname, "#%d", j);
265 *name = strsave(iname);
268 if (sqlca.sqlerrd[2] > 1)
270 if (sqlca.sqlcode != 0)
271 return(MR_INGRES_ERR);
273 *name = strsave(strtrim(iname));
274 if (**name == '#' && !strcasecmp(type, "USER"))
276 if (cachesize < CACHESIZE) {
277 i = (struct item *) malloc(sizeof(struct item));
281 cachehead.prev = i->prev;
282 i->prev->next = &cachehead;
284 strcpy(i->name, *name);
285 strcpy(i->type, type);
286 i->nhash = hashname(*name, type);
288 i->next = cachehead.next;
289 i->prev = &cachehead;
290 cachehead.next->prev = i;
292 /* find the end of the transaction chain & add this item */
293 for (t = &cachehead; t->trans && t != i; t = t->trans);
296 i->trans = (struct item *)NULL;
302 /* Explicitly add something to the cache without doing a lookup in the
306 cache_entry(name, type, id)
311 register struct item *i, *t;
313 for (i = cachehead.next; i != &cachehead; i = i->next)
314 if (i->id == id && !strcmp(i->type, type)) {
315 if (strcmp(i->name, name)) {
316 strcpy(i->name, name);
317 i->nhash = hashname(name, type);
321 if (cachesize < CACHESIZE) {
322 i = (struct item *) malloc(sizeof(struct item));
326 cachehead.prev = i->prev;
327 i->prev->next = &cachehead;
329 strcpy(i->name, name);
330 strcpy(i->type, type);
331 i->nhash = hashname(name, type);
333 i->next = cachehead.next;
334 i->prev = &cachehead;
335 cachehead.next->prev = i;
337 /* find the end of the transaction chain & add this item */
338 for (t = &cachehead; t->trans && t != i; t = t->trans);
341 i->trans = (struct item *)NULL;
347 /* Flush something that may or may not already be in the cache. */
349 flush_name(name, type)
354 register struct item *i;
356 h = hashname(name, type);
358 for (i = cachehead.next; i != &cachehead; i = i->next) {
359 if (!strcmp(name, i->name) && !strcasecmp(type, i->type)) {
361 i->next->prev = i->prev;
362 i->prev->next = i->next;
370 /* Called when a transaction is committed to also commit any cache changes.
371 * Just throws away the list of cache changes for this transaction.
376 cachehead.trans = (struct item *)NULL;
380 /* Called whan a transaction is aborted to throw away any cache changes
381 * from that transaction.
386 register struct item *i, *t;
388 for (i = cachehead.trans; i; i = t) {
390 flush_name(i->name, i->type);
392 cachehead.trans = (struct item *)NULL;