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