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