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