Skip to content
This repository
Browse code

Don't do more than one bg fetch for the same blob

Closes #120
  • Loading branch information...
commit fb8d696cc090e2c4ee6fa4623b00ac84f744fa3b 1 parent c1a8847
Dustin Sallings authored February 16, 2013
10  blobs.go
@@ -444,6 +444,8 @@ func hasBlob(oid string) bool {
444 444
 	return err == nil
445 445
 }
446 446
 
  447
+var fetchLocks namedLock
  448
+
447 449
 func performFetch(oid, prev string) {
448 450
 	c := captureResponseWriter{w: ioutil.Discard}
449 451
 
@@ -458,7 +460,13 @@ func performFetch(oid, prev string) {
458 460
 		return
459 461
 	}
460 462
 
461  
-	err = getBlobFromRemote(&c, oid, http.Header{}, 100)
  463
+	if fetchLocks.Lock(oid) {
  464
+		defer fetchLocks.Unlock(oid)
  465
+		err = getBlobFromRemote(&c, oid, http.Header{}, 100)
  466
+	} else {
  467
+		log.Printf("Not fetching remote, already in progress.")
  468
+		return
  469
+	}
462 470
 
463 471
 	if err == nil && c.statusCode == 200 {
464 472
 		if prev != "" {
37  namedlock.go
... ...
@@ -0,0 +1,37 @@
  1
+package main
  2
+
  3
+import (
  4
+	"sync"
  5
+)
  6
+
  7
+type namedLock struct {
  8
+	locks map[string]bool
  9
+	mutex sync.Mutex
  10
+}
  11
+
  12
+// Acquire a lock by name, returns true if acquired.
  13
+func (nl *namedLock) Lock(s string) bool {
  14
+	nl.mutex.Lock()
  15
+	defer nl.mutex.Unlock()
  16
+
  17
+	if nl.locks == nil {
  18
+		nl.locks = map[string]bool{}
  19
+	}
  20
+
  21
+	held := nl.locks[s]
  22
+	if !held {
  23
+		nl.locks[s] = true
  24
+	}
  25
+	return !held
  26
+}
  27
+
  28
+func (nl *namedLock) Unlock(s string) {
  29
+	nl.mutex.Lock()
  30
+	defer nl.mutex.Unlock()
  31
+
  32
+	if !nl.locks[s] {
  33
+		panic(s + " was not held")
  34
+	}
  35
+
  36
+	delete(nl.locks, s)
  37
+}
35  namedlock_test.go
... ...
@@ -0,0 +1,35 @@
  1
+package main
  2
+
  3
+import (
  4
+	"testing"
  5
+)
  6
+
  7
+func TestNamedLock(t *testing.T) {
  8
+	nl := namedLock{}
  9
+
  10
+	if nl.Lock("t1") == false {
  11
+		t.Fatalf("Expected initial lock to succeed")
  12
+	}
  13
+
  14
+	if nl.Lock("t1") == true {
  15
+		t.Fatalf("Expected subsequent lock to fail")
  16
+	}
  17
+
  18
+	if nl.Lock("t2") == false {
  19
+		t.Fatalf("Expected initial lock (2) to succeed")
  20
+	}
  21
+
  22
+	if nl.Lock("t2") == true {
  23
+		t.Fatalf("Expected subsequent lock (2) to fail")
  24
+	}
  25
+
  26
+	nl.Unlock("t1")
  27
+	nl.Unlock("t2")
  28
+
  29
+	defer func() {
  30
+		if x := recover(); x == nil {
  31
+			t.Fatalf("Expected panic on double free")
  32
+		}
  33
+	}()
  34
+	nl.Unlock("t1")
  35
+}

0 notes on commit fb8d696

Please sign in to comment.
Something went wrong with that request. Please try again.