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