]> git.ipfire.org Git - thirdparty/squid.git/blob - src/cache_diff.cc
Updated copyright
[thirdparty/squid.git] / src / cache_diff.cc
1
2 /*
3 * $Id: cache_diff.cc,v 1.15 2001/01/12 00:37:15 wessels Exp $
4 *
5 * AUTHOR: Alex Rousskov
6 *
7 * SQUID Web Proxy Cache http://www.squid-cache.org/
8 * ----------------------------------------------------------
9 *
10 * Squid is the result of efforts by numerous individuals from
11 * the Internet community; see the CONTRIBUTORS file for full
12 * details. Many organizations have provided support for Squid's
13 * development; see the SPONSORS file for full details. Squid is
14 * Copyrighted (C) 2001 by the Regents of the University of
15 * California; see the COPYRIGHT file for full details. Squid
16 * incorporates software developed and/or copyrighted by other
17 * sources; see the CREDITS file for full details.
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
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
32 *
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;
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 */
50 } CacheIndex;
51
52
53 typedef struct _CacheEntry {
54 const cache_key *key;
55 struct _CacheEntry *next;
56 /* storeSwapLogData s; */
57 unsigned char key_arr[MD5_DIGEST_CHARS];
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
75 static int cacheIndexScan(CacheIndex * idx, const char *fname, FILE * file);
76
77
78 static CacheEntry *
79 cacheEntryCreate(const storeSwapLogData * s)
80 {
81 CacheEntry *e = xcalloc(1, sizeof(CacheEntry));
82 assert(s);
83 /* e->s = *s; */
84 xmemcpy(e->key_arr, s->key, MD5_DIGEST_CHARS);
85 e->key = &e->key_arr[0];
86 return e;
87 }
88
89 static void
90 cacheEntryDestroy(CacheEntry * e)
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
111 cacheIndexDestroy(CacheIndex * idx)
112 {
113 hash_link *hashr = NULL;
114 if (idx) {
115 /* destroy hash list contents */
116 hash_first(idx->hash);
117 while (hashr = hash_next(idx->hash)) {
118 hash_remove_link(idx->hash, hashr);
119 cacheEntryDestroy((CacheEntry *) hashr);
120 }
121 /* destroy the hash table itself */
122 hashFreeMemory(idx->hash);
123 xfree(idx);
124 }
125 }
126
127 static int
128 cacheIndexAddLog(CacheIndex * idx, const char *fname)
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 }
140 #if defined(_SQUID_CYGWIN_)
141 setmode(fileno(file), O_BINARY);
142 #endif
143 scanned_count = cacheIndexScan(idx, fname, file);
144
145 fclose(file);
146 return scanned_count;
147 }
148
149 static void
150 cacheIndexInitReport(CacheIndex * idx)
151 {
152 assert(idx);
153 fprintf(stderr, "%s: bad swap_add: %d\n",
154 idx->name, idx->bad_add_count);
155 fprintf(stderr, "%s: bad swap_del: %d\n",
156 idx->name, idx->bad_del_count);
157 fprintf(stderr, "%s: scanned lines: %d\n",
158 idx->name, idx->scanned_count);
159 }
160
161 static int
162 cacheIndexScan(CacheIndex * idx, const char *fname, FILE * file)
163 {
164 int count = 0;
165 storeSwapLogData s;
166 fprintf(stderr, "%s scanning\n", fname);
167 while (fread(&s, sizeof(s), 1, file) == 1) {
168 count++;
169 idx->scanned_count++;
170 /* if (s.op <= SWAP_LOG_NOP || s.op >= SWAP_LOG_MAX)
171 * continue; */
172 if (s.op == SWAP_LOG_ADD) {
173 CacheEntry *olde = (CacheEntry *) hash_lookup(idx->hash, s.key);
174 if (olde) {
175 idx->bad_add_count++;
176 } else {
177 CacheEntry *e = cacheEntryCreate(&s);
178 hash_join(idx->hash, &e->hash);
179 idx->count++;
180 }
181 } else if (s.op == SWAP_LOG_DEL) {
182 CacheEntry *olde = (CacheEntry *) hash_lookup(idx->hash, s.key);
183 if (!olde)
184 idx->bad_del_count++;
185 else {
186 assert(idx->count);
187 hash_remove_link(idx->hash, (hash_link *) olde);
188 cacheEntryDestroy(olde);
189 idx->count--;
190 }
191 } else {
192 fprintf(stderr, "%s:%d: unknown swap log action\n", fname, count);
193 exit(-3);
194 }
195 }
196 fprintf(stderr, "%s:%d: scanned (size: %d bytes)\n",
197 fname, count, (int) (count * sizeof(CacheEntry)));
198 return count;
199 }
200
201 static void
202 cacheIndexCmpReport(CacheIndex * idx, int shared_count)
203 {
204 assert(idx && shared_count <= idx->count);
205
206 printf("%s:\t %7d = %7d + %7d (%7.2f%% + %7.2f%%)\n",
207 idx->name,
208 idx->count,
209 idx->count - shared_count,
210 shared_count,
211 xpercent(idx->count - shared_count, idx->count),
212 xpercent(shared_count, idx->count));
213 }
214
215 static void
216 cacheIndexCmp(CacheIndex * idx1, CacheIndex * idx2)
217 {
218 int shared_count = 0;
219 int hashed_count = 0;
220 hash_link *hashr = NULL;
221 CacheIndex *small_idx = idx1;
222 CacheIndex *large_idx = idx2;
223 assert(idx1 && idx2);
224
225 /* check our guess */
226 if (idx1->count > idx2->count) {
227 small_idx = idx2;
228 large_idx = idx1;
229 }
230 /* find shared_count */
231 hash_first(small_idx->hash);
232 for (hashr = hash_next(small_idx->hash)) {
233 hashed_count++;
234 if (hash_lookup(large_idx->hash, hashr->key))
235 shared_count++;
236 }
237 assert(hashed_count == small_idx->count);
238
239 cacheIndexCmpReport(idx1, shared_count);
240 cacheIndexCmpReport(idx2, shared_count);
241 }
242
243
244 static int
245 usage(const char *prg_name)
246 {
247 fprintf(stderr, "usage: %s <label1>: <swap_state>... <label2>: <swap_state>...\n",
248 prg_name);
249 return -1;
250 }
251
252 int
253 main(int argc, char *argv[])
254 {
255 CacheIndex *CacheIdx[2];
256 CacheIndex *idx = NULL;
257 int idxCount = 0;
258 int i;
259
260 if (argc < 5)
261 return usage(argv[0]);
262
263 for (i = 1; i < argc; ++i) {
264 const int len = strlen(argv[i]);
265 if (!len)
266 return usage(argv[0]);
267 if (argv[i][len - 1] == ':') {
268 idxCount++;
269 if (len < 2 || idxCount > 2)
270 return usage(argv[0]);
271 idx = cacheIndexCreate(argv[i]);
272 CacheIdx[idxCount - 1] = idx;
273 } else {
274 if (!idx)
275 return usage(argv[0]);
276 cacheIndexAddLog(idx, argv[i]);
277 }
278 }
279
280 if (idxCount != 2)
281 return usage(argv[0]);
282
283 cacheIndexInitReport(CacheIdx[0]);
284 cacheIndexInitReport(CacheIdx[1]);
285
286 cacheIndexCmp(CacheIdx[0], CacheIdx[1]);
287
288 cacheIndexDestroy(CacheIdx[0]);
289 cacheIndexDestroy(CacheIdx[1]);
290
291 return 1;
292 }