Skip to content

Commit c203993

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 05d90d7 commit c203993

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
@@ -3,6 +3,7 @@
33
#include "../win32.h"
44
#include "fscache.h"
55
#include "config.h"
6+
#include "../../mem-pool.h"
67

78
static volatile long initialized;
89
static DWORD dwTlsIndex;
@@ -17,6 +18,7 @@ static CRITICAL_SECTION mutex;
1718
struct fscache {
1819
volatile long enabled;
1920
struct hashmap map;
21+
struct mem_pool mem_pool;
2022
unsigned int lstat_requests;
2123
unsigned int opendir_requests;
2224
unsigned int fscache_requests;
@@ -121,11 +123,12 @@ static void fsentry_init(struct fsentry *fse, struct fsentry *list,
121123
/*
122124
* Allocate an fsentry structure on the heap.
123125
*/
124-
static struct fsentry *fsentry_alloc(struct fsentry *list, const char *name,
126+
static struct fsentry *fsentry_alloc(struct fscache *cache, struct fsentry *list, const char *name,
125127
size_t len)
126128
{
127129
/* overallocate fsentry and copy the name to the end */
128-
struct fsentry *fse = xmalloc(sizeof(struct fsentry) + len + 1);
130+
struct fsentry *fse =
131+
mem_pool_alloc(&cache->mem_pool, sizeof(*fse) + len + 1);
129132
/* init the rest of the structure */
130133
fsentry_init(fse, list, name, len);
131134
fse->next = NULL;
@@ -145,35 +148,29 @@ inline static void fsentry_addref(struct fsentry *fse)
145148
}
146149

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

155-
if (InterlockedDecrement(&(fse->u.refcnt)))
156-
return;
157-
158-
while (fse) {
159-
struct fsentry *next = fse->next;
160-
free(fse);
161-
fse = next;
162-
}
158+
InterlockedDecrement(&(fse->u.refcnt));
163159
}
164160

165161
/*
166162
* Allocate and initialize an fsentry from a WIN32_FIND_DATA structure.
167163
*/
168-
static struct fsentry *fseentry_create_entry(struct fsentry *list,
164+
static struct fsentry *fseentry_create_entry(struct fscache *cache,
165+
struct fsentry *list,
169166
const WIN32_FIND_DATAW *fdata)
170167
{
171168
char buf[MAX_PATH * 3];
172169
int len;
173170
struct fsentry *fse;
174171
len = xwcstoutf(buf, fdata->cFileName, ARRAY_SIZE(buf));
175172

176-
fse = fsentry_alloc(list, buf, len);
173+
fse = fsentry_alloc(cache, list, buf, len);
177174

178175
fse->st_mode = file_attr_to_st_mode(fdata->dwFileAttributes);
179176
fse->dirent.d_type = S_ISDIR(fse->st_mode) ? DT_DIR : DT_REG;
@@ -191,7 +188,7 @@ static struct fsentry *fseentry_create_entry(struct fsentry *list,
191188
* Dir should not contain trailing '/'. Use an empty string for the current
192189
* directory (not "."!).
193190
*/
194-
static struct fsentry *fsentry_create_list(const struct fsentry *dir,
191+
static struct fsentry *fsentry_create_list(struct fscache *cache, const struct fsentry *dir,
195192
int *dir_not_found)
196193
{
197194
wchar_t pattern[MAX_PATH + 2]; /* + 2 for '/' '*' */
@@ -230,14 +227,14 @@ static struct fsentry *fsentry_create_list(const struct fsentry *dir,
230227
}
231228

232229
/* allocate object to hold directory listing */
233-
list = fsentry_alloc(NULL, dir->dirent.d_name, dir->len);
230+
list = fsentry_alloc(cache, NULL, dir->dirent.d_name, dir->len);
234231
list->st_mode = S_IFDIR;
235232
list->dirent.d_type = DT_DIR;
236233

237234
/* walk directory and build linked list of fsentry structures */
238235
phead = &list->next;
239236
do {
240-
*phead = fseentry_create_entry(list, &fdata);
237+
*phead = fseentry_create_entry(cache, list, &fdata);
241238
phead = &(*phead)->next;
242239
} while (FindNextFileW(h, &fdata));
243240

@@ -249,7 +246,7 @@ static struct fsentry *fsentry_create_list(const struct fsentry *dir,
249246
if (err == ERROR_NO_MORE_FILES)
250247
return list;
251248

252-
/* otherwise free the list and return error */
249+
/* otherwise release the list and return error */
253250
fsentry_release(list);
254251
errno = err_win_to_posix(err);
255252
return NULL;
@@ -272,7 +269,9 @@ static void fscache_add(struct fscache *cache, struct fsentry *fse)
272269
*/
273270
static void fscache_clear(struct fscache *cache)
274271
{
275-
hashmap_clear_and_free(&cache->map, struct fsentry, ent);
272+
mem_pool_discard(&cache->mem_pool, 0);
273+
mem_pool_init(&cache->mem_pool, 0);
274+
hashmap_clear(&cache->map);
276275
hashmap_init(&cache->map, (hashmap_cmp_fn)fsentry_cmp, NULL, 0);
277276
cache->lstat_requests = cache->opendir_requests = 0;
278277
cache->fscache_misses = cache->fscache_requests = 0;
@@ -325,7 +324,7 @@ static struct fsentry *fscache_get(struct fscache *cache, struct fsentry *key)
325324
}
326325

327326
/* create the directory listing */
328-
fse = fsentry_create_list(key->list ? key->list : key, &dir_not_found);
327+
fse = fsentry_create_list(cache, key->list ? key->list : key, &dir_not_found);
329328

330329
/* leave on error (errno set by fsentry_create_list) */
331330
if (!fse) {
@@ -335,7 +334,7 @@ static struct fsentry *fscache_get(struct fscache *cache, struct fsentry *key)
335334
* empty, which for all practical matters is the same
336335
* thing as far as fscache is concerned).
337336
*/
338-
fse = fsentry_alloc(key->list->list,
337+
fse = fsentry_alloc(cache, key->list->list,
339338
key->list->dirent.d_name,
340339
key->list->len);
341340
fse->st_mode = 0;
@@ -414,6 +413,7 @@ int fscache_enable(size_t initial_size)
414413
* '4' was determined empirically by testing several repos
415414
*/
416415
hashmap_init(&cache->map, (hashmap_cmp_fn)fsentry_cmp, NULL, initial_size * 4);
416+
mem_pool_init(&cache->mem_pool, 0);
417417
if (!TlsSetValue(dwTlsIndex, cache))
418418
BUG("TlsSetValue error");
419419
}
@@ -445,7 +445,8 @@ void fscache_disable(void)
445445
"total requests/misses %u/%u\n",
446446
cache->lstat_requests, cache->opendir_requests,
447447
cache->fscache_requests, cache->fscache_misses);
448-
fscache_clear(cache);
448+
mem_pool_discard(&cache->mem_pool, 0);
449+
hashmap_clear(&cache->map);
449450
free(cache);
450451
}
451452

@@ -630,6 +631,8 @@ void fscache_merge(struct fscache *dest)
630631
while ((e = hashmap_iter_next(&iter)))
631632
hashmap_add(&dest->map, e);
632633

634+
mem_pool_combine(&dest->mem_pool, &cache->mem_pool);
635+
633636
dest->lstat_requests += cache->lstat_requests;
634637
dest->opendir_requests += cache->opendir_requests;
635638
dest->fscache_requests += cache->fscache_requests;

0 commit comments

Comments
 (0)