Skip to content

Commit 1ad0115

Browse files
benpeartdscho
authored andcommitted
fscache: teach fscache to use mempool
Now that the fscache is single threaded, take advantage of the mem_pool as the allocator to significantly reduce the cost of allocations and frees. With the reduced cost of free, in future patches, we can start freeing the fscache at the end of commands instead of just leaking it. Signed-off-by: Ben Peart <[email protected]> Signed-off-by: Johannes Schindelin <[email protected]>
1 parent 580ced9 commit 1ad0115

File tree

1 file changed

+24
-21
lines changed

1 file changed

+24
-21
lines changed

compat/win32/fscache.c

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "../../abspath.h"
77
#include "../../trace.h"
88
#include "config.h"
9+
#include "../../mem-pool.h"
910

1011
static volatile long initialized;
1112
static DWORD dwTlsIndex;
@@ -20,6 +21,7 @@ static CRITICAL_SECTION mutex;
2021
struct fscache {
2122
volatile long enabled;
2223
struct hashmap map;
24+
struct mem_pool mem_pool;
2325
unsigned int lstat_requests;
2426
unsigned int opendir_requests;
2527
unsigned int fscache_requests;
@@ -124,11 +126,12 @@ static void fsentry_init(struct fsentry *fse, struct fsentry *list,
124126
/*
125127
* Allocate an fsentry structure on the heap.
126128
*/
127-
static struct fsentry *fsentry_alloc(struct fsentry *list, const char *name,
129+
static struct fsentry *fsentry_alloc(struct fscache *cache, struct fsentry *list, const char *name,
128130
size_t len)
129131
{
130132
/* overallocate fsentry and copy the name to the end */
131-
struct fsentry *fse = xmalloc(sizeof(struct fsentry) + len + 1);
133+
struct fsentry *fse =
134+
mem_pool_alloc(&cache->mem_pool, sizeof(*fse) + len + 1);
132135
/* init the rest of the structure */
133136
fsentry_init(fse, list, name, len);
134137
fse->next = NULL;
@@ -148,35 +151,29 @@ inline static void fsentry_addref(struct fsentry *fse)
148151
}
149152

150153
/*
151-
* Release the reference to an fsentry, frees the memory if its the last ref.
154+
* Release the reference to an fsentry.
152155
*/
153156
static void fsentry_release(struct fsentry *fse)
154157
{
155158
if (fse->list)
156159
fse = fse->list;
157160

158-
if (InterlockedDecrement(&(fse->u.refcnt)))
159-
return;
160-
161-
while (fse) {
162-
struct fsentry *next = fse->next;
163-
free(fse);
164-
fse = next;
165-
}
161+
InterlockedDecrement(&(fse->u.refcnt));
166162
}
167163

168164
/*
169165
* Allocate and initialize an fsentry from a WIN32_FIND_DATA structure.
170166
*/
171-
static struct fsentry *fseentry_create_entry(struct fsentry *list,
167+
static struct fsentry *fseentry_create_entry(struct fscache *cache,
168+
struct fsentry *list,
172169
const WIN32_FIND_DATAW *fdata)
173170
{
174171
char buf[MAX_PATH * 3];
175172
int len;
176173
struct fsentry *fse;
177174
len = xwcstoutf(buf, fdata->cFileName, ARRAY_SIZE(buf));
178175

179-
fse = fsentry_alloc(list, buf, len);
176+
fse = fsentry_alloc(cache, list, buf, len);
180177

181178
fse->st_mode = file_attr_to_st_mode(fdata->dwFileAttributes);
182179
fse->dirent.d_type = S_ISDIR(fse->st_mode) ? DT_DIR : DT_REG;
@@ -194,7 +191,7 @@ static struct fsentry *fseentry_create_entry(struct fsentry *list,
194191
* Dir should not contain trailing '/'. Use an empty string for the current
195192
* directory (not "."!).
196193
*/
197-
static struct fsentry *fsentry_create_list(const struct fsentry *dir,
194+
static struct fsentry *fsentry_create_list(struct fscache *cache, const struct fsentry *dir,
198195
int *dir_not_found)
199196
{
200197
wchar_t pattern[MAX_PATH + 2]; /* + 2 for '/' '*' */
@@ -233,14 +230,14 @@ static struct fsentry *fsentry_create_list(const struct fsentry *dir,
233230
}
234231

235232
/* allocate object to hold directory listing */
236-
list = fsentry_alloc(NULL, dir->dirent.d_name, dir->len);
233+
list = fsentry_alloc(cache, NULL, dir->dirent.d_name, dir->len);
237234
list->st_mode = S_IFDIR;
238235
list->dirent.d_type = DT_DIR;
239236

240237
/* walk directory and build linked list of fsentry structures */
241238
phead = &list->next;
242239
do {
243-
*phead = fseentry_create_entry(list, &fdata);
240+
*phead = fseentry_create_entry(cache, list, &fdata);
244241
phead = &(*phead)->next;
245242
} while (FindNextFileW(h, &fdata));
246243

@@ -252,7 +249,7 @@ static struct fsentry *fsentry_create_list(const struct fsentry *dir,
252249
if (err == ERROR_NO_MORE_FILES)
253250
return list;
254251

255-
/* otherwise free the list and return error */
252+
/* otherwise release the list and return error */
256253
fsentry_release(list);
257254
errno = err_win_to_posix(err);
258255
return NULL;
@@ -275,7 +272,9 @@ static void fscache_add(struct fscache *cache, struct fsentry *fse)
275272
*/
276273
static void fscache_clear(struct fscache *cache)
277274
{
278-
hashmap_clear_and_free(&cache->map, struct fsentry, ent);
275+
mem_pool_discard(&cache->mem_pool, 0);
276+
mem_pool_init(&cache->mem_pool, 0);
277+
hashmap_clear(&cache->map);
279278
hashmap_init(&cache->map, (hashmap_cmp_fn)fsentry_cmp, NULL, 0);
280279
cache->lstat_requests = cache->opendir_requests = 0;
281280
cache->fscache_misses = cache->fscache_requests = 0;
@@ -328,7 +327,7 @@ static struct fsentry *fscache_get(struct fscache *cache, struct fsentry *key)
328327
}
329328

330329
/* create the directory listing */
331-
fse = fsentry_create_list(key->list ? key->list : key, &dir_not_found);
330+
fse = fsentry_create_list(cache, key->list ? key->list : key, &dir_not_found);
332331

333332
/* leave on error (errno set by fsentry_create_list) */
334333
if (!fse) {
@@ -338,7 +337,7 @@ static struct fsentry *fscache_get(struct fscache *cache, struct fsentry *key)
338337
* empty, which for all practical matters is the same
339338
* thing as far as fscache is concerned).
340339
*/
341-
fse = fsentry_alloc(key->list->list,
340+
fse = fsentry_alloc(cache, key->list->list,
342341
key->list->dirent.d_name,
343342
key->list->len);
344343
fse->st_mode = 0;
@@ -417,6 +416,7 @@ int fscache_enable(size_t initial_size)
417416
* '4' was determined empirically by testing several repos
418417
*/
419418
hashmap_init(&cache->map, (hashmap_cmp_fn)fsentry_cmp, NULL, initial_size * 4);
419+
mem_pool_init(&cache->mem_pool, 0);
420420
if (!TlsSetValue(dwTlsIndex, cache))
421421
BUG("TlsSetValue error");
422422
}
@@ -448,7 +448,8 @@ void fscache_disable(void)
448448
"total requests/misses %u/%u\n",
449449
cache->lstat_requests, cache->opendir_requests,
450450
cache->fscache_requests, cache->fscache_misses);
451-
fscache_clear(cache);
451+
mem_pool_discard(&cache->mem_pool, 0);
452+
hashmap_clear(&cache->map);
452453
free(cache);
453454
}
454455

@@ -633,6 +634,8 @@ void fscache_merge(struct fscache *dest)
633634
while ((e = hashmap_iter_next(&iter)))
634635
hashmap_add(&dest->map, e);
635636

637+
mem_pool_combine(&dest->mem_pool, &cache->mem_pool);
638+
636639
dest->lstat_requests += cache->lstat_requests;
637640
dest->opendir_requests += cache->opendir_requests;
638641
dest->fscache_requests += cache->fscache_requests;

0 commit comments

Comments
 (0)