path: root/grep.c
diff options
authorMatheus Tavares <>2020-01-16 02:39:54 (GMT)
committerJunio C Hamano <>2020-01-17 21:52:14 (GMT)
commit1d1729caebd41b340dd8dd61057f613da4df526c (patch)
treece20d1ca66674bbca7ce8165172598a06a28d0ce /grep.c
parent31877c9aec21e0824fd4fcf415069cf8dfae4b72 (diff)
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 <> Signed-off-by: Junio C Hamano <>
Diffstat (limited to 'grep.c')
1 files changed, 19 insertions, 20 deletions
diff --git a/grep.c b/grep.c
index c028f70..13232a9 100644
--- a/grep.c
+++ b/grep.c
@@ -1540,11 +1540,6 @@ static inline void grep_attr_unlock(void)
- * Same as git_attr_mutex, but protecting the thread-unsafe object db access.
- */
-pthread_mutex_t grep_read_mutex;
static int match_funcname(struct grep_opt *opt, struct grep_source *gs, char *bol, char *eol)
xdemitconf_t *xecfg = opt->priv;
@@ -1741,13 +1736,20 @@ static int fill_textconv_grep(struct repository *r,
- * fill_textconv is not remotely thread-safe; it may load objects
- * behind the scenes, and it modifies the global diff tempfile
- * structure.
+ * fill_textconv is not remotely thread-safe; it modifies the global
+ * diff tempfile structure, writes to the_repo's odb and might
+ * internally call thread-unsafe functions such as the
+ * prepare_packed_git() lazy-initializator. Because of the last two, we
+ * must ensure mutual exclusion between this call and the object reading
+ * API, thus we use obj_read_lock() here.
+ *
+ * TODO: allowing text conversion to run in parallel with object
+ * reading operations might increase performance in the multithreaded
+ * non-worktreee git-grep with --textconv.
- grep_read_lock();
+ obj_read_lock();
size = fill_textconv(r, driver, df, &buf);
- grep_read_unlock();
+ obj_read_unlock();
@@ -1813,12 +1815,15 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle
grep_source_load_driver(gs, opt->repo->index);
* We might set up the shared textconv cache data here, which
- * is not thread-safe.
+ * is not thread-safe. Also, get_oid_with_context() and
+ * parse_object() might be internally called. As they are not
+ * currenty thread-safe and might be racy with object reading,
+ * obj_read_lock() must be called.
- grep_read_lock();
+ obj_read_lock();
textconv = userdiff_get_textconv(opt->repo, gs->driver);
- grep_read_unlock();
+ obj_read_unlock();
@@ -2118,10 +2123,7 @@ static int grep_source_load_oid(struct grep_source *gs)
enum object_type type;
- grep_read_lock();
gs->buf = read_object_file(gs->identifier, &type, &gs->size);
- grep_read_unlock();
if (!gs->buf)
return error(_("'%s': unable to read %s"),
@@ -2186,11 +2188,8 @@ void grep_source_load_driver(struct grep_source *gs,
- if (gs->path) {
- grep_read_lock();
+ if (gs->path)
gs->driver = userdiff_find_by_path(istate, gs->path);
- grep_read_unlock();
- }
if (!gs->driver)
gs->driver = userdiff_find_by_name("default");