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