]> andersk Git - moira.git/blob - server/cache.qc
added a check for "Sr" to the title stuff
[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 "sms_server.h"
19
20
21 extern char *whoami, *strsave();
22 extern int ingres_errno, sms_errcode;
23
24
25 /*** NOTE **************************************************************
26  *
27  *      This code depends 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 id;
50     int use;
51 };
52
53 static struct item  cache[CACHESIZE];
54 static struct item *ncache[CACHESIZE];
55 static struct item *icache[CACHESIZE];
56
57 /* use counter for implementing LRU */
58 static int use = 1;
59 /* statistics counters */
60 int cachehits = 0, cachemisses = 0;
61
62 /* ID hash function */
63 #define hashid(id, type) (((id) + *(type)) % CACHESIZE)
64
65
66 /* Name hash function. */
67
68 int hashname(name, type)
69 register char *name;
70 char *type;
71 {
72     register int val = *type;
73
74     while (*name)
75       val = val<<5 - val + *name++ - '`';
76     return(val % CACHESIZE);
77 }
78
79
80 /* Initialize the cache, flushing any old data, and report the statistics
81  * if the cache was previously in use.
82  */
83
84 flush_cache()
85 {
86     int i;
87
88     if (cachehits + cachemisses != 0)
89       com_err(whoami, 0, "Flushing cache; %d hits, %d misses, %d%% hit rate",
90               cachehits, cachemisses,
91               (100 * cachehits) / (cachehits + cachemisses));
92     cachehits = cachemisses = 0;
93     for (i = 0; i < CACHESIZE; i++) {
94         cache[i].use = 0;
95         ncache[i] = NULL;
96         icache[i] = NULL;
97     }
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     struct item *i, *mini;
111 ##  char *iname;
112 ##  int j, rowcount;
113     int ctr, minv;
114
115     i = ncache[hashname(name, type)];
116     if (i && !strcmp(name, i->name) && !strcasecmp(type, i->type)) {
117         *id = i->id;
118         i->use = use++;
119         cachehits++;
120         return(SMS_SUCCESS);
121     }
122
123     cachemisses++;
124     iname = name;
125
126     switch (*type) {
127     case 'U':
128     case 'u':
129 ##      repeat retrieve (j = users.users_id) where users.#login=@iname
130         break;
131     case 'L':
132     case 'l':
133 ##      repeat retrieve (j = list.list_id) where list.#name=@iname
134         break;
135     case 'M':
136     case 'm':
137 ##      repeat retrieve (j = machine.mach_id) where machine.#name=uppercase(@iname)
138         break;
139     case 'C':
140     case 'c':
141 ##      repeat retrieve (j = cluster.clu_id) where cluster.#name=@iname
142         break;
143     case 'F':
144     case 'f':
145 ##      repeat retrieve (j = filesys.filsys_id) where filesys.#label=@iname
146         break;
147     case 'S':
148     case 's':
149 ##      repeat retrieve (j = strings.string_id) where strings.#string=@iname
150         break;
151     default:
152         return(SMS_INTERNAL);
153     }
154 ##  inquire_equel(rowcount = "rowcount")
155     if (ingres_errno) return(sms_errcode);
156     if (rowcount == 0)
157       return(SMS_NO_MATCH);
158     if (rowcount > 1)
159       return(SMS_NOT_UNIQUE);
160     *id = j;
161     if (name[0] == '#' && !strcasecmp(type, "USER"))
162       return(SMS_SUCCESS);
163     minv = use;
164     for (i = &cache[0]; i < &cache[CACHESIZE]; i++) {
165         if (i->use < minv) {
166             minv = i->use;
167             mini = i;
168             if (minv == 0)
169               break;
170         }
171     }
172     mini->id = j;
173     mini->use = use++;
174     strcpy(mini->name, name);
175     strcpy(mini->type, type);
176     ncache[hashname(name, type)] = icache[hashid(j, type)] = mini;
177     return(SMS_SUCCESS);
178 ##}
179
180
181 /* Perform an ID to name mapping.  name should be a pointer to a pointer to
182  * malloc'ed data.  The buffer it refers to will be freed, and a new buffer
183  * allocated with the answer.
184  */
185
186 int id_to_name(id, type, name)
187 int id;
188 char *type;
189 char **name;
190 ##{
191     struct item *i, *mini;
192 ##  char iname[NAMESZ];
193 ##  int j, rowcount;
194     int ctr, minv;
195
196     i = icache[hashid(id, type)];
197     if (i && id == i->id && !strcasecmp(type, i->type)) {
198         free(*name);
199         *name = strsave(i->name);
200         i->use = use++;
201         cachehits++;
202         return(SMS_SUCCESS);
203     }
204
205     cachemisses++;
206     j = id;
207
208     switch (*type) {
209     case 'U':
210     case 'u':
211 ##      repeat retrieve (iname = users.login) where users.users_id=@j
212         break;
213     case 'L':
214     case 'l':
215 ##      repeat retrieve (iname = list.name) where list.list_id=@j
216         break;
217     case 'M':
218     case 'm':
219 ##      repeat retrieve (iname = machine.name) where machine.mach_id=@j
220         break;
221     case 'C':
222     case 'c':
223 ##      repeat retrieve (iname = cluster.name) where cluster.clu_id=@j
224         break;
225     case 'F':
226     case 'f':
227 ##      repeat retrieve (iname = filesys.label) where filesys.filsys_id=@j
228         break;
229     case 'S':
230     case 's':
231 ##      repeat retrieve (iname = strings.string) where strings.string_id=@j
232         break;
233     default:
234         return(SMS_INTERNAL);
235     }
236 ##  inquire_equel(rowcount = "rowcount")
237     if (ingres_errno) return(sms_errcode);
238     if (rowcount == 0) {
239         free(*name);
240         sprintf(iname, "#%d", j);
241         *name = strsave(iname);
242         return(SMS_NO_MATCH);
243     }
244     if (rowcount != 1)
245       return(SMS_INTERNAL);
246     free(*name);
247     *name = strsave(strtrim(iname));
248     if (**name == '#' && !strcasecmp(type, "USER"))
249       return(SMS_SUCCESS);
250     minv = use;
251     for (i = &cache[0]; i < &cache[CACHESIZE]; i++) {
252         if (i->use < minv) {
253             minv = i->use;
254             mini = i;
255             if (minv == 0)
256               break;
257         }
258     }
259     mini->id = id;
260     mini->use = use++;
261     strcpy(mini->name, *name);
262     strcpy(mini->type, type);
263     ncache[hashname(name, type)] = icache[hashid(id, type)] = mini;
264     return(SMS_SUCCESS);
265 ##}
266
267
268 /* Explicitly add something to the cache without doing a lookup in the
269  * database.
270  */
271
272 cache_entry(name, type, id)
273 char *name;
274 char *type;
275 int id;
276 {
277     int minv;
278     struct item *i, *mini;
279
280     i = icache[hashid(id, type)];
281     if (i->id == id &&
282         !strcasecmp(i->type, type) &&
283         !strcmp(i->name, name))
284       return(SMS_SUCCESS);
285     minv = use;
286     if (i)
287       mini = i;
288     else
289       for (i = &cache[0]; i < &cache[CACHESIZE]; i++) {
290           if (i->use < minv) {
291               minv = i->use;
292               mini = i;
293               if (minv == 0)
294                 break;
295           }
296       }
297     mini->id = id;
298     mini->use = use++;
299     strcpy(mini->name, name);
300     strcpy(mini->type, type);
301     ncache[hashname(name, type)] = icache[hashid(id, type)] = mini;
302 }
303
304
305 /* Flush something that may or may not already be in the cache. */
306
307 flush_name(name, type)
308 char *name;
309 char *type;
310 {
311     struct item *i;
312
313     i = ncache[hashname(name, type)];
314     if (i && !strcmp(name, i->name) && !strcasecmp(type, i->type)) {
315         ncache[hashname(name, type)] = NULL;
316         icache[hashid(i->id, type)] = NULL;
317         i->use = 0;
318         return(SMS_SUCCESS);
319     }
320 }
This page took 0.05902 seconds and 5 git commands to generate.