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