summaryrefslogtreecommitdiffabout
path: root/ui-repolist.c
authorLars Hjemli <hjemli@gmail.com>2008-11-29 15:46:37 (UTC)
committer Lars Hjemli <hjemli@gmail.com>2008-11-29 15:46:37 (UTC)
commit8813170390f3c3a0f4743afbc92ede42953fa3b0 (patch) (unidiff)
tree39305350baee1eb564aae00294634bbe544983d3 /ui-repolist.c
parent54272e60965ec6a98b49cbf67d72a4b1f5adc55b (diff)
downloadcgit-8813170390f3c3a0f4743afbc92ede42953fa3b0.zip
cgit-8813170390f3c3a0f4743afbc92ede42953fa3b0.tar.gz
cgit-8813170390f3c3a0f4743afbc92ede42953fa3b0.tar.bz2
ui-repolist: implement lazy caching of repo->mtime
When sorting the list of repositories by their last modification time, cgit would (in the worst case) invoke fstat(3) four times and open(3) twice for each callback from qsort(3). This obviously scales very badly. Now, the calculated modtime for each repo is saved in repo->mtime, thus keeping the number of stat/open invocations identical for sorted and unsorted repo-listings. Signed-off-by: Lars Hjemli <hjemli@gmail.com>
Diffstat (limited to 'ui-repolist.c') (more/less context) (ignore whitespace changes)
-rw-r--r--ui-repolist.c16
1 files changed, 12 insertions, 4 deletions
diff --git a/ui-repolist.c b/ui-repolist.c
index cf27cb3..aa743bf 100644
--- a/ui-repolist.c
+++ b/ui-repolist.c
@@ -1,143 +1,151 @@
1/* ui-repolist.c: functions for generating the repolist page 1/* ui-repolist.c: functions for generating the repolist page
2 * 2 *
3 * Copyright (C) 2006 Lars Hjemli 3 * Copyright (C) 2006 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 <time.h> 9#include <time.h>
10 10
11#include "cgit.h" 11#include "cgit.h"
12#include "html.h" 12#include "html.h"
13#include "ui-shared.h" 13#include "ui-shared.h"
14 14
15time_t read_agefile(char *path) 15time_t read_agefile(char *path)
16{ 16{
17 FILE *f; 17 FILE *f;
18 static char buf[64], buf2[64]; 18 static char buf[64], buf2[64];
19 19
20 if (!(f = fopen(path, "r"))) 20 if (!(f = fopen(path, "r")))
21 return -1; 21 return -1;
22 if (fgets(buf, sizeof(buf), f) == NULL) 22 if (fgets(buf, sizeof(buf), f) == NULL)
23 return -1; 23 return -1;
24 fclose(f); 24 fclose(f);
25 if (parse_date(buf, buf2, sizeof(buf2))) 25 if (parse_date(buf, buf2, sizeof(buf2)))
26 return strtoul(buf2, NULL, 10); 26 return strtoul(buf2, NULL, 10);
27 else 27 else
28 return 0; 28 return 0;
29} 29}
30 30
31static int get_repo_modtime(const struct cgit_repo *repo, time_t *mtime) 31static int get_repo_modtime(const struct cgit_repo *repo, time_t *mtime)
32{ 32{
33 char *path; 33 char *path;
34 struct stat s; 34 struct stat s;
35 struct cgit_repo *r = (struct cgit_repo *)repo;
35 36
37 if (repo->mtime != -1) {
38 *mtime = repo->mtime;
39 return 1;
40 }
36 path = fmt("%s/%s", repo->path, ctx.cfg.agefile); 41 path = fmt("%s/%s", repo->path, ctx.cfg.agefile);
37 if (stat(path, &s) == 0) { 42 if (stat(path, &s) == 0) {
38 *mtime = read_agefile(path); 43 *mtime = read_agefile(path);
44 r->mtime = *mtime;
39 return 1; 45 return 1;
40 } 46 }
41 47
42 path = fmt("%s/refs/heads/%s", repo->path, repo->defbranch); 48 path = fmt("%s/refs/heads/%s", repo->path, repo->defbranch);
43 if (stat(path, &s) == 0) { 49 if (stat(path, &s) == 0)
44 *mtime = s.st_mtime; 50 *mtime = s.st_mtime;
45 return 1; 51 else
46 } 52 *mtime = 0;
47 return 0; 53
54 r->mtime = *mtime;
55 return (r->mtime != 0);
48} 56}
49 57
50static void print_modtime(struct cgit_repo *repo) 58static void print_modtime(struct cgit_repo *repo)
51{ 59{
52 time_t t; 60 time_t t;
53 if (get_repo_modtime(repo, &t)) 61 if (get_repo_modtime(repo, &t))
54 cgit_print_age(t, -1, NULL); 62 cgit_print_age(t, -1, NULL);
55} 63}
56 64
57int is_match(struct cgit_repo *repo) 65int is_match(struct cgit_repo *repo)
58{ 66{
59 if (!ctx.qry.search) 67 if (!ctx.qry.search)
60 return 1; 68 return 1;
61 if (repo->url && strcasestr(repo->url, ctx.qry.search)) 69 if (repo->url && strcasestr(repo->url, ctx.qry.search))
62 return 1; 70 return 1;
63 if (repo->name && strcasestr(repo->name, ctx.qry.search)) 71 if (repo->name && strcasestr(repo->name, ctx.qry.search))
64 return 1; 72 return 1;
65 if (repo->desc && strcasestr(repo->desc, ctx.qry.search)) 73 if (repo->desc && strcasestr(repo->desc, ctx.qry.search))
66 return 1; 74 return 1;
67 if (repo->owner && strcasestr(repo->owner, ctx.qry.search)) 75 if (repo->owner && strcasestr(repo->owner, ctx.qry.search))
68 return 1; 76 return 1;
69 return 0; 77 return 0;
70} 78}
71 79
72int is_in_url(struct cgit_repo *repo) 80int is_in_url(struct cgit_repo *repo)
73{ 81{
74 if (!ctx.qry.url) 82 if (!ctx.qry.url)
75 return 1; 83 return 1;
76 if (repo->url && !prefixcmp(repo->url, ctx.qry.url)) 84 if (repo->url && !prefixcmp(repo->url, ctx.qry.url))
77 return 1; 85 return 1;
78 return 0; 86 return 0;
79} 87}
80 88
81void print_sort_header(const char *title, const char *sort) 89void print_sort_header(const char *title, const char *sort)
82{ 90{
83 htmlf("<th class='left'><a href='./?s=%s", sort); 91 htmlf("<th class='left'><a href='./?s=%s", sort);
84 if (ctx.qry.search) { 92 if (ctx.qry.search) {
85 html("&q="); 93 html("&q=");
86 html_url_arg(ctx.qry.search); 94 html_url_arg(ctx.qry.search);
87 } 95 }
88 htmlf("'>%s</a></th>", title); 96 htmlf("'>%s</a></th>", title);
89} 97}
90 98
91void print_header(int columns) 99void print_header(int columns)
92{ 100{
93 html("<tr class='nohover'>"); 101 html("<tr class='nohover'>");
94 print_sort_header("Name", "name"); 102 print_sort_header("Name", "name");
95 print_sort_header("Description", "desc"); 103 print_sort_header("Description", "desc");
96 print_sort_header("Owner", "owner"); 104 print_sort_header("Owner", "owner");
97 print_sort_header("Idle", "idle"); 105 print_sort_header("Idle", "idle");
98 if (ctx.cfg.enable_index_links) 106 if (ctx.cfg.enable_index_links)
99 html("<th class='left'>Links</th>"); 107 html("<th class='left'>Links</th>");
100 html("</tr>\n"); 108 html("</tr>\n");
101} 109}
102 110
103 111
104void print_pager(int items, int pagelen, char *search) 112void print_pager(int items, int pagelen, char *search)
105{ 113{
106 int i; 114 int i;
107 html("<div class='pager'>"); 115 html("<div class='pager'>");
108 for(i = 0; i * pagelen < items; i++) 116 for(i = 0; i * pagelen < items; i++)
109 cgit_index_link(fmt("[%d]", i+1), fmt("Page %d", i+1), NULL, 117 cgit_index_link(fmt("[%d]", i+1), fmt("Page %d", i+1), NULL,
110 search, i * pagelen); 118 search, i * pagelen);
111 html("</div>"); 119 html("</div>");
112} 120}
113 121
114static int cmp(const char *s1, const char *s2) 122static int cmp(const char *s1, const char *s2)
115{ 123{
116 if (s1 && s2) 124 if (s1 && s2)
117 return strcmp(s1, s2); 125 return strcmp(s1, s2);
118 if (s1 && !s2) 126 if (s1 && !s2)
119 return -1; 127 return -1;
120 if (s2 && !s1) 128 if (s2 && !s1)
121 return 1; 129 return 1;
122 return 0; 130 return 0;
123} 131}
124 132
125static int sort_name(const void *a, const void *b) 133static int sort_name(const void *a, const void *b)
126{ 134{
127 const struct cgit_repo *r1 = a; 135 const struct cgit_repo *r1 = a;
128 const struct cgit_repo *r2 = b; 136 const struct cgit_repo *r2 = b;
129 137
130 return cmp(r1->name, r2->name); 138 return cmp(r1->name, r2->name);
131} 139}
132 140
133static int sort_desc(const void *a, const void *b) 141static int sort_desc(const void *a, const void *b)
134{ 142{
135 const struct cgit_repo *r1 = a; 143 const struct cgit_repo *r1 = a;
136 const struct cgit_repo *r2 = b; 144 const struct cgit_repo *r2 = b;
137 145
138 return cmp(r1->desc, r2->desc); 146 return cmp(r1->desc, r2->desc);
139} 147}
140 148
141static int sort_owner(const void *a, const void *b) 149static int sort_owner(const void *a, const void *b)
142{ 150{
143 const struct cgit_repo *r1 = a; 151 const struct cgit_repo *r1 = a;