Skip to content

Commit 82c9f96

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 38a3b43 commit 82c9f96

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;
@@ -119,11 +121,12 @@ static void fsentry_init(struct fsentry *fse, struct fsentry *list,
119121
/*
120122
* Allocate an fsentry structure on the heap.
121123
*/
122-
static struct fsentry *fsentry_alloc(struct fsentry *list, const char *name,
124+
static struct fsentry *fsentry_alloc(struct fscache *cache, struct fsentry *list, const char *name,
123125
size_t len)
124126
{
125127
/* overallocate fsentry and copy the name to the end */
126-
struct fsentry *fse = xmalloc(sizeof(struct fsentry) + len + 1);
128+
struct fsentry *fse =
129+
mem_pool_alloc(&cache->mem_pool, sizeof(*fse) + len + 1);
127130
/* init the rest of the structure */
128131
fsentry_init(fse, list, name, len);
129132
fse->next = NULL;
@@ -143,35 +146,29 @@ inline static void fsentry_addref(struct fsentry *fse)
143146
}
144147

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

153-
if (InterlockedDecrement(&(fse->u.refcnt)))
154-
return;
155-
156-
while (fse) {
157-
struct fsentry *next = fse->next;
158-
free(fse);
159-
fse = next;
160-
}
156+
InterlockedDecrement(&(fse->u.refcnt));
161157
}
162158

163159
/*
164160
* Allocate and initialize an fsentry from a WIN32_FIND_DATA structure.
165161
*/
166-
static struct fsentry *fseentry_create_entry(struct fsentry *list,
162+
static struct fsentry *fseentry_create_entry(struct fscache *cache,
163+
struct fsentry *list,
167164
const WIN32_FIND_DATAW *fdata)
168165
{
169166
char buf[MAX_PATH * 3];
170167
int len;
171168
struct fsentry *fse;
172169
len = xwcstoutf(buf, fdata->cFileName, ARRAY_SIZE(buf));
173170

174-
fse = fsentry_alloc(list, buf, len);
171+
fse = fsentry_alloc(cache, list, buf, len);
175172

176173
fse->st_mode = file_attr_to_st_mode(fdata->dwFileAttributes);
177174
fse->dirent.d_type = S_ISDIR(fse->st_mode) ? DT_DIR : DT_REG;
@@ -189,7 +186,7 @@ static struct fsentry *fseentry_create_entry(struct fsentry *list,
189186
* Dir should not contain trailing '/'. Use an empty string for the current
190187
* directory (not "."!).
191188
*/
192-
static struct fsentry *fsentry_create_list(const struct fsentry *dir,
189+
static struct fsentry *fsentry_create_list(struct fscache *cache, const struct fsentry *dir,
193190
int *dir_not_found)
194191
{
195192
wchar_t pattern[MAX_PATH + 2]; /* + 2 for '/' '*' */
@@ -228,14 +225,14 @@ static struct fsentry *fsentry_create_list(const struct fsentry *dir,
228225
}
229226

230227
/* allocate object to hold directory listing */
231-
list = fsentry_alloc(NULL, dir->dirent.d_name, dir->len);
228+
list = fsentry_alloc(cache, NULL, dir->dirent.d_name, dir->len);
232229
list->st_mode = S_IFDIR;
233230
list->dirent.d_type = DT_DIR;
234231

235232
/* walk directory and build linked list of fsentry structures */
236233
phead = &list->next;
237234
do {
238-
*phead = fseentry_create_entry(list, &fdata);
235+
*phead = fseentry_create_entry(cache, list, &fdata);
239236
phead = &(*phead)->next;
240237
} while (FindNextFileW(h, &fdata));
241238

@@ -247,7 +244,7 @@ static struct fsentry *fsentry_create_list(const struct fsentry *dir,
247244
if (err == ERROR_NO_MORE_FILES)
248245
return list;
249246

250-
/* otherwise free the list and return error */
247+
/* otherwise release the list and return error */
251248
fsentry_release(list);
252249
errno = err_win_to_posix(err);
253250
return NULL;
@@ -270,7 +267,9 @@ static void fscache_add(struct fscache *cache, struct fsentry *fse)
270267
*/
271268
static void fscache_clear(struct fscache *cache)
272269
{
273-
hashmap_clear_and_free(&cache->map, struct fsentry, ent);
270+
mem_pool_discard(&cache->mem_pool, 0);
271+
mem_pool_init(&cache->mem_pool, 0);
272+
hashmap_clear(&cache->map);
274273
hashmap_init(&cache->map, (hashmap_cmp_fn)fsentry_cmp, NULL, 0);
275274
cache->lstat_requests = cache->opendir_requests = 0;
276275
cache->fscache_misses = cache->fscache_requests = 0;
@@ -323,7 +322,7 @@ static struct fsentry *fscache_get(struct fscache *cache, struct fsentry *key)
323322
}
324323

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

328327
/* leave on error (errno set by fsentry_create_list) */
329328
if (!fse) {
@@ -333,7 +332,7 @@ static struct fsentry *fscache_get(struct fscache *cache, struct fsentry *key)
333332
* empty, which for all practical matters is the same
334333
* thing as far as fscache is concerned).
335334
*/
336-
fse = fsentry_alloc(key->list->list,
335+
fse = fsentry_alloc(cache, key->list->list,
337336
key->list->dirent.d_name,
338337
key->list->len);
339338
fse->st_mode = 0;
@@ -412,6 +411,7 @@ int fscache_enable(size_t initial_size)
412411
* '4' was determined empirically by testing several repos
413412
*/
414413
hashmap_init(&cache->map, (hashmap_cmp_fn)fsentry_cmp, NULL, initial_size * 4);
414+
mem_pool_init(&cache->mem_pool, 0);
415415
if (!TlsSetValue(dwTlsIndex, cache))
416416
BUG("TlsSetValue error");
417417
}
@@ -443,7 +443,8 @@ void fscache_disable(void)
443443
"total requests/misses %u/%u\n",
444444
cache->lstat_requests, cache->opendir_requests,
445445
cache->fscache_requests, cache->fscache_misses);
446-
fscache_clear(cache);
446+
mem_pool_discard(&cache->mem_pool, 0);
447+
hashmap_clear(&cache->map);
447448
free(cache);
448449
}
449450

@@ -626,6 +627,8 @@ void fscache_merge(struct fscache *dest)
626627
while ((e = hashmap_iter_next(&iter)))
627628
hashmap_add(&dest->map, e);
628629

630+
mem_pool_combine(&dest->mem_pool, &cache->mem_pool);
631+
629632
dest->lstat_requests += cache->lstat_requests;
630633
dest->opendir_requests += cache->opendir_requests;
631634
dest->fscache_requests += cache->fscache_requests;

0 commit comments

Comments
 (0)