fbaca9698c
Docker-DCO-1.1-Signed-off-by: Alexandr Morozov <lk4d4math@gmail.com> (github: LK4D4)
102 lines
2.5 KiB
Go
102 lines
2.5 KiB
Go
package truncindex
|
|
|
|
import (
|
|
"fmt"
|
|
"index/suffixarray"
|
|
"strings"
|
|
"sync"
|
|
)
|
|
|
|
// 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
|
|
index *suffixarray.Index
|
|
ids map[string]bool
|
|
bytes []byte
|
|
}
|
|
|
|
func NewTruncIndex(ids []string) (idx *TruncIndex) {
|
|
idx = &TruncIndex{
|
|
ids: make(map[string]bool),
|
|
bytes: []byte{' '},
|
|
}
|
|
for _, id := range ids {
|
|
idx.ids[id] = true
|
|
idx.bytes = append(idx.bytes, []byte(id+" ")...)
|
|
}
|
|
idx.index = suffixarray.New(idx.bytes)
|
|
return
|
|
}
|
|
|
|
func (idx *TruncIndex) addId(id string) error {
|
|
if strings.Contains(id, " ") {
|
|
return fmt.Errorf("Illegal character: ' '")
|
|
}
|
|
if _, exists := idx.ids[id]; exists {
|
|
return fmt.Errorf("Id already exists: %s", id)
|
|
}
|
|
idx.ids[id] = true
|
|
idx.bytes = append(idx.bytes, []byte(id+" ")...)
|
|
return nil
|
|
}
|
|
|
|
func (idx *TruncIndex) Add(id string) error {
|
|
idx.Lock()
|
|
defer idx.Unlock()
|
|
if err := idx.addId(id); err != nil {
|
|
return err
|
|
}
|
|
idx.index = suffixarray.New(idx.bytes)
|
|
return nil
|
|
}
|
|
|
|
func (idx *TruncIndex) AddWithoutSuffixarrayUpdate(id string) error {
|
|
idx.Lock()
|
|
defer idx.Unlock()
|
|
return idx.addId(id)
|
|
}
|
|
|
|
func (idx *TruncIndex) UpdateSuffixarray() {
|
|
idx.Lock()
|
|
defer idx.Unlock()
|
|
idx.index = suffixarray.New(idx.bytes)
|
|
}
|
|
|
|
func (idx *TruncIndex) Delete(id string) error {
|
|
idx.Lock()
|
|
defer idx.Unlock()
|
|
if _, exists := idx.ids[id]; !exists {
|
|
return fmt.Errorf("No such id: %s", id)
|
|
}
|
|
before, after, err := idx.lookup(id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
delete(idx.ids, id)
|
|
idx.bytes = append(idx.bytes[:before], idx.bytes[after:]...)
|
|
idx.index = suffixarray.New(idx.bytes)
|
|
return nil
|
|
}
|
|
|
|
func (idx *TruncIndex) lookup(s string) (int, int, error) {
|
|
offsets := idx.index.Lookup([]byte(" "+s), -1)
|
|
//log.Printf("lookup(%s): %v (index bytes: '%s')\n", s, offsets, idx.index.Bytes())
|
|
if offsets == nil || len(offsets) == 0 || len(offsets) > 1 {
|
|
return -1, -1, fmt.Errorf("No such id: %s", s)
|
|
}
|
|
offsetBefore := offsets[0] + 1
|
|
offsetAfter := offsetBefore + strings.Index(string(idx.bytes[offsetBefore:]), " ")
|
|
return offsetBefore, offsetAfter, nil
|
|
}
|
|
|
|
func (idx *TruncIndex) Get(s string) (string, error) {
|
|
idx.RLock()
|
|
defer idx.RUnlock()
|
|
before, after, err := idx.lookup(s)
|
|
//log.Printf("Get(%s) bytes=|%s| before=|%d| after=|%d|\n", s, idx.bytes, before, after)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return string(idx.bytes[before:after]), err
|
|
}
|