]> git.ipfire.org Git - thirdparty/squid.git/blame - src/test_cache_digest.cc
Prep for 3.3.12 and 3.4.4
[thirdparty/squid.git] / src / test_cache_digest.cc
CommitLineData
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 45typedef 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
53typedef struct _Cache Cache;
62e76326 54
26ac0430 55struct _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 67typedef 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 77typedef 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 83typedef enum {
84 frError = -2, frMore = -1, frEof = 0, frOk = 1
85} fr_result;
62e76326 86
6d80b36f 87typedef struct _FileIterator FileIterator;
b644367b 88typedef fr_result(*FI_READER) (FileIterator * fi);
00b23815 89
26ac0430 90struct _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 103static time_t cur_time = -1; /* timestamp of the current log entry */
6d80b36f 104
c411be12 105/* copied from url.c */
26ac0430
AJ
106const 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 118static HttpRequestMethod
6d80b36f 119methodStrToId(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 142static void fileIteratorAdvance(FileIterator * fi);
6d80b36f 143
00b23815 144static FileIterator *
145fileIteratorCreate(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
164static void
b644367b 165fileIteratorDestroy(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 178static void
b644367b 179fileIteratorSetCurTime(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 186static void
b644367b 187fileIteratorAdvance(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 225static CacheEntry *
226cacheEntryCreate(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 236static void
237cacheEntryDestroy(CacheEntry * e)
c411be12 238{
6d80b36f 239 assert(e);
240 xfree(e);
241}
242
6d80b36f 243/* Cache */
c411be12 244
6d80b36f 245static Cache *
246cacheCreate(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
256static void
6d80b36f 257cacheDestroy(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 281static void
6d80b36f 282cacheResetDigest(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
331static void
332cacheQueryPeer(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
352static void
b644367b 353cacheQueryReport(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 375static void
376cacheReport(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 384static void
b644367b 385cacheFetch(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
394static fr_result
395swapStateReader(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
417static fr_result
418accessLogReader(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 503static void
b644367b 504cachePurge(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
523static void
b644367b 524cacheStore(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
540static void
b644367b 541cacheUpdateStore(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 558static int
559usage(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
566int
567main(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}