]>
Commit | Line | Data |
---|---|---|
8667b856 | 1 | /* |
94faad3e | 2 | * $Id: cache_diff.cc,v 1.2 1998/03/29 20:18:46 rousskov 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 | |
26 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
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; | |
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 */ | |
45 | } CacheIndex; | |
46 | ||
47 | ||
48 | typedef struct _CacheEntry { | |
49 | const cache_key *key; | |
50 | struct _CacheEntry *next; | |
51 | storeSwapLogData s; | |
52 | } CacheEntry; | |
53 | ||
54 | ||
55 | /* copied from url.c */ | |
56 | const char *RequestMethodStr[] = | |
57 | { | |
58 | "NONE", | |
59 | "GET", | |
60 | "POST", | |
61 | "PUT", | |
62 | "HEAD", | |
63 | "CONNECT", | |
64 | "TRACE", | |
65 | "PURGE" | |
66 | }; | |
67 | ||
68 | ||
69 | static int cacheIndexScan(CacheIndex *idx, const char *fname, FILE *file); | |
70 | ||
71 | ||
72 | static CacheEntry * | |
73 | cacheEntryCreate(const storeSwapLogData *s) | |
74 | { | |
75 | CacheEntry *e = xcalloc(1, sizeof(CacheEntry)); | |
76 | assert(s); | |
77 | e->s = *s; | |
78 | e->key = &e->s.key[0]; | |
79 | return e; | |
80 | } | |
81 | ||
82 | static void | |
83 | cacheEntryDestroy(CacheEntry *e) | |
84 | { | |
85 | assert(e); | |
86 | xfree(e); | |
87 | } | |
88 | ||
89 | static CacheIndex * | |
90 | cacheIndexCreate(const char *name) | |
91 | { | |
92 | CacheIndex *idx; | |
93 | if (!name || !strlen(name)) | |
94 | return NULL; | |
95 | ||
96 | idx = xcalloc(1, sizeof(CacheIndex)); | |
97 | idx->name = name; | |
98 | idx->hash = hash_create(storeKeyHashCmp, 2e6, storeKeyHashHash); | |
99 | ||
100 | return idx; | |
101 | } | |
102 | ||
103 | static void | |
104 | cacheIndexDestroy(CacheIndex *idx) | |
105 | { | |
106 | hash_link *hashr = NULL; | |
107 | if (idx) { | |
108 | /* destroy hash list contents */ | |
109 | for (hashr = hash_first(idx->hash); hashr; hashr = hash_next(idx->hash)) { | |
110 | hash_remove_link(idx->hash, hashr); | |
111 | cacheEntryDestroy((CacheEntry*)hashr); | |
112 | } | |
113 | /* destroy the hash table itself */ | |
114 | hashFreeMemory(idx->hash); | |
115 | xfree(idx); | |
116 | } | |
117 | } | |
118 | ||
119 | static int | |
120 | cacheIndexAddLog(CacheIndex *idx, const char *fname) | |
121 | { | |
122 | FILE *file; | |
123 | int scanned_count = 0; | |
124 | assert(idx); | |
125 | assert(fname && strlen(fname)); | |
126 | ||
127 | file = fopen(fname, "r"); | |
128 | if (!file) { | |
129 | fprintf(stderr, "cannot open %s: %s\n", fname, strerror(errno)); | |
130 | return 0; | |
131 | } | |
132 | ||
133 | scanned_count = cacheIndexScan(idx, fname, file); | |
134 | ||
135 | fclose(file); | |
136 | return scanned_count; | |
137 | } | |
138 | ||
139 | static void | |
140 | cacheIndexInitReport(CacheIndex *idx) | |
141 | { | |
142 | assert(idx); | |
143 | fprintf(stderr, "%s: bad swap_add: %d\n", | |
144 | idx->name, idx->bad_add_count); | |
145 | fprintf(stderr, "%s: bad swap_del: %d\n", | |
146 | idx->name, idx->bad_del_count); | |
147 | fprintf(stderr, "%s: scanned lines: %d\n", | |
148 | idx->name, idx->scanned_count); | |
149 | } | |
150 | ||
151 | static int | |
152 | cacheIndexScan(CacheIndex *idx, const char *fname, FILE *file) | |
153 | { | |
154 | int count = 0; | |
155 | storeSwapLogData s; | |
156 | fprintf(stderr, "%s scanning\n", fname); | |
157 | while (fread(&s, sizeof(s), 1, file) == 1) { | |
158 | count++; | |
159 | idx->scanned_count++; | |
160 | /* if (s.op <= SWAP_LOG_NOP || s.op >= SWAP_LOG_MAX) | |
161 | continue; */ | |
162 | if (s.op == SWAP_LOG_ADD) { | |
163 | CacheEntry *olde = (CacheEntry *) hash_lookup(idx->hash, s.key); | |
164 | if (olde) { | |
165 | idx->bad_add_count++; | |
166 | } else { | |
167 | CacheEntry *e = cacheEntryCreate(&s); | |
168 | hash_join(idx->hash, (hash_link*) e); | |
169 | idx->count++; | |
170 | } | |
171 | } else | |
172 | if (s.op == SWAP_LOG_DEL) { | |
173 | CacheEntry *olde = (CacheEntry *) hash_lookup(idx->hash, s.key); | |
174 | if (!olde) | |
175 | idx->bad_del_count++; | |
176 | else { | |
94faad3e | 177 | hash_remove_link(idx->hash, (hash_link*) olde); |
8667b856 | 178 | } |
179 | } else { | |
180 | fprintf(stderr, "%s:%d: unknown swap log action\n", fname, count); | |
181 | exit(-3); | |
182 | } | |
183 | } | |
184 | fprintf(stderr, "%s:%d: scanned (size: %d bytes)\n", | |
185 | fname, count, count*sizeof(CacheEntry)); | |
186 | return count; | |
187 | } | |
188 | ||
189 | static void | |
190 | cacheIndexCmpReport(CacheIndex *idx, int shared_count) | |
191 | { | |
192 | assert(idx && shared_count <= idx->count); | |
193 | ||
194 | printf("%s:\t %7d %7.2f%% + %7.2f%%\n", | |
195 | idx->name, | |
196 | idx->count, | |
197 | xpercent(idx->count-shared_count, idx->count), | |
198 | xpercent(shared_count, idx->count)); | |
199 | } | |
200 | ||
201 | static void | |
202 | cacheIndexCmp(CacheIndex *idx1, CacheIndex *idx2) | |
203 | { | |
204 | int shared_count = 0; | |
205 | hash_link *hashr = NULL; | |
206 | CacheIndex *small_idx = idx1; | |
207 | CacheIndex *large_idx = idx2; | |
208 | assert(idx1 && idx2); | |
209 | ||
210 | /* check our guess */ | |
211 | if (idx1->count > idx2->count) { | |
212 | small_idx = idx2; | |
213 | large_idx = idx1; | |
214 | } | |
215 | /* find shared_count */ | |
216 | for (hashr = hash_first(small_idx->hash); hashr; hashr = hash_next(small_idx->hash)) { | |
217 | if (hash_lookup(large_idx->hash, hashr->key)) | |
218 | shared_count++; | |
219 | } | |
220 | ||
221 | cacheIndexCmpReport(idx1, shared_count); | |
222 | cacheIndexCmpReport(idx2, shared_count); | |
223 | } | |
224 | ||
225 | ||
226 | static int | |
227 | usage(const char *prg_name) | |
228 | { | |
229 | fprintf(stderr, "usage: %s <label1>: <swap_state>... <label2>: <swap_state>...\n", | |
230 | prg_name); | |
231 | return -1; | |
232 | } | |
233 | ||
234 | int | |
235 | main(int argc, char *argv[]) | |
236 | { | |
237 | CacheIndex *CacheIdx[2]; | |
238 | CacheIndex *idx = NULL; | |
239 | int idxCount = 0; | |
240 | int i; | |
241 | ||
242 | if (argc < 5) | |
243 | return usage(argv[0]); | |
244 | ||
245 | for (i = 1; i < argc; ++i) { | |
246 | const int len = strlen(argv[i]); | |
247 | if (!len) | |
248 | return usage(argv[0]); | |
249 | if (argv[i][len-1] == ':') { | |
250 | idxCount++; | |
251 | if (len < 2 || idxCount > 2) | |
252 | return usage(argv[0]); | |
253 | idx = cacheIndexCreate(argv[i]); | |
254 | CacheIdx[idxCount-1] = idx; | |
255 | } else { | |
256 | if (!idx) | |
257 | return usage(argv[0]); | |
258 | cacheIndexAddLog(idx, argv[i]); | |
259 | } | |
260 | } | |
261 | ||
262 | if (idxCount != 2) | |
263 | return usage(argv[0]); | |
264 | ||
265 | cacheIndexInitReport(CacheIdx[0]); | |
266 | cacheIndexInitReport(CacheIdx[1]); | |
267 | ||
268 | cacheIndexCmp(CacheIdx[0], CacheIdx[1]); | |
269 | ||
270 | cacheIndexDestroy(CacheIdx[0]); | |
271 | cacheIndexDestroy(CacheIdx[1]); | |
272 | ||
273 | return 1; | |
274 | } |