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