]> andersk Git - moira.git/blame - server/cache.qc
Initial revision
[moira.git] / server / cache.qc
CommitLineData
dc37f07c 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
13static 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
21extern char *whoami, *strsave();
22extern 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
46struct item {
47 char name[NAMESZ];
48 char type[9];
49 int id;
50 int use;
51};
52
53static struct item cache[CACHESIZE];
54static struct item *ncache[CACHESIZE];
55static struct item *icache[CACHESIZE];
56
57/* use counter for implementing LRU */
58static int use = 1;
59/* statistics counters */
60int cachehits = 0, cachemisses = 0;
61
62/* ID hash function */
63#define hashid(id, type) (((id) + *(type)) % CACHESIZE)
64
65
66/* Name hash function. */
67
68int hashname(name, type)
69register char *name;
70char *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
84flush_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
105int name_to_id(name, type, id)
106char *name;
107char *type;
108int *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
186int id_to_name(id, type, name)
187int id;
188char *type;
189char **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
272cache_entry(name, type, id)
273char *name;
274char *type;
275int 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
307flush_name(name, type)
308char *name;
309char *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.091897 seconds and 5 git commands to generate.