]> andersk Git - moira.git/blob - server/cache.pc
fa155d3d2e74f3fa5b01050cdb65edf27ae439c3
[moira.git] / server / cache.pc
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 <string.h>
15 #include "mr_server.h"
16 #include "query.h"
17 EXEC SQL INCLUDE sqlca;
18
19 EXEC SQL WHENEVER SQLERROR DO dbmserr();
20
21 extern char *whoami;
22
23 /* Cache parameters: */
24 #define CACHESIZE 101           /* number of cache slots */
25 #define NAMESZ 257              /* max size of a name */
26
27 struct item {
28     char name[NAMESZ];
29     enum tables type;
30     int nhash;
31     int id;
32     struct item *next;
33     struct item *prev;
34     struct item *trans;         /* keep track of transactions */
35 };
36
37 static struct item cachehead;
38 static int cachesize;
39
40 /* statistics counters */
41 int cachehits = 0, cachemisses = 0;
42
43
44 /* Name hash function. */
45
46 int hashname(name, type)
47      char *name;
48      enum tables type;
49 {
50     register int val = type;
51
52     while (*name)
53       val = (val<<5) - val + *name++ - '`';
54     return(val);
55 }
56
57
58 /* Initialize the cache, flushing any old data, and report the statistics
59  * if the cache was previously in use.
60  */
61
62 void flush_cache(void)
63 {
64     register struct item *i;
65
66     if (cachehits + cachemisses != 0)
67       com_err(whoami, 0, "Flushing cache; %d hits, %d misses, %d%% hit rate",
68               cachehits, cachemisses,
69               (100 * cachehits) / (cachehits + cachemisses));
70     else
71       cachehead.next = cachehead.prev = &cachehead;
72     cachehits = cachemisses = cachesize = 0;
73     for (i = cachehead.next; i != &cachehead; i = i->next) {
74         if (i->prev != &cachehead)
75           free(i->prev);
76     }
77     if (cachehead.prev != &cachehead)
78       free(cachehead.prev);
79     cachehead.next = cachehead.prev = &cachehead;
80     cachehead.trans = (struct item *)NULL;
81 }
82
83
84 /* Do a name to ID translation.  id will be updated with the answer if
85  * it is available, and as a side effect the cache is updated.
86  */
87
88 int name_to_id(name, type, id)
89      char *name;
90      enum tables type;
91      int *id;
92 {
93     register struct item *i, *t;
94     EXEC SQL BEGIN DECLARE SECTION;
95     char *iname;
96     int j, h;
97     EXEC SQL END DECLARE SECTION;
98
99     h = hashname(name, type);
100     for (i = cachehead.next; i != &cachehead; i = i->next) {
101         if (i->nhash != h ||
102             strcmp(name, i->name) ||
103             type!=i->type)
104           continue;
105         *id = i->id;
106         cachehits++;
107         i->next->prev = i->prev;
108         i->prev->next = i->next;
109         i->next = cachehead.next;
110         i->prev = &cachehead;
111         cachehead.next->prev = i;
112         cachehead.next = i;
113         return(MR_SUCCESS);
114     }
115
116     cachemisses++;
117     iname = name;
118
119     switch (type)
120       {
121       case USERS_TABLE:
122         if (strchr(iname, '@') || (strlen(iname) > 8)) {
123           sqlca.sqlcode = SQL_NO_MATCH;
124           break;
125         }
126         EXEC SQL SELECT users_id INTO :j FROM users WHERE login=:iname;
127         break;
128       case LIST_TABLE:
129         EXEC SQL SELECT list_id INTO :j FROM list WHERE name=:iname;
130         break;
131       case MACHINE_TABLE:
132         EXEC SQL SELECT mach_id INTO :j FROM machine WHERE name=UPPER(:iname);
133         break;
134       case SUBNET_TABLE:
135         EXEC SQL SELECT snet_id INTO :j FROM subnet WHERE name=UPPER(:iname);
136         break;
137       case CLUSTER_TABLE:
138         EXEC SQL SELECT clu_id INTO :j FROM clusters WHERE name=:iname;
139         break;
140       case FILESYS_TABLE:
141         EXEC SQL SELECT filsys_id INTO :j FROM filesys WHERE label=:iname;
142         break;
143       case STRINGS_TABLE:
144         if (!iname[0]) { /* special-case empty string */
145           *id=0;
146           return MR_SUCCESS;
147         }
148         EXEC SQL SELECT string_id INTO :j FROM strings WHERE string=:iname;
149         break;
150       default:
151         return(MR_INTERNAL);
152     }
153     if (sqlca.sqlcode == SQL_NO_MATCH)
154       return(MR_NO_MATCH);
155     if (sqlca.sqlerrd[2] > 1)
156       return(MR_NOT_UNIQUE);
157     if (sqlca.sqlcode != 0)
158       return(MR_DBMS_ERR);
159     *id = j;
160     if (name[0] == '#' && type!=USERS_TABLE)
161       return(MR_SUCCESS);
162     if (cachesize < CACHESIZE) {
163         i = (struct item *) malloc(sizeof(struct item));
164         cachesize++;
165     } else {
166         i = cachehead.prev;
167         cachehead.prev = i->prev;
168         i->prev->next = &cachehead;
169     }
170     strcpy(i->name, name);
171     i->type=type;
172     i->nhash = h;
173     i->id = j;
174     i->next = cachehead.next;
175     i->prev = &cachehead;
176     i->trans = NULL;
177     cachehead.next->prev = i;
178     cachehead.next = i;
179     /* find the end of the transaction chain & add this item */
180     for (t = &cachehead; t->trans && t != i; t = t->trans);
181     if (t != i) t->trans = i;
182     return(MR_SUCCESS);
183 }
184
185
186 /* Perform an ID to name mapping.  name should be a pointer to a pointer to
187  * malloc'ed data.  The buffer it refers to will be freed, and a new buffer
188  * allocated with the answer.
189  */
190
191 int id_to_name(id, type, name)
192      int id;
193      enum tables type;
194      char **name;
195 {
196     register struct item *i, *t;
197     EXEC SQL BEGIN DECLARE SECTION;
198     char iname[NAMESZ];
199     int j;
200     EXEC SQL END DECLARE SECTION;
201
202     for (i = cachehead.next; i != &cachehead; i = i->next) {
203         if (i->id != id || type!=i->type) continue;
204         free(*name);
205         *name = strsave(i->name);
206         cachehits++;
207         i->next->prev = i->prev;
208         i->prev->next = i->next;
209         i->next = cachehead.next;
210         i->prev = &cachehead;
211         cachehead.next->prev = i;
212         cachehead.next = i;
213         return(MR_SUCCESS);
214     }
215
216     cachemisses++;
217     j = id;
218
219     switch (type)
220       {
221       case USERS_TABLE:
222         EXEC SQL SELECT login INTO :iname FROM users WHERE users_id=:j;
223         break;
224       case LIST_TABLE:
225         EXEC SQL SELECT name INTO :iname FROM list WHERE list_id=:j;
226         break;
227       case MACHINE_TABLE:
228         EXEC SQL SELECT name INTO :iname FROM machine WHERE mach_id=:j;
229         break;
230       case SUBNET_TABLE:
231         EXEC SQL SELECT name INTO :iname FROM subnet WHERE snet_id=:j;
232         break;
233       case CLUSTER_TABLE:
234         EXEC SQL SELECT name INTO :iname FROM clusters WHERE clu_id=:j;
235         break;
236       case FILESYS_TABLE:
237         EXEC SQL SELECT label INTO :iname FROM filesys WHERE filsys_id=:j;
238         break;
239       case STRINGS_TABLE:
240         EXEC SQL SELECT string INTO :iname FROM strings WHERE string_id=:j;
241         break;
242     default:
243         return(MR_INTERNAL);
244     }
245     if (sqlca.sqlcode == SQL_NO_MATCH) {
246         free(*name);
247         sprintf(iname, "#%d", j);
248         *name = strsave(iname);
249         return(MR_NO_MATCH);
250     }
251     if (sqlca.sqlerrd[2] > 1)
252       return(MR_INTERNAL);
253     if (sqlca.sqlcode != 0)
254       return(MR_DBMS_ERR);
255     free(*name);
256     *name = strsave(strtrim(iname));
257     if (**name == '#' && type!=USERS_TABLE)
258       return(MR_SUCCESS);
259     if (cachesize < CACHESIZE) {
260         i = (struct item *) malloc(sizeof(struct item));
261         cachesize++;
262     } else {
263         i = cachehead.prev;
264         cachehead.prev = i->prev;
265         i->prev->next = &cachehead;
266     }
267     strcpy(i->name, *name);
268     i->type=type;
269     i->nhash = hashname(*name, type);
270     i->id = id;
271     i->next = cachehead.next;
272     i->prev = &cachehead;
273     i->trans = NULL;
274     cachehead.next->prev = i;
275     cachehead.next = i;
276     /* find the end of the transaction chain & add this item */
277     for (t = &cachehead; t->trans && t != i; t = t->trans);
278     if (t != i) t->trans = i;
279     return(MR_SUCCESS);
280 }
281
282
283 /* Explicitly add something to the cache without doing a lookup in the
284  * database.
285  */
286
287 int cache_entry(name, type, id)
288      char *name;
289      enum tables type;
290      int id;
291 {
292     register struct item *i, *t;
293
294     for (i = cachehead.next; i != &cachehead; i = i->next)
295       if (i->id == id && i->type==type) {
296           if (strcmp(i->name, name)) {
297               strcpy(i->name, name);
298               i->nhash = hashname(name, type);
299           }
300           return(MR_SUCCESS);
301       }
302     if (cachesize < CACHESIZE) {
303         i = (struct item *) malloc(sizeof(struct item));
304         cachesize++;
305     } else {
306         i = cachehead.prev;
307         cachehead.prev = i->prev;
308         i->prev->next = &cachehead;
309     }
310     strcpy(i->name, name);
311     i->type=type;
312     i->nhash = hashname(name, type);
313     i->id = id;
314     i->next = cachehead.next;
315     i->prev = &cachehead;
316     i->trans = NULL;
317     cachehead.next->prev = i;
318     cachehead.next = i;
319     /* find the end of the transaction chain & add this item */
320     for (t = &cachehead; t->trans && t != i; t = t->trans);
321     if (t != i) t->trans = i;
322     return(MR_SUCCESS);
323 }
324
325
326 /* Flush something that may or may not already be in the cache. */
327
328 void flush_name(name, type)
329      char *name;
330      enum tables type;
331 {
332     int h;
333     register struct item *i;
334
335     h = hashname(name, type);
336
337     for (i = cachehead.next; i != &cachehead; i = i->next) {
338         if (!strcmp(name, i->name) && type==i->type) {
339             cachesize--;
340             i->next->prev = i->prev;
341             i->prev->next = i->next;
342             free(i);
343         }
344     }
345 }
346
347
348 /* Called when a transaction is committed to also commit any cache changes.
349  * Just throws away the list of cache changes for this transaction.
350  */
351
352 void cache_commit(void)
353 {
354     cachehead.trans = (struct item *)NULL;
355 }
356
357
358 /* Called whan a transaction is aborted to throw away any cache changes
359  * from that transaction.
360  */
361
362 void cache_abort(void)
363 {
364     register struct item *i, *t;
365
366     for (i = cachehead.trans; i; i = t) {
367         t = i->trans;
368         flush_name(i->name, i->type);
369     }
370     cachehead.trans = (struct item *)NULL;
371 }
This page took 0.174213 seconds and 3 git commands to generate.