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