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