source: releases/0.11.0/lib/lru_cache.c@ 293

Last change on this file since 293 was 147, checked in by tim, 16 years ago

added talloc library

incorporated talloc into winsec and lru_cache modules

introduced talloc into SK caching system

  • Property svn:keywords set to Id
File size: 7.9 KB
Line 
1/*
2 * Copyright (C) 2008-2009 Timothy D. Morgan
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3 of the License.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16 *
17 * $Id: lru_cache.c 147 2009-02-22 19:31:52Z tim $
18 */
19
20#include "lru_cache.h"
21
22
23#define LRU_CACHE_DEBUG 0
24
25/* XXX: really should replace this with a real universal hash or other
26 * fast HMAC.
27 */
28static uint32_t lru_cache_compute_hash(uint32_t num_buckets,
29 uint32_t secret,
30 const void* buf,
31 uint32_t buf_len)
32{
33 uint32_t i;
34 uint32_t ret_val = 0x243f6a88;
35 unsigned char* s = (unsigned char*)&secret;
36 const unsigned char* b = (unsigned char*)buf;
37
38 for(i=0; i<buf_len; i++)
39 ret_val = (ret_val+(i^s[i%4])*b[i]) % num_buckets;
40
41 return ret_val;
42}
43
44/* Returns approximately floor(log_2(n)) (log base 2 of n, floored)
45 * If n == 0, returns 0
46 */
47static uint32_t lru_cache_floor_log2(uint32_t n)
48{
49 uint32_t ret_val;
50
51 for(ret_val=31; ret_val > 1; ret_val--)
52 if((n & (1 << ret_val)) != 0)
53 return ret_val;
54
55 return 0;
56}
57
58#if 0
59static void lru_cache_print(lru_cache* ht)
60{
61 uint32_t i;
62 lru_cache_element* cur;
63
64 printf("from newest to oldest:\n");
65 for(cur=ht->newest; cur != NULL; cur=cur->older)
66 {
67 /* write(STDOUT_FILENO, cur->index, cur->index_len);*/
68 printf("%p", (void*)cur);
69 printf("\n");
70 if(cur->older == ht->newest)
71 {
72 printf("??? Loop in LRU list!!");
73 break;
74 }
75 }
76 printf("\n");
77
78 printf("table:\n");
79 for(i=0; i<ht->num_buckets; i++)
80 {
81 printf("%.8X: ", i);
82 for(cur=ht->table[i]; cur != NULL; cur=cur->next)
83 {
84 /* write(STDOUT_FILENO, cur->index, cur->index_len);*/
85 printf("%p", (void*)cur);
86 printf("|");
87
88 if(cur->next == ht->table[i])
89 {
90 printf("??? Loop in table chain!!");
91 break;
92 }
93 }
94 printf("\n");
95 }
96}
97#endif
98
99
100lru_cache* lru_cache_create(uint32_t max_keys, uint32_t secret)
101{
102 return lru_cache_create_ctx(NULL, max_keys, secret, false);
103}
104
105
106lru_cache* lru_cache_create_ctx(void* talloc_ctx, uint32_t max_keys,
107 uint32_t secret, bool talloc_data)
108{
109 lru_cache* ret_val;
110
111 ret_val = talloc(talloc_ctx, lru_cache);
112 if(ret_val == NULL)
113 return NULL;
114
115 if(max_keys == 0)
116 ret_val->num_buckets = 1024;
117 else
118 {
119 ret_val->num_buckets = max_keys/lru_cache_floor_log2(max_keys);
120 if(ret_val->num_buckets < 1)
121 ret_val->num_buckets = 1;
122 }
123
124 ret_val->table = talloc_array(ret_val,
125 lru_cache_element*, ret_val->num_buckets);
126 if(ret_val->table == NULL)
127 {
128 talloc_free(ret_val);
129 return NULL;
130 }
131
132 ret_val->oldest = NULL;
133 ret_val->newest = NULL;
134 ret_val->max_keys = max_keys;
135 ret_val->secret = secret;
136 ret_val->talloc_data = talloc_data;
137 ret_val->num_keys = 0;
138 memset(ret_val->table, 0, ret_val->num_buckets*sizeof(lru_cache_element*));
139
140 return ret_val;
141}
142
143
144void lru_cache_destroy(lru_cache* ht)
145{
146 ht->secret = 0;
147 talloc_free(ht);
148}
149
150
151
152bool lru_cache_update(lru_cache* ht, const void* index,
153 uint32_t index_len, void* data)
154{
155 uint32_t hash, lru_hash;
156 lru_cache_element* cur;
157 lru_cache_element* last = NULL;
158 lru_cache_element* e = NULL;
159 void* tmp_index;
160
161 hash = lru_cache_compute_hash(ht->num_buckets, ht->secret, index, index_len);
162 for(cur = ht->table[hash]; cur != NULL && e == NULL; cur=cur->next)
163 {
164 if((index_len == cur->index_len)
165 && memcmp(cur->index, index, index_len) == 0)
166 { e = cur; }
167 }
168
169 if(e != NULL)
170 { /* We found the index, so we're going to overwrite the data.
171 * We also need to reposition the element to the newest position,
172 * so remove it from the list for now.
173 */
174 if(ht->talloc_data)
175 talloc_free(e->data);
176
177 if(e->newer == NULL)
178 ht->newest = e->older;
179 else
180 e->newer->older = e->older;
181
182 if(e->older == NULL)
183 ht->oldest = e->newer;
184 else
185 e->older->newer = e->newer;
186 }
187 else
188 { /* We didn't find an identical index. */
189
190 if((ht->max_keys != 0) && (ht->num_keys >= ht->max_keys))
191 { /* Eliminate the least recently used item, but reuse the element
192 * structure to minimize reallocation.
193 */
194 e = ht->oldest;
195 if(ht->newest == ht->oldest)
196 {
197 ht->newest = NULL;
198 ht->oldest = NULL;
199 }
200 else
201 {
202 ht->oldest = e->newer;
203 e->newer->older = NULL;
204 }
205 e->newer = NULL;
206 e->older = NULL;
207
208 last = NULL;
209 lru_hash = lru_cache_compute_hash(ht->num_buckets, ht->secret,
210 e->index, e->index_len);
211 for(cur = ht->table[lru_hash]; cur != e && cur != NULL;
212 last=cur, cur=cur->next)
213 { continue; }
214
215 if(last == NULL)
216 ht->table[lru_hash] = e->next;
217 else
218 last->next = e->next;
219 e->next = NULL;
220
221 if(ht->talloc_data)
222 talloc_free(e->data);
223
224 tmp_index = talloc_realloc_size(e, e->index, index_len);
225 if(tmp_index == NULL)
226 {
227 talloc_free(e);
228 return false;
229 }
230 else
231 e->index = tmp_index;
232 }
233 else
234 { /* Brand new element because we have room to spare. */
235
236 e = talloc(ht->table, lru_cache_element);
237 if(e == NULL)
238 return false;
239
240 e->index = talloc_size(e, index_len);
241 if(e->index == NULL)
242 {
243 talloc_free(e);
244 return false;
245 }
246
247 /* New entry, increment counters. */
248 ht->num_keys++;
249 }
250 memcpy(e->index, index, index_len);
251 e->index_len = index_len;
252
253 /* Insert at beginning of chain, in a vaguely LRU style */
254 e->next = ht->table[hash];
255 ht->table[hash] = e;
256 }
257 e->data = data;
258 if(ht->talloc_data)
259 talloc_steal(e, e->data);
260
261 /* Finally, let's insert the element to the newest position in the LRU list.*/
262 if(ht->newest != NULL)
263 ht->newest->newer = e;
264 e->newer = NULL;
265 e->older = ht->newest;
266 ht->newest = e;
267 if(ht->oldest == NULL)
268 ht->oldest = e;
269
270 return true;
271}
272
273
274void* lru_cache_find(lru_cache* ht, const void* index,
275 uint32_t index_len)
276{
277 uint32_t hash;
278 lru_cache_element* cur;
279
280 hash = lru_cache_compute_hash(ht->num_buckets, ht->secret, index, index_len);
281 for(cur = ht->table[hash]; (cur != NULL); cur = cur->next)
282 {
283 if((index_len == cur->index_len)
284 && memcmp(cur->index, index, index_len) == 0)
285 { break; }
286 }
287
288 if(cur != NULL && cur->newer != NULL)
289 { /* Need to move this element up to the newest slot. */
290
291 cur->newer->older = cur->older;
292
293 if(cur->older == NULL)
294 ht->oldest = cur->newer;
295 else
296 cur->older->newer = cur->newer;
297
298 cur->newer = NULL;
299 cur->older = ht->newest;
300 ht->newest->newer = cur;
301 ht->newest = cur;
302 }
303
304 if(cur != NULL)
305 return cur->data;
306 else
307 return NULL;
308}
309
310
311
312bool lru_cache_remove(lru_cache* ht, const void* index,
313 uint32_t index_len)
314{
315 uint32_t hash;
316 lru_cache_element* cur;
317 lru_cache_element* last = NULL;
318
319 hash = lru_cache_compute_hash(ht->num_buckets, ht->secret,
320 index, index_len);
321 for(cur=ht->table[hash]; (cur != NULL);
322 last=cur, cur=cur->next)
323 {
324 if((index_len == cur->index_len)
325 && memcmp(cur->index, index, index_len) == 0)
326 { break; }
327 }
328
329 if(cur == NULL)
330 return false;
331
332 /* Detach from list */
333 if(cur->newer == NULL)
334 ht->newest = cur->older;
335 else
336 cur->newer->older = cur->older;
337
338 if(cur->older == NULL)
339 ht->oldest = cur->newer;
340 else
341 cur->older->newer = cur->newer;
342
343 /* Detach from hash table */
344 if(last == NULL)
345 ht->table[hash] = cur->next;
346 else
347 last->next = cur->next;
348
349 talloc_free(cur);
350
351 /* Removing entry, decrement counters. */
352 ht->num_keys--;
353
354 return true;
355}
Note: See TracBrowser for help on using the repository browser.