]>
Commit | Line | Data |
---|---|---|
8667b856 | 1 | /* |
4ac4a490 | 2 | * Copyright (C) 1996-2017 The Squid Software Foundation and contributors |
e25c139f | 3 | * |
bbc27441 AJ |
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. | |
8667b856 | 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 | ||
582c2af2 | 15 | #include "squid.h" |
1a30fdf5 | 16 | #include <cerrno> |
21d845b1 | 17 | |
26ac0430 | 18 | typedef struct { |
8667b856 | 19 | const char *name; |
20 | hash_table *hash; | |
f53969cc SM |
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 */ | |
2fadd50d | 25 | } CacheIndex; |
8667b856 | 26 | |
26ac0430 | 27 | typedef struct _CacheEntry { |
8667b856 | 28 | const cache_key *key; |
62e76326 | 29 | |
8667b856 | 30 | struct _CacheEntry *next; |
51ee7c82 | 31 | /* StoreSwapLogData s; */ |
c3031d67 | 32 | unsigned char key_arr[SQUID_MD5_DIGEST_LENGTH]; |
2fadd50d | 33 | } CacheEntry; |
8667b856 | 34 | |
1afe05c5 | 35 | static int cacheIndexScan(CacheIndex * idx, const char *fname, FILE * file); |
8667b856 | 36 | |
8667b856 | 37 | static CacheEntry * |
51ee7c82 | 38 | cacheEntryCreate(const StoreSwapLogData * s) |
8667b856 | 39 | { |
40 | CacheEntry *e = xcalloc(1, sizeof(CacheEntry)); | |
41 | assert(s); | |
edc1d6da | 42 | /* e->s = *s; */ |
41d00cd3 | 43 | memcpy(e->key_arr, s->key, SQUID_MD5_DIGEST_LENGTH); |
edc1d6da | 44 | e->key = &e->key_arr[0]; |
8667b856 | 45 | return e; |
46 | } | |
47 | ||
48 | static void | |
1afe05c5 | 49 | cacheEntryDestroy(CacheEntry * e) |
8667b856 | 50 | { |
51 | assert(e); | |
52 | xfree(e); | |
53 | } | |
54 | ||
55 | static CacheIndex * | |
56 | cacheIndexCreate(const char *name) | |
57 | { | |
58 | CacheIndex *idx; | |
62e76326 | 59 | |
8667b856 | 60 | if (!name || !strlen(name)) |
62e76326 | 61 | return NULL; |
8667b856 | 62 | |
63 | idx = xcalloc(1, sizeof(CacheIndex)); | |
62e76326 | 64 | |
8667b856 | 65 | idx->name = name; |
62e76326 | 66 | |
8667b856 | 67 | idx->hash = hash_create(storeKeyHashCmp, 2e6, storeKeyHashHash); |
68 | ||
69 | return idx; | |
70 | } | |
71 | ||
72 | static void | |
1afe05c5 | 73 | cacheIndexDestroy(CacheIndex * idx) |
8667b856 | 74 | { |
75 | hash_link *hashr = NULL; | |
62e76326 | 76 | |
8667b856 | 77 | if (idx) { |
62e76326 | 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); | |
8667b856 | 90 | } |
91 | } | |
92 | ||
93 | static int | |
1afe05c5 | 94 | cacheIndexAddLog(CacheIndex * idx, const char *fname) |
8667b856 | 95 | { |
96 | FILE *file; | |
97 | int scanned_count = 0; | |
98 | assert(idx); | |
99 | assert(fname && strlen(fname)); | |
100 | ||
101 | file = fopen(fname, "r"); | |
62e76326 | 102 | |
8667b856 | 103 | if (!file) { |
62e76326 | 104 | fprintf(stderr, "cannot open %s: %s\n", fname, strerror(errno)); |
105 | return 0; | |
8667b856 | 106 | } |
62e76326 | 107 | |
be266cb2 | 108 | #if _SQUID_WINDOWS_ |
c4aefe96 | 109 | setmode(fileno(file), O_BINARY); |
110 | #endif | |
62e76326 | 111 | |
8667b856 | 112 | scanned_count = cacheIndexScan(idx, fname, file); |
113 | ||
114 | fclose(file); | |
62e76326 | 115 | |
8667b856 | 116 | return scanned_count; |
117 | } | |
118 | ||
119 | static void | |
1afe05c5 | 120 | cacheIndexInitReport(CacheIndex * idx) |
8667b856 | 121 | { |
122 | assert(idx); | |
123 | fprintf(stderr, "%s: bad swap_add: %d\n", | |
62e76326 | 124 | idx->name, idx->bad_add_count); |
1afe05c5 | 125 | fprintf(stderr, "%s: bad swap_del: %d\n", |
62e76326 | 126 | idx->name, idx->bad_del_count); |
1afe05c5 | 127 | fprintf(stderr, "%s: scanned lines: %d\n", |
62e76326 | 128 | idx->name, idx->scanned_count); |
8667b856 | 129 | } |
130 | ||
131 | static int | |
1afe05c5 | 132 | cacheIndexScan(CacheIndex * idx, const char *fname, FILE * file) |
8667b856 | 133 | { |
134 | int count = 0; | |
51ee7c82 | 135 | StoreSwapLogData s; |
8667b856 | 136 | fprintf(stderr, "%s scanning\n", fname); |
62e76326 | 137 | |
8667b856 | 138 | while (fread(&s, sizeof(s), 1, file) == 1) { |
d7ae3534 FC |
139 | ++count; |
140 | ++ idx->scanned_count; | |
3f9d4dc2 | 141 | /* if (!s.sane()) |
62e76326 | 142 | * continue; */ |
143 | ||
144 | if (s.op == SWAP_LOG_ADD) { | |
145 | CacheEntry *olde = (CacheEntry *) hash_lookup(idx->hash, s.key); | |
146 | ||
147 | if (olde) { | |
d7ae3534 | 148 | ++ idx->bad_add_count; |
62e76326 | 149 | } else { |
150 | CacheEntry *e = cacheEntryCreate(&s); | |
151 | hash_join(idx->hash, &e->hash); | |
d7ae3534 | 152 | ++ idx->count; |
62e76326 | 153 | } |
154 | } else if (s.op == SWAP_LOG_DEL) { | |
155 | CacheEntry *olde = (CacheEntry *) hash_lookup(idx->hash, s.key); | |
156 | ||
157 | if (!olde) | |
d7ae3534 | 158 | ++ idx->bad_del_count; |
62e76326 | 159 | else { |
160 | assert(idx->count); | |
161 | hash_remove_link(idx->hash, (hash_link *) olde); | |
162 | cacheEntryDestroy(olde); | |
5e263176 | 163 | -- idx->count; |
62e76326 | 164 | } |
165 | } else { | |
166 | fprintf(stderr, "%s:%d: unknown swap log action\n", fname, count); | |
167 | exit(-3); | |
168 | } | |
8667b856 | 169 | } |
62e76326 | 170 | |
1afe05c5 | 171 | fprintf(stderr, "%s:%d: scanned (size: %d bytes)\n", |
62e76326 | 172 | fname, count, (int) (count * sizeof(CacheEntry))); |
8667b856 | 173 | return count; |
174 | } | |
175 | ||
176 | static void | |
1afe05c5 | 177 | cacheIndexCmpReport(CacheIndex * idx, int shared_count) |
8667b856 | 178 | { |
179 | assert(idx && shared_count <= idx->count); | |
180 | ||
f97c9706 | 181 | printf("%s:\t %7d = %7d + %7d (%7.2f%% + %7.2f%%)\n", |
62e76326 | 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)); | |
8667b856 | 188 | } |
189 | ||
190 | static void | |
1afe05c5 | 191 | cacheIndexCmp(CacheIndex * idx1, CacheIndex * idx2) |
8667b856 | 192 | { |
193 | int shared_count = 0; | |
681e7924 | 194 | int hashed_count = 0; |
8667b856 | 195 | hash_link *hashr = NULL; |
196 | CacheIndex *small_idx = idx1; | |
197 | CacheIndex *large_idx = idx2; | |
198 | assert(idx1 && idx2); | |
199 | ||
200 | /* check our guess */ | |
62e76326 | 201 | |
8667b856 | 202 | if (idx1->count > idx2->count) { |
62e76326 | 203 | small_idx = idx2; |
204 | large_idx = idx1; | |
8667b856 | 205 | } |
62e76326 | 206 | |
8667b856 | 207 | /* find shared_count */ |
0f6bebac | 208 | hash_first(small_idx->hash); |
62e76326 | 209 | |
0f6bebac | 210 | for (hashr = hash_next(small_idx->hash)) { |
d7ae3534 | 211 | ++hashed_count; |
62e76326 | 212 | |
213 | if (hash_lookup(large_idx->hash, hashr->key)) | |
d7ae3534 | 214 | ++shared_count; |
8667b856 | 215 | } |
62e76326 | 216 | |
681e7924 | 217 | assert(hashed_count == small_idx->count); |
8667b856 | 218 | |
219 | cacheIndexCmpReport(idx1, shared_count); | |
220 | cacheIndexCmpReport(idx2, shared_count); | |
221 | } | |
222 | ||
8667b856 | 223 | static int |
224 | usage(const char *prg_name) | |
225 | { | |
226 | fprintf(stderr, "usage: %s <label1>: <swap_state>... <label2>: <swap_state>...\n", | |
62e76326 | 227 | prg_name); |
8667b856 | 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) | |
62e76326 | 240 | return usage(argv[0]); |
8667b856 | 241 | |
242 | for (i = 1; i < argc; ++i) { | |
62e76326 | 243 | const int len = strlen(argv[i]); |
244 | ||
245 | if (!len) | |
246 | return usage(argv[0]); | |
247 | ||
248 | if (argv[i][len - 1] == ':') { | |
d7ae3534 | 249 | ++idxCount; |
62e76326 | 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 | } | |
8667b856 | 263 | } |
264 | ||
265 | if (idxCount != 2) | |
62e76326 | 266 | return usage(argv[0]); |
8667b856 | 267 | |
268 | cacheIndexInitReport(CacheIdx[0]); | |
62e76326 | 269 | |
8667b856 | 270 | cacheIndexInitReport(CacheIdx[1]); |
271 | ||
272 | cacheIndexCmp(CacheIdx[0], CacheIdx[1]); | |
273 | ||
274 | cacheIndexDestroy(CacheIdx[0]); | |
62e76326 | 275 | |
8667b856 | 276 | cacheIndexDestroy(CacheIdx[1]); |
277 | ||
278 | return 1; | |
279 | } | |
f53969cc | 280 |