Skip to content

Commit 05bed69

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 c62bd7e commit 05bed69

File tree

1 file changed

+24
-21
lines changed

1 file changed

+24
-21
lines changed

compat/win32/fscache.c

+24-21
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,9 @@ 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+
mem_pool_init(&cache->mem_pool, 0);
269+
hashmap_free(&cache->map);
271270
hashmap_init(&cache->map, (hashmap_cmp_fn)fsentry_cmp, NULL, 0);
272271
cache->lstat_requests = cache->opendir_requests = 0;
273272
cache->fscache_misses = cache->fscache_requests = 0;
@@ -320,7 +319,7 @@ static struct fsentry *fscache_get(struct fscache *cache, struct fsentry *key)
320319
}
321320

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

325324
/* leave on error (errno set by fsentry_create_list) */
326325
if (!fse) {
@@ -330,7 +329,7 @@ static struct fsentry *fscache_get(struct fscache *cache, struct fsentry *key)
330329
* empty, which for all practical matters is the same
331330
* thing as far as fscache is concerned).
332331
*/
333-
fse = fsentry_alloc(key->list->list,
332+
fse = fsentry_alloc(cache, key->list->list,
334333
key->list->dirent.d_name,
335334
key->list->len);
336335
fse->st_mode = 0;
@@ -409,6 +408,7 @@ int fscache_enable(size_t initial_size)
409408
* '4' was determined empirically by testing several repos
410409
*/
411410
hashmap_init(&cache->map, (hashmap_cmp_fn)fsentry_cmp, NULL, initial_size * 4);
411+
mem_pool_init(&cache->mem_pool, 0);
412412
if (!TlsSetValue(dwTlsIndex, cache))
413413
BUG("TlsSetValue error");
414414
}
@@ -440,7 +440,8 @@ void fscache_disable(void)
440440
"total requests/misses %u/%u\n",
441441
cache->lstat_requests, cache->opendir_requests,
442442
cache->fscache_requests, cache->fscache_misses);
443-
fscache_clear(cache);
443+
mem_pool_discard(&cache->mem_pool, 0);
444+
hashmap_free(&cache->map);
444445
free(cache);
445446
}
446447

@@ -623,6 +624,8 @@ void fscache_merge(struct fscache *dest)
623624
while ((e = hashmap_iter_next(&iter)))
624625
hashmap_add(&dest->map, e);
625626

627+
mem_pool_combine(&dest->mem_pool, &cache->mem_pool);
628+
626629
dest->lstat_requests += cache->lstat_requests;
627630
dest->opendir_requests += cache->opendir_requests;
628631
dest->fscache_requests += cache->fscache_requests;

0 commit comments

Comments
 (0)