]>
Commit | Line | Data |
---|---|---|
1afe05c5 | 1 | |
c411be12 | 2 | /* |
6d80b36f | 3 | * $Id: test_cache_digest.cc,v 1.7 1998/04/01 00:14:03 rousskov Exp $ |
c411be12 | 4 | * |
5 | * AUTHOR: Alex Rousskov | |
6 | * | |
7 | * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ | |
8 | * -------------------------------------------------------- | |
9 | * | |
10 | * Squid is the result of efforts by numerous individuals from the | |
11 | * Internet community. Development is led by Duane Wessels of the | |
12 | * National Laboratory for Applied Network Research and funded by | |
13 | * the National Science Foundation. | |
14 | * | |
15 | * This program is free software; you can redistribute it and/or modify | |
16 | * it under the terms of the GNU General Public License as published by | |
17 | * the Free Software Foundation; either version 2 of the License, or | |
18 | * (at your option) any later version. | |
19 | * | |
20 | * This program is distributed in the hope that it will be useful, | |
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
23 | * GNU General Public License for more details. | |
24 | * | |
25 | * You should have received a copy of the GNU General Public License | |
26 | * along with this program; if not, write to the Free Software | |
27 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
28 | * | |
29 | */ | |
30 | ||
31 | /* | |
32 | * Test-suite for playing with cache digests | |
33 | */ | |
34 | ||
35 | #include "squid.h" | |
36 | ||
37 | typedef struct { | |
6d80b36f | 38 | int query_count; |
39 | int true_hit_count; | |
40 | int true_miss_count; | |
41 | int false_hit_count; | |
42 | int false_miss_count; | |
43 | } CacheQueryStats; | |
44 | ||
45 | typedef struct _Cache Cache; | |
46 | struct _Cache { | |
c411be12 | 47 | const char *name; |
48 | hash_table *hash; | |
49 | CacheDigest *digest; | |
6d80b36f | 50 | Cache *peer; |
51 | CacheQueryStats qstats; | |
1afe05c5 | 52 | int count; /* #currently cached entries */ |
1afe05c5 | 53 | int bad_add_count; /* #duplicate adds */ |
54 | int bad_del_count; /* #dels with no prior add */ | |
6d80b36f | 55 | }; |
c411be12 | 56 | |
57 | ||
58 | typedef struct _CacheEntry { | |
59 | const cache_key *key; | |
60 | struct _CacheEntry *next; | |
c411be12 | 61 | unsigned char key_arr[MD5_DIGEST_CHARS]; |
6d80b36f | 62 | /* storeSwapLogData s; */ |
c411be12 | 63 | } CacheEntry; |
64 | ||
6d80b36f | 65 | /* parsed access log entry */ |
66 | typedef struct { | |
67 | cache_key key[MD5_DIGEST_CHARS]; | |
68 | time_t timestamp; | |
69 | short int use_icp; /* true/false */ | |
70 | } RawAccessLogEntry; | |
71 | ||
72 | typedef enum { frError = -2, frMore = -1, frEof = 0, frOk = 1 } fr_result; | |
73 | typedef struct _FileIterator FileIterator; | |
74 | typedef fr_result (*FI_READER)(FileIterator *fi); | |
00b23815 | 75 | |
6d80b36f | 76 | struct _FileIterator { |
00b23815 | 77 | const char *fname; |
78 | FILE *file; | |
79 | time_t inner_time; /* timestamp of the current entry */ | |
80 | int line_count; /* number of lines scanned */ | |
81 | int bad_line_count; /* number of parsing errors */ | |
6d80b36f | 82 | int time_warp_count;/* number of out-of-order entries in the file */ |
00b23815 | 83 | FI_READER reader; /* reads next entry and updates inner_time */ |
84 | void *entry; /* buffer for the current entry, freed with xfree() */ | |
6d80b36f | 85 | }; |
00b23815 | 86 | |
6d80b36f | 87 | /* globals */ |
88 | static time_t cur_time = -1; /* timestamp of the current log entry */ | |
89 | ||
90 | #if 0 | |
00b23815 | 91 | |
92 | static int cacheIndexScanCleanPrefix(CacheIndex * idx, const char *fname, FILE * file); | |
93 | static int cacheIndexScanAccessLog(CacheIndex * idx, const char *fname, FILE * file); | |
c411be12 | 94 | |
6d80b36f | 95 | #endif |
96 | ||
c411be12 | 97 | /* copied from url.c */ |
98 | const char *RequestMethodStr[] = | |
99 | { | |
100 | "NONE", | |
101 | "GET", | |
102 | "POST", | |
103 | "PUT", | |
104 | "HEAD", | |
105 | "CONNECT", | |
106 | "TRACE", | |
107 | "PURGE" | |
108 | }; | |
76e3f5c2 | 109 | /* copied from url.c */ |
110 | static method_t | |
6d80b36f | 111 | methodStrToId(const char *s) |
76e3f5c2 | 112 | { |
113 | if (strcasecmp(s, "GET") == 0) { | |
1afe05c5 | 114 | return METHOD_GET; |
76e3f5c2 | 115 | } else if (strcasecmp(s, "POST") == 0) { |
1afe05c5 | 116 | return METHOD_POST; |
76e3f5c2 | 117 | } else if (strcasecmp(s, "PUT") == 0) { |
1afe05c5 | 118 | return METHOD_PUT; |
76e3f5c2 | 119 | } else if (strcasecmp(s, "HEAD") == 0) { |
1afe05c5 | 120 | return METHOD_HEAD; |
76e3f5c2 | 121 | } else if (strcasecmp(s, "CONNECT") == 0) { |
1afe05c5 | 122 | return METHOD_CONNECT; |
76e3f5c2 | 123 | } else if (strcasecmp(s, "TRACE") == 0) { |
1afe05c5 | 124 | return METHOD_TRACE; |
76e3f5c2 | 125 | } else if (strcasecmp(s, "PURGE") == 0) { |
1afe05c5 | 126 | return METHOD_PURGE; |
76e3f5c2 | 127 | } |
128 | return METHOD_NONE; | |
129 | } | |
c411be12 | 130 | |
00b23815 | 131 | /* FileIterator */ |
132 | ||
6d80b36f | 133 | static void fileIteratorAdvance(FileIterator *fi); |
134 | ||
00b23815 | 135 | static FileIterator * |
136 | fileIteratorCreate(const char *fname, FI_READER reader) | |
137 | { | |
138 | FileIterator *fi = xcalloc(1, sizeof(FileIterator)); | |
139 | assert(fname && reader); | |
140 | fi->fname = fname; | |
141 | fi->reader = reader; | |
6d80b36f | 142 | fi->file = fopen(fname, "r"); |
143 | if (!fi->file) { | |
144 | fprintf(stderr, "cannot open %s: %s\n", fname, strerror(errno)); | |
145 | return NULL; | |
146 | } else | |
147 | fprintf(stderr, "opened %s\n", fname); | |
00b23815 | 148 | fileIteratorAdvance(fi); |
6d80b36f | 149 | return fi; |
00b23815 | 150 | } |
151 | ||
152 | static void | |
153 | fileIteratorDestroy(FileIterator *fi) | |
154 | { | |
155 | assert(fi); | |
6d80b36f | 156 | if (fi->file) { |
157 | fclose(fi->file); | |
158 | fprintf(stderr, "closed %s\n", fi->fname); | |
159 | } | |
00b23815 | 160 | xfree(fi->entry); |
161 | xfree(fi); | |
162 | } | |
163 | ||
164 | static void | |
165 | fileIteratorAdvance(FileIterator *fi) | |
166 | { | |
6d80b36f | 167 | int res; |
00b23815 | 168 | assert(fi); |
169 | do { | |
6d80b36f | 170 | time_t last_time = fi->inner_time; |
171 | res = fi->reader(fi); | |
00b23815 | 172 | fi->line_count++; |
6d80b36f | 173 | if (res == frError) |
00b23815 | 174 | fi->bad_line_count++; |
175 | else | |
6d80b36f | 176 | if (res == frEof) |
177 | fi->inner_time = -1; | |
178 | else | |
179 | if (fi->inner_time < last_time) { | |
180 | assert(last_time >= 0); | |
181 | fi->time_warp_count++; | |
182 | fi->inner_time = last_time; | |
183 | } | |
184 | /* report progress */ | |
185 | if (!(fi->line_count % 50000)) | |
186 | fprintf(stderr, "%s scanned %d K entries (%d bad)\n", | |
187 | fi->fname, fi->line_count / 1000, fi->bad_line_count); | |
00b23815 | 188 | } while (res < 0); |
189 | } | |
190 | ||
6d80b36f | 191 | /* CacheEntry */ |
00b23815 | 192 | |
6d80b36f | 193 | static CacheEntry * |
194 | cacheEntryCreate(const storeSwapLogData * s) | |
195 | { | |
196 | CacheEntry *e = xcalloc(1, sizeof(CacheEntry)); | |
197 | assert(s); | |
198 | /* e->s = *s; */ | |
199 | xmemcpy(e->key_arr, s->key, MD5_DIGEST_CHARS); | |
200 | e->key = &e->key_arr[0]; | |
201 | return e; | |
202 | } | |
00b23815 | 203 | |
6d80b36f | 204 | static void |
205 | cacheEntryDestroy(CacheEntry * e) | |
c411be12 | 206 | { |
6d80b36f | 207 | assert(e); |
208 | xfree(e); | |
209 | } | |
210 | ||
c411be12 | 211 | |
6d80b36f | 212 | /* Cache */ |
c411be12 | 213 | |
6d80b36f | 214 | static Cache * |
215 | cacheCreate(const char *name) | |
216 | { | |
217 | Cache *c; | |
218 | assert(name && strlen(name)); | |
219 | c = xcalloc(1, sizeof(Cache)); | |
220 | c->name = name; | |
221 | c->hash = hash_create(storeKeyHashCmp, 2e6, storeKeyHashHash); | |
222 | return c; | |
c411be12 | 223 | } |
224 | ||
225 | static void | |
6d80b36f | 226 | cacheDestroy(Cache * cache) |
c411be12 | 227 | { |
6d80b36f | 228 | CacheEntry *e = NULL; |
229 | hash_table *hash; | |
230 | assert(cache); | |
231 | hash = cache->hash; | |
232 | /* destroy hash table contents */ | |
233 | for (e = hash_first(hash); e; e = hash_next(hash)) { | |
234 | hash_remove_link(hash, (hash_link*)e); | |
235 | cacheEntryDestroy(e); | |
c411be12 | 236 | } |
6d80b36f | 237 | /* destroy the hash table itself */ |
238 | hashFreeMemory(hash); | |
239 | if (cache->digest) | |
240 | cacheDigestDestroy(cache->digest); | |
241 | xfree(cache); | |
c411be12 | 242 | } |
243 | ||
6d80b36f | 244 | /* re-digests currently hashed entries */ |
c411be12 | 245 | static void |
6d80b36f | 246 | cacheResetDigest(Cache * cache) |
c411be12 | 247 | { |
6d80b36f | 248 | CacheEntry *e = NULL; |
249 | hash_table *hash; | |
c411be12 | 250 | struct timeval t_start, t_end; |
6d80b36f | 251 | |
252 | assert(cache); | |
253 | fprintf(stderr, "%s: init-ing digest with %d entries\n", cache->name, cache->count); | |
254 | if (cache->digest) | |
255 | cacheDigestDestroy(cache->digest); | |
256 | hash = cache->hash; | |
257 | cache->digest = cacheDigestCreate(2 * cache->count + 1); /* 50% utilization */ | |
258 | if (!cache->count) | |
259 | return; | |
c411be12 | 260 | gettimeofday(&t_start, NULL); |
6d80b36f | 261 | for (e = hash_first(hash); e; e = hash_next(hash)) { |
262 | cacheDigestAdd(cache->digest, e->key); | |
c411be12 | 263 | } |
264 | gettimeofday(&t_end, NULL); | |
6d80b36f | 265 | assert(cache->digest->count == cache->count); |
1afe05c5 | 266 | fprintf(stderr, "%s: init-ed digest with %d entries\n", |
6d80b36f | 267 | cache->name, cache->digest->count); |
c411be12 | 268 | fprintf(stderr, "%s: init took: %f sec, %f sec/M\n", |
6d80b36f | 269 | cache->name, |
c411be12 | 270 | tvSubDsec(t_start, t_end), |
6d80b36f | 271 | (double) 1e6 * tvSubDsec(t_start, t_end) / cache->count); |
1c729cf1 | 272 | /* check how long it takes to traverse the hash */ |
273 | gettimeofday(&t_start, NULL); | |
6d80b36f | 274 | for (e = hash_first(hash); e; e = hash_next(hash)) { |
1c729cf1 | 275 | } |
276 | gettimeofday(&t_end, NULL); | |
277 | fprintf(stderr, "%s: hash scan took: %f sec, %f sec/M\n", | |
6d80b36f | 278 | cache->name, |
1c729cf1 | 279 | tvSubDsec(t_start, t_end), |
6d80b36f | 280 | (double) 1e6 * tvSubDsec(t_start, t_end) / cache->count); |
281 | } | |
282 | ||
283 | static void | |
284 | cacheQueryPeer(Cache * cache, const cache_key * key) | |
285 | { | |
286 | const int peer_has_it = hash_lookup(cache->peer->hash, key) != NULL; | |
287 | const int we_think_we_have_it = cacheDigestTest(cache->digest, key); | |
288 | ||
289 | cache->qstats.query_count++; | |
290 | if (peer_has_it) { | |
291 | if (we_think_we_have_it) | |
292 | cache->qstats.true_hit_count++; | |
293 | else | |
294 | cache->qstats.false_miss_count++; | |
295 | } else { | |
296 | if (we_think_we_have_it) | |
297 | cache->qstats.false_hit_count++; | |
298 | else | |
299 | cache->qstats.true_miss_count++; | |
300 | } | |
301 | } | |
302 | ||
303 | static void | |
304 | cacheQueryReport(Cache * cache, CacheQueryStats *stats) | |
305 | { | |
306 | fprintf(stdout, "%s: icp: %d\n", cache->name, stats->query_count); | |
307 | fprintf(stdout, "%s: t-hit: %d (%d%%) t-miss: %d (%d%%) t-*: %d (%d%%)\n", | |
308 | cache->name, | |
309 | stats->true_hit_count, xpercentInt(stats->true_hit_count, stats->query_count), | |
310 | stats->true_miss_count, xpercentInt(stats->true_miss_count, stats->query_count), | |
311 | stats->true_hit_count + stats->true_miss_count, | |
312 | xpercentInt(stats->true_hit_count + stats->true_miss_count, stats->query_count) | |
313 | ); | |
314 | fprintf(stdout, "%s: f-hit: %d (%d%%) f-miss: %d (%d%%) f-*: %d (%d%%)\n", | |
315 | cache->name, | |
316 | stats->false_hit_count, xpercentInt(stats->false_hit_count, stats->query_count), | |
317 | stats->false_miss_count, xpercentInt(stats->false_miss_count, stats->query_count), | |
318 | stats->false_hit_count + stats->false_miss_count, | |
319 | xpercentInt(stats->false_hit_count + stats->false_miss_count, stats->query_count) | |
320 | ); | |
c411be12 | 321 | } |
322 | ||
6d80b36f | 323 | #if 0 |
324 | ||
c411be12 | 325 | static int |
6d80b36f | 326 | cacheAddLog(Cache * idx, const char *fname) |
c411be12 | 327 | { |
328 | FILE *file; | |
329 | int scanned_count = 0; | |
330 | assert(idx); | |
331 | assert(fname && strlen(fname)); | |
332 | ||
333 | file = fopen(fname, "r"); | |
334 | if (!file) { | |
335 | fprintf(stderr, "cannot open %s: %s\n", fname, strerror(errno)); | |
336 | return 0; | |
337 | } | |
338 | scanned_count = cacheIndexScanCleanPrefix(idx, fname, file); | |
339 | fclose(file); | |
340 | return scanned_count; | |
341 | } | |
342 | ||
343 | static void | |
6d80b36f | 344 | cacheInitReport(Cache * cache) |
c411be12 | 345 | { |
346 | assert(idx); | |
347 | fprintf(stderr, "%s: bad swap_add: %d\n", | |
348 | idx->name, idx->bad_add_count); | |
1afe05c5 | 349 | fprintf(stderr, "%s: bad swap_del: %d\n", |
c411be12 | 350 | idx->name, idx->bad_del_count); |
1afe05c5 | 351 | fprintf(stderr, "%s: scanned lines: %d\n", |
c411be12 | 352 | idx->name, idx->scanned_count); |
353 | } | |
354 | ||
355 | #if 0 | |
356 | static int | |
6d80b36f | 357 | cacheGetLogEntry(Cache * idx, storeSwapLogData * s) |
c411be12 | 358 | { |
359 | if (!idx->has_log_entry) | |
360 | cacheIndexStepLogEntry(); | |
361 | if (idx->has_log_entry) { | |
362 | *s = idx->log_entry_buf; | |
363 | return 1; | |
364 | } | |
365 | return 0; | |
366 | } | |
367 | ||
368 | static int | |
6d80b36f | 369 | cacheStepLogEntry(Cache * cache) |
c411be12 | 370 | { |
371 | if (fread(&idx->log_entry_buf, sizeof(idx->log_entry_buf), 1, idx->log) == 1) { | |
372 | int op = (int) idx->log_entry_buf.op; | |
373 | idx->scanned_count++; | |
374 | idx->has_log_entry = 1; | |
375 | if (op != SWAP_LOG_ADD && op != SWAP_LOG_DEL) { | |
376 | fprintf(stderr, "%s:%d: unknown swap log action %d\n", idx->log_fname, idx->scanned_count, op); | |
377 | exit(-3); | |
378 | } | |
379 | } else | |
380 | idx->has_log_entry = 0; | |
381 | } | |
382 | ||
383 | static int | |
6d80b36f | 384 | cacheScan(Cache * idx, const char *fname, FILE * file) |
c411be12 | 385 | { |
386 | int count = 0; | |
387 | int del_count = 0; | |
388 | storeSwapLogData s; | |
389 | fprintf(stderr, "%s scanning\n", fname); | |
390 | while (fread(&s, sizeof(s), 1, file) == 1) { | |
391 | count++; | |
392 | idx->scanned_count++; | |
393 | if (s.op == SWAP_LOG_ADD) { | |
394 | CacheEntry *olde = (CacheEntry *) hash_lookup(idx->hash, s.key); | |
395 | if (olde) { | |
396 | idx->bad_add_count++; | |
397 | } else { | |
398 | CacheEntry *e = cacheEntryCreate(&s); | |
1afe05c5 | 399 | hash_join(idx->hash, (hash_link *) e); |
c411be12 | 400 | idx->count++; |
401 | } | |
1afe05c5 | 402 | } else if (s.op == SWAP_LOG_DEL) { |
c411be12 | 403 | CacheEntry *olde = (CacheEntry *) hash_lookup(idx->hash, s.key); |
404 | if (!olde) | |
405 | idx->bad_del_count++; | |
406 | else { | |
407 | assert(idx->count); | |
1afe05c5 | 408 | hash_remove_link(idx->hash, (hash_link *) olde); |
c411be12 | 409 | cacheEntryDestroy(olde); |
410 | idx->count--; | |
411 | } | |
412 | del_count++; | |
413 | } else { | |
414 | fprintf(stderr, "%s:%d: unknown swap log action\n", fname, count); | |
415 | exit(-3); | |
416 | } | |
417 | } | |
418 | fprintf(stderr, "%s scanned %d entries, alloc: %d bytes\n", | |
1afe05c5 | 419 | fname, count, |
420 | (int) (count * sizeof(CacheEntry))); | |
c411be12 | 421 | return count; |
422 | } | |
423 | #endif | |
424 | ||
76e3f5c2 | 425 | /* Us */ |
426 | ||
76e3f5c2 | 427 | static int |
6d80b36f | 428 | cacheAddAccessLog(Cache * idx, const char *fname) |
76e3f5c2 | 429 | { |
430 | FILE *file; | |
431 | int scanned_count = 0; | |
432 | assert(!idx); | |
433 | assert(fname && strlen(fname)); | |
434 | ||
435 | file = fopen(fname, "r"); | |
436 | if (!file) { | |
437 | fprintf(stderr, "cannot open %s: %s\n", fname, strerror(errno)); | |
438 | return 0; | |
439 | } | |
440 | scanned_count = cacheIndexScanAccessLog(idx, fname, file); | |
441 | fclose(file); | |
442 | return scanned_count; | |
443 | } | |
444 | ||
6d80b36f | 445 | #endif |
446 | ||
447 | static void | |
448 | cacheFetch(Cache *cache, const RawAccessLogEntry *e) | |
449 | { | |
450 | assert(e); | |
451 | if (e->use_icp) | |
452 | cacheQueryPeer(cache, e->key); | |
453 | } | |
454 | ||
455 | static fr_result | |
456 | swapStateReader(FileIterator * fi) | |
457 | { | |
458 | storeSwapLogData *entry; | |
459 | if (!fi->entry) | |
460 | fi->entry = xcalloc(1, sizeof(storeSwapLogData)); | |
461 | entry = fi->entry; | |
462 | if (fread(entry, sizeof(*entry), 1, fi->file) != 1) | |
463 | return frEof; | |
464 | fi->inner_time = entry->lastref; | |
465 | if (entry->op != SWAP_LOG_ADD && entry->op != SWAP_LOG_DEL) { | |
466 | fprintf(stderr, "%s:%d: unknown swap log action\n", fi->fname, fi->line_count); | |
467 | exit(-3); | |
468 | } | |
469 | return frOk; | |
470 | } | |
471 | ||
472 | static fr_result | |
473 | accessLogReader(FileIterator * fi) | |
76e3f5c2 | 474 | { |
475 | static char buf[4096]; | |
6d80b36f | 476 | RawAccessLogEntry *entry; |
477 | char *url; | |
478 | char *method; | |
479 | int method_id = METHOD_NONE; | |
480 | char *hier = NULL; | |
481 | ||
482 | assert(fi); | |
483 | if (!fi->entry) | |
484 | fi->entry = xcalloc(1, sizeof(RawAccessLogEntry)); | |
485 | else | |
486 | memset(fi->entry, 0, sizeof(RawAccessLogEntry)); | |
487 | entry = fi->entry; | |
488 | if (!fgets(buf, sizeof(buf), fi->file)) | |
489 | return frEof; /* eof */ | |
490 | entry->timestamp = fi->inner_time = (time_t)atoi(buf); | |
491 | url = strstr(buf, "://"); | |
492 | hier = url ? strstr(url, " - ") : NULL; | |
493 | ||
494 | if (!url || !hier) { | |
495 | /*fprintf(stderr, "%s:%d: strange access log entry '%s'\n", | |
496 | * fname, scanned_count, buf); */ | |
497 | return frError; | |
498 | } | |
499 | method = url; | |
500 | while (!isdigit(*method)) { | |
501 | if (*method == ' ') | |
502 | *method = '\0'; | |
503 | --method; | |
504 | } | |
505 | method += 2; | |
506 | method_id = methodStrToId(method); | |
507 | if (method_id == METHOD_NONE) { | |
508 | /*fprintf(stderr, "%s:%d: invalid method %s in '%s'\n", | |
509 | * fname, scanned_count, method, buf); */ | |
510 | return frError; | |
511 | } | |
512 | while (*url) url--; | |
513 | url++; | |
514 | *hier = '\0'; | |
515 | hier += 3; | |
516 | *strchr(hier, '/') = '\0'; | |
517 | /*fprintf(stdout, "%s:%d: %s %s %s\n", | |
518 | * fname, count, method, url, hier); */ | |
519 | entry->use_icp = /* no ICP lookup for these status codes */ | |
520 | strcmp(hier, "NONE") && | |
521 | strcmp(hier, "DIRECT") && | |
522 | strcmp(hier, "FIREWALL_IP_DIRECT") && | |
523 | strcmp(hier, "LOCAL_IP_DIRECT") && | |
524 | strcmp(hier, "NO_DIRECT_FAIL") && | |
525 | strcmp(hier, "NO_PARENT_DIRECT") && | |
526 | strcmp(hier, "SINGLE_PARENT") && | |
527 | strcmp(hier, "PASSTHROUGH_PARENT") && | |
528 | strcmp(hier, "SSL_PARENT_MISS") && | |
529 | strcmp(hier, "DEFAULT_PARENT"); | |
530 | if (!entry->use_icp) | |
531 | return frMore; | |
532 | memcpy(entry->key, storeKeyPublic(url, method_id), sizeof(entry->key)); | |
533 | /*fprintf(stdout, "%s:%d: %s %s %s %s\n", | |
534 | fname, count, method, storeKeyText(entry->key), url, hier); */ | |
535 | return frOk; | |
536 | } | |
537 | ||
538 | ||
539 | static void | |
540 | cachePurge(Cache *cache, storeSwapLogData *s) | |
541 | { | |
542 | CacheEntry *olde = (CacheEntry *) hash_lookup(cache->hash, s->key); | |
543 | if (!olde) { | |
544 | cache->bad_del_count++; | |
545 | } else { | |
546 | assert(cache->count); | |
547 | hash_remove_link(cache->hash, (hash_link *) olde); | |
548 | cacheEntryDestroy(olde); | |
549 | cache->count--; | |
550 | } | |
551 | } | |
552 | ||
553 | static void | |
554 | cacheStore(Cache *cache, storeSwapLogData *s, int update_digest) | |
555 | { | |
556 | CacheEntry *olde = (CacheEntry *) hash_lookup(cache->hash, s->key); | |
557 | if (olde) { | |
558 | cache->bad_add_count++; | |
559 | } else { | |
560 | CacheEntry *e = cacheEntryCreate(s); | |
561 | hash_join(cache->hash, (hash_link *) e); | |
562 | cache->count++; | |
563 | if (update_digest) | |
564 | cacheDigestAdd(cache->digest, e->key); | |
565 | } | |
566 | } | |
567 | ||
568 | static void | |
569 | cacheUpdateStore(Cache *cache, storeSwapLogData *s, int update_digest) | |
570 | { | |
571 | switch (s->op) { | |
572 | case SWAP_LOG_ADD: | |
573 | cacheStore(cache, s, update_digest); | |
574 | break; | |
575 | case SWAP_LOG_DEL: | |
576 | cachePurge(cache, s); | |
577 | break; | |
578 | default: | |
579 | assert(0); | |
76e3f5c2 | 580 | } |
76e3f5c2 | 581 | } |
582 | ||
c411be12 | 583 | static int |
584 | usage(const char *prg_name) | |
585 | { | |
586 | fprintf(stderr, "usage: %s <access_log> <swap_state> ...\n", | |
587 | prg_name); | |
588 | return -1; | |
589 | } | |
590 | ||
591 | int | |
592 | main(int argc, char *argv[]) | |
593 | { | |
00b23815 | 594 | FileIterator **fis = NULL; |
595 | const int fi_count = argc-1; | |
6d80b36f | 596 | int active_fi_count = 0; |
597 | Cache *them, *us; | |
598 | int i; | |
c411be12 | 599 | |
600 | if (argc < 3) | |
601 | return usage(argv[0]); | |
602 | ||
6d80b36f | 603 | them = cacheCreate("them"); |
604 | us = cacheCreate("us"); | |
605 | them->peer = us; | |
606 | us->peer = them; | |
607 | ||
00b23815 | 608 | fis = xcalloc(fi_count, sizeof(FileIterator *)); |
609 | /* init iterators with files */ | |
610 | fis[0] = fileIteratorCreate(argv[1], accessLogReader); | |
c411be12 | 611 | for (i = 2; i < argc; ++i) { |
00b23815 | 612 | fis[i-1] = fileIteratorCreate(argv[i], swapStateReader); |
c411be12 | 613 | } |
6d80b36f | 614 | /* read prefix to get start-up contents of the peer cache */ |
00b23815 | 615 | for (i = 1; i < fi_count; ++i) { |
6d80b36f | 616 | FileIterator *fi = fis[i]; |
617 | while (fi->inner_time > 0) { | |
618 | if (((storeSwapLogData*)fi->entry)->op != SWAP_LOG_ADD) { | |
619 | break; | |
620 | } else { | |
621 | cacheStore(them, fi->entry, 0); | |
622 | fileIteratorAdvance(fi); | |
623 | } | |
624 | } | |
00b23815 | 625 | } |
626 | /* digest peer cache content */ | |
6d80b36f | 627 | cacheResetDigest(them); |
628 | us->digest = cacheDigestClone(them->digest); /* @netw@ */ | |
629 | ||
630 | /* iterate, use the iterator with the smallest positive inner_time */ | |
00b23815 | 631 | cur_time = -1; |
6d80b36f | 632 | do { |
633 | int next_i = -1; | |
634 | time_t next_time = -1; | |
635 | active_fi_count = 0; | |
636 | for (i = 0; i < fi_count; ++i) { | |
637 | if (fis[i]->inner_time >= 0) { | |
638 | if (!active_fi_count || fis[i]->inner_time < next_time) { | |
639 | next_i = i; | |
640 | next_time = fis[i]->inner_time; | |
641 | } | |
642 | active_fi_count++; | |
643 | } | |
00b23815 | 644 | } |
6d80b36f | 645 | if (next_i >= 0) { |
646 | /* skip access log entries recorder before creation of swap.state */ | |
647 | if (cur_time > 0 || next_i > 0) { | |
648 | cur_time = next_time; | |
649 | /*fprintf(stderr, "%2d time: %d %s", next_i, (int)cur_time, ctime(&cur_time));*/ | |
650 | if (next_i == 0) | |
651 | cacheFetch(us, fis[next_i]->entry); | |
652 | else | |
653 | cacheUpdateStore(them, fis[next_i]->entry, 0); | |
654 | } | |
655 | fileIteratorAdvance(fis[next_i]); | |
656 | } | |
657 | } while (active_fi_count); | |
658 | ||
659 | /* report */ | |
660 | cacheQueryReport(us, &us->qstats); | |
661 | ||
662 | /* clean */ | |
663 | for (i = 0; i < argc-1; ++i) { | |
00b23815 | 664 | fileIteratorDestroy(fis[i]); |
665 | } | |
666 | xfree(fis); | |
6d80b36f | 667 | cacheDestroy(them); |
668 | cacheDestroy(us); | |
76e3f5c2 | 669 | return 0; |
c411be12 | 670 | } |