Skip to content

Commit 1d1729c

Browse files
matheustavaresgitster
authored andcommitted
grep: replace grep_read_mutex by internal obj read lock
git-grep uses 'grep_read_mutex' to protect its calls to object reading operations. But these have their own internal lock now, which ensures a better performance (allowing parallel access to more regions). So, let's remove the former and, instead, activate the latter with enable_obj_read_lock(). Sections that are currently protected by 'grep_read_mutex' but are not internally protected by the object reading lock should be surrounded by obj_read_lock() and obj_read_unlock(). These guarantee mutual exclusion with object reading operations, keeping the current behavior and avoiding race conditions. Namely, these places are: In grep.c: - fill_textconv() at fill_textconv_grep(). - userdiff_get_textconv() at grep_source_1(). In builtin/grep.c: - parse_object_or_die() and the submodule functions at grep_submodule(). - deref_tag() and gitmodules_config_oid() at grep_objects(). If these functions become thread-safe, in the future, we might remove the locking and probably get some speedup. Note that some of the submodule functions will already be thread-safe (or close to being thread-safe) with the internal object reading lock. However, as some of them will require additional modifications to be removed from the critical section, this will be done in its own patch. Signed-off-by: Matheus Tavares <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 31877c9 commit 1d1729c

File tree

3 files changed

+35
-63
lines changed

3 files changed

+35
-63
lines changed

builtin/grep.c

Lines changed: 16 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -200,12 +200,12 @@ static void start_threads(struct grep_opt *opt)
200200
int i;
201201

202202
pthread_mutex_init(&grep_mutex, NULL);
203-
pthread_mutex_init(&grep_read_mutex, NULL);
204203
pthread_mutex_init(&grep_attr_mutex, NULL);
205204
pthread_cond_init(&cond_add, NULL);
206205
pthread_cond_init(&cond_write, NULL);
207206
pthread_cond_init(&cond_result, NULL);
208207
grep_use_locks = 1;
208+
enable_obj_read_lock();
209209

210210
for (i = 0; i < ARRAY_SIZE(todo); i++) {
211211
strbuf_init(&todo[i].out, 0);
@@ -257,12 +257,12 @@ static int wait_all(void)
257257
free(threads);
258258

259259
pthread_mutex_destroy(&grep_mutex);
260-
pthread_mutex_destroy(&grep_read_mutex);
261260
pthread_mutex_destroy(&grep_attr_mutex);
262261
pthread_cond_destroy(&cond_add);
263262
pthread_cond_destroy(&cond_write);
264263
pthread_cond_destroy(&cond_result);
265264
grep_use_locks = 0;
265+
disable_obj_read_lock();
266266

267267
return hit;
268268
}
@@ -295,16 +295,6 @@ static int grep_cmd_config(const char *var, const char *value, void *cb)
295295
return st;
296296
}
297297

