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