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