]> andersk Git - moira.git/blob - server/cache.dc
updated to handle subnets as well
[moira.git] / server / cache.dc
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
10 static char *rcsid_cache_dc = "$Header$";
11 #endif lint
12
13 #include <mit-copyright.h>
14 #include "query.h"
15 #include "mr_server.h"
16 EXEC SQL INCLUDE sqlca;
17
18 EXEC SQL WHENEVER SQLERROR CALL ingerr;
19
20 extern char *whoami, *strsave();
21 extern 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
33  *              Subnet
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
46 struct item {
47     char name[NAMESZ];
48     char type[9];
49     int nhash;
50     int id;
51     struct item *next;
52     struct item *prev;
53     struct item *trans;         /* keep track of transactions */
54 };
55
56 static struct item cachehead;
57 static int cachesize;
58
59 /* statistics counters */
60 int cachehits = 0, cachemisses = 0;
61
62
63 /* Name hash function. */
64
65 int hashname(name, type)
66 register char *name;
67 char *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
81 flush_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;
99     cachehead.trans = (struct item *)NULL;
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
107 int name_to_id(name, type, id)
108 char *name;
109 char *type;
110 int *id;
111 {
112     register struct item *i, *t;
113     EXEC SQL BEGIN DECLARE SECTION;
114     char *iname;
115     int j, rowcount;
116     EXEC SQL END DECLARE SECTION;
117     int h, ctr;
118
119     h = hashname(name, type);
120     for (i = cachehead.next; i != &cachehead; i = i->next) {
121         if (i->nhash != h ||
122             strcmp(name, i->name) ||
123             strcasecmp(type, i->type))
124           continue;
125         *id = i->id;
126         cachehits++;
127         i->next->prev = i->prev;
128         i->prev->next = i->next;
129         i->next = cachehead.next;
130         i->prev = &cachehead;
131         cachehead.next->prev = i;
132         cachehead.next = i;
133         return(MR_SUCCESS);
134     }
135
136     cachemisses++;
137     iname = name;
138
139     switch (*type) {
140     case 'U':
141     case 'u':
142         if (index(iname, '@') || (strlen(iname) > 8)) {
143             sqlca.sqlcode = 100;
144             break;
145         }
146         EXEC SQL SELECT users_id INTO :j FROM users WHERE login=:iname;
147         break;
148     case 'L':
149     case 'l':
150         EXEC SQL SELECT list_id INTO :j FROM list WHERE name=:iname;
151         break;
152     case 'M':
153     case 'm':
154         EXEC SQL SELECT mach_id INTO :j FROM machine WHERE name=UPPERCASE(:iname);
155         break;
156     case 'S':
157     case 's':
158         EXEC SQL SELECT snet_id INTO :j FROM subnet WHERE name=UPPERCASE(:iname);
159         break;
160     case 'C':
161     case 'c':
162         EXEC SQL SELECT clu_id INTO :j FROM cluster WHERE name=:iname;
163         break;
164     case 'F':
165     case 'f':
166         EXEC SQL SELECT filsys_id INTO :j FROM filesys WHERE label=:iname;
167         break;
168     case 'S':
169     case 's':
170         EXEC SQL SELECT string_id INTO :j FROM strings WHERE string=:iname;
171         break;
172     default:
173         return(MR_INTERNAL);
174     }
175     if (sqlca.sqlcode == 100)
176       return(MR_NO_MATCH);
177     if (sqlca.sqlerrd[2] > 1)
178       return(MR_NOT_UNIQUE);
179     if (sqlca.sqlcode != 0)
180       return(MR_INGRES_ERR);
181     *id = j;
182     if (name[0] == '#' && !strcasecmp(type, "USER"))
183       return(MR_SUCCESS);
184     if (cachesize < CACHESIZE) {
185         i = (struct item *) malloc(sizeof(struct item));
186         cachesize++;
187     } else {
188         i = cachehead.prev;
189         cachehead.prev = i->prev;
190         i->prev->next = &cachehead;
191     }
192     strcpy(i->name, name);
193     strcpy(i->type, type);
194     i->nhash = h;
195     i->id = j;
196     i->next = cachehead.next;
197     i->prev = &cachehead;
198     cachehead.next->prev = i;
199     cachehead.next = i;
200     /* find the end of the transaction chain & add this item */
201     for (t = &cachehead; t->trans && t != i; t = t->trans);
202     if (t != i) {
203         t->trans = i;
204         i->trans = (struct item *)NULL;
205     }
206     return(MR_SUCCESS);
207 }
208
209
210 /* Perform an ID to name mapping.  name should be a pointer to a pointer to
211  * malloc'ed data.  The buffer it refers to will be freed, and a new buffer
212  * allocated with the answer.
213  */
214
215 int id_to_name(id, type, name)
216 int id;
217 char *type;
218 char **name;
219 {
220     register struct item *i, *t;
221     EXEC SQL BEGIN DECLARE SECTION;
222     char iname[NAMESZ];
223     int j, rowcount;
224     EXEC SQL END DECLARE SECTION;
225     int ctr;
226
227     for (i = cachehead.next; i != &cachehead; i = i->next) {
228         if (i->id != id || strcasecmp(type, i->type)) continue;
229         free(*name);
230         *name = strsave(i->name);
231         cachehits++;
232         i->next->prev = i->prev;
233         i->prev->next = i->next;
234         i->next = cachehead.next;
235         i->prev = &cachehead;
236         cachehead.next->prev = i;
237         cachehead.next = i;
238         return(MR_SUCCESS);
239     }
240
241     cachemisses++;
242     j = id;
243
244     switch (*type) {
245     case 'U':
246     case 'u':
247         EXEC SQL SELECT CHAR(login) INTO :iname FROM users WHERE users_id=:j;
248         break;
249     case 'L':
250     case 'l':
251         EXEC SQL SELECT CHAR(name) INTO :iname FROM list WHERE list_id=:j;
252         break;
253     case 'M':
254     case 'm':
255         EXEC SQL SELECT CHAR(name) INTO :iname FROM machine WHERE mach_id=:j;
256         break;
257     case 'S':
258     case 's':
259         EXEC SQL SELECT CHAR(name) INTO :iname FROM subnet WHERE snet_id=:j;
260         break;
261     case 'C':
262     case 'c':
263         EXEC SQL SELECT CHAR(name) INTO :iname FROM cluster WHERE clu_id=:j;
264         break;
265     case 'F':
266     case 'f':
267         EXEC SQL SELECT CHAR(label) INTO :iname FROM filesys WHERE filsys_id=:j;
268         break;
269     case 'S':
270     case 's':
271         EXEC SQL SELECT CHAR(string) INTO :iname FROM strings WHERE string_id=:j;
272         break;
273     default:
274         return(MR_INTERNAL);
275     }
276     if (sqlca.sqlcode == 100) {
277         free(*name);
278         sprintf(iname, "#%d", j);
279         *name = strsave(iname);
280         return(MR_NO_MATCH);
281     }
282     if (sqlca.sqlerrd[2] > 1)
283       return(MR_INTERNAL);
284     if (sqlca.sqlcode != 0)
285       return(MR_INGRES_ERR);
286     free(*name);
287     *name = strsave(strtrim(iname));
288     if (**name == '#' && !strcasecmp(type, "USER"))
289       return(MR_SUCCESS);
290     if (cachesize < CACHESIZE) {
291         i = (struct item *) malloc(sizeof(struct item));
292         cachesize++;
293     } else {
294         i = cachehead.prev;
295         cachehead.prev = i->prev;
296         i->prev->next = &cachehead;
297     }
298     strcpy(i->name, *name);
299     strcpy(i->type, type);
300     i->nhash = hashname(*name, type);
301     i->id = id;
302     i->next = cachehead.next;
303     i->prev = &cachehead;
304     cachehead.next->prev = i;
305     cachehead.next = i;
306     /* find the end of the transaction chain & add this item */
307     for (t = &cachehead; t->trans && t != i; t = t->trans);
308     if (t != i) {
309         t->trans = i;
310         i->trans = (struct item *)NULL;
311     }
312     return(MR_SUCCESS);
313 }
314
315
316 /* Explicitly add something to the cache without doing a lookup in the
317  * database.
318  */
319
320 cache_entry(name, type, id)
321 char *name;
322 char *type;
323 int id;
324 {
325     register struct item *i, *t;
326
327     for (i = cachehead.next; i != &cachehead; i = i->next)
328       if (i->id == id && !strcmp(i->type, type)) {
329           if (strcmp(i->name, name)) {
330               strcpy(i->name, name);
331               i->nhash = hashname(name, type);
332           }
333           return(MR_SUCCESS);
334       }
335     if (cachesize < CACHESIZE) {
336         i = (struct item *) malloc(sizeof(struct item));
337         cachesize++;
338     } else {
339         i = cachehead.prev;
340         cachehead.prev = i->prev;
341         i->prev->next = &cachehead;
342     }
343     strcpy(i->name, name);
344     strcpy(i->type, type);
345     i->nhash = hashname(name, type);
346     i->id = id;
347     i->next = cachehead.next;
348     i->prev = &cachehead;
349     cachehead.next->prev = i;
350     cachehead.next = i;
351     /* find the end of the transaction chain & add this item */
352     for (t = &cachehead; t->trans && t != i; t = t->trans);
353     if (t != i) {
354         t->trans = i;
355         i->trans = (struct item *)NULL;
356     }
357     return(MR_SUCCESS);
358 }
359
360
361 /* Flush something that may or may not already be in the cache. */
362
363 flush_name(name, type)
364 char *name;
365 char *type;
366 {
367     int h;
368     register struct item *i;
369
370     h = hashname(name, type);
371
372     for (i = cachehead.next; i != &cachehead; i = i->next) {
373         if (!strcmp(name, i->name) && !strcasecmp(type, i->type)) {
374             cachesize--;
375             i->next->prev = i->prev;
376             i->prev->next = i->next;
377             free(i);
378             return(MR_SUCCESS);
379         }
380     }
381 }
382
383
384 /* Called when a transaction is committed to also commit any cache changes.
385  * Just throws away the list of cache changes for this transaction.
386  */
387
388 cache_commit()
389 {
390     cachehead.trans = (struct item *)NULL;
391 }
392
393
394 /* Called whan a transaction is aborted to throw away any cache changes
395  * from that transaction.
396  */
397
398 cache_abort()
399 {
400     register struct item *i, *t;
401
402     for (i = cachehead.trans; i; i = t) {
403         t = i->trans;
404         flush_name(i->name, i->type);
405     }
406     cachehead.trans = (struct item *)NULL;
407 }
This page took 0.069574 seconds and 5 git commands to generate.