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