]> andersk Git - moira.git/blob - server/cache.dc
23087adb38f05b4ac304eb7132f423bee75fcebe
[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 extern char *whoami, *strsave();
19 extern int ingres_errno, mr_errcode;
20
21
22 /*** NOTE **************************************************************
23  *
24  *    This code depends on each type starting with a unique letter.  If
25  *    any new types are added to the system that begin with the same
26  *    letter as one of the existing types:
27  *              User
28  *              List
29  *              String
30  *              Machine
31  *              Cluster
32  *              Filesystem
33  *    then we will have to rework the code that only looks at the first
34  *    letter of the types.
35  *
36  ***********************************************************************
37  */
38
39 /* Cache parameters: */
40 #define CACHESIZE 101           /* number of cache slots */
41 #define NAMESZ 257              /* max size of a name */
42
43 struct item {
44     char name[NAMESZ];
45     char type[9];
46     int nhash;
47     int id;
48     struct item *next;
49     struct item *prev;
50 };
51
52 static struct item cachehead;
53 static int cachesize;
54
55 /* statistics counters */
56 int cachehits = 0, cachemisses = 0;
57
58
59 /* Name hash function. */
60
61 int hashname(name, type)
62 register char *name;
63 char *type;
64 {
65     register int val = *type;
66
67     while (*name)
68       val = val<<5 - val + *name++ - '`';
69     return(val);
70 }
71
72
73 /* Initialize the cache, flushing any old data, and report the statistics
74  * if the cache was previously in use.
75  */
76
77 flush_cache()
78 {
79     register struct item *i;
80
81     if (cachehits + cachemisses != 0)
82       com_err(whoami, 0, "Flushing cache; %d hits, %d misses, %d%% hit rate",
83               cachehits, cachemisses,
84               (100 * cachehits) / (cachehits + cachemisses));
85     else
86       cachehead.next = cachehead.prev = &cachehead;
87     cachehits = cachemisses = cachesize = 0;
88     for (i = cachehead.next; i != &cachehead; i = i->next) {
89         if (i->prev != &cachehead)
90           free(i->prev);
91     }
92     if (cachehead.prev != &cachehead)
93       free(cachehead.prev);
94     cachehead.next = cachehead.prev = &cachehead;
95 }
96
97
98 /* Do a name to ID translation.  id will be updated with the answer if
99  * it is available, and as a side effect the cache is updated.
100  */
101
102 int name_to_id(name, type, id)
103 char *name;
104 char *type;
105 int *id;
106 {
107     register struct item *i;
108     EXEC SQL BEGIN DECLARE SECTION;
109     char *iname;
110     int j, rowcount;
111     EXEC SQL END DECLARE SECTION;
112     int h, ctr;
113
114     h = hashname(name, type);
115     for (i = cachehead.next; i != &cachehead; i = i->next) {
116         if (i->nhash != h ||
117             strcmp(name, i->name) ||
118             strcasecmp(type, i->type))
119           continue;
120         *id = i->id;
121         cachehits++;
122         i->next->prev = i->prev;
123         i->prev->next = i->next;
124         i->next = cachehead.next;
125         i->prev = &cachehead;
126         cachehead.next->prev = i;
127         cachehead.next = i;
128         return(MR_SUCCESS);
129     }
130
131     cachemisses++;
132     iname = name;
133
134     switch (*type) {
135     case 'U':
136     case 'u':
137         EXEC SQL SELECT users_id INTO :j FROM users WHERE login=:iname;
138         break;
139     case 'L':
140     case 'l':
141         EXEC SQL SELECT list_id INTO :j FROM list WHERE name=:iname;
142         break;
143     case 'M':
144     case 'm':
145         uppercase(iname);
146         EXEC SQL SELECT mach_id INTO :j FROM machine WHERE name=:iname;
147         break;
148     case 'C':
149     case 'c':
150         EXEC SQL SELECT clu_id INTO :j FROM cluster WHERE name=:iname;
151         break;
152     case 'F':
153     case 'f':
154         EXEC SQL SELECT filsys_id INTO :j FROM filesys WHERE label=:iname;
155         break;
156     case 'S':
157     case 's':
158         EXEC SQL SELECT string_id INTO :j FROM strings WHERE string=:iname;
159         break;
160     default:
161         return(MR_INTERNAL);
162     }
163     if (sqlca.sqlcode == 100)
164       return(MR_NO_MATCH);
165     if (sqlca.sqlerrd[2] > 1)
166       return(MR_NOT_UNIQUE);
167     if (sqlca.sqlcode != 0)
168       return(MR_INGRES_ERR);
169     *id = j;
170     if (name[0] == '#' && !strcasecmp(type, "USER"))
171       return(MR_SUCCESS);
172     if (cachesize < CACHESIZE) {
173         i = (struct item *) malloc(sizeof(struct item));
174         cachesize++;
175     } else {
176         i = cachehead.prev;
177         cachehead.prev = i->prev;
178         i->prev->next = &cachehead;
179     }
180     strcpy(i->name, name);
181     strcpy(i->type, type);
182     i->nhash = h;
183     i->id = j;
184     i->next = cachehead.next;
185     i->prev = &cachehead;
186     cachehead.next->prev = i;
187     cachehead.next = i;
188     return(MR_SUCCESS);
189 }
190
191
192 /* Perform an ID to name mapping.  name should be a pointer to a pointer to
193  * malloc'ed data.  The buffer it refers to will be freed, and a new buffer
194  * allocated with the answer.
195  */
196
197 int id_to_name(id, type, name)
198 int id;
199 char *type;
200 char **name;
201 {
202     register struct item *i;
203     EXEC SQL BEGIN DECLARE SECTION;
204     char iname[NAMESZ];
205     int j, rowcount;
206     EXEC SQL END DECLARE SECTION;
207     int ctr;
208
209     for (i = cachehead.next; i != &cachehead; i = i->next) {
210         if (i->id != id || strcasecmp(type, i->type)) continue;
211         free(*name);
212         *name = strsave(i->name);
213         cachehits++;
214         i->next->prev = i->prev;
215         i->prev->next = i->next;
216         i->next = cachehead.next;
217         i->prev = &cachehead;
218         cachehead.next->prev = i;
219         cachehead.next = i;
220         return(MR_SUCCESS);
221     }
222
223     cachemisses++;
224     j = id;
225
226     switch (*type) {
227     case 'U':
228     case 'u':
229         EXEC SQL SELECT login INTO :iname FROM users WHERE users_id=:j;
230         break;
231     case 'L':
232     case 'l':
233         EXEC SQL SELECT name INTO :iname FROM list WHERE list_id=:j;
234         break;
235     case 'M':
236     case 'm':
237         EXEC SQL SELECT name INTO :iname FROM machine WHERE mach_id=:j;
238         break;
239     case 'C':
240     case 'c':
241         EXEC SQL SELECT name INTO :iname FROM cluster WHERE clu_id=:j;
242         break;
243     case 'F':
244     case 'f':
245         EXEC SQL SELECT label INTO :iname FROM filesys WHERE filsys_id=:j;
246         break;
247     case 'S':
248     case 's':
249         EXEC SQL SELECT string INTO :iname FROM strings WHERE string_id=:j;
250         break;
251     default:
252         return(MR_INTERNAL);
253     }
254     if (sqlca.sqlcode == 100) {
255         free(*name);
256         sprintf(iname, "#%d", j);
257         *name = strsave(iname);
258         return(MR_NO_MATCH);
259     }
260     if (sqlca.sqlerrd[2] > 1)
261       return(MR_INTERNAL);
262     if (sqlca.sqlcode != 0)
263       return(MR_INGRES_ERR);
264     free(*name);
265     *name = strsave(strtrim(iname));
266     if (**name == '#' && !strcasecmp(type, "USER"))
267       return(MR_SUCCESS);
268     if (cachesize < CACHESIZE) {
269         i = (struct item *) malloc(sizeof(struct item));
270         cachesize++;
271     } else {
272         i = cachehead.prev;
273         cachehead.prev = i->prev;
274         i->prev->next = &cachehead;
275     }
276     strcpy(i->name, *name);
277     strcpy(i->type, type);
278     i->nhash = hashname(*name, type);
279     i->id = id;
280     i->next = cachehead.next;
281     i->prev = &cachehead;
282     cachehead.next->prev = i;
283     cachehead.next = i;
284     return(MR_SUCCESS);
285 }
286
287
288 /* Explicitly add something to the cache without doing a lookup in the
289  * database.
290  */
291
292 cache_entry(name, type, id)
293 char *name;
294 char *type;
295 int id;
296 {
297     register struct item *i;
298
299     for (i = cachehead.next; i != &cachehead; i = i->next)
300       if (i->id == id && !strcmp(i->type, type))
301         return(MR_SUCCESS);
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     strcpy(i->type, type);
312     i->nhash = hashname(name, type);
313     i->id = id;
314     i->next = cachehead.next;
315     i->prev = &cachehead;
316     cachehead.next->prev = i;
317     cachehead.next = i;
318     return(MR_SUCCESS);
319 }
320
321
322 /* Flush something that may or may not already be in the cache. */
323
324 flush_name(name, type)
325 char *name;
326 char *type;
327 {
328     int h;
329     register struct item *i;
330
331     h = hashname(name, type);
332
333     for (i = cachehead.next; i != &cachehead; i = i->next) {
334         if (!strcmp(name, i->name) && !strcasecmp(type, i->type)) {
335             cachesize--;
336             i->next->prev = i->prev;
337             i->prev->next = i->next;
338             free(i);
339             return(MR_SUCCESS);
340         }
341     }
342 }
This page took 0.049953 seconds and 3 git commands to generate.