Bump github.com/containers/storage@d10d868
Update the vendored copy of github.com/containers/storage to revision d10d8680af74070b362637408a7fe28c4b1f1eff. Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
This commit is contained in:
parent
d6bf131c07
commit
7c551964c0
20 changed files with 925 additions and 441 deletions
137
vendor/github.com/containers/storage/pkg/truncindex/truncindex.go
generated
vendored
Normal file
137
vendor/github.com/containers/storage/pkg/truncindex/truncindex.go
generated
vendored
Normal file
|
@ -0,0 +1,137 @@
|
|||
// Package truncindex provides a general 'index tree', used by Docker
|
||||
// in order to be able to reference containers by only a few unambiguous
|
||||
// characters of their id.
|
||||
package truncindex
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/tchap/go-patricia/patricia"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrEmptyPrefix is an error returned if the prefix was empty.
|
||||
ErrEmptyPrefix = errors.New("Prefix can't be empty")
|
||||
|
||||
// ErrIllegalChar is returned when a space is in the ID
|
||||
ErrIllegalChar = errors.New("illegal character: ' '")
|
||||
|
||||
// ErrNotExist is returned when ID or its prefix not found in index.
|
||||
ErrNotExist = errors.New("ID does not exist")
|
||||
)
|
||||
|
||||
// ErrAmbiguousPrefix is returned if the prefix was ambiguous
|
||||
// (multiple ids for the prefix).
|
||||
type ErrAmbiguousPrefix struct {
|
||||
prefix string
|
||||
}
|
||||
|
||||
func (e ErrAmbiguousPrefix) Error() string {
|
||||
return fmt.Sprintf("Multiple IDs found with provided prefix: %s", e.prefix)
|
||||
}
|
||||
|
||||
// TruncIndex allows the retrieval of string identifiers by any of their unique prefixes.
|
||||
// This is used to retrieve image and container IDs by more convenient shorthand prefixes.
|
||||
type TruncIndex struct {
|
||||
sync.RWMutex
|
||||
trie *patricia.Trie
|
||||
ids map[string]struct{}
|
||||
}
|
||||
|
||||
// NewTruncIndex creates a new TruncIndex and initializes with a list of IDs.
|
||||
func NewTruncIndex(ids []string) (idx *TruncIndex) {
|
||||
idx = &TruncIndex{
|
||||
ids: make(map[string]struct{}),
|
||||
|
||||
// Change patricia max prefix per node length,
|
||||
// because our len(ID) always 64
|
||||
trie: patricia.NewTrie(patricia.MaxPrefixPerNode(64)),
|
||||
}
|
||||
for _, id := range ids {
|
||||
idx.addID(id)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (idx *TruncIndex) addID(id string) error {
|
||||
if strings.Contains(id, " ") {
|
||||
return ErrIllegalChar
|
||||
}
|
||||
if id == "" {
|
||||
return ErrEmptyPrefix
|
||||
}
|
||||
if _, exists := idx.ids[id]; exists {
|
||||
return fmt.Errorf("id already exists: '%s'", id)
|
||||
}
|
||||
idx.ids[id] = struct{}{}
|
||||
if inserted := idx.trie.Insert(patricia.Prefix(id), struct{}{}); !inserted {
|
||||
return fmt.Errorf("failed to insert id: %s", id)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add adds a new ID to the TruncIndex.
|
||||
func (idx *TruncIndex) Add(id string) error {
|
||||
idx.Lock()
|
||||
defer idx.Unlock()
|
||||
if err := idx.addID(id); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete removes an ID from the TruncIndex. If there are multiple IDs
|
||||
// with the given prefix, an error is thrown.
|
||||
func (idx *TruncIndex) Delete(id string) error {
|
||||
idx.Lock()
|
||||
defer idx.Unlock()
|
||||
if _, exists := idx.ids[id]; !exists || id == "" {
|
||||
return fmt.Errorf("no such id: '%s'", id)
|
||||
}
|
||||
delete(idx.ids, id)
|
||||
if deleted := idx.trie.Delete(patricia.Prefix(id)); !deleted {
|
||||
return fmt.Errorf("no such id: '%s'", id)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get retrieves an ID from the TruncIndex. If there are multiple IDs
|
||||
// with the given prefix, an error is thrown.
|
||||
func (idx *TruncIndex) Get(s string) (string, error) {
|
||||
if s == "" {
|
||||
return "", ErrEmptyPrefix
|
||||
}
|
||||
var (
|
||||
id string
|
||||
)
|
||||
subTreeVisitFunc := func(prefix patricia.Prefix, item patricia.Item) error {
|
||||
if id != "" {
|
||||
// we haven't found the ID if there are two or more IDs
|
||||
id = ""
|
||||
return ErrAmbiguousPrefix{prefix: string(prefix)}
|
||||
}
|
||||
id = string(prefix)
|
||||
return nil
|
||||
}
|
||||
|
||||
idx.RLock()
|
||||
defer idx.RUnlock()
|
||||
if err := idx.trie.VisitSubtree(patricia.Prefix(s), subTreeVisitFunc); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if id != "" {
|
||||
return id, nil
|
||||
}
|
||||
return "", ErrNotExist
|
||||
}
|
||||
|
||||
// Iterate iterates over all stored IDs, and passes each of them to the given handler.
|
||||
func (idx *TruncIndex) Iterate(handler func(id string)) {
|
||||
idx.trie.Visit(func(prefix patricia.Prefix, item patricia.Item) error {
|
||||
handler(string(prefix))
|
||||
return nil
|
||||
})
|
||||
}
|
429
vendor/github.com/containers/storage/pkg/truncindex/truncindex_test.go
generated
vendored
Normal file
429
vendor/github.com/containers/storage/pkg/truncindex/truncindex_test.go
generated
vendored
Normal file
|
@ -0,0 +1,429 @@
|
|||
package truncindex
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/containers/storage/pkg/stringid"
|
||||
)
|
||||
|
||||
// Test the behavior of TruncIndex, an index for querying IDs from a non-conflicting prefix.
|
||||
func TestTruncIndex(t *testing.T) {
|
||||
ids := []string{}
|
||||
index := NewTruncIndex(ids)
|
||||
// Get on an empty index
|
||||
if _, err := index.Get("foobar"); err == nil {
|
||||
t.Fatal("Get on an empty index should return an error")
|
||||
}
|
||||
|
||||
// Spaces should be illegal in an id
|
||||
if err := index.Add("I have a space"); err == nil {
|
||||
t.Fatalf("Adding an id with ' ' should return an error")
|
||||
}
|
||||
|
||||
id := "99b36c2c326ccc11e726eee6ee78a0baf166ef96"
|
||||
// Add an id
|
||||
if err := index.Add(id); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Add an empty id (should fail)
|
||||
if err := index.Add(""); err == nil {
|
||||
t.Fatalf("Adding an empty id should return an error")
|
||||
}
|
||||
|
||||
// Get a non-existing id
|
||||
assertIndexGet(t, index, "abracadabra", "", true)
|
||||
// Get an empty id
|
||||
assertIndexGet(t, index, "", "", true)
|
||||
// Get the exact id
|
||||
assertIndexGet(t, index, id, id, false)
|
||||
// The first letter should match
|
||||
assertIndexGet(t, index, id[:1], id, false)
|
||||
// The first half should match
|
||||
assertIndexGet(t, index, id[:len(id)/2], id, false)
|
||||
// The second half should NOT match
|
||||
assertIndexGet(t, index, id[len(id)/2:], "", true)
|
||||
|
||||
id2 := id[:6] + "blabla"
|
||||
// Add an id
|
||||
if err := index.Add(id2); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// Both exact IDs should work
|
||||
assertIndexGet(t, index, id, id, false)
|
||||
assertIndexGet(t, index, id2, id2, false)
|
||||
|
||||
// 6 characters or less should conflict
|
||||
assertIndexGet(t, index, id[:6], "", true)
|
||||
assertIndexGet(t, index, id[:4], "", true)
|
||||
assertIndexGet(t, index, id[:1], "", true)
|
||||
|
||||
// An ambiguous id prefix should return an error
|
||||
if _, err := index.Get(id[:4]); err == nil {
|
||||
t.Fatal("An ambiguous id prefix should return an error")
|
||||
}
|
||||
|
||||
// 7 characters should NOT conflict
|
||||
assertIndexGet(t, index, id[:7], id, false)
|
||||
assertIndexGet(t, index, id2[:7], id2, false)
|
||||
|
||||
// Deleting a non-existing id should return an error
|
||||
if err := index.Delete("non-existing"); err == nil {
|
||||
t.Fatalf("Deleting a non-existing id should return an error")
|
||||
}
|
||||
|
||||
// Deleting an empty id should return an error
|
||||
if err := index.Delete(""); err == nil {
|
||||
t.Fatal("Deleting an empty id should return an error")
|
||||
}
|
||||
|
||||
// Deleting id2 should remove conflicts
|
||||
if err := index.Delete(id2); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// id2 should no longer work
|
||||
assertIndexGet(t, index, id2, "", true)
|
||||
assertIndexGet(t, index, id2[:7], "", true)
|
||||
assertIndexGet(t, index, id2[:11], "", true)
|
||||
|
||||
// conflicts between id and id2 should be gone
|
||||
assertIndexGet(t, index, id[:6], id, false)
|
||||
assertIndexGet(t, index, id[:4], id, false)
|
||||
assertIndexGet(t, index, id[:1], id, false)
|
||||
|
||||
// non-conflicting substrings should still not conflict
|
||||
assertIndexGet(t, index, id[:7], id, false)
|
||||
assertIndexGet(t, index, id[:15], id, false)
|
||||
assertIndexGet(t, index, id, id, false)
|
||||
|
||||
assertIndexIterate(t)
|
||||
}
|
||||
|
||||
func assertIndexIterate(t *testing.T) {
|
||||
ids := []string{
|
||||
"19b36c2c326ccc11e726eee6ee78a0baf166ef96",
|
||||
"28b36c2c326ccc11e726eee6ee78a0baf166ef96",
|
||||
"37b36c2c326ccc11e726eee6ee78a0baf166ef96",
|
||||
"46b36c2c326ccc11e726eee6ee78a0baf166ef96",
|
||||
}
|
||||
|
||||
index := NewTruncIndex(ids)
|
||||
|
||||
index.Iterate(func(targetId string) {
|
||||
for _, id := range ids {
|
||||
if targetId == id {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
t.Fatalf("An unknown ID '%s'", targetId)
|
||||
})
|
||||
}
|
||||
|
||||
func assertIndexGet(t *testing.T, index *TruncIndex, input, expectedResult string, expectError bool) {
|
||||
if result, err := index.Get(input); err != nil && !expectError {
|
||||
t.Fatalf("Unexpected error getting '%s': %s", input, err)
|
||||
} else if err == nil && expectError {
|
||||
t.Fatalf("Getting '%s' should return an error, not '%s'", input, result)
|
||||
} else if result != expectedResult {
|
||||
t.Fatalf("Getting '%s' returned '%s' instead of '%s'", input, result, expectedResult)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTruncIndexAdd100(b *testing.B) {
|
||||
var testSet []string
|
||||
for i := 0; i < 100; i++ {
|
||||
testSet = append(testSet, stringid.GenerateNonCryptoID())
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
index := NewTruncIndex([]string{})
|
||||
for _, id := range testSet {
|
||||
if err := index.Add(id); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTruncIndexAdd250(b *testing.B) {
|
||||
var testSet []string
|
||||
for i := 0; i < 250; i++ {
|
||||
testSet = append(testSet, stringid.GenerateNonCryptoID())
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
index := NewTruncIndex([]string{})
|
||||
for _, id := range testSet {
|
||||
if err := index.Add(id); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTruncIndexAdd500(b *testing.B) {
|
||||
var testSet []string
|
||||
for i := 0; i < 500; i++ {
|
||||
testSet = append(testSet, stringid.GenerateNonCryptoID())
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
index := NewTruncIndex([]string{})
|
||||
for _, id := range testSet {
|
||||
if err := index.Add(id); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTruncIndexGet100(b *testing.B) {
|
||||
var testSet []string
|
||||
var testKeys []string
|
||||
for i := 0; i < 100; i++ {
|
||||
testSet = append(testSet, stringid.GenerateNonCryptoID())
|
||||
}
|
||||
index := NewTruncIndex([]string{})
|
||||
for _, id := range testSet {
|
||||
if err := index.Add(id); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
l := rand.Intn(12) + 12
|
||||
testKeys = append(testKeys, id[:l])
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, id := range testKeys {
|
||||
if res, err := index.Get(id); err != nil {
|
||||
b.Fatal(res, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTruncIndexGet250(b *testing.B) {
|
||||
var testSet []string
|
||||
var testKeys []string
|
||||
for i := 0; i < 250; i++ {
|
||||
testSet = append(testSet, stringid.GenerateNonCryptoID())
|
||||
}
|
||||
index := NewTruncIndex([]string{})
|
||||
for _, id := range testSet {
|
||||
if err := index.Add(id); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
l := rand.Intn(12) + 12
|
||||
testKeys = append(testKeys, id[:l])
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, id := range testKeys {
|
||||
if res, err := index.Get(id); err != nil {
|
||||
b.Fatal(res, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTruncIndexGet500(b *testing.B) {
|
||||
var testSet []string
|
||||
var testKeys []string
|
||||
for i := 0; i < 500; i++ {
|
||||
testSet = append(testSet, stringid.GenerateNonCryptoID())
|
||||
}
|
||||
index := NewTruncIndex([]string{})
|
||||
for _, id := range testSet {
|
||||
if err := index.Add(id); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
l := rand.Intn(12) + 12
|
||||
testKeys = append(testKeys, id[:l])
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, id := range testKeys {
|
||||
if res, err := index.Get(id); err != nil {
|
||||
b.Fatal(res, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTruncIndexDelete100(b *testing.B) {
|
||||
var testSet []string
|
||||
for i := 0; i < 100; i++ {
|
||||
testSet = append(testSet, stringid.GenerateNonCryptoID())
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
b.StopTimer()
|
||||
index := NewTruncIndex([]string{})
|
||||
for _, id := range testSet {
|
||||
if err := index.Add(id); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
b.StartTimer()
|
||||
for _, id := range testSet {
|
||||
if err := index.Delete(id); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTruncIndexDelete250(b *testing.B) {
|
||||
var testSet []string
|
||||
for i := 0; i < 250; i++ {
|
||||
testSet = append(testSet, stringid.GenerateNonCryptoID())
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
b.StopTimer()
|
||||
index := NewTruncIndex([]string{})
|
||||
for _, id := range testSet {
|
||||
if err := index.Add(id); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
b.StartTimer()
|
||||
for _, id := range testSet {
|
||||
if err := index.Delete(id); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTruncIndexDelete500(b *testing.B) {
|
||||
var testSet []string
|
||||
for i := 0; i < 500; i++ {
|
||||
testSet = append(testSet, stringid.GenerateNonCryptoID())
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
b.StopTimer()
|
||||
index := NewTruncIndex([]string{})
|
||||
for _, id := range testSet {
|
||||
if err := index.Add(id); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
b.StartTimer()
|
||||
for _, id := range testSet {
|
||||
if err := index.Delete(id); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTruncIndexNew100(b *testing.B) {
|
||||
var testSet []string
|
||||
for i := 0; i < 100; i++ {
|
||||
testSet = append(testSet, stringid.GenerateNonCryptoID())
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
NewTruncIndex(testSet)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTruncIndexNew250(b *testing.B) {
|
||||
var testSet []string
|
||||
for i := 0; i < 250; i++ {
|
||||
testSet = append(testSet, stringid.GenerateNonCryptoID())
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
NewTruncIndex(testSet)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTruncIndexNew500(b *testing.B) {
|
||||
var testSet []string
|
||||
for i := 0; i < 500; i++ {
|
||||
testSet = append(testSet, stringid.GenerateNonCryptoID())
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
NewTruncIndex(testSet)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTruncIndexAddGet100(b *testing.B) {
|
||||
var testSet []string
|
||||
var testKeys []string
|
||||
for i := 0; i < 500; i++ {
|
||||
id := stringid.GenerateNonCryptoID()
|
||||
testSet = append(testSet, id)
|
||||
l := rand.Intn(12) + 12
|
||||
testKeys = append(testKeys, id[:l])
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
index := NewTruncIndex([]string{})
|
||||
for _, id := range testSet {
|
||||
if err := index.Add(id); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
for _, id := range testKeys {
|
||||
if res, err := index.Get(id); err != nil {
|
||||
b.Fatal(res, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTruncIndexAddGet250(b *testing.B) {
|
||||
var testSet []string
|
||||
var testKeys []string
|
||||
for i := 0; i < 500; i++ {
|
||||
id := stringid.GenerateNonCryptoID()
|
||||
testSet = append(testSet, id)
|
||||
l := rand.Intn(12) + 12
|
||||
testKeys = append(testKeys, id[:l])
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
index := NewTruncIndex([]string{})
|
||||
for _, id := range testSet {
|
||||
if err := index.Add(id); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
for _, id := range testKeys {
|
||||
if res, err := index.Get(id); err != nil {
|
||||
b.Fatal(res, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTruncIndexAddGet500(b *testing.B) {
|
||||
var testSet []string
|
||||
var testKeys []string
|
||||
for i := 0; i < 500; i++ {
|
||||
id := stringid.GenerateNonCryptoID()
|
||||
testSet = append(testSet, id)
|
||||
l := rand.Intn(12) + 12
|
||||
testKeys = append(testKeys, id[:l])
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
index := NewTruncIndex([]string{})
|
||||
for _, id := range testSet {
|
||||
if err := index.Add(id); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
for _, id := range testKeys {
|
||||
if res, err := index.Get(id); err != nil {
|
||||
b.Fatal(res, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue