]> andersk Git - moira.git/blob - server/cache.dc
6e621b80d59fb0e7fbe47f6444c473311f833b75
[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
19 extern char *whoami, *strsave();
20 extern int ingres_errno, mr_errcode;
21
22
23 /*** NOTE **************************************************************
24  *
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:
28  *              User
29  *              List
30  *              String
31  *              Machine
32  *              Cluster
33  *              Filesystem
34  *    then we will have to rework the code that only looks at the first
35  *    letter of the types.
36  *
37  ***********************************************************************
38  */
39
40 /* Cache parameters: */
41 #define CACHESIZE 101           /* number of cache slots */
42 #define NAMESZ 257              /* max size of a name */
43
44 struct item {
45     char name[NAMESZ];
46     char type[9];
47     int nhash;
48     int id;
49     struct item *next;
50     struct item *prev;
51     struct item *trans;         /* keep track of transactions */
52 };
53
54 static struct item cachehead;
55 static int cachesize;
56
57 /* statistics counters */
58 int cachehits = 0, cachemisses = 0;
59
60
61 /* Name hash function. */
62
63 int hashname(name, type)
64 register char *name;
65 char *type;
66 {
67     register int val = *type;
68
69     while (*name)
70       val = val<<5 - val + *name++ - '`';
71     return(val);
72 }
73
74
75 /* Initialize the cache, flushing any old data, and report the statistics
76  * if the cache was previously in use.
77  */
78
79 flush_cache()
80 {
81     register struct item *i;
82
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));
87     else
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)
92           free(i->prev);
93     }
94     if (cachehead.prev != &cachehead)
95       free(cachehead.prev);
96     cachehead.next = cachehead.prev = &cachehead;
97     cachehead.trans = (struct item *)NULL;
98 }
99
100
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.
103  */
104
105 int name_to_id(name, type, id)
106 char *name;
107 char *type;
108 int *id;
109 {
110     register struct item *i, *t;
111     EXEC SQL BEGIN DECLARE SECTION;
112     char *iname;
113     int j, rowcount;
114     EXEC SQL END DECLARE SECTION;
115     int h, ctr;
116
117     h = hashname(name, type);
118     for (i = cachehead.next; i != &cachehead; i = i->next) {
119         if (i->nhash != h ||
120             strcmp(name, i->name) ||
121             strcasecmp(type, i->type))
122           continue;
123         *id = i->id;
124         cachehits++;
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;
130         cachehead.next = i;
131         return(MR_SUCCESS);
132     }
133
134     cachemisses++;
135     iname = name;
136
137     switch (*type) {
138     case 'U':
139     case 'u':
140         EXEC SQL SELECT users_id INTO :j FROM users WHERE login=:iname;
141         break;
142     case 'L':
143     case 'l':
144         EXEC SQL SELECT list_id INTO :j FROM list WHERE name=:iname;
145         break;
146     case 'M':
147     case 'm':
148         EXEC SQL SELECT mach_id INTO :j FROM machine WHERE name=uppercase(:iname);
149         break;
150     case 'C':
151     case 'c':
152         EXEC SQL SELECT clu_id INTO :j FROM cluster WHERE name=:iname;
153         break;
154     case 'F':
155     case 'f':
156         EXEC SQL SELECT filsys_id INTO :j FROM filesys WHERE label=:iname;
157         break;
158     case 'S':
159     case 's':
160         EXEC SQL SELECT string_id INTO :j FROM strings WHERE string=:iname;
161         break;
162     default:
163         return(MR_INTERNAL);
164     }
165     if (sqlca.sqlcode == 100)
166       return(MR_NO_MATCH);
167     if (sqlca.sqlerrd[2] > 1)
168       return(MR_NOT_UNIQUE);
169     if (sqlca.sqlcode != 0)
170       return(MR_INGRES_ERR);
171     *id = j;
172     if (name[0] == '#' && !strcasecmp(type, "USER"))
173       return(MR_SUCCESS);
174     if (cachesize < CACHESIZE) {
175         i = (struct item *) malloc(sizeof(struct item));
176         cachesize++;
177     } else {
178         i = cachehead.prev;
179         cachehead.prev = i->prev;
180         i->prev->next = &cachehead;
181     }
182     strcpy(i->name, name);
183     strcpy(i->type, type);
184     i->nhash = h;
185     i->id = j;
186     i->next = cachehead.next;
187     i->prev = &cachehead;
188     cachehead.next->prev = i;
189     cachehead.next = i;
190     /* find the end of the transaction chain & add this item */
191     for (t = &cachehead; t->trans && t != i; t = t->trans);
192     if (t != i) {
193         t->trans = i;
194         i->trans = (struct item *)NULL;
195     }
196     return(MR_SUCCESS);
197 }
198
199
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.
203  */
204
205 int id_to_name(id, type, name)
206 int id;
207 char *type;
208 char **name;
209 {
210     register struct item *i;
211     EXEC SQL BEGIN DECLARE SECTION;
212     char iname[NAMESZ];
213     int j, rowcount;
214     EXEC SQL END DECLARE SECTION;
215     int ctr;
216
217     for (i = cachehead.next; i != &cachehead; i = i->next) {
218         if (i->id != id || strcasecmp(type, i->type)) continue;
219         free(*name);
220         *name = strsave(i->name);
221         cachehits++;
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;
227         cachehead.next = i;
228         return(MR_SUCCESS);
229     }
230
231     cachemisses++;
232     j = id;
233
234     switch (*type) {
235     case 'U':
236     case 'u':
237         EXEC SQL SELECT login INTO :iname FROM users WHERE users_id=:j;
238         break;
239     case 'L':
240     case 'l':
241         EXEC SQL SELECT name INTO :iname FROM list WHERE list_id=:j;
242         break;
243     case 'M':
244     case 'm':
245         EXEC SQL SELECT name INTO :iname FROM machine WHERE mach_id=:j;
246         break;
247     case 'C':
248     case 'c':
249         EXEC SQL SELECT name INTO :iname FROM cluster WHERE clu_id=:j;
250         break;
251     case 'F':
252     case 'f':
253         EXEC SQL SELECT label INTO :iname FROM filesys WHERE filsys_id=:j;
254         break;
255     case 'S':
256     case 's':
257         EXEC SQL SELECT string INTO :iname FROM strings WHERE string_id=:j;
258         break;
259     default:
260         return(MR_INTERNAL);
261     }
262     if (sqlca.sqlcode == 100) {
263         free(*name);
264         sprintf(iname, "#%d", j);
265         *name = strsave(iname);
266         return(MR_NO_MATCH);
267     }
268     if (sqlca.sqlerrd[2] > 1)
269       return(MR_INTERNAL);
270     if (sqlca.sqlcode != 0)
271       return(MR_INGRES_ERR);
272     free(*name);
273     *name = strsave(strtrim(iname));
274     if (**name == '#' && !strcasecmp(type, "USER"))
275       return(MR_SUCCESS);
276     if (cachesize < CACHESIZE) {
277         i = (struct item *) malloc(sizeof(struct item));
278         cachesize++;
279     } else {
280         i = cachehead.prev;
281         cachehead.prev = i->prev;
282         i->prev->next = &cachehead;
283     }
284     strcpy(i->name, *name);
285     strcpy(i->type, type);
286     i->nhash = hashname(*name, type);
287     i->id = id;
288     i->next = cachehead.next;
289     i->prev = &cachehead;
290     cachehead.next->prev = i;
291     cachehead.next = i;
292     /* find the end of the transaction chain & add this item */
293     for (t = &cachehead; t->trans && t != i; t = t->trans);
294     if (t != i) {
295         t->trans = i;
296         i->trans = (struct item *)NULL;
297     }
298     return(MR_SUCCESS);
299 }
300
301
302 /* Explicitly add something to the cache without doing a lookup in the
303  * database.
304  */
305
306 cache_entry(name, type, id)
307 char *name;
308 char *type;
309 int id;
310 {
311     register struct item *i, *t;
312
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);
318           }
319           return(MR_SUCCESS);
320       }
321     if (cachesize < CACHESIZE) {
322         i = (struct item *) malloc(sizeof(struct item));
323         cachesize++;
324     } else {
325         i = cachehead.prev;
326         cachehead.prev = i->prev;
327         i->prev->next = &cachehead;
328     }
329     strcpy(i->name, name);
330     strcpy(i->type, type);
331     i->nhash = hashname(name, type);
332     i->id = id;
333     i->next = cachehead.next;
334     i->prev = &cachehead;
335     cachehead.next->prev = i;
336     cachehead.next = i;
337     /* find the end of the transaction chain & add this item */
338     for (t = &cachehead; t->trans && t != i; t = t->trans);
339     if (t != i) {
340         t->trans = i;
341         i->trans = (struct item *)NULL;
342     }
343     return(MR_SUCCESS);
344 }
345
346
347 /* Flush something that may or may not already be in the cache. */
348
349 flush_name(name, type)
350 char *name;
351 char *type;
352 {
353     int h;
354     register struct item *i;
355
356     h = hashname(name, type);
357
358     for (i = cachehead.next; i != &cachehead; i = i->next) {
359         if (!strcmp(name, i->name) && !strcasecmp(type, i->type)) {
360             cachesize--;
361             i->next->prev = i->prev;
362             i->prev->next = i->next;
363             free(i);
364             return(MR_SUCCESS);
365         }
366     }
367 }
368
369
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.
372  */
373
374 cache_commit()
375 {
376     cachehead.trans = (struct item *)NULL;
377 }
378
379
380 /* Called whan a transaction is aborted to throw away any cache changes
381  * from that transaction.
382  */
383
384 cache_abort()
385 {
386     register struct item *i, *t;
387
388     for (i = cachehead.trans; i; i = t) {
389         t = i->trans;
390         flush_name(i->name, i->type);
391     }
392     cachehead.trans = (struct item *)NULL;
393 }
This page took 0.059728 seconds and 3 git commands to generate.