]> andersk Git - moira.git/blob - server/cache.qc
Used /bin/sh format instead of /bin/csh format, by accident.
[moira.git] / server / cache.qc
1 /*
2  *      $Source$
3  *      $Author$
4  *      $Header$
5  *
6  *      Copyright (C) 1989 by the Massachusetts Institute of Technology
7  *      For copying and distribution information, please see the file
8  *      <mit-copyright.h>.
9  *
10  */
11
12 #ifndef lint
13 static char *rcsid_qsupport_qc = "$Header$";
14 #endif lint
15
16 #include <mit-copyright.h>
17 #include "query.h"
18 #include "mr_server.h"
19
20
21 extern char *whoami, *strsave();
22 extern int ingres_errno, mr_errcode;
23
24
25 /*** NOTE **************************************************************
26  *
27  *    This code depends on each type starting with a unique letter.  If
28  *    any new types are added to the system that begin with the same
29  *    letter as one of the existing types:
30  *              User
31  *              List
32  *              String
33  *              Machine
34  *              Cluster
35  *              Filesystem
36  *    then we will have to rework the code that only looks at the first
37  *    letter of the types.
38  *
39  ***********************************************************************
40  */
41
42 /* Cache parameters: */
43 #define CACHESIZE 101           /* number of cache slots */
44 #define NAMESZ 257              /* max size of a name */
45
46 struct item {
47     char name[NAMESZ];
48     char type[9];
49     int nhash;
50     int id;
51     struct item *next;
52     struct item *prev;
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 }
99
100
101 /* Do a name to ID translation.  id will be updated with the answer if
102  * it is available, and as a side effect the cache is updated.
103  */
104
105 int name_to_id(name, type, id)
106 char *name;
107 char *type;
108 int *id;
109 ##{
110     register struct item *i;
111 ##  char *iname;
112 ##  int j, rowcount;
113     int h, ctr;
114
115     h = hashname(name, type);
116     for (i = cachehead.next; i != &cachehead; i = i->next) {
117         if (i->nhash != h ||
118             strcmp(name, i->name) ||
119             strcasecmp(type, i->type))
120           continue;
121         *id = i->id;
122         cachehits++;
123         i->next->prev = i->prev;
124         i->prev->next = i->next;
125         i->next = cachehead.next;
126         i->prev = &cachehead;
127         cachehead.next->prev = i;
128         cachehead.next = i;
129         return(MR_SUCCESS);
130     }
131
132     cachemisses++;
133     iname = name;
134
135     switch (*type) {
136     case 'U':
137     case 'u':
138 ##      repeat retrieve (j = users.users_id) where users.#login=@iname
139         break;
140     case 'L':
141     case 'l':
142 ##      repeat retrieve (j = list.list_id) where list.#name=@iname
143         break;
144     case 'M':
145     case 'm':
146 ##      repeat retrieve (j = machine.mach_id) where machine.#name=uppercase(@iname)
147         break;
148     case 'C':
149     case 'c':
150 ##      repeat retrieve (j = cluster.clu_id) where cluster.#name=@iname
151         break;
152     case 'F':
153     case 'f':
154 ##      repeat retrieve (j = filesys.filsys_id) where filesys.#label=@iname
155         break;
156     case 'S':
157     case 's':
158 ##      repeat retrieve (j = strings.string_id) where strings.#string=@iname
159         break;
160     default:
161         return(MR_INTERNAL);
162     }
163 ##  inquire_equel(rowcount = "rowcount")
164     if (ingres_errno) return(mr_errcode);
165     if (rowcount == 0)
166       return(MR_NO_MATCH);
167     if (rowcount > 1)
168       return(MR_NOT_UNIQUE);
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 ##  char iname[NAMESZ];
204 ##  int j, rowcount;
205     int ctr;
206
207     for (i = cachehead.next; i != &cachehead; i = i->next) {
208         if (i->id != id || strcasecmp(type, i->type)) continue;
209         free(*name);
210         *name = strsave(i->name);
211         cachehits++;
212         i->next->prev = i->prev;
213         i->prev->next = i->next;
214         i->next = cachehead.next;
215         i->prev = &cachehead;
216         cachehead.next->prev = i;
217         cachehead.next = i;
218         return(MR_SUCCESS);
219     }
220
221     cachemisses++;
222     j = id;
223
224     switch (*type) {
225     case 'U':
226     case 'u':
227 ##      repeat retrieve (iname = users.login) where users.users_id=@j
228         break;
229     case 'L':
230     case 'l':
231 ##      repeat retrieve (iname = list.name) where list.list_id=@j
232         break;
233     case 'M':
234     case 'm':
235 ##      repeat retrieve (iname = machine.name) where machine.mach_id=@j
236         break;
237     case 'C':
238     case 'c':
239 ##      repeat retrieve (iname = cluster.name) where cluster.clu_id=@j
240         break;
241     case 'F':
242     case 'f':
243 ##      repeat retrieve (iname = filesys.label) where filesys.filsys_id=@j
244         break;
245     case 'S':
246     case 's':
247 ##      repeat retrieve (iname = strings.string) where strings.string_id=@j
248         break;
249     default:
250         return(MR_INTERNAL);
251     }
252 ##  inquire_equel(rowcount = "rowcount")
253     if (ingres_errno) return(mr_errcode);
254     if (rowcount == 0) {
255         free(*name);
256         sprintf(iname, "#%d", j);
257         *name = strsave(iname);
258         return(MR_NO_MATCH);
259     }
260     if (rowcount != 1)
261       return(MR_INTERNAL);
262     free(*name);
263     *name = strsave(strtrim(iname));
264     if (**name == '#' && !strcasecmp(type, "USER"))
265       return(MR_SUCCESS);
266     if (cachesize < CACHESIZE) {
267         i = (struct item *) malloc(sizeof(struct item));
268         cachesize++;
269     } else {
270         i = cachehead.prev;
271         cachehead.prev = i->prev;
272         i->prev->next = &cachehead;
273     }
274     strcpy(i->name, *name);
275     strcpy(i->type, type);
276     i->nhash = hashname(*name, type);
277     i->id = id;
278     i->next = cachehead.next;
279     i->prev = &cachehead;
280     cachehead.next->prev = i;
281     cachehead.next = i;
282     return(MR_SUCCESS);
283 ##}
284
285
286 /* Explicitly add something to the cache without doing a lookup in the
287  * database.
288  */
289
290 cache_entry(name, type, id)
291 char *name;
292 char *type;
293 int id;
294 {
295     register struct item *i;
296
297     for (i = cachehead.next; i != &cachehead; i = i->next)
298       if (i->id == id && !strcmp(i->type, type))
299         return(MR_SUCCESS);
300     if (cachesize < CACHESIZE) {
301         i = (struct item *) malloc(sizeof(struct item));
302         cachesize++;
303     } else {
304         i = cachehead.prev;
305         cachehead.prev = i->prev;
306         i->prev->next = &cachehead;
307     }
308     strcpy(i->name, name);
309     strcpy(i->type, type);
310     i->nhash = hashname(name, type);
311     i->id = id;
312     i->next = cachehead.next;
313     i->prev = &cachehead;
314     cachehead.next->prev = i;
315     cachehead.next = i;
316     return(MR_SUCCESS);
317 }
318
319
320 /* Flush something that may or may not already be in the cache. */
321
322 flush_name(name, type)
323 char *name;
324 char *type;
325 {
326     int h;
327     register struct item *i;
328
329     h = hashname(name, type);
330
331     for (i = cachehead.next; i != &cachehead; i = i->next) {
332         if (!strcmp(name, i->name) && !strcasecmp(type, i->type)) {
333             cachesize--;
334             i->next->prev = i->prev;
335             i->prev->next = i->next;
336             free(i);
337             return(MR_SUCCESS);
338         }
339     }
340 }
This page took 0.067545 seconds and 5 git commands to generate.