4 This file is part of fusedav.
6 fusedav is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 fusedav is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
14 License for more details.
16 You should have received a copy of the GNU General Public License
17 along with fusedav; if not, write to the Free Software Foundation,
18 Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33 #include "statcache.h"
34 #include "filecache.h"
39 #define CACHE_SIZE 2049
40 #define CACHE_TIMEOUT 60
43 struct dir_entry
*next
;
58 int valid
, filling
, in_use
, valid2
;
61 struct dir_entry
*entries
, *entries2
;
66 static struct cache_entry
*cache
= NULL
;
67 static pthread_mutex_t stat_cache_mutex
= PTHREAD_MUTEX_INITIALIZER
;
68 static pthread_mutex_t dir_cache_mutex
= PTHREAD_MUTEX_INITIALIZER
;
70 static uint32_t calc_hash(const char *s
) {
74 h
^= * (const uint8_t*) s
;
75 h
= (h
<< 8) | (h
>> 24);
81 int stat_cache_get(const char *fn
, struct stat
*st
) {
83 struct cache_entry
*ce
;
88 fprintf(stderr
, "CGET: %s\n", fn
);
93 ce
= cache
+ (h
% CACHE_SIZE
);
95 pthread_mutex_lock(&stat_cache_mutex
);
97 if (ce
->stat_info
.valid
&&
98 ce
->stat_info
.filename
&&
99 ce
->stat_info
.hash
== h
&&
100 !strcmp(ce
->stat_info
.filename
, fn
) &&
101 time(NULL
) <= ce
->stat_info
.dead
) {
103 *st
= ce
->stat_info
.st
;
105 if ((f
= file_cache_get(fn
))) {
106 st
->st_size
= file_cache_get_size(f
);
113 pthread_mutex_unlock(&stat_cache_mutex
);
118 void stat_cache_set(const char *fn
, const struct stat
*st
) {
120 struct cache_entry
*ce
;
123 fprintf(stderr
, "CSET: %s\n", fn
);
127 ce
= cache
+ (h
% CACHE_SIZE
);
129 pthread_mutex_lock(&stat_cache_mutex
);
131 if (!ce
->stat_info
.filename
|| ce
->stat_info
.hash
!= h
|| strcmp(ce
->stat_info
.filename
, fn
)) {
132 free(ce
->stat_info
.filename
);
133 ce
->stat_info
.filename
= strdup(fn
);
134 ce
->stat_info
.hash
= h
;
137 ce
->stat_info
.st
= *st
;
138 ce
->stat_info
.dead
= time(NULL
)+CACHE_TIMEOUT
;
139 ce
->stat_info
.valid
= 1;
141 pthread_mutex_unlock(&stat_cache_mutex
);
144 void stat_cache_invalidate(const char*fn
) {
146 struct cache_entry
*ce
;
151 ce
= cache
+ (h
% CACHE_SIZE
);
153 pthread_mutex_lock(&stat_cache_mutex
);
155 ce
->stat_info
.valid
= 0;
156 free(ce
->stat_info
.filename
);
157 ce
->stat_info
.filename
= NULL
;
159 pthread_mutex_unlock(&stat_cache_mutex
);
162 static void free_dir_entries(struct dir_entry
*de
) {
165 struct dir_entry
*next
= de
->next
;
172 void dir_cache_begin(const char *fn
) {
174 struct cache_entry
*ce
;
175 struct dir_entry
*de
= NULL
, *de2
= NULL
;
179 ce
= cache
+ (h
% CACHE_SIZE
);
181 pthread_mutex_lock(&dir_cache_mutex
);
183 if (!ce
->dir_info
.filling
) {
185 if (!ce
->dir_info
.filename
|| ce
->dir_info
.hash
!= h
|| strcmp(ce
->dir_info
.filename
, fn
)) {
186 free(ce
->dir_info
.filename
);
187 ce
->dir_info
.filename
= strdup(fn
);
188 ce
->dir_info
.hash
= h
;
190 de
= ce
->dir_info
.entries
;
191 ce
->dir_info
.entries
= NULL
;
192 ce
->dir_info
.valid
= 0;
195 de2
= ce
->dir_info
.entries2
;
196 ce
->dir_info
.entries2
= NULL
;
197 ce
->dir_info
.valid2
= 0;
198 ce
->dir_info
.filling
= 1;
201 pthread_mutex_unlock(&dir_cache_mutex
);
202 free_dir_entries(de
);
203 free_dir_entries(de2
);
206 void dir_cache_finish(const char *fn
, int success
) {
208 struct cache_entry
*ce
;
209 struct dir_entry
*de
= NULL
;
213 ce
= cache
+ (h
% CACHE_SIZE
);
215 pthread_mutex_lock(&dir_cache_mutex
);
217 if (ce
->dir_info
.filling
&&
218 ce
->dir_info
.filename
&&
219 ce
->dir_info
.hash
== h
&&
220 !strcmp(ce
->dir_info
.filename
, fn
)) {
222 assert(!ce
->dir_info
.valid2
);
226 ce
->dir_info
.valid2
= 1;
227 ce
->dir_info
.filling
= 0;
228 ce
->dir_info
.dead2
= time(NULL
)+CACHE_TIMEOUT
;
230 if (!ce
->dir_info
.in_use
) {
231 de
= ce
->dir_info
.entries
;
232 ce
->dir_info
.entries
= ce
->dir_info
.entries2
;
233 ce
->dir_info
.entries2
= NULL
;
234 ce
->dir_info
.dead
= ce
->dir_info
.dead2
;
235 ce
->dir_info
.valid2
= 0;
236 ce
->dir_info
.valid
= 1;
240 ce
->dir_info
.filling
= 0;
241 de
= ce
->dir_info
.entries2
;
242 ce
->dir_info
.entries2
= NULL
;
246 pthread_mutex_unlock(&dir_cache_mutex
);
247 free_dir_entries(de
);
250 void dir_cache_add(const char *fn
, const char *subdir
, int is_dir
) {
252 struct cache_entry
*ce
;
256 ce
= cache
+ (h
% CACHE_SIZE
);
258 pthread_mutex_lock(&dir_cache_mutex
);
260 if (ce
->dir_info
.filling
&&
261 ce
->dir_info
.filename
&&
262 ce
->dir_info
.hash
== h
&&
263 !strcmp(ce
->dir_info
.filename
, fn
)) {
267 assert(!ce
->dir_info
.valid2
);
269 n
= malloc(sizeof(struct dir_entry
) + strlen(subdir
) + 1);
272 strcpy(n
->filename
, subdir
);
275 n
->next
= ce
->dir_info
.entries2
;
276 ce
->dir_info
.entries2
= n
;
279 pthread_mutex_unlock(&dir_cache_mutex
);
282 int dir_cache_enumerate(const char *fn
, void (*f
) (const char*fn
, const char *subdir
, int is_dir
, void *user
), void *user
) {
284 struct cache_entry
*ce
;
285 struct dir_entry
*de
= NULL
;
291 ce
= cache
+ (h
% CACHE_SIZE
);
293 pthread_mutex_lock(&dir_cache_mutex
);
295 if (ce
->dir_info
.valid
&&
296 ce
->dir_info
.filename
&&
297 ce
->dir_info
.hash
== h
&&
298 !strcmp(ce
->dir_info
.filename
, fn
) &&
299 time(NULL
) <= ce
->dir_info
.dead
) {
301 ce
->dir_info
.in_use
= 1;
302 pthread_mutex_unlock(&dir_cache_mutex
);
304 for (de
= ce
->dir_info
.entries
; de
; de
= de
->next
)
305 f(fn
, de
->filename
, de
->is_dir
, user
);
307 pthread_mutex_lock(&dir_cache_mutex
);
308 ce
->dir_info
.in_use
= 0;
310 if (ce
->dir_info
.valid2
) {
311 de
= ce
->dir_info
.entries
;
312 ce
->dir_info
.entries
= ce
->dir_info
.entries2
;
313 ce
->dir_info
.entries2
= NULL
;
314 ce
->dir_info
.dead
= ce
->dir_info
.dead2
;
315 ce
->dir_info
.valid2
= 0;
316 ce
->dir_info
.valid
= 1;
322 pthread_mutex_unlock(&dir_cache_mutex
);
323 free_dir_entries(de
);
328 void dir_cache_invalidate(const char*fn
) {
330 struct cache_entry
*ce
;
331 struct dir_entry
*de
= NULL
;
335 ce
= cache
+ (h
% CACHE_SIZE
);
336 pthread_mutex_lock(&dir_cache_mutex
);
338 if (ce
->dir_info
.valid
&&
339 ce
->dir_info
.filename
&&
340 ce
->dir_info
.hash
== h
&&
341 !strcmp(ce
->dir_info
.filename
, fn
)) {
343 ce
->dir_info
.valid
= 0;
344 de
= ce
->dir_info
.entries
;
345 ce
->dir_info
.entries
= NULL
;
348 pthread_mutex_unlock(&dir_cache_mutex
);
349 free_dir_entries(de
);
352 void dir_cache_invalidate_parent(const char *fn
) {
355 if ((p
= ne_path_parent(fn
))) {
358 if (strcmp(p
, "/") && l
) {
363 dir_cache_invalidate(p
);
366 dir_cache_invalidate(fn
);
369 void cache_free(void) {
371 struct cache_entry
*ce
;
376 for (h
= 0, ce
= cache
; h
< CACHE_SIZE
; h
++, ce
++) {
377 free(ce
->stat_info
.filename
);
378 free(ce
->dir_info
.filename
);
379 free_dir_entries(ce
->dir_info
.entries
);
380 free_dir_entries(ce
->dir_info
.entries2
);
383 memset(cache
, 0, sizeof(struct cache_entry
)*CACHE_SIZE
);
386 void cache_alloc(void) {
391 cache
= malloc(sizeof(struct cache_entry
)*CACHE_SIZE
);
393 memset(cache
, 0, sizeof(struct cache_entry
)*CACHE_SIZE
);