]>
Commit | Line | Data |
---|---|---|
c411be12 | 1 | /* |
b8ae064d | 2 | * Copyright (C) 1996-2023 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)); |
a1b1756c | 117 | return nullptr; |
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 | { |
a1b1756c | 221 | CacheEntry *e = nullptr; |
6d80b36f | 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 | |
a901d0b4 | 236 | delete cache->digest; |
6d80b36f | 237 | xfree(cache); |
c411be12 | 238 | } |
239 | ||
6d80b36f | 240 | /* re-digests currently hashed entries */ |
c411be12 | 241 | static void |
6d80b36f | 242 | cacheResetDigest(Cache * cache) |
c411be12 | 243 | { |
a1b1756c | 244 | CacheEntry *e = nullptr; |
6d80b36f | 245 | hash_table *hash; |
62e76326 | 246 | |
c411be12 | 247 | struct timeval t_start, t_end; |
6d80b36f | 248 | |
249 | assert(cache); | |
250 | fprintf(stderr, "%s: init-ing digest with %d entries\n", cache->name, cache->count); | |
62e76326 | 251 | |
6d80b36f | 252 | hash = cache->hash; |
62e76326 | 253 | |
a901d0b4 | 254 | delete cache->digest; |
e04fc9d3 | 255 | cache->digest = new CacheDigest(cache->count + 1, 6); |
62e76326 | 256 | |
6d80b36f | 257 | if (!cache->count) |
62e76326 | 258 | return; |
259 | ||
a1b1756c | 260 | gettimeofday(&t_start, nullptr); |
62e76326 | 261 | |
0f6bebac | 262 | hash_first(hash); |
62e76326 | 263 | |
e6ccf245 | 264 | while ((e = (CacheEntry *)hash_next(hash))) { |
fbba122c | 265 | cache->digest->add(e->key); |
c411be12 | 266 | } |
62e76326 | 267 | |
a1b1756c | 268 | gettimeofday(&t_end, nullptr); |
6d80b36f | 269 | assert(cache->digest->count == cache->count); |
1afe05c5 | 270 | fprintf(stderr, "%s: init-ed digest with %d entries\n", |
62e76326 | 271 | cache->name, cache->digest->count); |
c411be12 | 272 | fprintf(stderr, "%s: init took: %f sec, %f sec/M\n", |
62e76326 | 273 | cache->name, |
274 | tvSubDsec(t_start, t_end), | |
275 | (double) 1e6 * tvSubDsec(t_start, t_end) / cache->count); | |
1c729cf1 | 276 | /* check how long it takes to traverse the hash */ |
a1b1756c | 277 | gettimeofday(&t_start, nullptr); |
e6ccf245 | 278 | hash_first(hash); |
62e76326 | 279 | |
280 | for (e = (CacheEntry *)hash_next(hash); e; e = (CacheEntry *)hash_next(hash)) {} | |
281 | ||
a1b1756c | 282 | gettimeofday(&t_end, nullptr); |
1c729cf1 | 283 | fprintf(stderr, "%s: hash scan took: %f sec, %f sec/M\n", |
62e76326 | 284 | cache->name, |
285 | tvSubDsec(t_start, t_end), | |
286 | (double) 1e6 * tvSubDsec(t_start, t_end) / cache->count); | |
6d80b36f | 287 | } |
288 | ||
289 | static void | |
290 | cacheQueryPeer(Cache * cache, const cache_key * key) | |
291 | { | |
292 | const int peer_has_it = hash_lookup(cache->peer->hash, key) != NULL; | |
5bc5e81f | 293 | const int we_think_we_have_it = cache->digest->test(key); |
6d80b36f | 294 | |
5db6bf73 | 295 | ++ cache->qstats.query_count; |
62e76326 | 296 | |
6d80b36f | 297 | if (peer_has_it) { |
62e76326 | 298 | if (we_think_we_have_it) |
5db6bf73 | 299 | ++ cache->qstats.true_hit_count; |
62e76326 | 300 | else |
5db6bf73 | 301 | ++ cache->qstats.false_miss_count; |
6d80b36f | 302 | } else { |
62e76326 | 303 | if (we_think_we_have_it) |
5db6bf73 | 304 | ++ cache->qstats.false_hit_count; |
62e76326 | 305 | else |
5db6bf73 | 306 | ++ cache->qstats.true_miss_count; |
6d80b36f | 307 | } |
308 | } | |
309 | ||
310 | static void | |
b644367b | 311 | cacheQueryReport(Cache * cache, CacheQueryStats * stats) |
6d80b36f | 312 | { |
b644367b | 313 | fprintf(stdout, "%s: peer queries: %d (%d%%)\n", |
62e76326 | 314 | cache->name, |
315 | stats->query_count, xpercentInt(stats->query_count, cache->req_count) | |
316 | ); | |
6d80b36f | 317 | fprintf(stdout, "%s: t-hit: %d (%d%%) t-miss: %d (%d%%) t-*: %d (%d%%)\n", |
62e76326 | 318 | cache->name, |
319 | stats->true_hit_count, xpercentInt(stats->true_hit_count, stats->query_count), | |
320 | stats->true_miss_count, xpercentInt(stats->true_miss_count, stats->query_count), | |
321 | stats->true_hit_count + stats->true_miss_count, | |
322 | xpercentInt(stats->true_hit_count + stats->true_miss_count, stats->query_count) | |
323 | ); | |
6d80b36f | 324 | fprintf(stdout, "%s: f-hit: %d (%d%%) f-miss: %d (%d%%) f-*: %d (%d%%)\n", |
62e76326 | 325 | cache->name, |
326 | stats->false_hit_count, xpercentInt(stats->false_hit_count, stats->query_count), | |
327 | stats->false_miss_count, xpercentInt(stats->false_miss_count, stats->query_count), | |
328 | stats->false_hit_count + stats->false_miss_count, | |
329 | xpercentInt(stats->false_hit_count + stats->false_miss_count, stats->query_count) | |
330 | ); | |
c411be12 | 331 | } |
332 | ||
c2186446 | 333 | static void |
334 | cacheReport(Cache * cache) | |
335 | { | |
b644367b | 336 | fprintf(stdout, "%s: entries: %d reqs: %d bad-add: %d bad-del: %d\n", |
62e76326 | 337 | cache->name, cache->count, cache->req_count, |
338 | cache->bad_add_count, cache->bad_del_count); | |
c2186446 | 339 | |
c2186446 | 340 | } |
341 | ||
6d80b36f | 342 | static void |
b644367b | 343 | cacheFetch(Cache * cache, const RawAccessLogEntry * e) |
6d80b36f | 344 | { |
345 | assert(e); | |
5db6bf73 | 346 | ++ cache->req_count; |
62e76326 | 347 | |
6d80b36f | 348 | if (e->use_icp) |
62e76326 | 349 | cacheQueryPeer(cache, e->key); |
6d80b36f | 350 | } |
351 | ||
352 | static fr_result | |
353 | swapStateReader(FileIterator * fi) | |
354 | { | |
355 | storeSwapLogData *entry; | |
62e76326 | 356 | |
6d80b36f | 357 | if (!fi->entry) |
62e76326 | 358 | fi->entry = xcalloc(1, sizeof(storeSwapLogData)); |
359 | ||
e6ccf245 | 360 | entry = (storeSwapLogData *)fi->entry; |
62e76326 | 361 | |
6d80b36f | 362 | if (fread(entry, sizeof(*entry), 1, fi->file) != 1) |
62e76326 | 363 | return frEof; |
364 | ||
6d80b36f | 365 | fi->inner_time = entry->lastref; |
62e76326 | 366 | |
6d80b36f | 367 | if (entry->op != SWAP_LOG_ADD && entry->op != SWAP_LOG_DEL) { |
62e76326 | 368 | fprintf(stderr, "%s:%d: unknown swap log action\n", fi->fname, fi->line_count); |
369 | exit(-3); | |
6d80b36f | 370 | } |
62e76326 | 371 | |
6d80b36f | 372 | return frOk; |
373 | } | |
374 | ||
375 | static fr_result | |
376 | accessLogReader(FileIterator * fi) | |
76e3f5c2 | 377 | { |
378 | static char buf[4096]; | |
6d80b36f | 379 | RawAccessLogEntry *entry; |
380 | char *url; | |
381 | char *method; | |
60745f24 | 382 | HttpRequestMethod method_id = METHOD_NONE; |
a1b1756c | 383 | char *hier = nullptr; |
6d80b36f | 384 | |
385 | assert(fi); | |
62e76326 | 386 | |
6d80b36f | 387 | if (!fi->entry) |
62e76326 | 388 | fi->entry = xcalloc(1, sizeof(RawAccessLogEntry)); |
6d80b36f | 389 | else |
62e76326 | 390 | memset(fi->entry, 0, sizeof(RawAccessLogEntry)); |
391 | ||
e6ccf245 | 392 | entry = (RawAccessLogEntry*)fi->entry; |
62e76326 | 393 | |
6d80b36f | 394 | if (!fgets(buf, sizeof(buf), fi->file)) |
f53969cc | 395 | return frEof; /* eof */ |
62e76326 | 396 | |
b644367b | 397 | entry->timestamp = fi->inner_time = (time_t) atoi(buf); |
62e76326 | 398 | |
6d80b36f | 399 | url = strstr(buf, "://"); |
62e76326 | 400 | |
6d80b36f | 401 | hier = url ? strstr(url, " - ") : NULL; |
402 | ||
403 | if (!url || !hier) { | |
62e76326 | 404 | /*fprintf(stderr, "%s:%d: strange access log entry '%s'\n", |
405 | * fname, scanned_count, buf); */ | |
406 | return frError; | |
6d80b36f | 407 | } |
62e76326 | 408 | |
6d80b36f | 409 | method = url; |
62e76326 | 410 | |
ec451a0f | 411 | while (!xisdigit(*method)) { |
62e76326 | 412 | if (*method == ' ') |
413 | *method = '\0'; | |
414 | ||
415 | --method; | |
6d80b36f | 416 | } |
62e76326 | 417 | |
6d80b36f | 418 | method += 2; |
419 | method_id = methodStrToId(method); | |
62e76326 | 420 | |
6d80b36f | 421 | if (method_id == METHOD_NONE) { |
62e76326 | 422 | /*fprintf(stderr, "%s:%d: invalid method %s in '%s'\n", |
423 | * fname, scanned_count, method, buf); */ | |
424 | return frError; | |
6d80b36f | 425 | } |
62e76326 | 426 | |
b644367b | 427 | while (*url) |
5e263176 | 428 | --url; |
62e76326 | 429 | |
5db6bf73 | 430 | ++url; |
62e76326 | 431 | |
6d80b36f | 432 | *hier = '\0'; |
62e76326 | 433 | |
6d80b36f | 434 | hier += 3; |
62e76326 | 435 | |
6d80b36f | 436 | *strchr(hier, '/') = '\0'; |
62e76326 | 437 | |
6d80b36f | 438 | /*fprintf(stdout, "%s:%d: %s %s %s\n", |
439 | * fname, count, method, url, hier); */ | |
b644367b | 440 | entry->use_icp = strcmp(hier, "NONE"); |
62e76326 | 441 | |
b644367b | 442 | /* no ICP lookup for these status codes */ |
62e76326 | 443 | /* strcmp(hier, "NONE") && |
444 | * strcmp(hier, "DIRECT") && | |
445 | * strcmp(hier, "FIREWALL_IP_DIRECT") && | |
446 | * strcmp(hier, "LOCAL_IP_DIRECT") && | |
447 | * strcmp(hier, "NO_DIRECT_FAIL") && | |
448 | * strcmp(hier, "NO_PARENT_DIRECT") && | |
449 | * strcmp(hier, "SINGLE_PARENT") && | |
450 | * strcmp(hier, "PASSTHROUGH_PARENT") && | |
451 | * strcmp(hier, "SSL_PARENT_MISS") && | |
452 | * strcmp(hier, "DEFAULT_PARENT"); | |
453 | */ | |
41d00cd3 | 454 | memcpy(entry->key, storeKeyPublic(url, method_id), sizeof(entry->key)); |
62e76326 | 455 | |
6d80b36f | 456 | /*fprintf(stdout, "%s:%d: %s %s %s %s\n", |
b644367b | 457 | * fname, count, method, storeKeyText(entry->key), url, hier); */ |
6d80b36f | 458 | return frOk; |
459 | } | |
460 | ||
6d80b36f | 461 | static void |
b644367b | 462 | cachePurge(Cache * cache, storeSwapLogData * s, int update_digest) |
6d80b36f | 463 | { |
464 | CacheEntry *olde = (CacheEntry *) hash_lookup(cache->hash, s->key); | |
62e76326 | 465 | |
6d80b36f | 466 | if (!olde) { |
5db6bf73 | 467 | ++ cache->bad_del_count; |
6d80b36f | 468 | } else { |
62e76326 | 469 | assert(cache->count); |
470 | hash_remove_link(cache->hash, (hash_link *) olde); | |
471 | ||
472 | if (update_digest) | |
fbba122c | 473 | cache->digest->remove(s->key); |
62e76326 | 474 | |
475 | cacheEntryDestroy(olde); | |
476 | ||
5e263176 | 477 | -- cache->count; |
6d80b36f | 478 | } |
479 | } | |
480 | ||
481 | static void | |
b644367b | 482 | cacheStore(Cache * cache, storeSwapLogData * s, int update_digest) |
6d80b36f | 483 | { |
484 | CacheEntry *olde = (CacheEntry *) hash_lookup(cache->hash, s->key); | |
62e76326 | 485 | |
6d80b36f | 486 | if (olde) { |
5db6bf73 | 487 | ++ cache->bad_add_count; |
6d80b36f | 488 | } else { |
62e76326 | 489 | CacheEntry *e = cacheEntryCreate(s); |
490 | hash_join(cache->hash, (hash_link *)&e->key); | |
5db6bf73 | 491 | ++ cache->count; |
62e76326 | 492 | |
493 | if (update_digest) | |
fbba122c | 494 | cache->digest->add(e->key); |
6d80b36f | 495 | } |
496 | } | |
497 | ||
498 | static void | |
b644367b | 499 | cacheUpdateStore(Cache * cache, storeSwapLogData * s, int update_digest) |
6d80b36f | 500 | { |
501 | switch (s->op) { | |
62e76326 | 502 | |
b644367b | 503 | case SWAP_LOG_ADD: |
62e76326 | 504 | cacheStore(cache, s, update_digest); |
505 | break; | |
506 | ||
b644367b | 507 | case SWAP_LOG_DEL: |
62e76326 | 508 | cachePurge(cache, s, update_digest); |
509 | break; | |
510 | ||
b644367b | 511 | default: |
62e76326 | 512 | assert(0); |
76e3f5c2 | 513 | } |
76e3f5c2 | 514 | } |
515 | ||
c411be12 | 516 | static int |
517 | usage(const char *prg_name) | |
518 | { | |
519 | fprintf(stderr, "usage: %s <access_log> <swap_state> ...\n", | |
62e76326 | 520 | prg_name); |
24885773 | 521 | return EXIT_FAILURE; |
c411be12 | 522 | } |
523 | ||
524 | int | |
525 | main(int argc, char *argv[]) | |
526 | { | |
a1b1756c | 527 | FileIterator **fis = nullptr; |
b644367b | 528 | const int fi_count = argc - 1; |
6d80b36f | 529 | int active_fi_count = 0; |
b2ab5fd1 | 530 | time_t ready_time; |
6d80b36f | 531 | Cache *them, *us; |
532 | int i; | |
c411be12 | 533 | |
534 | if (argc < 3) | |
62e76326 | 535 | return usage(argv[0]); |
c411be12 | 536 | |
6d80b36f | 537 | them = cacheCreate("them"); |
62e76326 | 538 | |
6d80b36f | 539 | us = cacheCreate("us"); |
62e76326 | 540 | |
6d80b36f | 541 | them->peer = us; |
62e76326 | 542 | |
6d80b36f | 543 | us->peer = them; |
544 | ||
e6ccf245 | 545 | fis = (FileIterator **)xcalloc(fi_count, sizeof(FileIterator *)); |
62e76326 | 546 | |
00b23815 | 547 | /* init iterators with files */ |
548 | fis[0] = fileIteratorCreate(argv[1], accessLogReader); | |
62e76326 | 549 | |
37eeba76 | 550 | for (i = 2; i < argc; ++i) |
62e76326 | 551 | fis[i - 1] = fileIteratorCreate(argv[i], swapStateReader); |
552 | ||
37eeba76 | 553 | /* check that all files were found */ |
554 | for (i = 0; i < fi_count; ++i) | |
62e76326 | 555 | if (!fis[i]) |
556 | return -2; | |
557 | ||
6d80b36f | 558 | /* read prefix to get start-up contents of the peer cache */ |
b2ab5fd1 | 559 | ready_time = -1; |
62e76326 | 560 | |
00b23815 | 561 | for (i = 1; i < fi_count; ++i) { |
62e76326 | 562 | FileIterator *fi = fis[i]; |
563 | ||
564 | while (fi->inner_time > 0) { | |
565 | if (((storeSwapLogData *) fi->entry)->op == SWAP_LOG_DEL) { | |
566 | cachePurge(them, (storeSwapLogData *)fi->entry, 0); | |
567 | ||
568 | if (ready_time < 0) | |
569 | ready_time = fi->inner_time; | |
570 | } else { | |
571 | if (ready_time > 0 && fi->inner_time > ready_time) | |
572 | break; | |
573 | ||
574 | cacheStore(them, (storeSwapLogData *)fi->entry, 0); | |
575 | } | |
576 | ||
577 | fileIteratorAdvance(fi); | |
578 | } | |
00b23815 | 579 | } |
62e76326 | 580 | |
00b23815 | 581 | /* digest peer cache content */ |
6d80b36f | 582 | cacheResetDigest(them); |
62e76326 | 583 | |
fab3d38b | 584 | us->digest = them->digest->clone(); |
6d80b36f | 585 | |
b2ab5fd1 | 586 | /* shift the time in access log to match ready_time */ |
587 | fileIteratorSetCurTime(fis[0], ready_time); | |
588 | ||
6d80b36f | 589 | /* iterate, use the iterator with the smallest positive inner_time */ |
00b23815 | 590 | cur_time = -1; |
62e76326 | 591 | |
6d80b36f | 592 | do { |
62e76326 | 593 | int next_i = -1; |
594 | time_t next_time = -1; | |
595 | active_fi_count = 0; | |
596 | ||
597 | for (i = 0; i < fi_count; ++i) { | |
598 | if (fis[i]->inner_time >= 0) { | |
599 | if (!active_fi_count || fis[i]->inner_time < next_time) { | |
600 | next_i = i; | |
601 | next_time = fis[i]->inner_time; | |
602 | } | |
603 | ||
5db6bf73 | 604 | ++active_fi_count; |
62e76326 | 605 | } |
606 | } | |
607 | ||
608 | if (next_i >= 0) { | |
609 | cur_time = next_time; | |
610 | /*fprintf(stderr, "%2d time: %d %s", next_i, (int)cur_time, ctime(&cur_time)); */ | |
611 | ||
612 | if (next_i == 0) | |
613 | cacheFetch(us, (RawAccessLogEntry *)fis[next_i]->entry); | |
614 | else | |
615 | cacheUpdateStore(them, (storeSwapLogData *)fis[next_i]->entry, 1); | |
616 | ||
617 | fileIteratorAdvance(fis[next_i]); | |
618 | } | |
6d80b36f | 619 | } while (active_fi_count); |
620 | ||
621 | /* report */ | |
c2186446 | 622 | cacheReport(them); |
62e76326 | 623 | |
c2186446 | 624 | cacheReport(us); |
62e76326 | 625 | |
6d80b36f | 626 | cacheQueryReport(us, &us->qstats); |
627 | ||
628 | /* clean */ | |
b644367b | 629 | for (i = 0; i < argc - 1; ++i) { |
62e76326 | 630 | fileIteratorDestroy(fis[i]); |
00b23815 | 631 | } |
62e76326 | 632 | |
00b23815 | 633 | xfree(fis); |
6d80b36f | 634 | cacheDestroy(them); |
635 | cacheDestroy(us); | |
24885773 | 636 | return EXIT_SUCCESS; |
c411be12 | 637 | } |
f53969cc | 638 |