]> andersk Git - moira.git/blame - server/cache.pc
eliminate use of the `register' keyword: let the compiler decide
[moira.git] / server / cache.pc
CommitLineData
7de02494 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
10static char *rcsid_cache_dc = "$Header$";
11#endif lint
12
13#include <mit-copyright.h>
03c05291 14#include <string.h>
7de02494 15#include "mr_server.h"
03c05291 16#include "query.h"
7de02494 17EXEC SQL INCLUDE sqlca;
18
03c05291 19EXEC SQL WHENEVER SQLERROR DO dbmserr();
7de02494 20
03c05291 21extern char *whoami;
7de02494 22
23/* Cache parameters: */
24#define CACHESIZE 101 /* number of cache slots */
25#define NAMESZ 257 /* max size of a name */
26
27struct item {
5eaef520 28 char name[NAMESZ];
29 enum tables type;
30 int nhash;
31 int id;
32 struct item *next;
33 struct item *prev;
34 struct item *trans; /* keep track of transactions */
7de02494 35};
36
37static struct item cachehead;
38static int cachesize;
39
40/* statistics counters */
41int cachehits = 0, cachemisses = 0;
42
43
44/* Name hash function. */
45
5eaef520 46int hashname(char *name, enum tables type)
7de02494 47{
44d12d58 48 int val = type;
7de02494 49
5eaef520 50 while (*name)
51 val = (val << 5) - val + *name++ - '`';
52 return val;
7de02494 53}
54
55
56/* Initialize the cache, flushing any old data, and report the statistics
57 * if the cache was previously in use.
58 */
59
03c05291 60void flush_cache(void)
7de02494 61{
44d12d58 62 struct item *i;
7de02494 63
5eaef520 64 if (cachehits + cachemisses != 0)
65 {
7de02494 66 com_err(whoami, 0, "Flushing cache; %d hits, %d misses, %d%% hit rate",
67 cachehits, cachemisses,
68 (100 * cachehits) / (cachehits + cachemisses));
7de02494 69 }
5eaef520 70 else
7de02494 71 cachehead.next = cachehead.prev = &cachehead;
5eaef520 72 cachehits = cachemisses = cachesize = 0;
73 for (i = cachehead.next; i != &cachehead; i = i->next)
74 {
75 if (i->prev != &cachehead)
76 free(i->prev);
77 }
78 if (cachehead.prev != &cachehead)
79 free(cachehead.prev);
80 cachehead.next = cachehead.prev = &cachehead;
81 cachehead.trans = NULL;
7de02494 82}
83
84
85/* Do a name to ID translation. id will be updated with the answer if
86 * it is available, and as a side effect the cache is updated.
87 */
88
5eaef520 89int name_to_id(char *name, enum tables type, int *id)
7de02494 90{
44d12d58 91 struct item *i, *t;
5eaef520 92 EXEC SQL BEGIN DECLARE SECTION;
93 char *iname;
94 int j, h;
95 EXEC SQL END DECLARE SECTION;
96
97 h = hashname(name, type);
98 for (i = cachehead.next; i != &cachehead; i = i->next)
99 {
100 if (i->nhash != h || strcmp(name, i->name) || type != i->type)
101 continue;
102 *id = i->id;
103 cachehits++;
104 i->next->prev = i->prev;
105 i->prev->next = i->next;
106 i->next = cachehead.next;
107 i->prev = &cachehead;
108 cachehead.next->prev = i;
109 cachehead.next = i;
110 return MR_SUCCESS;
7de02494 111 }
112
5eaef520 113 cachemisses++;
114 iname = name;
7de02494 115
5eaef520 116 switch (type)
117 {
118 case USERS_TABLE:
119 if (strchr(iname, '@') || (strlen(iname) > 8))
120 {
03c05291 121 sqlca.sqlcode = SQL_NO_MATCH;
122 break;
06c1c8ff 123 }
5eaef520 124 EXEC SQL SELECT users_id INTO :j FROM users WHERE login = :iname;
125 break;
126 case LIST_TABLE:
127 EXEC SQL SELECT list_id INTO :j FROM list WHERE name = :iname;
128 break;
129 case MACHINE_TABLE:
130 EXEC SQL SELECT mach_id INTO :j FROM machine WHERE name = UPPER(:iname);
131 break;
132 case SUBNET_TABLE:
133 EXEC SQL SELECT snet_id INTO :j FROM subnet WHERE name = UPPER(:iname);
134 break;
135 case CLUSTER_TABLE:
136 EXEC SQL SELECT clu_id INTO :j FROM clusters WHERE name = :iname;
137 break;
138 case FILESYS_TABLE:
139 EXEC SQL SELECT filsys_id INTO :j FROM filesys WHERE label = :iname;
140 break;
141 case STRINGS_TABLE:
142 if (!iname[0]) /* special-case empty string */
143 {
144 *id = 0;
03c05291 145 return MR_SUCCESS;
146 }
5eaef520 147 EXEC SQL SELECT string_id INTO :j FROM strings WHERE string = :iname;
148 break;
149 default:
150 return MR_INTERNAL;
151 }
152 if (sqlca.sqlcode == SQL_NO_MATCH)
153 return MR_NO_MATCH;
154 if (sqlca.sqlerrd[2] > 1)
155 return MR_NOT_UNIQUE;
156 if (sqlca.sqlcode)
157 return MR_DBMS_ERR;
158 *id = j;
159 if (name[0] == '#' && type != USERS_TABLE)
160 return MR_SUCCESS;
161 if (cachesize < CACHESIZE)
162 {
163 i = malloc(sizeof(struct item));
164 cachesize++;
7de02494 165 }
5eaef520 166 else
167 {
168 i = cachehead.prev;
169 cachehead.prev = i->prev;
170 i->prev->next = &cachehead;
7de02494 171 }
5eaef520 172 strcpy(i->name, name);
173 i->type = type;
174 i->nhash = h;
175 i->id = j;
176 i->next = cachehead.next;
177 i->prev = &cachehead;
178 i->trans = NULL;
179 cachehead.next->prev = i;
180 cachehead.next = i;
181 /* find the end of the transaction chain & add this item */
182 for (t = &cachehead; t->trans && t != i; t = t->trans)
183 ;
184 if (t != i)
185 t->trans = i;
186 return MR_SUCCESS;
7de02494 187}
188
189
190/* Perform an ID to name mapping. name should be a pointer to a pointer to
191 * malloc'ed data. The buffer it refers to will be freed, and a new buffer
192 * allocated with the answer.
193 */
194
5eaef520 195int id_to_name(int id, enum tables type, char **name)
7de02494 196{
44d12d58 197 struct item *i, *t;
5eaef520 198 EXEC SQL BEGIN DECLARE SECTION;
199 char iname[NAMESZ];
200 int j;
201 EXEC SQL END DECLARE SECTION;
202
203 for (i = cachehead.next; i != &cachehead; i = i->next)
204 {
205 if (i->id != id || type != i->type)
206 continue;
207 free(*name);
208 *name = strsave(i->name);
209 cachehits++;
210 i->next->prev = i->prev;
211 i->prev->next = i->next;
212 i->next = cachehead.next;
213 i->prev = &cachehead;
214 cachehead.next->prev = i;
215 cachehead.next = i;
216 return MR_SUCCESS;
7de02494 217 }
218
5eaef520 219 cachemisses++;
220 j = id;
221
222 switch (type)
223 {
224 case USERS_TABLE:
225 EXEC SQL SELECT login INTO :iname FROM users WHERE users_id = :j;
226 break;
227 case LIST_TABLE:
228 EXEC SQL SELECT name INTO :iname FROM list WHERE list_id = :j;
229 break;
230 case MACHINE_TABLE:
231 EXEC SQL SELECT name INTO :iname FROM machine WHERE mach_id = :j;
232 break;
233 case SUBNET_TABLE:
234 EXEC SQL SELECT name INTO :iname FROM subnet WHERE snet_id = :j;
235 break;
236 case CLUSTER_TABLE:
237 EXEC SQL SELECT name INTO :iname FROM clusters WHERE clu_id = :j;
238 break;
239 case FILESYS_TABLE:
240 EXEC SQL SELECT label INTO :iname FROM filesys WHERE filsys_id = :j;
241 break;
242 case STRINGS_TABLE:
243 EXEC SQL SELECT string INTO :iname FROM strings WHERE string_id = :j;
244 break;
7de02494 245 default:
5eaef520 246 return MR_INTERNAL;
7de02494 247 }
5eaef520 248 if (sqlca.sqlcode == SQL_NO_MATCH)
249 {
250 free(*name);
251 sprintf(iname, "#%d", j);
252 *name = strsave(iname);
253 return MR_NO_MATCH;
7de02494 254 }
5eaef520 255 if (sqlca.sqlerrd[2] > 1)
256 return MR_INTERNAL;
257 if (sqlca.sqlcode)
258 return MR_DBMS_ERR;
259 free(*name);
260 *name = strsave(strtrim(iname));
261 if (**name == '#' && type != USERS_TABLE)
262 return MR_SUCCESS;
263 if (cachesize < CACHESIZE)
264 {
265 i = malloc(sizeof(struct item));
266 cachesize++;
7de02494 267 }
5eaef520 268 else
269 {
270 i = cachehead.prev;
271 cachehead.prev = i->prev;
272 i->prev->next = &cachehead;
273 }
274 strcpy(i->name, *name);
275 i->type = type;
276 i->nhash = hashname(*name, type);
277 i->id = id;
278 i->next = cachehead.next;
279 i->prev = &cachehead;
280 i->trans = NULL;
281 cachehead.next->prev = i;
282 cachehead.next = i;
283 /* find the end of the transaction chain & add this item */
284 for (t = &cachehead; t->trans && t != i; t = t->trans)
285 ;
286 if (t != i)
287 t->trans = i;
288 return MR_SUCCESS;
7de02494 289}
290
291
292/* Explicitly add something to the cache without doing a lookup in the
293 * database.
294 */
295
5eaef520 296int cache_entry(char *name, enum tables type, int id)
7de02494 297{
44d12d58 298 struct item *i, *t;
5eaef520 299
300 for (i = cachehead.next; i != &cachehead; i = i->next)
301 {
302 if (i->id == id && i->type == type)
303 {
304 if (strcmp(i->name, name))
305 {
a49e54ea 306 strcpy(i->name, name);
307 i->nhash = hashname(name, type);
5eaef520 308 }
309 return MR_SUCCESS;
310 }
311 }
312 if (cachesize < CACHESIZE)
313 {
314 i = malloc(sizeof(struct item));
315 cachesize++;
316 }
317 else
318 {
319 i = cachehead.prev;
320 cachehead.prev = i->prev;
321 i->prev->next = &cachehead;
7de02494 322 }
5eaef520 323 strcpy(i->name, name);
324 i->type = type;
325 i->nhash = hashname(name, type);
326 i->id = id;
327 i->next = cachehead.next;
328 i->prev = &cachehead;
329 i->trans = NULL;
330 cachehead.next->prev = i;
331 cachehead.next = i;
332 /* find the end of the transaction chain & add this item */
333 for (t = &cachehead; t->trans && t != i; t = t->trans)
334 ;
335 if (t != i)
336 t->trans = i;
337 return MR_SUCCESS;
7de02494 338}
339
340
341/* Flush something that may or may not already be in the cache. */
342
5eaef520 343void flush_name(char *name, enum tables type)
7de02494 344{
44d12d58 345 struct item *i;
7de02494 346
5eaef520 347 /* first clear it out of the transaction chain */
348 for (i = &cachehead; i && i->trans; i = i->trans)
349 {
350 if (!strcmp(name, i->trans->name) && type == i->trans->type)
351 i->trans = i->trans->trans;
7f5495cf 352 }
7de02494 353
5eaef520 354 /* now remove it */
355 for (i = cachehead.next; i != &cachehead; i = i->next)
356 {
357 if (!strcmp(name, i->name) && type == i->type)
358 {
359 cachesize--;
360 i->next->prev = i->prev;
361 i->prev->next = i->next;
362 free(i);
7de02494 363 }
364 }
365}
a49e54ea 366
367
368/* Called when a transaction is committed to also commit any cache changes.
369 * Just throws away the list of cache changes for this transaction.
370 */
371
03c05291 372void cache_commit(void)
a49e54ea 373{
5eaef520 374 cachehead.trans = NULL;
a49e54ea 375}
376
377
378/* Called whan a transaction is aborted to throw away any cache changes
379 * from that transaction.
380 */
381
03c05291 382void cache_abort(void)
a49e54ea 383{
44d12d58 384 struct item *i, *t;
a49e54ea 385
5eaef520 386 for (i = cachehead.trans; i; i = t)
387 {
388 t = i->trans;
389 flush_name(i->name, i->type);
a49e54ea 390 }
5eaef520 391 cachehead.trans = NULL;
a49e54ea 392}
This page took 0.159814 seconds and 5 git commands to generate.