Skip to content

Commit d5a98ef

Browse files
benpeartderrickstolee
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 4f5f8b4 commit d5a98ef

File tree

1 file changed

+25
-21
lines changed

1 file changed

+25
-21
lines changed

compat/win32/fscache.c

Lines changed: 25 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;
@@ -116,11 +118,12 @@ static void fsentry_init(struct fsentry *fse, struct fsentry *list,
116118
/*
117119
* Allocate an fsentry structure on the heap.
118120
*/
119-
static struct fsentry *fsentry_alloc(struct fsentry *list, const char *name,
121+
static struct fsentry *fsentry_alloc(struct fscache *cache, struct fsentry *list, const char *name,
120122
size_t len)
121123
{
122124
/* overallocate fsentry and copy the name to the end */
123-
struct fsentry *fse = xmalloc(sizeof(struct fsentry) + len + 1);
125+
struct fsentry *fse =
126+
mem_pool_alloc(cache->mem_pool, sizeof(*fse) + len + 1);
124127
/* init the rest of the structure */
125128
fsentry_init(fse, list, name, len);
126129
fse->next = NULL;
@@ -140,35 +143,29 @@ inline static void fsentry_addref(struct fsentry *fse)
140143
}
141144

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

150-
if (InterlockedDecrement(&(fse->u.refcnt)))
151-
return;
152-
153-
while (fse) {
154-
struct fsentry *next = fse->next;
155-
free(fse);
156-
fse = next;
157-
}
153+
InterlockedDecrement(&(fse->u.refcnt));
158154
}
159155

160156
/*
161157
* Allocate and initialize an fsentry from a WIN32_FIND_DATA structure.
162158
*/
163-
static struct fsentry *fseentry_create_entry(struct fsentry *list,
159+
static struct fsentry *fseentry_create_entry(struct fscache *cache,
160+
struct fsentry *list,
164161
const WIN32_FIND_DATAW *fdata)
165162
{
166163
char buf[MAX_PATH * 3];
167164
int len;
168165
struct fsentry *fse;
169166
len = xwcstoutf(buf, fdata->cFileName, ARRAY_SIZE(buf));
170167

171-
fse = fsentry_alloc(list, buf, len);
168+
fse = fsentry_alloc(cache, list, buf, len);
172169

173170
fse->st_mode = file_attr_to_st_mode(fdata->dwFileAttributes);
174171
fse->dirent.d_type = S_ISDIR(fse->st_mode) ? DT_DIR : DT_REG;
@@ -186,7 +183,7 @@ static struct fsentry *fseentry_create_entry(struct fsentry *list,
186183
* Dir should not contain trailing '/'. Use an empty string for the current
187184
* directory (not "."!).
188185
*/
189-
static struct fsentry *fsentry_create_list(const struct fsentry *dir,
186+
static struct fsentry *fsentry_create_list(struct fscache *cache, const struct fsentry *dir,
190187
int *dir_not_found)
191188
{
192189
wchar_t pattern[MAX_PATH + 2]; /* + 2 for '/' '*' */
@@ -225,14 +222,14 @@ static struct fsentry *fsentry_create_list(const struct fsentry *dir,
225222
}
226223

227224
/* allocate object to hold directory listing */
228-
list = fsentry_alloc(NULL, dir->dirent.d_name, dir->len);
225+
list = fsentry_alloc(cache, NULL, dir->dirent.d_name, dir->len);
229226
list->st_mode = S_IFDIR;
230227
list->dirent.d_type = DT_DIR;
231228

232229
/* walk directory and build linked list of fsentry structures */
233230
phead = &list->next;
234231
do {
235-
*phead = fseentry_create_entry(list, &fdata);
232+
*phead = fseentry_create_entry(cache, list, &fdata);
236233
phead = &(*phead)->next;
237234
} while (FindNextFileW(h, &fdata));
238235

@@ -244,7 +241,7 @@ static struct fsentry *fsentry_create_list(const struct fsentry *dir,
244241
if (err == ERROR_NO_MORE_FILES)
245242
return list;
246243

247-
/* otherwise free the list and return error */
244+
/* otherwise release the list and return error */
248245
fsentry_release(list);
249246
errno = err_win_to_posix(err);
250247
return NULL;
@@ -267,7 +264,10 @@ static void fscache_add(struct fscache *cache, struct fsentry *fse)
267264
*/
268265
static void fscache_clear(struct fscache *cache)
269266
{
270-
hashmap_free_entries(&cache->map, struct fsentry, ent);
267+
mem_pool_discard(cache->mem_pool, 0);
268+
cache->mem_pool = NULL;
269+
mem_pool_init(&cache->mem_pool, 0);
270+
hashmap_free(&cache->map);
271271
hashmap_init(&cache->map, (hashmap_cmp_fn)fsentry_cmp, NULL, 0);
272272
cache->lstat_requests = cache->opendir_requests = 0;
273273
cache->fscache_misses = cache->fscache_requests = 0;
@@ -320,7 +320,7 @@ static struct fsentry *fscache_get(struct fscache *cache, struct fsentry *key)
320320
}
321321

322322
/* create the directory listing */
323-
fse = fsentry_create_list(key->list ? key->list : key, &dir_not_found);
323+
fse = fsentry_create_list(cache, key->list ? key->list : key, &dir_not_found);
324324

325325
/* leave on error (errno set by fsentry_create_list) */
326326
if (!fse) {
@@ -330,7 +330,7 @@ static struct fsentry *fscache_get(struct fscache *cache, struct fsentry *key)
330330
* empty, which for all practical matters is the same
331331
* thing as far as fscache is concerned).
332332
*/
333-
fse = fsentry_alloc(key->list->list,
333+
fse = fsentry_alloc(cache, key->list->list,
334334
key->list->dirent.d_name,
335335
key->list->len);
336336
fse->st_mode = 0;
@@ -409,6 +409,7 @@ int fscache_enable(size_t initial_size)
409409
* '4' was determined empirically by testing several repos
410410
*/
411411
hashmap_init(&cache->map, (hashmap_cmp_fn)fsentry_cmp, NULL, initial_size * 4);
412+
mem_pool_init(&cache->mem_pool, 0);
412413
if (!TlsSetValue(dwTlsIndex, cache))
413414
BUG("TlsSetValue error");
414415
}
@@ -440,7 +441,8 @@ void fscache_disable(void)
440441
"total requests/misses %u/%u\n",
441442
cache->lstat_requests, cache->opendir_requests,
442443
cache->fscache_requests, cache->fscache_misses);
443-
fscache_clear(cache);
444+
mem_pool_discard(cache->mem_pool, 0);
445+
hashmap_free(&cache->map);
444446
free(cache);
445447
}
446448

@@ -623,6 +625,8 @@ void fscache_merge(struct fscache *dest)
623625
while ((e = hashmap_iter_next(&iter)))
624626
hashmap_add(&dest->map, e);
625627

628+
mem_pool_combine(dest->mem_pool, cache->mem_pool);
629+
626630
dest->lstat_requests += cache->lstat_requests;
627631
dest->opendir_requests += cache->opendir_requests;
628632
dest->fscache_requests += cache->fscache_requests;

0 commit comments

Comments
 (0)