]> git.ipfire.org Git - thirdparty/squid.git/blob - src/cache_diff.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / cache_diff.cc
1 /*
2 * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9 /*
10 * Computes the difference between the contents of two caches
11 * using swap logs
12 * Reports the percentage of common files and other stats
13 */
14
15 #include "squid.h"
16 #include <cerrno>
17
18 typedef struct {
19 const char *name;
20 hash_table *hash;
21 int count; /* #currently cached entries */
22 int scanned_count; /* #scanned entries */
23 int bad_add_count; /* #duplicate adds */
24 int bad_del_count; /* #dels with no prior add */
25 } CacheIndex;
26
27 typedef struct _CacheEntry {
28 const cache_key *key;
29
30 struct _CacheEntry *next;
31 /* StoreSwapLogData s; */
32 unsigned char key_arr[SQUID_MD5_DIGEST_LENGTH];
33 } CacheEntry;
34
35 static int cacheIndexScan(CacheIndex * idx, const char *fname, FILE * file);
36
37 static CacheEntry *
38 cacheEntryCreate(const StoreSwapLogData * s)
39 {
40 CacheEntry *e = xcalloc(1, sizeof(CacheEntry));
41 assert(s);
42 /* e->s = *s; */
43 memcpy(e->key_arr, s->key, SQUID_MD5_DIGEST_LENGTH);
44 e->key = &e->key_arr[0];
45 return e;
46 }
47
48 static void
49 cacheEntryDestroy(CacheEntry * e)
50 {
51 assert(e);
52 xfree(e);
53 }
54
55 static CacheIndex *
56 cacheIndexCreate(const char *name)
57 {
58 CacheIndex *idx;
59
60 if (!name || !strlen(name))
61 return NULL;
62
63 idx = xcalloc(1, sizeof(CacheIndex));
64
65 idx->name = name;
66
67 idx->hash = hash_create(storeKeyHashCmp, 2e6, storeKeyHashHash);
68
69 return idx;
70 }
71
72 static void
73 cacheIndexDestroy(CacheIndex * idx)
74 {
75 hash_link *hashr = NULL;
76
77 if (idx) {
78 /* destroy hash list contents */
79 hash_first(idx->hash);
80
81 while (hashr = hash_next(idx->hash)) {
82 hash_remove_link(idx->hash, hashr);
83 cacheEntryDestroy((CacheEntry *) hashr);
84 }
85
86 /* destroy the hash table itself */
87 hashFreeMemory(idx->hash);
88
89 xfree(idx);
90 }
91 }
92
93 static int
94 cacheIndexAddLog(CacheIndex * idx, const char *fname)
95 {
96 FILE *file;
97 int scanned_count = 0;
98 assert(idx);
99 assert(fname && strlen(fname));
100
101 file = fopen(fname, "r");
102
103 if (!file) {
104 fprintf(stderr, "cannot open %s: %s\n", fname, strerror(errno));
105 return 0;
106 }
107
108 #if _SQUID_WINDOWS_
109 setmode(fileno(file), O_BINARY);
110 #endif
111
112 scanned_count = cacheIndexScan(idx, fname, file);
113
114 fclose(file);
115
116 return scanned_count;
117 }
118
119 static void
120 cacheIndexInitReport(CacheIndex * idx)
121 {
122 assert(idx);
123 fprintf(stderr, "%s: bad swap_add: %d\n",
124 idx->name, idx->bad_add_count);
125 fprintf(stderr, "%s: bad swap_del: %d\n",
126 idx->name, idx->bad_del_count);
127 fprintf(stderr, "%s: scanned lines: %d\n",
128 idx->name, idx->scanned_count);
129 }
130
131 static int
132 cacheIndexScan(CacheIndex * idx, const char *fname, FILE * file)
133 {
134 int count = 0;
135 StoreSwapLogData s;
136 fprintf(stderr, "%s scanning\n", fname);
137
138 while (fread(&s, sizeof(s), 1, file) == 1) {
139 ++count;
140 ++ idx->scanned_count;
141 /* if (!s.sane())
142 * continue; */
143
144 if (s.op == SWAP_LOG_ADD) {
145 CacheEntry *olde = (CacheEntry *) hash_lookup(idx->hash, s.key);
146
147 if (olde) {
148 ++ idx->bad_add_count;
149 } else {
150 CacheEntry *e = cacheEntryCreate(&s);
151 hash_join(idx->hash, &e->hash);
152 ++ idx->count;
153 }
154 } else if (s.op == SWAP_LOG_DEL) {
155 CacheEntry *olde = (CacheEntry *) hash_lookup(idx->hash, s.key);
156
157 if (!olde)
158 ++ idx->bad_del_count;
159 else {
160 assert(idx->count);
161 hash_remove_link(idx->hash, (hash_link *) olde);
162 cacheEntryDestroy(olde);
163 -- idx->count;
164 }
165 } else {
166 fprintf(stderr, "%s:%d: unknown swap log action\n", fname, count);
167 exit(-3);
168 }
169 }
170
171 fprintf(stderr, "%s:%d: scanned (size: %d bytes)\n",
172 fname, count, (int) (count * sizeof(CacheEntry)));
173 return count;
174 }
175
176 static void
177 cacheIndexCmpReport(CacheIndex * idx, int shared_count)
178 {
179 assert(idx && shared_count <= idx->count);
180
181 printf("%s:\t %7d = %7d + %7d (%7.2f%% + %7.2f%%)\n",
182 idx->name,
183 idx->count,
184 idx->count - shared_count,
185 shared_count,
186 xpercent(idx->count - shared_count, idx->count),
187 xpercent(shared_count, idx->count));
188 }
189
190 static void
191 cacheIndexCmp(CacheIndex * idx1, CacheIndex * idx2)
192 {
193 int shared_count = 0;
194 int hashed_count = 0;
195 hash_link *hashr = NULL;
196 CacheIndex *small_idx = idx1;
197 CacheIndex *large_idx = idx2;
198 assert(idx1 && idx2);
199
200 /* check our guess */
201
202 if (idx1->count > idx2->count) {
203 small_idx = idx2;
204 large_idx = idx1;
205 }
206
207 /* find shared_count */
208 hash_first(small_idx->hash);
209
210 for (hashr = hash_next(small_idx->hash)) {
211 ++hashed_count;
212
213 if (hash_lookup(large_idx->hash, hashr->key))
214 ++shared_count;
215 }
216
217 assert(hashed_count == small_idx->count);
218
219 cacheIndexCmpReport(idx1, shared_count);
220 cacheIndexCmpReport(idx2, shared_count);
221 }
222
223 static int
224 usage(const char *prg_name)
225 {
226 fprintf(stderr, "usage: %s <label1>: <swap_state>... <label2>: <swap_state>...\n",
227 prg_name);
228 return -1;
229 }
230
231 int
232 main(int argc, char *argv[])
233 {
234 CacheIndex *CacheIdx[2];
235 CacheIndex *idx = NULL;
236 int idxCount = 0;
237 int i;
238
239 if (argc < 5)
240 return usage(argv[0]);
241
242 for (i = 1; i < argc; ++i) {
243 const int len = strlen(argv[i]);
244
245 if (!len)
246 return usage(argv[0]);
247
248 if (argv[i][len - 1] == ':') {
249 ++idxCount;
250
251 if (len < 2 || idxCount > 2)
252 return usage(argv[0]);
253
254 idx = cacheIndexCreate(argv[i]);
255
256 CacheIdx[idxCount - 1] = idx;
257 } else {
258 if (!idx)
259 return usage(argv[0]);
260
261 cacheIndexAddLog(idx, argv[i]);
262 }
263 }
264
265 if (idxCount != 2)
266 return usage(argv[0]);
267
268 cacheIndexInitReport(CacheIdx[0]);
269
270 cacheIndexInitReport(CacheIdx[1]);
271
272 cacheIndexCmp(CacheIdx[0], CacheIdx[1]);
273
274 cacheIndexDestroy(CacheIdx[0]);
275
276 cacheIndexDestroy(CacheIdx[1]);
277
278 return 1;
279 }
280