298-
static void *lock_and_read_oid_file(const struct object_id *oid, enum object_type *type, unsigned long *size)
299-
{
300-
void *data;
301-
302-
grep_read_lock();
303-
data = read_object_file(oid, type, size);
304-
grep_read_unlock();
305-
return data;
306-
}
307-
308298
static int grep_oid(struct grep_opt *opt, const struct object_id *oid,
309299
const char *filename, int tree_name_len,
310300
const char *path)
@@ -413,20 +403,20 @@ static int grep_submodule(struct grep_opt *opt,
413403

414404
/*
415405
* NEEDSWORK: submodules functions need to be protected because they
416-
* access the object store via config_from_gitmodules(): the latter
417-
* uses get_oid() which, for now, relies on the global the_repository
418-
* object.
406+
* call config_from_gitmodules(): the latter contains in its call stack
407+
* many thread-unsafe operations that are racy with object reading, such
408+
* as parse_object() and is_promisor_object().
419409
*/
420-
grep_read_lock();
410+
obj_read_lock();
421411
sub = submodule_from_path(superproject, &null_oid, path);
422412

423413
if (!is_submodule_active(superproject, path)) {
424-
grep_read_unlock();
414+
obj_read_unlock();
425415
return 0;
426416
}
427417

428418
if (repo_submodule_init(&subrepo, superproject, sub)) {
429-
grep_read_unlock();
419+
obj_read_unlock();
430420
return 0;
431421
}
432422

@@ -443,7 +433,7 @@ static int grep_submodule(struct grep_opt *opt,
443433
* object.
444434
*/
445435
add_to_alternates_memory(subrepo.objects->odb->path);
446-
grep_read_unlock();
436+
obj_read_unlock();
447437

448438
memcpy(&subopt, opt, sizeof(subopt));
449439
subopt.repo = &subrepo;
@@ -455,13 +445,12 @@ static int grep_submodule(struct grep_opt *opt,
455445
unsigned long size;
456446
struct strbuf base = STRBUF_INIT;
457447

458-
grep_read_lock();
448+
obj_read_lock();
459449
object = parse_object_or_die(oid, oid_to_hex(oid));
450+
obj_read_unlock();
460451
data = read_object_with_reference(&subrepo,
461452
&object->oid, tree_type,
462453
&size, NULL);
463-
grep_read_unlock();
464-
465454
if (!data)
466455
die(_("unable to read tree (%s)"), oid_to_hex(&object->oid));
467456

@@ -586,7 +575,7 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
586575
void *data;
587576
unsigned long size;
588577

589-
data = lock_and_read_oid_file(&entry.oid, &type, &size);
578+
data = read_object_file(&entry.oid, &type, &size);
590579
if (!data)
591580
die(_("unable to read tree (%s)"),
592581
oid_to_hex(&entry.oid));
@@ -624,12 +613,9 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
624613
struct strbuf base;
625614
int hit, len;
626615

627-
grep_read_lock();
628616
data = read_object_with_reference(opt->repo,
629617
&obj->oid, tree_type,
630618
&size, NULL);
631-
grep_read_unlock();
632-
633619
if (!data)
634620
die(_("unable to read tree (%s)"), oid_to_hex(&obj->oid));
635621

@@ -659,17 +645,17 @@ static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec,
659645
for (i = 0; i < nr; i++) {
660646
struct object *real_obj;
661647

662-
grep_read_lock();
648+
obj_read_lock();
663649
real_obj = deref_tag(opt->repo, list->objects[i].item,
664650
NULL, 0);
665-
grep_read_unlock();
651+
obj_read_unlock();
666652

667653
/* load the gitmodules file for this rev */
668654
if (recurse_submodules) {
669655
submodule_free(opt->repo);
670-
grep_read_lock();
656+
obj_read_lock();
671657
gitmodules_config_oid(&real_obj->oid);
672-
grep_read_unlock();
658+
obj_read_unlock();
673659
}
674660
if (grep_object(opt, pathspec, real_obj, list->objects[i].name,
675661
list->objects[i].path)) {

grep.c

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1540,11 +1540,6 @@ static inline void grep_attr_unlock(void)
15401540
pthread_mutex_unlock(&grep_attr_mutex);
15411541
}
15421542

1543-
/*
1544-
* Same as git_attr_mutex, but protecting the thread-unsafe object db access.
1545-
*/
1546-
pthread_mutex_t grep_read_mutex;
1547-
15481543
static int match_funcname(struct grep_opt *opt, struct grep_source *gs, char *bol, char *eol)
15491544
{
15501545
xdemitconf_t *xecfg = opt->priv;
@@ -1741,13 +1736,20 @@ static int fill_textconv_grep(struct repository *r,
17411736
}
17421737

17431738
/*
1744-
* fill_textconv is not remotely thread-safe; it may load objects
1745-
* behind the scenes, and it modifies the global diff tempfile
1746-
* structure.
1739+
* fill_textconv is not remotely thread-safe; it modifies the global
1740+
* diff tempfile structure, writes to the_repo's odb and might
1741+
* internally call thread-unsafe functions such as the
1742+
* prepare_packed_git() lazy-initializator. Because of the last two, we
1743+
* must ensure mutual exclusion between this call and the object reading
1744+
* API, thus we use obj_read_lock() here.
1745+
*
1746+
* TODO: allowing text conversion to run in parallel with object
1747+
* reading operations might increase performance in the multithreaded
1748+
* non-worktreee git-grep with --textconv.
17471749
*/
1748-
grep_read_lock();
1750+
obj_read_lock();
17491751
size = fill_textconv(r, driver, df, &buf);
1750-
grep_read_unlock();
1752+
obj_read_unlock();
17511753
free_filespec(df);
17521754

17531755
/*
@@ -1813,12 +1815,15 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle
18131815
grep_source_load_driver(gs, opt->repo->index);
18141816
/*
18151817
* We might set up the shared textconv cache data here, which
1816-
* is not thread-safe.
1818+
* is not thread-safe. Also, get_oid_with_context() and
1819+
* parse_object() might be internally called. As they are not
1820+
* currenty thread-safe and might be racy with object reading,
1821+
* obj_read_lock() must be called.
18171822
*/
18181823
grep_attr_lock();
1819-
grep_read_lock();
1824+
obj_read_lock();
18201825
textconv = userdiff_get_textconv(opt->repo, gs->driver);
1821-
grep_read_unlock();
1826+
obj_read_unlock();
18221827
grep_attr_unlock();
18231828
}
18241829

@@ -2118,10 +2123,7 @@ static int grep_source_load_oid(struct grep_source *gs)
21182123
{
21192124
enum object_type type;
21202125

2121-
grep_read_lock();
21222126
gs->buf = read_object_file(gs->identifier, &type, &gs->size);
2123-
grep_read_unlock();
2124-
21252127
if (!gs->buf)
21262128
return error(_("'%s': unable to read %s"),
21272129
gs->name,
@@ -2186,11 +2188,8 @@ void grep_source_load_driver(struct grep_source *gs,
21862188
return;
21872189

21882190
grep_attr_lock();
2189-
if (gs->path) {
2190-
grep_read_lock();
2191+
if (gs->path)
21912192
gs->driver = userdiff_find_by_path(istate, gs->path);
2192-
grep_read_unlock();
2193-
}
21942193
if (!gs->driver)
21952194
gs->driver = userdiff_find_by_name("default");
21962195
grep_attr_unlock();

grep.h

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -220,18 +220,5 @@ int grep_threads_ok(const struct grep_opt *opt);
220220
*/
221221
extern int grep_use_locks;
222222
extern pthread_mutex_t grep_attr_mutex;
223-
extern pthread_mutex_t grep_read_mutex;
224-
225-
static inline void grep_read_lock(void)
226-
{
227-
if (grep_use_locks)
228-
pthread_mutex_lock(&grep_read_mutex);
229-
}
230-
231-
static inline void grep_read_unlock(void)
232-
{
233-
if (grep_use_locks)
234-
pthread_mutex_unlock(&grep_read_mutex);
235-
}
236223

237224
#endif

0 commit comments

Comments
 (0)