]> andersk Git - moira.git/blame - server/cache.dc
Diane Delgado's changes for a fixed table-locking order
[moira.git] / server / cache.dc
CommitLineData
7de02494 1/*
2 * $Header$
3 *
4 * Copyright (C) 1989, 1990 by the Massachusetts Institute of Technology
5 * For copying and distribution information, please see the file
6 * <mit-copyright.h>.
7 */
8
9#ifndef lint
10static char *rcsid_cache_dc = "$Header$";
11#endif lint
12
13#include <mit-copyright.h>
14#include "query.h"
15#include "mr_server.h"
16EXEC SQL INCLUDE sqlca;
17
45bf7573 18EXEC SQL WHENEVER SQLERROR CALL ingerr;
a49e54ea 19
7de02494 20extern char *whoami, *strsave();
21extern int ingres_errno, mr_errcode;
22
23
24/*** NOTE **************************************************************
25 *
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:
29 * User
30 * List
31 * String
32 * Machine
8ea172d2 33 * Subnet
7de02494 34 * Cluster
35 * Filesystem
36 * then we will have to rework the code that only looks at the first
37 * letter of the types.
38 *
39 ***********************************************************************
40 */
41
42/* Cache parameters: */
43#define CACHESIZE 101 /* number of cache slots */
44#define NAMESZ 257 /* max size of a name */
45
46struct item {
47 char name[NAMESZ];
48 char type[9];
49 int nhash;
50 int id;
51 struct item *next;
52 struct item *prev;
a49e54ea 53 struct item *trans; /* keep track of transactions */
7de02494 54};
55
56static struct item cachehead;
57static int cachesize;
58
59/* statistics counters */
60int cachehits = 0, cachemisses = 0;
61
62
63/* Name hash function. */
64
65int hashname(name, type)
66register char *name;
67char *type;
68{
69 register int val = *type;
70
71 while (*name)
72 val = val<<5 - val + *name++ - '`';
73 return(val);
74}
75
76
77/* Initialize the cache, flushing any old data, and report the statistics
78 * if the cache was previously in use.
79 */
80
81flush_cache()
82{
83 register struct item *i;
84
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));
89 else
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)
94 free(i->prev);
95 }
96 if (cachehead.prev != &cachehead)
97 free(cachehead.prev);
98 cachehead.next = cachehead.prev = &cachehead;
a49e54ea 99 cachehead.trans = (struct item *)NULL;
7de02494 100}
101
102
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.
105 */
106
107int name_to_id(name, type, id)
108char *name;
109char *type;
110int *id;
111{
a49e54ea 112 register struct item *i, *t;
7de02494 113 EXEC SQL BEGIN DECLARE SECTION;
4bd3537c 114 char *iname;
7de02494 115 int j, rowcount;
116 EXEC SQL END DECLARE SECTION;
86f3e5d5 117 char key;
7de02494 118 int h, ctr;
119
4bd3537c 120 h = hashname(name, type);
7de02494 121 for (i = cachehead.next; i != &cachehead; i = i->next) {
122 if (i->nhash != h ||
4bd3537c 123 strcmp(name, i->name) ||
7de02494 124 strcasecmp(type, i->type))
125 continue;
126 *id = i->id;
127 cachehits++;
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;
133 cachehead.next = i;
134 return(MR_SUCCESS);
135 }
136
137 cachemisses++;
4bd3537c 138 iname = name;
86f3e5d5 139 key = *type;
7de02494 140
86f3e5d5 141 if (!strcasecmp(type, "subnet"))
142 key = 'N';
143
144 switch (key) {
7de02494 145 case 'U':
146 case 'u':
cb8990ed 147 if (index(iname, '@') || (strlen(iname) > 8)) {
06c1c8ff 148 sqlca.sqlcode = 100;
149 break;
150 }
7de02494 151 EXEC SQL SELECT users_id INTO :j FROM users WHERE login=:iname;
152 break;
153 case 'L':
154 case 'l':
155 EXEC SQL SELECT list_id INTO :j FROM list WHERE name=:iname;
156 break;
157 case 'M':
158 case 'm':
99e09b48 159 EXEC SQL SELECT mach_id INTO :j FROM machine WHERE name=UPPERCASE(:iname);
7de02494 160 break;
86f3e5d5 161 case 'N':
162 case 'n':
8ea172d2 163 EXEC SQL SELECT snet_id INTO :j FROM subnet WHERE name=UPPERCASE(:iname);
164 break;
7de02494 165 case 'C':
166 case 'c':
167 EXEC SQL SELECT clu_id INTO :j FROM cluster WHERE name=:iname;
168 break;
169 case 'F':
170 case 'f':
171 EXEC SQL SELECT filsys_id INTO :j FROM filesys WHERE label=:iname;
172 break;
173 case 'S':
174 case 's':
175 EXEC SQL SELECT string_id INTO :j FROM strings WHERE string=:iname;
176 break;
177 default:
178 return(MR_INTERNAL);
179 }
180 if (sqlca.sqlcode == 100)
181 return(MR_NO_MATCH);
182 if (sqlca.sqlerrd[2] > 1)
183 return(MR_NOT_UNIQUE);
184 if (sqlca.sqlcode != 0)
185 return(MR_INGRES_ERR);
186 *id = j;
4bd3537c 187 if (name[0] == '#' && !strcasecmp(type, "USER"))
7de02494 188 return(MR_SUCCESS);
189 if (cachesize < CACHESIZE) {
190 i = (struct item *) malloc(sizeof(struct item));
191 cachesize++;
192 } else {
193 i = cachehead.prev;
194 cachehead.prev = i->prev;
195 i->prev->next = &cachehead;
196 }
4bd3537c 197 strcpy(i->name, name);
7de02494 198 strcpy(i->type, type);
199 i->nhash = h;
200 i->id = j;
201 i->next = cachehead.next;
202 i->prev = &cachehead;
203 cachehead.next->prev = i;
204 cachehead.next = i;
a49e54ea 205 /* find the end of the transaction chain & add this item */
206 for (t = &cachehead; t->trans && t != i; t = t->trans);
207 if (t != i) {
208 t->trans = i;
209 i->trans = (struct item *)NULL;
210 }
7de02494 211 return(MR_SUCCESS);
212}
213
214
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.
218 */
219
220int id_to_name(id, type, name)
221int id;
222char *type;
223char **name;
224{
45bf7573 225 register struct item *i, *t;
7de02494 226 EXEC SQL BEGIN DECLARE SECTION;
227 char iname[NAMESZ];
228 int j, rowcount;
229 EXEC SQL END DECLARE SECTION;
86f3e5d5 230 char key;
7de02494 231 int ctr;
232
233 for (i = cachehead.next; i != &cachehead; i = i->next) {
234 if (i->id != id || strcasecmp(type, i->type)) continue;
235 free(*name);
236 *name = strsave(i->name);
237 cachehits++;
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;
243 cachehead.next = i;
244 return(MR_SUCCESS);
245 }
246
247 cachemisses++;
248 j = id;
86f3e5d5 249 key = *type;
250 if (!strcasecmp(type, "subnet"))
251 key = 'N';
7de02494 252
86f3e5d5 253 switch (key) {
7de02494 254 case 'U':
255 case 'u':
a112f91e 256 EXEC SQL SELECT CHAR(login) INTO :iname FROM users WHERE users_id=:j;
7de02494 257 break;
258 case 'L':
259 case 'l':
a112f91e 260 EXEC SQL SELECT CHAR(name) INTO :iname FROM list WHERE list_id=:j;
7de02494 261 break;
262 case 'M':
263 case 'm':
a112f91e 264 EXEC SQL SELECT CHAR(name) INTO :iname FROM machine WHERE mach_id=:j;
7de02494 265 break;
86f3e5d5 266 case 'N':
267 case 'n':
8ea172d2 268 EXEC SQL SELECT CHAR(name) INTO :iname FROM subnet WHERE snet_id=:j;
269 break;
7de02494 270 case 'C':
271 case 'c':
a112f91e 272 EXEC SQL SELECT CHAR(name) INTO :iname FROM cluster WHERE clu_id=:j;
7de02494 273 break;
274 case 'F':
275 case 'f':
a112f91e 276 EXEC SQL SELECT CHAR(label) INTO :iname FROM filesys WHERE filsys_id=:j;
7de02494 277 break;
278 case 'S':
279 case 's':
a112f91e 280 EXEC SQL SELECT CHAR(string) INTO :iname FROM strings WHERE string_id=:j;
7de02494 281 break;
282 default:
283 return(MR_INTERNAL);
284 }
285 if (sqlca.sqlcode == 100) {
286 free(*name);
287 sprintf(iname, "#%d", j);
288 *name = strsave(iname);
289 return(MR_NO_MATCH);
290 }
291 if (sqlca.sqlerrd[2] > 1)
292 return(MR_INTERNAL);
293 if (sqlca.sqlcode != 0)
294 return(MR_INGRES_ERR);
295 free(*name);
296 *name = strsave(strtrim(iname));
297 if (**name == '#' && !strcasecmp(type, "USER"))
298 return(MR_SUCCESS);
299 if (cachesize < CACHESIZE) {
300 i = (struct item *) malloc(sizeof(struct item));
301 cachesize++;
302 } else {
303 i = cachehead.prev;
304 cachehead.prev = i->prev;
305 i->prev->next = &cachehead;
306 }
307 strcpy(i->name, *name);
308 strcpy(i->type, type);
309 i->nhash = hashname(*name, type);
310 i->id = id;
311 i->next = cachehead.next;
312 i->prev = &cachehead;
313 cachehead.next->prev = i;
314 cachehead.next = i;
a49e54ea 315 /* find the end of the transaction chain & add this item */
316 for (t = &cachehead; t->trans && t != i; t = t->trans);
317 if (t != i) {
318 t->trans = i;
319 i->trans = (struct item *)NULL;
320 }
7de02494 321 return(MR_SUCCESS);
322}
323
324
325/* Explicitly add something to the cache without doing a lookup in the
326 * database.
327 */
328
329cache_entry(name, type, id)
330char *name;
331char *type;
332int id;
333{
a49e54ea 334 register struct item *i, *t;
7de02494 335
336 for (i = cachehead.next; i != &cachehead; i = i->next)
a49e54ea 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);
341 }
342 return(MR_SUCCESS);
343 }
7de02494 344 if (cachesize < CACHESIZE) {
345 i = (struct item *) malloc(sizeof(struct item));
346 cachesize++;
347 } else {
348 i = cachehead.prev;
349 cachehead.prev = i->prev;
350 i->prev->next = &cachehead;
351 }
352 strcpy(i->name, name);
353 strcpy(i->type, type);
354 i->nhash = hashname(name, type);
355 i->id = id;
356 i->next = cachehead.next;
357 i->prev = &cachehead;
358 cachehead.next->prev = i;
359 cachehead.next = i;
a49e54ea 360 /* find the end of the transaction chain & add this item */
361 for (t = &cachehead; t->trans && t != i; t = t->trans);
362 if (t != i) {
363 t->trans = i;
364 i->trans = (struct item *)NULL;
365 }
7de02494 366 return(MR_SUCCESS);
367}
368
369
370/* Flush something that may or may not already be in the cache. */
371
372flush_name(name, type)
373char *name;
374char *type;
375{
376 int h;
377 register struct item *i;
378
379 h = hashname(name, type);
380
381 for (i = cachehead.next; i != &cachehead; i = i->next) {
382 if (!strcmp(name, i->name) && !strcasecmp(type, i->type)) {
383 cachesize--;
384 i->next->prev = i->prev;
385 i->prev->next = i->next;
386 free(i);
387 return(MR_SUCCESS);
388 }
389 }
390}
a49e54ea 391
392
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.
395 */
396
397cache_commit()
398{
399 cachehead.trans = (struct item *)NULL;
400}
401
402
403/* Called whan a transaction is aborted to throw away any cache changes
404 * from that transaction.
405 */
406
407cache_abort()
408{
409 register struct item *i, *t;
410
411 for (i = cachehead.trans; i; i = t) {
412 t = i->trans;
413 flush_name(i->name, i->type);
414 }
415 cachehead.trans = (struct item *)NULL;
416}
This page took 0.521774 seconds and 5 git commands to generate.