]>
Commit | Line | Data |
---|---|---|
f740a279 | 1 | |
8667b856 | 2 | /* |
186477c1 | 3 | * $Id: cache_diff.cc,v 1.13 2000/10/31 23:48:13 wessels Exp $ |
8667b856 | 4 | * |
5 | * AUTHOR: Alex Rousskov | |
6 | * | |
7 | * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ | |
e25c139f | 8 | * ---------------------------------------------------------- |
8667b856 | 9 | * |
10 | * Squid is the result of efforts by numerous individuals from the | |
11 | * Internet community. Development is led by Duane Wessels of the | |
e25c139f | 12 | * National Laboratory for Applied Network Research and funded by the |
13 | * National Science Foundation. Squid is Copyrighted (C) 1998 by | |
efd900cb | 14 | * the Regents of the University of California. Please see the |
15 | * COPYRIGHT file for full details. Squid incorporates software | |
16 | * developed and/or copyrighted by other sources. Please see the | |
17 | * CREDITS file for full details. | |
8667b856 | 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 | * |
8667b856 | 33 | */ |
34 | ||
35 | /* | |
36 | * Computes the difference between the contents of two caches | |
37 | * using swap logs | |
38 | * Reports the percentage of common files and other stats | |
39 | */ | |
40 | ||
41 | #include "squid.h" | |
42 | ||
43 | typedef struct { | |
44 | const char *name; | |
45 | hash_table *hash; | |
1afe05c5 | 46 | int count; /* #currently cached entries */ |
47 | int scanned_count; /* #scanned entries */ | |
48 | int bad_add_count; /* #duplicate adds */ | |
49 | int bad_del_count; /* #dels with no prior add */ | |
8667b856 | 50 | } CacheIndex; |
51 | ||
52 | ||
53 | typedef struct _CacheEntry { | |
54 | const cache_key *key; | |
55 | struct _CacheEntry *next; | |
edc1d6da | 56 | /* storeSwapLogData s; */ |
57 | unsigned char key_arr[MD5_DIGEST_CHARS]; | |
8667b856 | 58 | } CacheEntry; |
59 | ||
60 | ||
61 | /* copied from url.c */ | |
62 | const char *RequestMethodStr[] = | |
63 | { | |
64 | "NONE", | |
65 | "GET", | |
66 | "POST", | |
67 | "PUT", | |
68 | "HEAD", | |
69 | "CONNECT", | |
70 | "TRACE", | |
71 | "PURGE" | |
72 | }; | |
73 | ||
74 | ||
1afe05c5 | 75 | static int cacheIndexScan(CacheIndex * idx, const char *fname, FILE * file); |
8667b856 | 76 | |
77 | ||
78 | static CacheEntry * | |
1afe05c5 | 79 | cacheEntryCreate(const storeSwapLogData * s) |
8667b856 | 80 | { |
81 | CacheEntry *e = xcalloc(1, sizeof(CacheEntry)); | |
82 | assert(s); | |
edc1d6da | 83 | /* e->s = *s; */ |
84 | xmemcpy(e->key_arr, s->key, MD5_DIGEST_CHARS); | |
85 | e->key = &e->key_arr[0]; | |
8667b856 | 86 | return e; |
87 | } | |
88 | ||
89 | static void | |
1afe05c5 | 90 | cacheEntryDestroy(CacheEntry * e) |
8667b856 | 91 | { |
92 | assert(e); | |
93 | xfree(e); | |
94 | } | |
95 | ||
96 | static CacheIndex * | |
97 | cacheIndexCreate(const char *name) | |
98 | { | |
99 | CacheIndex *idx; | |
100 | if (!name || !strlen(name)) | |
101 | return NULL; | |
102 | ||
103 | idx = xcalloc(1, sizeof(CacheIndex)); | |
104 | idx->name = name; | |
105 | idx->hash = hash_create(storeKeyHashCmp, 2e6, storeKeyHashHash); | |
106 | ||
107 | return idx; | |
108 | } | |
109 | ||
110 | static void | |
1afe05c5 | 111 | cacheIndexDestroy(CacheIndex * idx) |
8667b856 | 112 | { |
113 | hash_link *hashr = NULL; | |
114 | if (idx) { | |
115 | /* destroy hash list contents */ | |
0f6bebac | 116 | hash_first(idx->hash); |
117 | while (hashr = hash_next(idx->hash)) { | |
8667b856 | 118 | hash_remove_link(idx->hash, hashr); |
1afe05c5 | 119 | cacheEntryDestroy((CacheEntry *) hashr); |
8667b856 | 120 | } |
121 | /* destroy the hash table itself */ | |
122 | hashFreeMemory(idx->hash); | |
123 | xfree(idx); | |
124 | } | |
125 | } | |
126 | ||
127 | static int | |
1afe05c5 | 128 | cacheIndexAddLog(CacheIndex * idx, const char *fname) |
8667b856 | 129 | { |
130 | FILE *file; | |
131 | int scanned_count = 0; | |
132 | assert(idx); | |
133 | assert(fname && strlen(fname)); | |
134 | ||
135 | file = fopen(fname, "r"); | |
136 | if (!file) { | |
137 | fprintf(stderr, "cannot open %s: %s\n", fname, strerror(errno)); | |
138 | return 0; | |
139 | } | |
8667b856 | 140 | scanned_count = cacheIndexScan(idx, fname, file); |
141 | ||
142 | fclose(file); | |
143 | return scanned_count; | |
144 | } | |
145 | ||
146 | static void | |
1afe05c5 | 147 | cacheIndexInitReport(CacheIndex * idx) |
8667b856 | 148 | { |
149 | assert(idx); | |
150 | fprintf(stderr, "%s: bad swap_add: %d\n", | |
151 | idx->name, idx->bad_add_count); | |
1afe05c5 | 152 | fprintf(stderr, "%s: bad swap_del: %d\n", |
8667b856 | 153 | idx->name, idx->bad_del_count); |
1afe05c5 | 154 | fprintf(stderr, "%s: scanned lines: %d\n", |
8667b856 | 155 | idx->name, idx->scanned_count); |
156 | } | |
157 | ||
158 | static int | |
1afe05c5 | 159 | cacheIndexScan(CacheIndex * idx, const char *fname, FILE * file) |
8667b856 | 160 | { |
161 | int count = 0; | |
162 | storeSwapLogData s; | |
163 | fprintf(stderr, "%s scanning\n", fname); | |
164 | while (fread(&s, sizeof(s), 1, file) == 1) { | |
165 | count++; | |
166 | idx->scanned_count++; | |
167 | /* if (s.op <= SWAP_LOG_NOP || s.op >= SWAP_LOG_MAX) | |
1afe05c5 | 168 | * continue; */ |
8667b856 | 169 | if (s.op == SWAP_LOG_ADD) { |
170 | CacheEntry *olde = (CacheEntry *) hash_lookup(idx->hash, s.key); | |
171 | if (olde) { | |
172 | idx->bad_add_count++; | |
173 | } else { | |
174 | CacheEntry *e = cacheEntryCreate(&s); | |
186477c1 | 175 | hash_join(idx->hash, &e->hash); |
8667b856 | 176 | idx->count++; |
177 | } | |
1afe05c5 | 178 | } else if (s.op == SWAP_LOG_DEL) { |
8667b856 | 179 | CacheEntry *olde = (CacheEntry *) hash_lookup(idx->hash, s.key); |
180 | if (!olde) | |
181 | idx->bad_del_count++; | |
182 | else { | |
681e7924 | 183 | assert(idx->count); |
1afe05c5 | 184 | hash_remove_link(idx->hash, (hash_link *) olde); |
681e7924 | 185 | cacheEntryDestroy(olde); |
186 | idx->count--; | |
8667b856 | 187 | } |
188 | } else { | |
189 | fprintf(stderr, "%s:%d: unknown swap log action\n", fname, count); | |
190 | exit(-3); | |
191 | } | |
192 | } | |
1afe05c5 | 193 | fprintf(stderr, "%s:%d: scanned (size: %d bytes)\n", |
194 | fname, count, (int) (count * sizeof(CacheEntry))); | |
8667b856 | 195 | return count; |
196 | } | |
197 | ||
198 | static void | |
1afe05c5 | 199 | cacheIndexCmpReport(CacheIndex * idx, int shared_count) |
8667b856 | 200 | { |
201 | assert(idx && shared_count <= idx->count); | |
202 | ||
f97c9706 | 203 | printf("%s:\t %7d = %7d + %7d (%7.2f%% + %7.2f%%)\n", |
204 | idx->name, | |
205 | idx->count, | |
7028e201 | 206 | idx->count - shared_count, |
207 | shared_count, | |
1afe05c5 | 208 | xpercent(idx->count - shared_count, idx->count), |
8667b856 | 209 | xpercent(shared_count, idx->count)); |
210 | } | |
211 | ||
212 | static void | |
1afe05c5 | 213 | cacheIndexCmp(CacheIndex * idx1, CacheIndex * idx2) |
8667b856 | 214 | { |
215 | int shared_count = 0; | |
681e7924 | 216 | int hashed_count = 0; |
8667b856 | 217 | hash_link *hashr = NULL; |
218 | CacheIndex *small_idx = idx1; | |
219 | CacheIndex *large_idx = idx2; | |
220 | assert(idx1 && idx2); | |
221 | ||
222 | /* check our guess */ | |
223 | if (idx1->count > idx2->count) { | |
224 | small_idx = idx2; | |
225 | large_idx = idx1; | |
226 | } | |
227 | /* find shared_count */ | |
0f6bebac | 228 | hash_first(small_idx->hash); |
229 | for (hashr = hash_next(small_idx->hash)) { | |
681e7924 | 230 | hashed_count++; |
8667b856 | 231 | if (hash_lookup(large_idx->hash, hashr->key)) |
232 | shared_count++; | |
233 | } | |
681e7924 | 234 | assert(hashed_count == small_idx->count); |
8667b856 | 235 | |
236 | cacheIndexCmpReport(idx1, shared_count); | |
237 | cacheIndexCmpReport(idx2, shared_count); | |
238 | } | |
239 | ||
240 | ||
241 | static int | |
242 | usage(const char *prg_name) | |
243 | { | |
244 | fprintf(stderr, "usage: %s <label1>: <swap_state>... <label2>: <swap_state>...\n", | |
245 | prg_name); | |
246 | return -1; | |
247 | } | |
248 | ||
249 | int | |
250 | main(int argc, char *argv[]) | |
251 | { | |
252 | CacheIndex *CacheIdx[2]; | |
253 | CacheIndex *idx = NULL; | |
254 | int idxCount = 0; | |
255 | int i; | |
256 | ||
257 | if (argc < 5) | |
258 | return usage(argv[0]); | |
259 | ||
260 | for (i = 1; i < argc; ++i) { | |
261 | const int len = strlen(argv[i]); | |
262 | if (!len) | |
263 | return usage(argv[0]); | |
1afe05c5 | 264 | if (argv[i][len - 1] == ':') { |
8667b856 | 265 | idxCount++; |
266 | if (len < 2 || idxCount > 2) | |
267 | return usage(argv[0]); | |
268 | idx = cacheIndexCreate(argv[i]); | |
1afe05c5 | 269 | CacheIdx[idxCount - 1] = idx; |
8667b856 | 270 | } else { |
271 | if (!idx) | |
272 | return usage(argv[0]); | |
273 | cacheIndexAddLog(idx, argv[i]); | |
274 | } | |
275 | } | |
276 | ||
277 | if (idxCount != 2) | |
278 | return usage(argv[0]); | |
279 | ||
280 | cacheIndexInitReport(CacheIdx[0]); | |
281 | cacheIndexInitReport(CacheIdx[1]); | |
282 | ||
283 | cacheIndexCmp(CacheIdx[0], CacheIdx[1]); | |
284 | ||
285 | cacheIndexDestroy(CacheIdx[0]); | |
286 | cacheIndexDestroy(CacheIdx[1]); | |
287 | ||
288 | return 1; | |
289 | } |