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