git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Jeff King <peff@peff.net>
To: "René Scharfe" <l.s.r@web.de>
Cc: Shawn Pearce <spearce@spearce.org>,
	Martin von Gagern <Martin.vGagern@gmx.net>,
	git@vger.kernel.org, Junio C Hamano <gitster@pobox.com>
Subject: Re: [BUG] resolved deltas
Date: Thu, 28 Aug 2014 18:15:19 -0400	[thread overview]
Message-ID: <20140828221518.GA18799@peff.net> (raw)
In-Reply-To: <20140828220821.GA31545@peff.net>

On Thu, Aug 28, 2014 at 06:08:21PM -0400, Jeff King wrote:

> So we need some kind of mutual exclusion so that only one thread
> proceeds with resolving the delta. The "real_type" check sort-of
> functions in that way (except of course it is not actually thread safe).

Here's a patch which implements that. Since I couldn't replicate the
original problem with helgrind, I am just guessing at whether it
properly fixes it (well, it is more than just a guess; I used my brain
to analyze it, but that is far from foolproof).

It uses a single lock. I did a best-of-five timing of "git index-pack
--verify" on the kernel repo, both before and after. The results ended
up quite similar (both about 57s), though the run-to-run numbers are all
over the place (up to about 65s in the worst case). So maybe it is not
so bad.

As I implemented, I realized that even with the mutex, I really was just
implementing compare_and_swap (and I wrote it that way to make it more
obvious). So if we wanted to, it would be trivial to replace the
"claim_delta" function with a true compare-and-swap instruction if the
compiler and processor support it.

---
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index f7dc5b0..ed9e253 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -112,6 +112,10 @@ static pthread_mutex_t deepest_delta_mutex;
 #define deepest_delta_lock()	lock_mutex(&deepest_delta_mutex)
 #define deepest_delta_unlock()	unlock_mutex(&deepest_delta_mutex)
 
+static pthread_mutex_t object_entry_mutex;
+#define object_entry_lock()	lock_mutex(&object_entry_mutex)
+#define object_entry_unlock()	unlock_mutex(&object_entry_mutex)
+
 static pthread_key_t key;
 
 static inline void lock_mutex(pthread_mutex_t *mutex)
@@ -135,6 +139,7 @@ static void init_thread(void)
 	init_recursive_mutex(&read_mutex);
 	pthread_mutex_init(&counter_mutex, NULL);
 	pthread_mutex_init(&work_mutex, NULL);
+	pthread_mutex_init(&object_entry_mutex, NULL);
 	if (show_stat)
 		pthread_mutex_init(&deepest_delta_mutex, NULL);
 	pthread_key_create(&key, NULL);
@@ -157,6 +162,7 @@ static void cleanup_thread(void)
 	pthread_mutex_destroy(&read_mutex);
 	pthread_mutex_destroy(&counter_mutex);
 	pthread_mutex_destroy(&work_mutex);
+	pthread_mutex_destroy(&object_entry_mutex);
 	if (show_stat)
 		pthread_mutex_destroy(&deepest_delta_mutex);
 	for (i = 0; i < nr_threads; i++)
@@ -862,7 +868,6 @@ static void resolve_delta(struct object_entry *delta_obj,
 {
 	void *base_data, *delta_data;
 
-	delta_obj->real_type = base->obj->real_type;
 	if (show_stat) {
 		delta_obj->delta_depth = base->obj->delta_depth + 1;
 		deepest_delta_lock();
@@ -888,6 +893,21 @@ static void resolve_delta(struct object_entry *delta_obj,
 	counter_unlock();
 }
 
+static int claim_delta(struct object_entry *delta_obj,
+		       enum object_type delta_type,
+		       enum object_type base_type)
+{
+	enum object_type old_type;
+
+	object_entry_lock();
+	old_type = delta_obj->real_type;
+	if (old_type == delta_type)
+		delta_obj->real_type = base_type;
+	object_entry_unlock();
+
+	return old_type == delta_type;
+}
+
 static struct base_data *find_unresolved_deltas_1(struct base_data *base,
 						  struct base_data *prev_base)
 {
@@ -914,7 +934,7 @@ static struct base_data *find_unresolved_deltas_1(struct base_data *base,
 	if (base->ref_first <= base->ref_last) {
 		struct object_entry *child = objects + deltas[base->ref_first].obj_no;
 
-		if (child->real_type == OBJ_REF_DELTA) {
+		if (claim_delta(child, OBJ_REF_DELTA, base->obj->real_type)) {
 			struct base_data *result = alloc_base_data();
 
 			resolve_delta(child, base, result);
@@ -930,7 +950,7 @@ static struct base_data *find_unresolved_deltas_1(struct base_data *base,
 	if (base->ofs_first <= base->ofs_last) {
 		struct object_entry *child = objects + deltas[base->ofs_first].obj_no;
 
-		if (child->real_type == OBJ_OFS_DELTA) {
+		if (claim_delta(child, OBJ_OFS_DELTA, base->obj->real_type)) {
 			struct base_data *result = alloc_base_data();
 
 			resolve_delta(child, base, result);

  reply	other threads:[~2014-08-28 22:15 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-08-21 11:35 [BUG] resolved deltas Petr Stodulka
2014-08-21 18:25 ` Petr Stodulka
2014-08-22 19:41 ` Martin von Gagern
2014-08-23 10:12   ` René Scharfe
2014-08-23 10:56     ` Jeff King
2014-08-23 11:04       ` Jeff King
2014-08-23 11:18         ` Jeff King
2014-08-25 16:39           ` René Scharfe
2014-08-28 22:08             ` Jeff King
2014-08-28 22:15               ` Jeff King [this message]
2014-08-28 23:04                 ` Jeff King
2014-08-28 22:22               ` Jeff King
2014-08-28 23:14                 ` Junio C Hamano
2014-08-29 20:55                   ` Jeff King
2014-08-29 20:57                     ` [PATCH 1/2] index-pack: fix race condition with duplicate bases Jeff King
2014-08-29 20:58                     ` [PATCH 2/2] index-pack: handle duplicate base objects gracefully Jeff King
2014-08-29 21:56                       ` Junio C Hamano
2014-08-29 22:08                         ` Jeff King
2014-08-30  2:59                           ` Shawn Pearce
2014-08-30 13:16                             ` Jeff King
2014-08-30 16:00                               ` René Scharfe
2014-08-31 15:17                                 ` Jeff King
2014-08-31 16:30                                   ` René Scharfe
2014-08-31  1:10                               ` Shawn Pearce
2014-08-31 15:24                                 ` Jeff King
2014-08-31 22:23                                   ` Junio C Hamano
2014-08-30 13:23                     ` [PATCH 3/2] t5309: mark delta-cycle failover tests as passing Jeff King
2014-08-31 15:15                       ` Jeff King
2014-09-02 17:19                         ` Junio C Hamano
2014-08-25 17:19       ` [BUG] resolved deltas Shawn Pearce

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20140828221518.GA18799@peff.net \
    --to=peff@peff.net \
    --cc=Martin.vGagern@gmx.net \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=l.s.r@web.de \
    --cc=spearce@spearce.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).