whitespace cleanup
[fusedav.git] / src / statcache.c
blob3105a5b84c9f2620fd9439584df135551acc5a9e
1 /* $Id$ */
3 /***
4 Copyright (c) 2004-2006 Lennart Poettering
6 Permission is hereby granted, free of charge, to any person
7 obtaining a copy of this software and associated documentation files
8 (the "Software"), to deal in the Software without restriction,
9 including without limitation the rights to use, copy, modify, merge,
10 publish, distribute, sublicense, and/or sell copies of the Software,
11 and to permit persons to whom the Software is furnished to do so,
12 subject to the following conditions:
14 The above copyright notice and this permission notice shall be
15 included in all copies or substantial portions of the Software.
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 SOFTWARE.
25 ***/
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
31 #include <stdio.h>
32 #include <inttypes.h>
33 #include <time.h>
34 #include <string.h>
35 #include <malloc.h>
36 #include <pthread.h>
37 #include <assert.h>
39 #include "statcache.h"
40 #include "filecache.h"
41 #include "fusedav.h"
43 #include <ne_uri.h>
45 #define CACHE_SIZE 2049
46 #define CACHE_TIMEOUT 60
48 struct dir_entry {
49 struct dir_entry *next;
50 char filename[];
53 struct cache_entry {
54 struct {
55 int valid;
56 uint32_t hash;
57 char *filename;
58 time_t dead;
59 struct stat st;
60 } stat_info;
62 struct {
63 int valid, filling, in_use, valid2;
64 uint32_t hash;
65 char *filename;
66 struct dir_entry *entries, *entries2;
67 time_t dead, dead2;
68 } dir_info;
71 static struct cache_entry *cache = NULL;
72 static pthread_mutex_t stat_cache_mutex = PTHREAD_MUTEX_INITIALIZER;
73 static pthread_mutex_t dir_cache_mutex = PTHREAD_MUTEX_INITIALIZER;
75 static uint32_t calc_hash(const char *s) {
76 uint32_t h = 0;
78 for (; *s; s++) {
79 h ^= * (const uint8_t*) s;
80 h = (h << 8) | (h >> 24);
83 return h;
86 int stat_cache_get(const char *fn, struct stat *st) {
87 uint32_t h;
88 struct cache_entry *ce;
89 int r = -1;
90 void *f;
92 if (debug)
93 fprintf(stderr, "CGET: %s\n", fn);
95 assert(cache);
97 h = calc_hash(fn);
98 ce = cache + (h % CACHE_SIZE);
100 pthread_mutex_lock(&stat_cache_mutex);
102 if (ce->stat_info.valid &&
103 ce->stat_info.filename &&
104 ce->stat_info.hash == h &&
105 !strcmp(ce->stat_info.filename, fn) &&
106 time(NULL) <= ce->stat_info.dead) {
108 *st = ce->stat_info.st;
110 if ((f = file_cache_get(fn))) {
111 st->st_size = file_cache_get_size(f);
112 file_cache_unref(f);
115 r = 0;
118 pthread_mutex_unlock(&stat_cache_mutex);
120 return r;
123 void stat_cache_set(const char *fn, const struct stat*st) {
124 uint32_t h;
125 struct cache_entry *ce;
127 if (debug)
128 fprintf(stderr, "CSET: %s\n", fn);
129 assert(cache);
131 h = calc_hash(fn);
132 ce = cache + (h % CACHE_SIZE);
134 pthread_mutex_lock(&stat_cache_mutex);
136 if (!ce->stat_info.filename || ce->stat_info.hash != h || strcmp(ce->stat_info.filename, fn)) {
137 free(ce->stat_info.filename);
138 ce->stat_info.filename = strdup(fn);
139 ce->stat_info.hash = h;
142 ce->stat_info.st = *st;
143 ce->stat_info.dead = time(NULL)+CACHE_TIMEOUT;
144 ce->stat_info.valid = 1;
146 pthread_mutex_unlock(&stat_cache_mutex);
149 void stat_cache_invalidate(const char*fn) {
150 uint32_t h;
151 struct cache_entry *ce;
153 assert(cache);
155 h = calc_hash(fn);
156 ce = cache + (h % CACHE_SIZE);
158 pthread_mutex_lock(&stat_cache_mutex);
160 ce->stat_info.valid = 0;
161 free(ce->stat_info.filename);
162 ce->stat_info.filename = NULL;
164 pthread_mutex_unlock(&stat_cache_mutex);
167 static void free_dir_entries(struct dir_entry *de) {
169 while (de) {
170 struct dir_entry *next = de->next;
171 free(de);
172 de = next;
177 void dir_cache_begin(const char *fn) {
178 uint32_t h;
179 struct cache_entry *ce;
180 struct dir_entry *de = NULL, *de2 = NULL;
181 assert(cache);
183 h = calc_hash(fn);
184 ce = cache + (h % CACHE_SIZE);
186 pthread_mutex_lock(&dir_cache_mutex);
188 if (!ce->dir_info.filling) {
190 if (!ce->dir_info.filename || ce->dir_info.hash != h || strcmp(ce->dir_info.filename, fn)) {
191 free(ce->dir_info.filename);
192 ce->dir_info.filename = strdup(fn);
193 ce->dir_info.hash = h;
195 de = ce->dir_info.entries;
196 ce->dir_info.entries = NULL;
197 ce->dir_info.valid = 0;
200 de2 = ce->dir_info.entries2;
201 ce->dir_info.entries2 = NULL;
202 ce->dir_info.valid2 = 0;
203 ce->dir_info.filling = 1;
206 pthread_mutex_unlock(&dir_cache_mutex);
207 free_dir_entries(de);
208 free_dir_entries(de2);
211 void dir_cache_finish(const char *fn, int success) {
212 uint32_t h;
213 struct cache_entry *ce;
214 struct dir_entry *de = NULL;
215 assert(cache);
217 h = calc_hash(fn);
218 ce = cache + (h % CACHE_SIZE);
220 pthread_mutex_lock(&dir_cache_mutex);
222 if (ce->dir_info.filling &&
223 ce->dir_info.filename &&
224 ce->dir_info.hash == h &&
225 !strcmp(ce->dir_info.filename, fn)) {
227 assert(!ce->dir_info.valid2);
229 if (success) {
231 ce->dir_info.valid2 = 1;
232 ce->dir_info.filling = 0;
233 ce->dir_info.dead2 = time(NULL)+CACHE_TIMEOUT;
235 if (!ce->dir_info.in_use) {
236 de = ce->dir_info.entries;
237 ce->dir_info.entries = ce->dir_info.entries2;
238 ce->dir_info.entries2 = NULL;
239 ce->dir_info.dead = ce->dir_info.dead2;
240 ce->dir_info.valid2 = 0;
241 ce->dir_info.valid = 1;
244 } else {
245 ce->dir_info.filling = 0;
246 de = ce->dir_info.entries2;
247 ce->dir_info.entries2 = NULL;
251 pthread_mutex_unlock(&dir_cache_mutex);
252 free_dir_entries(de);
255 void dir_cache_add(const char *fn, const char *subdir) {
256 uint32_t h;
257 struct cache_entry *ce;
258 assert(cache);
260 h = calc_hash(fn);
261 ce = cache + (h % CACHE_SIZE);
263 pthread_mutex_lock(&dir_cache_mutex);
265 if (ce->dir_info.filling &&
266 ce->dir_info.filename &&
267 ce->dir_info.hash == h &&
268 !strcmp(ce->dir_info.filename, fn)) {
270 struct dir_entry *n;
272 assert(!ce->dir_info.valid2);
274 n = malloc(sizeof(struct dir_entry) + strlen(subdir) + 1);
275 assert(n);
277 strcpy(n->filename, subdir);
279 n->next = ce->dir_info.entries2;
280 ce->dir_info.entries2 = n;
283 pthread_mutex_unlock(&dir_cache_mutex);
286 int dir_cache_enumerate(const char *fn, void (*f) (const char*fn, const char *subdir, void *user), void *user) {
287 uint32_t h;
288 struct cache_entry *ce;
289 struct dir_entry *de = NULL;
290 int r = -1;
292 assert(cache && f);
294 h = calc_hash(fn);
295 ce = cache + (h % CACHE_SIZE);
297 pthread_mutex_lock(&dir_cache_mutex);
299 if (ce->dir_info.valid &&
300 ce->dir_info.filename &&
301 ce->dir_info.hash == h &&
302 !strcmp(ce->dir_info.filename, fn) &&
303 time(NULL) <= ce->dir_info.dead) {
305 ce->dir_info.in_use = 1;
306 pthread_mutex_unlock(&dir_cache_mutex);
308 for (de = ce->dir_info.entries; de; de = de->next)
309 f(fn, de->filename, user);
311 pthread_mutex_lock(&dir_cache_mutex);
312 ce->dir_info.in_use = 0;
314 if (ce->dir_info.valid2) {
315 de = ce->dir_info.entries;
316 ce->dir_info.entries = ce->dir_info.entries2;
317 ce->dir_info.entries2 = NULL;
318 ce->dir_info.dead = ce->dir_info.dead2;
319 ce->dir_info.valid2 = 0;
320 ce->dir_info.valid = 1;
323 r = 0;
326 pthread_mutex_unlock(&dir_cache_mutex);
327 free_dir_entries(de);
329 return r;
332 void dir_cache_invalidate(const char*fn) {
333 uint32_t h;
334 struct cache_entry *ce;
335 struct dir_entry *de = NULL;
336 assert(cache && fn);
338 h = calc_hash(fn);
339 ce = cache + (h % CACHE_SIZE);
340 pthread_mutex_lock(&dir_cache_mutex);
342 if (ce->dir_info.valid &&
343 ce->dir_info.filename &&
344 ce->dir_info.hash == h &&
345 !strcmp(ce->dir_info.filename, fn)) {
347 ce->dir_info.valid = 0;
348 de = ce->dir_info.entries;
349 ce->dir_info.entries = NULL;
352 pthread_mutex_unlock(&dir_cache_mutex);
353 free_dir_entries(de);
356 void dir_cache_invalidate_parent(const char *fn) {
357 char *p;
359 if ((p = ne_path_parent(fn))) {
360 int l = strlen(p);
362 if (strcmp(p, "/") && l) {
363 if (p[l-1] == '/')
364 p[l-1] = 0;
367 dir_cache_invalidate(p);
368 free(p);
369 } else
370 dir_cache_invalidate(fn);
373 void cache_free(void) {
374 uint32_t h;
375 struct cache_entry *ce;
377 if (!cache)
378 return;
380 for (h = 0, ce = cache; h < CACHE_SIZE; h++, ce++) {
381 free(ce->stat_info.filename);
382 free(ce->dir_info.filename);
383 free_dir_entries(ce->dir_info.entries);
384 free_dir_entries(ce->dir_info.entries2);
387 memset(cache, 0, sizeof(struct cache_entry)*CACHE_SIZE);
390 void cache_alloc(void) {
392 if (cache)
393 return;
395 cache = malloc(sizeof(struct cache_entry)*CACHE_SIZE);
396 assert(cache);
397 memset(cache, 0, sizeof(struct cache_entry)*CACHE_SIZE);