summaryrefslogtreecommitdiff
path: root/packfile.c
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2020-02-14 20:54:20 (GMT)
committerJunio C Hamano <gitster@pobox.com>2020-02-14 20:54:20 (GMT)
commit56ceb64eb0377acb2884226d4fb7d7c3f4032354 (patch)
tree3ab8775533954b285d1abf67d2ea0f53c7149154 /packfile.c
parent0da63da7942ce810126cd54d9f72a46f3d616895 (diff)
parentf1928f04b2510c522c25d482e6ab4a17077add9a (diff)
downloadgit-56ceb64eb0377acb2884226d4fb7d7c3f4032354.zip
git-56ceb64eb0377acb2884226d4fb7d7c3f4032354.tar.gz
git-56ceb64eb0377acb2884226d4fb7d7c3f4032354.tar.bz2
Merge branch 'mt/threaded-grep-in-object-store'
Traditionally, we avoided threaded grep while searching in objects (as opposed to files in the working tree) as accesses to the object layer is not thread-safe. This limitation is getting lifted. * mt/threaded-grep-in-object-store: grep: use no. of cores as the default no. of threads grep: move driver pre-load out of critical section grep: re-enable threads in non-worktree case grep: protect packed_git [re-]initialization grep: allow submodule functions to run in parallel submodule-config: add skip_if_read option to repo_read_gitmodules() grep: replace grep_read_mutex by internal obj read lock object-store: allow threaded access to object reading replace-object: make replace operations thread-safe grep: fix racy calls in grep_objects() grep: fix race conditions at grep_submodule() grep: fix race conditions on userdiff calls
Diffstat (limited to 'packfile.c')
-rw-r--r--packfile.c34
1 files changed, 34 insertions, 0 deletions
diff --git a/packfile.c b/packfile.c
index 514bc57..99dd1a7 100644
--- a/packfile.c
+++ b/packfile.c
@@ -1004,12 +1004,14 @@ void reprepare_packed_git(struct repository *r)
{
struct object_directory *odb;
+ obj_read_lock();
for (odb = r->objects->odb; odb; odb = odb->next)
odb_clear_loose_cache(odb);
r->objects->approximate_object_count_valid = 0;
r->objects->packed_git_initialized = 0;
prepare_packed_git(r);
+ obj_read_unlock();
}
struct packed_git *get_packed_git(struct repository *r)
@@ -1086,7 +1088,23 @@ unsigned long get_size_from_delta(struct packed_git *p,
do {
in = use_pack(p, w_curs, curpos, &stream.avail_in);
stream.next_in = in;
+ /*
+ * Note: the window section returned by use_pack() must be
+ * available throughout git_inflate()'s unlocked execution. To
+ * ensure no other thread will modify the window in the
+ * meantime, we rely on the packed_window.inuse_cnt. This
+ * counter is incremented before window reading and checked
+ * before window disposal.
+ *
+ * Other worrying sections could be the call to close_pack_fd(),
+ * which can close packs even with in-use windows, and to
+ * reprepare_packed_git(). Regarding the former, mmap doc says:
+ * "closing the file descriptor does not unmap the region". And
+ * for the latter, it won't re-open already available packs.
+ */
+ obj_read_unlock();
st = git_inflate(&stream, Z_FINISH);
+ obj_read_lock();
curpos += stream.next_in - in;
} while ((st == Z_OK || st == Z_BUF_ERROR) &&
stream.total_out < sizeof(delta_head));
@@ -1445,6 +1463,14 @@ static void add_delta_base_cache(struct packed_git *p, off_t base_offset,
struct delta_base_cache_entry *ent = xmalloc(sizeof(*ent));
struct list_head *lru, *tmp;
+ /*
+ * Check required to avoid redundant entries when more than one thread
+ * is unpacking the same object, in unpack_entry() (since its phases I
+ * and III might run concurrently across multiple threads).
+ */
+ if (in_delta_base_cache(p, base_offset))
+ return;
+
delta_base_cached += base_size;
list_for_each_safe(lru, tmp, &delta_base_cache_lru) {
@@ -1574,7 +1600,15 @@ static void *unpack_compressed_entry(struct packed_git *p,
do {
in = use_pack(p, w_curs, curpos, &stream.avail_in);
stream.next_in = in;
+ /*
+ * Note: we must ensure the window section returned by
+ * use_pack() will be available throughout git_inflate()'s
+ * unlocked execution. Please refer to the comment at
+ * get_size_from_delta() to see how this is done.
+ */
+ obj_read_unlock();
st = git_inflate(&stream, Z_FINISH);
+ obj_read_lock();
if (!stream.avail_out)
break; /* the payload is larger than it should be */
curpos += stream.next_in - in;