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