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:
35 * then we will have to rework the code that only looks at the first
36 * letter of the types.
38 ***********************************************************************
41 /* Cache parameters: */
42 #define CACHESIZE 101 /* number of cache slots */
43 #define NAMESZ 257 /* max size of a name */
52 struct item *trans; /* keep track of transactions */
55 static struct item cachehead;
58 /* statistics counters */
59 int cachehits = 0, cachemisses = 0;
62 /* Name hash function. */
64 int hashname(name, type)
68 register int val = *type;
71 val = val<<5 - val + *name++ - '`';
76 /* Initialize the cache, flushing any old data, and report the statistics
77 * if the cache was previously in use.
82 register struct item *i;
84 if (cachehits + cachemisses != 0)
85 com_err(whoami, 0, "Flushing cache; %d hits, %d misses, %d%% hit rate",
86 cachehits, cachemisses,
87 (100 * cachehits) / (cachehits + cachemisses));
89 cachehead.next = cachehead.prev = &cachehead;
90 cachehits = cachemisses = cachesize = 0;
91 for (i = cachehead.next; i != &cachehead; i = i->next) {
92 if (i->prev != &cachehead)
95 if (cachehead.prev != &cachehead)
97 cachehead.next = cachehead.prev = &cachehead;
98 cachehead.trans = (struct item *)NULL;
102 /* Do a name to ID translation. id will be updated with the answer if
103 * it is available, and as a side effect the cache is updated.
106 int name_to_id(name, type, id)
111 register struct item *i, *t;
112 EXEC SQL BEGIN DECLARE SECTION;
115 EXEC SQL END DECLARE SECTION;
118 undouble_single_quotes(iname,name);
120 h = hashname(iname, type);
121 for (i = cachehead.next; i != &cachehead; i = i->next) {
123 strcmp(iname, 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;
142 if (index(iname, '@')) {
146 EXEC SQL SELECT users_id INTO :j FROM users WHERE login=:iname;
150 EXEC SQL SELECT list_id INTO :j FROM list WHERE name=:iname;
154 EXEC SQL SELECT mach_id INTO :j FROM machine WHERE name=UPPERCASE(:iname);
158 EXEC SQL SELECT clu_id INTO :j FROM cluster WHERE name=:iname;
162 EXEC SQL SELECT filsys_id INTO :j FROM filesys WHERE label=:iname;
166 EXEC SQL SELECT string_id INTO :j FROM strings WHERE string=:iname;
171 if (sqlca.sqlcode == 100)
173 if (sqlca.sqlerrd[2] > 1)
174 return(MR_NOT_UNIQUE);
175 if (sqlca.sqlcode != 0)
176 return(MR_INGRES_ERR);
178 if (iname[0] == '#' && !strcasecmp(type, "USER"))
180 if (cachesize < CACHESIZE) {
181 i = (struct item *) malloc(sizeof(struct item));
185 cachehead.prev = i->prev;
186 i->prev->next = &cachehead;
188 strcpy(i->name, iname);
189 strcpy(i->type, type);
192 i->next = cachehead.next;
193 i->prev = &cachehead;
194 cachehead.next->prev = i;
196 /* find the end of the transaction chain & add this item */
197 for (t = &cachehead; t->trans && t != i; t = t->trans);
200 i->trans = (struct item *)NULL;
206 undouble_single_quotes(to, from)
212 for(t=to,f=from; *f; ) {
213 if(*f=='\'' && f[1]=='\'') f++;
220 /* Perform an ID to name mapping. name should be a pointer to a pointer to
221 * malloc'ed data. The buffer it refers to will be freed, and a new buffer
222 * allocated with the answer.
225 int id_to_name(id, type, name)
230 register struct item *i, *t;
231 EXEC SQL BEGIN DECLARE SECTION;
234 EXEC SQL END DECLARE SECTION;
237 for (i = cachehead.next; i != &cachehead; i = i->next) {
238 if (i->id != id || strcasecmp(type, i->type)) continue;
240 *name = strsave(i->name);
242 i->next->prev = i->prev;
243 i->prev->next = i->next;
244 i->next = cachehead.next;
245 i->prev = &cachehead;
246 cachehead.next->prev = i;
257 EXEC SQL SELECT CHAR(login) INTO :iname FROM users WHERE users_id=:j;
261 EXEC SQL SELECT CHAR(name) INTO :iname FROM list WHERE list_id=:j;
265 EXEC SQL SELECT CHAR(name) INTO :iname FROM machine WHERE mach_id=:j;
269 EXEC SQL SELECT CHAR(name) INTO :iname FROM cluster WHERE clu_id=:j;
273 EXEC SQL SELECT CHAR(label) INTO :iname FROM filesys WHERE filsys_id=:j;
277 EXEC SQL SELECT CHAR(string) INTO :iname FROM strings WHERE string_id=:j;
282 if (sqlca.sqlcode == 100) {
284 sprintf(iname, "#%d", j);
285 *name = strsave(iname);
288 if (sqlca.sqlerrd[2] > 1)
290 if (sqlca.sqlcode != 0)
291 return(MR_INGRES_ERR);
293 *name = strsave(strtrim(iname));
294 if (**name == '#' && !strcasecmp(type, "USER"))
296 if (cachesize < CACHESIZE) {
297 i = (struct item *) malloc(sizeof(struct item));
301 cachehead.prev = i->prev;
302 i->prev->next = &cachehead;
304 strcpy(i->name, *name);
305 strcpy(i->type, type);
306 i->nhash = hashname(*name, type);
308 i->next = cachehead.next;
309 i->prev = &cachehead;
310 cachehead.next->prev = i;
312 /* find the end of the transaction chain & add this item */
313 for (t = &cachehead; t->trans && t != i; t = t->trans);
316 i->trans = (struct item *)NULL;
322 /* Explicitly add something to the cache without doing a lookup in the
326 cache_entry(name, type, id)
331 register struct item *i, *t;
333 for (i = cachehead.next; i != &cachehead; i = i->next)
334 if (i->id == id && !strcmp(i->type, type)) {
335 if (strcmp(i->name, name)) {
336 strcpy(i->name, name);
337 i->nhash = hashname(name, type);
341 if (cachesize < CACHESIZE) {
342 i = (struct item *) malloc(sizeof(struct item));
346 cachehead.prev = i->prev;
347 i->prev->next = &cachehead;
349 strcpy(i->name, name);
350 strcpy(i->type, type);
351 i->nhash = hashname(name, type);
353 i->next = cachehead.next;
354 i->prev = &cachehead;
355 cachehead.next->prev = i;
357 /* find the end of the transaction chain & add this item */
358 for (t = &cachehead; t->trans && t != i; t = t->trans);
361 i->trans = (struct item *)NULL;
367 /* Flush something that may or may not already be in the cache. */
369 flush_name(name, type)
374 register struct item *i;
376 h = hashname(name, type);
378 for (i = cachehead.next; i != &cachehead; i = i->next) {
379 if (!strcmp(name, i->name) && !strcasecmp(type, i->type)) {
381 i->next->prev = i->prev;
382 i->prev->next = i->next;
390 /* Called when a transaction is committed to also commit any cache changes.
391 * Just throws away the list of cache changes for this transaction.
396 cachehead.trans = (struct item *)NULL;
400 /* Called whan a transaction is aborted to throw away any cache changes
401 * from that transaction.
406 register struct item *i, *t;
408 for (i = cachehead.trans; i; i = t) {
410 flush_name(i->name, i->type);
412 cachehead.trans = (struct item *)NULL;