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:
commit
fe9f5610c4
2 changed files with 30 additions and 1 deletions
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Add table
Reference in a new issue