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