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