1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Merge pull request #29953 from williammartin/truncindex-iterate-lock

Fix non thread-safe Iteration around go-patricia
This commit is contained in:
Vincent Demeester 2017-01-09 20:23:35 +01:00 committed by GitHub
commit fe9f5610c4
2 changed files with 30 additions and 1 deletions

View file

@ -125,8 +125,13 @@ func (idx *TruncIndex) Get(s string) (string, error) {
return "", ErrNotExist return "", ErrNotExist
} }
// Iterate iterates over all stored IDs, and passes each of them to the given handler. // Iterate iterates over all stored IDs and passes each of them to the given
// handler. Take care that the handler method does not call any public
// method on truncindex as the internal locking is not reentrant/recursive
// and will result in deadlock.
func (idx *TruncIndex) Iterate(handler func(id string)) { func (idx *TruncIndex) Iterate(handler func(id string)) {
idx.Lock()
defer idx.Unlock()
idx.trie.Visit(func(prefix patricia.Prefix, item patricia.Item) error { idx.trie.Visit(func(prefix patricia.Prefix, item patricia.Item) error {
handler(string(prefix)) handler(string(prefix))
return nil return nil

View file

@ -3,6 +3,7 @@ package truncindex
import ( import (
"math/rand" "math/rand"
"testing" "testing"
"time"
"github.com/docker/docker/pkg/stringid" "github.com/docker/docker/pkg/stringid"
) )
@ -98,6 +99,7 @@ func TestTruncIndex(t *testing.T) {
assertIndexGet(t, index, id, id, false) assertIndexGet(t, index, id, id, false)
assertIndexIterate(t) assertIndexIterate(t)
assertIndexIterateDoNotPanic(t)
} }
func assertIndexIterate(t *testing.T) { func assertIndexIterate(t *testing.T) {
@ -121,6 +123,28 @@ func assertIndexIterate(t *testing.T) {
}) })
} }
func assertIndexIterateDoNotPanic(t *testing.T) {
ids := []string{
"19b36c2c326ccc11e726eee6ee78a0baf166ef96",
"28b36c2c326ccc11e726eee6ee78a0baf166ef96",
}
index := NewTruncIndex(ids)
iterationStarted := make(chan bool, 1)
go func() {
<-iterationStarted
index.Delete("19b36c2c326ccc11e726eee6ee78a0baf166ef96")
}()
index.Iterate(func(targetId string) {
if targetId == "19b36c2c326ccc11e726eee6ee78a0baf166ef96" {
iterationStarted <- true
time.Sleep(100 * time.Millisecond)
}
})
}
func assertIndexGet(t *testing.T, index *TruncIndex, input, expectedResult string, expectError bool) { func assertIndexGet(t *testing.T, index *TruncIndex, input, expectedResult string, expectError bool) {
if result, err := index.Get(input); err != nil && !expectError { if result, err := index.Get(input); err != nil && !expectError {
t.Fatalf("Unexpected error getting '%s': %s", input, err) t.Fatalf("Unexpected error getting '%s': %s", input, err)