author | Lars Hjemli <hjemli@gmail.com> | 2008-04-28 10:10:13 (UTC) |
---|---|---|
committer | Lars Hjemli <hjemli@gmail.com> | 2008-04-28 10:10:13 (UTC) |
commit | 9000bbf865cb3578ba5ed3810dc44253cb46ec7f (patch) (unidiff) | |
tree | a9917628c40301862d1b1d6f5ecaf803ecc0f714 | |
parent | 939d32fda70ea66c9db51687beb3cea6da7b0599 (diff) | |
download | cgit-9000bbf865cb3578ba5ed3810dc44253cb46ec7f.zip cgit-9000bbf865cb3578ba5ed3810dc44253cb46ec7f.tar.gz cgit-9000bbf865cb3578ba5ed3810dc44253cb46ec7f.tar.bz2 |
Add page 'ls_cache'
This new page will list all entries found in the current cache, which is
useful when reviewing the new cache implementation. There are no links to
the new page, but it's reachable by adding 'p=ls_cache' to any cgit url.
Signed-off-by: Lars Hjemli <hjemli@gmail.com>
-rw-r--r-- | cache.c | 68 | ||||
-rw-r--r-- | cache.h | 3 | ||||
-rw-r--r-- | cmd.c | 21 |
3 files changed, 87 insertions, 5 deletions
@@ -239,105 +239,173 @@ static int process_slot(struct cache_slot *slot) | |||
239 | } | 239 | } |
240 | print_slot(slot); | 240 | print_slot(slot); |
241 | close_slot(slot); | 241 | close_slot(slot); |
242 | return 0; | 242 | return 0; |
243 | } | 243 | } |
244 | 244 | ||
245 | /* If the cache slot does not exist (or its key doesn't match the | 245 | /* If the cache slot does not exist (or its key doesn't match the |
246 | * current key), lets try to create a new cache slot for this | 246 | * current key), lets try to create a new cache slot for this |
247 | * request. If this fails (for whatever reason), lets just generate | 247 | * request. If this fails (for whatever reason), lets just generate |
248 | * the content without caching it and fool the caller to belive | 248 | * the content without caching it and fool the caller to belive |
249 | * everything worked out (but print a warning on stdout). | 249 | * everything worked out (but print a warning on stdout). |
250 | */ | 250 | */ |
251 | 251 | ||
252 | close_slot(slot); | 252 | close_slot(slot); |
253 | if ((err = lock_slot(slot)) != 0) { | 253 | if ((err = lock_slot(slot)) != 0) { |
254 | cache_log("[cgit] Unable to lock slot %s: %s (%d)\n", | 254 | cache_log("[cgit] Unable to lock slot %s: %s (%d)\n", |
255 | slot->lock_name, strerror(err), err); | 255 | slot->lock_name, strerror(err), err); |
256 | slot->fn(slot->cbdata); | 256 | slot->fn(slot->cbdata); |
257 | return 0; | 257 | return 0; |
258 | } | 258 | } |
259 | 259 | ||
260 | if ((err = fill_slot(slot)) != 0) { | 260 | if ((err = fill_slot(slot)) != 0) { |
261 | cache_log("[cgit] Unable to fill slot %s: %s (%d)\n", | 261 | cache_log("[cgit] Unable to fill slot %s: %s (%d)\n", |
262 | slot->lock_name, strerror(err), err); | 262 | slot->lock_name, strerror(err), err); |
263 | unlock_slot(slot, 0); | 263 | unlock_slot(slot, 0); |
264 | close_lock(slot); | 264 | close_lock(slot); |
265 | slot->fn(slot->cbdata); | 265 | slot->fn(slot->cbdata); |
266 | return 0; | 266 | return 0; |
267 | } | 267 | } |
268 | // We've got a valid cache slot in the lock file, which | 268 | // We've got a valid cache slot in the lock file, which |
269 | // is about to replace the old cache slot. But if we | 269 | // is about to replace the old cache slot. But if we |
270 | // release the lockfile and then try to open the new cache | 270 | // release the lockfile and then try to open the new cache |
271 | // slot, we might get a race condition with a concurrent | 271 | // slot, we might get a race condition with a concurrent |
272 | // writer for the same cache slot (with a different key). | 272 | // writer for the same cache slot (with a different key). |
273 | // Lets avoid such a race by just printing the content of | 273 | // Lets avoid such a race by just printing the content of |
274 | // the lock file. | 274 | // the lock file. |
275 | slot->cache_fd = slot->lock_fd; | 275 | slot->cache_fd = slot->lock_fd; |
276 | unlock_slot(slot, 1); | 276 | unlock_slot(slot, 1); |
277 | err = print_slot(slot); | 277 | err = print_slot(slot); |
278 | close_slot(slot); | 278 | close_slot(slot); |
279 | return err; | 279 | return err; |
280 | } | 280 | } |
281 | 281 | ||
282 | /* Print cached content to stdout, generate the content if necessary. */ | 282 | /* Print cached content to stdout, generate the content if necessary. */ |
283 | int cache_process(int size, const char *path, const char *key, int ttl, | 283 | int cache_process(int size, const char *path, const char *key, int ttl, |
284 | cache_fill_fn fn, void *cbdata) | 284 | cache_fill_fn fn, void *cbdata) |
285 | { | 285 | { |
286 | unsigned long hash; | 286 | unsigned long hash; |
287 | int len, i; | 287 | int len, i; |
288 | char filename[1024]; | 288 | char filename[1024]; |
289 | char lockname[1024 + 5]; /* 5 = ".lock" */ | 289 | char lockname[1024 + 5]; /* 5 = ".lock" */ |
290 | struct cache_slot slot; | 290 | struct cache_slot slot; |
291 | 291 | ||
292 | /* If the cache is disabled, just generate the content */ | 292 | /* If the cache is disabled, just generate the content */ |
293 | if (size <= 0) { | 293 | if (size <= 0) { |
294 | fn(cbdata); | 294 | fn(cbdata); |
295 | return 0; | 295 | return 0; |
296 | } | 296 | } |
297 | 297 | ||
298 | /* Verify input, calculate filenames */ | 298 | /* Verify input, calculate filenames */ |
299 | if (!path) { | 299 | if (!path) { |
300 | cache_log("[cgit] Cache path not specified, caching is disabled\n"); | 300 | cache_log("[cgit] Cache path not specified, caching is disabled\n"); |
301 | fn(cbdata); | 301 | fn(cbdata); |
302 | return 0; | 302 | return 0; |
303 | } | 303 | } |
304 | len = strlen(path); | 304 | len = strlen(path); |
305 | if (len > sizeof(filename) - 10) { /* 10 = "/01234567\0" */ | 305 | if (len > sizeof(filename) - 10) { /* 10 = "/01234567\0" */ |
306 | cache_log("[cgit] Cache path too long, caching is disabled: %s\n", | 306 | cache_log("[cgit] Cache path too long, caching is disabled: %s\n", |
307 | path); | 307 | path); |
308 | fn(cbdata); | 308 | fn(cbdata); |
309 | return 0; | 309 | return 0; |
310 | } | 310 | } |
311 | if (!key) | 311 | if (!key) |
312 | key = ""; | 312 | key = ""; |
313 | hash = hash_str(key) % size; | 313 | hash = hash_str(key) % size; |
314 | strcpy(filename, path); | 314 | strcpy(filename, path); |
315 | if (filename[len - 1] != '/') | 315 | if (filename[len - 1] != '/') |
316 | filename[len++] = '/'; | 316 | filename[len++] = '/'; |
317 | for(i = 0; i < 8; i++) { | 317 | for(i = 0; i < 8; i++) { |
318 | sprintf(filename + len++, "%x", | 318 | sprintf(filename + len++, "%x", |
319 | (unsigned char)(hash & 0xf)); | 319 | (unsigned char)(hash & 0xf)); |
320 | hash >>= 4; | 320 | hash >>= 4; |
321 | } | 321 | } |
322 | filename[len] = '\0'; | 322 | filename[len] = '\0'; |
323 | strcpy(lockname, filename); | 323 | strcpy(lockname, filename); |
324 | strcpy(lockname + len, ".lock"); | 324 | strcpy(lockname + len, ".lock"); |
325 | slot.fn = fn; | 325 | slot.fn = fn; |
326 | slot.cbdata = cbdata; | 326 | slot.cbdata = cbdata; |
327 | slot.ttl = ttl; | 327 | slot.ttl = ttl; |
328 | slot.cache_name = filename; | 328 | slot.cache_name = filename; |
329 | slot.lock_name = lockname; | 329 | slot.lock_name = lockname; |
330 | slot.key = key; | 330 | slot.key = key; |
331 | slot.keylen = strlen(key); | 331 | slot.keylen = strlen(key); |
332 | return process_slot(&slot); | 332 | return process_slot(&slot); |
333 | } | 333 | } |
334 | 334 | ||
335 | /* Return a strftime formatted date/time | ||
336 | * NB: the result from this function is to shared memory | ||
337 | */ | ||
338 | char *sprintftime(const char *format, time_t time) | ||
339 | { | ||
340 | static char buf[64]; | ||
341 | struct tm *tm; | ||
342 | |||
343 | if (!time) | ||
344 | return NULL; | ||
345 | tm = gmtime(&time); | ||
346 | strftime(buf, sizeof(buf)-1, format, tm); | ||
347 | return buf; | ||
348 | } | ||
349 | |||
350 | int cache_ls(const char *path) | ||
351 | { | ||
352 | DIR *dir; | ||
353 | struct dirent *ent; | ||
354 | int err = 0; | ||
355 | struct cache_slot slot; | ||
356 | char fullname[1024]; | ||
357 | char *name; | ||
358 | |||
359 | if (!path) { | ||
360 | cache_log("[cgit] cache path not specified\n"); | ||
361 | return -1; | ||
362 | } | ||
363 | if (strlen(path) > 1024 - 10) { | ||
364 | cache_log("[cgit] cache path too long: %s\n", | ||
365 | path); | ||
366 | return -1; | ||
367 | } | ||
368 | dir = opendir(path); | ||
369 | if (!dir) { | ||
370 | err = errno; | ||
371 | cache_log("[cgit] unable to open path %s: %s (%d)\n", | ||
372 | path, strerror(err), err); | ||
373 | return err; | ||
374 | } | ||
375 | strcpy(fullname, path); | ||
376 | name = fullname + strlen(path); | ||
377 | if (*(name - 1) != '/') { | ||
378 | *name++ = '/'; | ||
379 | *name = '\0'; | ||
380 | } | ||
381 | slot.cache_name = fullname; | ||
382 | while((ent = readdir(dir)) != NULL) { | ||
383 | if (strlen(ent->d_name) != 8) | ||
384 | continue; | ||
385 | strcpy(name, ent->d_name); | ||
386 | if ((err = open_slot(&slot)) != 0) { | ||
387 | cache_log("[cgit] unable to open path %s: %s (%d)\n", | ||
388 | fullname, strerror(err), err); | ||
389 | continue; | ||
390 | } | ||
391 | printf("%s %s %10lld %s\n", | ||
392 | name, | ||
393 | sprintftime("%Y-%m-%d %H:%M:%S", | ||
394 | slot.cache_st.st_mtime), | ||
395 | slot.cache_st.st_size, | ||
396 | slot.buf); | ||
397 | close_slot(&slot); | ||
398 | } | ||
399 | closedir(dir); | ||
400 | return 0; | ||
401 | } | ||
402 | |||
335 | /* Print a message to stdout */ | 403 | /* Print a message to stdout */ |
336 | void cache_log(const char *format, ...) | 404 | void cache_log(const char *format, ...) |
337 | { | 405 | { |
338 | va_list args; | 406 | va_list args; |
339 | va_start(args, format); | 407 | va_start(args, format); |
340 | vfprintf(stderr, format, args); | 408 | vfprintf(stderr, format, args); |
341 | va_end(args); | 409 | va_end(args); |
342 | } | 410 | } |
343 | 411 | ||
@@ -1,32 +1,35 @@ | |||
1 | /* | 1 | /* |
2 | * Since git has it's own cache.h which we include, | 2 | * Since git has it's own cache.h which we include, |
3 | * lets test on CGIT_CACHE_H to avoid confusion | 3 | * lets test on CGIT_CACHE_H to avoid confusion |
4 | */ | 4 | */ |
5 | 5 | ||
6 | #ifndef CGIT_CACHE_H | 6 | #ifndef CGIT_CACHE_H |
7 | #define CGIT_CACHE_H | 7 | #define CGIT_CACHE_H |
8 | 8 | ||
9 | typedef void (*cache_fill_fn)(void *cbdata); | 9 | typedef void (*cache_fill_fn)(void *cbdata); |
10 | 10 | ||
11 | 11 | ||
12 | /* Print cached content to stdout, generate the content if necessary. | 12 | /* Print cached content to stdout, generate the content if necessary. |
13 | * | 13 | * |
14 | * Parameters | 14 | * Parameters |
15 | * size max number of cache files | 15 | * size max number of cache files |
16 | * path directory used to store cache files | 16 | * path directory used to store cache files |
17 | * key the key used to lookup cache files | 17 | * key the key used to lookup cache files |
18 | * ttl max cache time in seconds for this key | 18 | * ttl max cache time in seconds for this key |
19 | * fn content generator function for this key | 19 | * fn content generator function for this key |
20 | * cbdata user-supplied data to the content generator function | 20 | * cbdata user-supplied data to the content generator function |
21 | * | 21 | * |
22 | * Return value | 22 | * Return value |
23 | * 0 indicates success, everyting else is an error | 23 | * 0 indicates success, everyting else is an error |
24 | */ | 24 | */ |
25 | extern int cache_process(int size, const char *path, const char *key, int ttl, | 25 | extern int cache_process(int size, const char *path, const char *key, int ttl, |
26 | cache_fill_fn fn, void *cbdata); | 26 | cache_fill_fn fn, void *cbdata); |
27 | 27 | ||
28 | 28 | ||
29 | /* List info about all cache entries on stdout */ | ||
30 | extern int cache_ls(const char *path); | ||
31 | |||
29 | /* Print a message to stdout */ | 32 | /* Print a message to stdout */ |
30 | extern void cache_log(const char *format, ...); | 33 | extern void cache_log(const char *format, ...); |
31 | 34 | ||
32 | #endif /* CGIT_CACHE_H */ | 35 | #endif /* CGIT_CACHE_H */ |
@@ -1,112 +1,123 @@ | |||
1 | /* cmd.c: the cgit command dispatcher | 1 | /* cmd.c: the cgit command dispatcher |
2 | * | 2 | * |
3 | * Copyright (C) 2008 Lars Hjemli | 3 | * Copyright (C) 2008 Lars Hjemli |
4 | * | 4 | * |
5 | * Licensed under GNU General Public License v2 | 5 | * Licensed under GNU General Public License v2 |
6 | * (see COPYING for full license text) | 6 | * (see COPYING for full license text) |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include "cgit.h" | 9 | #include "cgit.h" |
10 | #include "cmd.h" | 10 | #include "cmd.h" |
11 | #include "cache.h" | ||
12 | #include "ui-shared.h" | ||
11 | #include "ui-blob.h" | 13 | #include "ui-blob.h" |
12 | #include "ui-commit.h" | 14 | #include "ui-commit.h" |
13 | #include "ui-diff.h" | 15 | #include "ui-diff.h" |
14 | #include "ui-log.h" | 16 | #include "ui-log.h" |
15 | #include "ui-patch.h" | 17 | #include "ui-patch.h" |
16 | #include "ui-refs.h" | 18 | #include "ui-refs.h" |
17 | #include "ui-repolist.h" | 19 | #include "ui-repolist.h" |
18 | #include "ui-snapshot.h" | 20 | #include "ui-snapshot.h" |
19 | #include "ui-summary.h" | 21 | #include "ui-summary.h" |
20 | #include "ui-tag.h" | 22 | #include "ui-tag.h" |
21 | #include "ui-tree.h" | 23 | #include "ui-tree.h" |
22 | 24 | ||
23 | static void blob_fn(struct cgit_context *ctx) | 25 | static void blob_fn(struct cgit_context *ctx) |
24 | { | 26 | { |
25 | cgit_print_blob(ctx->qry.sha1, ctx->qry.path); | 27 | cgit_print_blob(ctx->qry.sha1, ctx->qry.path); |
26 | } | 28 | } |
27 | 29 | ||
28 | static void commit_fn(struct cgit_context *ctx) | 30 | static void commit_fn(struct cgit_context *ctx) |
29 | { | 31 | { |
30 | cgit_print_commit(ctx->qry.sha1); | 32 | cgit_print_commit(ctx->qry.sha1); |
31 | } | 33 | } |
32 | 34 | ||
33 | static void diff_fn(struct cgit_context *ctx) | 35 | static void diff_fn(struct cgit_context *ctx) |
34 | { | 36 | { |
35 | cgit_print_diff(ctx->qry.sha1, ctx->qry.sha2, ctx->qry.path); | 37 | cgit_print_diff(ctx->qry.sha1, ctx->qry.sha2, ctx->qry.path); |
36 | } | 38 | } |
37 | 39 | ||
38 | static void repolist_fn(struct cgit_context *ctx) | ||
39 | { | ||
40 | cgit_print_repolist(); | ||
41 | } | ||
42 | |||
43 | static void log_fn(struct cgit_context *ctx) | 40 | static void log_fn(struct cgit_context *ctx) |
44 | { | 41 | { |
45 | cgit_print_log(ctx->qry.sha1, ctx->qry.ofs, ctx->cfg.max_commit_count, | 42 | cgit_print_log(ctx->qry.sha1, ctx->qry.ofs, ctx->cfg.max_commit_count, |
46 | ctx->qry.grep, ctx->qry.search, ctx->qry.path, 1); | 43 | ctx->qry.grep, ctx->qry.search, ctx->qry.path, 1); |
47 | } | 44 | } |
48 | 45 | ||
46 | static void ls_cache_fn(struct cgit_context *ctx) | ||
47 | { | ||
48 | ctx->page.mimetype = "text/plain"; | ||
49 | ctx->page.filename = "ls-cache.txt"; | ||
50 | cgit_print_http_headers(ctx); | ||
51 | cache_ls(ctx->cfg.cache_root); | ||
52 | } | ||
53 | |||
54 | static void repolist_fn(struct cgit_context *ctx) | ||
55 | { | ||
56 | cgit_print_repolist(); | ||
57 | } | ||
58 | |||
49 | static void patch_fn(struct cgit_context *ctx) | 59 | static void patch_fn(struct cgit_context *ctx) |
50 | { | 60 | { |
51 | cgit_print_patch(ctx->qry.sha1); | 61 | cgit_print_patch(ctx->qry.sha1); |
52 | } | 62 | } |
53 | 63 | ||
54 | static void refs_fn(struct cgit_context *ctx) | 64 | static void refs_fn(struct cgit_context *ctx) |
55 | { | 65 | { |
56 | cgit_print_refs(); | 66 | cgit_print_refs(); |
57 | } | 67 | } |
58 | 68 | ||
59 | static void snapshot_fn(struct cgit_context *ctx) | 69 | static void snapshot_fn(struct cgit_context *ctx) |
60 | { | 70 | { |
61 | cgit_print_snapshot(ctx->qry.head, ctx->qry.sha1, | 71 | cgit_print_snapshot(ctx->qry.head, ctx->qry.sha1, |
62 | cgit_repobasename(ctx->repo->url), ctx->qry.path, | 72 | cgit_repobasename(ctx->repo->url), ctx->qry.path, |
63 | ctx->repo->snapshots); | 73 | ctx->repo->snapshots); |
64 | } | 74 | } |
65 | 75 | ||
66 | static void summary_fn(struct cgit_context *ctx) | 76 | static void summary_fn(struct cgit_context *ctx) |
67 | { | 77 | { |
68 | cgit_print_summary(); | 78 | cgit_print_summary(); |
69 | } | 79 | } |
70 | 80 | ||
71 | static void tag_fn(struct cgit_context *ctx) | 81 | static void tag_fn(struct cgit_context *ctx) |
72 | { | 82 | { |
73 | cgit_print_tag(ctx->qry.sha1); | 83 | cgit_print_tag(ctx->qry.sha1); |
74 | } | 84 | } |
75 | 85 | ||
76 | static void tree_fn(struct cgit_context *ctx) | 86 | static void tree_fn(struct cgit_context *ctx) |
77 | { | 87 | { |
78 | cgit_print_tree(ctx->qry.sha1, ctx->qry.path); | 88 | cgit_print_tree(ctx->qry.sha1, ctx->qry.path); |
79 | } | 89 | } |
80 | 90 | ||
81 | #define def_cmd(name, want_repo, want_layout) \ | 91 | #define def_cmd(name, want_repo, want_layout) \ |
82 | {#name, name##_fn, want_repo, want_layout} | 92 | {#name, name##_fn, want_repo, want_layout} |
83 | 93 | ||
84 | struct cgit_cmd *cgit_get_cmd(struct cgit_context *ctx) | 94 | struct cgit_cmd *cgit_get_cmd(struct cgit_context *ctx) |
85 | { | 95 | { |
86 | static struct cgit_cmd cmds[] = { | 96 | static struct cgit_cmd cmds[] = { |
87 | def_cmd(blob, 1, 0), | 97 | def_cmd(blob, 1, 0), |
88 | def_cmd(commit, 1, 1), | 98 | def_cmd(commit, 1, 1), |
89 | def_cmd(diff, 1, 1), | 99 | def_cmd(diff, 1, 1), |
90 | def_cmd(log, 1, 1), | 100 | def_cmd(log, 1, 1), |
101 | def_cmd(ls_cache, 0, 0), | ||
91 | def_cmd(patch, 1, 0), | 102 | def_cmd(patch, 1, 0), |
92 | def_cmd(refs, 1, 1), | 103 | def_cmd(refs, 1, 1), |
93 | def_cmd(repolist, 0, 0), | 104 | def_cmd(repolist, 0, 0), |
94 | def_cmd(snapshot, 1, 0), | 105 | def_cmd(snapshot, 1, 0), |
95 | def_cmd(summary, 1, 1), | 106 | def_cmd(summary, 1, 1), |
96 | def_cmd(tag, 1, 1), | 107 | def_cmd(tag, 1, 1), |
97 | def_cmd(tree, 1, 1), | 108 | def_cmd(tree, 1, 1), |
98 | }; | 109 | }; |
99 | int i; | 110 | int i; |
100 | 111 | ||
101 | if (ctx->qry.page == NULL) { | 112 | if (ctx->qry.page == NULL) { |
102 | if (ctx->repo) | 113 | if (ctx->repo) |
103 | ctx->qry.page = "summary"; | 114 | ctx->qry.page = "summary"; |
104 | else | 115 | else |
105 | ctx->qry.page = "repolist"; | 116 | ctx->qry.page = "repolist"; |
106 | } | 117 | } |
107 | 118 | ||
108 | for(i = 0; i < sizeof(cmds)/sizeof(*cmds); i++) | 119 | for(i = 0; i < sizeof(cmds)/sizeof(*cmds); i++) |
109 | if (!strcmp(ctx->qry.page, cmds[i].name)) | 120 | if (!strcmp(ctx->qry.page, cmds[i].name)) |
110 | return &cmds[i]; | 121 | return &cmds[i]; |
111 | return NULL; | 122 | return NULL; |
112 | } | 123 | } |