mirror of https://github.com/status-im/consul.git
consul: Adding a key listing mechanism
This commit is contained in:
parent
416ff8f7d6
commit
dcbb55b874
|
@ -9,6 +9,7 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -245,6 +246,7 @@ func (s *StateStore) initialize() error {
|
||||||
"NodeDump": MDBTables{s.nodeTable, s.serviceTable, s.checkTable},
|
"NodeDump": MDBTables{s.nodeTable, s.serviceTable, s.checkTable},
|
||||||
"KVSGet": MDBTables{s.kvsTable},
|
"KVSGet": MDBTables{s.kvsTable},
|
||||||
"KVSList": MDBTables{s.kvsTable},
|
"KVSList": MDBTables{s.kvsTable},
|
||||||
|
"KVSListKeys": MDBTables{s.kvsTable},
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -902,6 +904,51 @@ func (s *StateStore) KVSList(prefix string) (uint64, structs.DirEntries, error)
|
||||||
return idx, ents, err
|
return idx, ents, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// KVSListKeys is used to list keys with a prefix, and up to a given seperator
|
||||||
|
func (s *StateStore) KVSListKeys(prefix, seperator string) (uint64, []string, error) {
|
||||||
|
tx, err := s.kvsTable.StartTxn(true, nil)
|
||||||
|
if err != nil {
|
||||||
|
return 0, nil, err
|
||||||
|
}
|
||||||
|
defer tx.Abort()
|
||||||
|
|
||||||
|
idx, err := s.kvsTable.LastIndexTxn(tx)
|
||||||
|
if err != nil {
|
||||||
|
return 0, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aggregate the stream
|
||||||
|
stream := make(chan interface{}, 128)
|
||||||
|
done := make(chan struct{})
|
||||||
|
var keys []string
|
||||||
|
go func() {
|
||||||
|
prefixLen := len(prefix)
|
||||||
|
last := ""
|
||||||
|
for raw := range stream {
|
||||||
|
ent := raw.(*structs.DirEntry)
|
||||||
|
after := ent.Key[prefixLen:]
|
||||||
|
|
||||||
|
// Check for the seperator
|
||||||
|
if idx := strings.Index(after, seperator); idx >= 0 {
|
||||||
|
toSep := ent.Key[:prefixLen+idx+1]
|
||||||
|
if last != toSep {
|
||||||
|
keys = append(keys, toSep)
|
||||||
|
last = toSep
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
keys = append(keys, ent.Key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Start the stream, and wait for completion
|
||||||
|
err = s.kvsTable.StreamTxn(stream, tx, "id_prefix", prefix)
|
||||||
|
<-done
|
||||||
|
return idx, keys, err
|
||||||
|
}
|
||||||
|
|
||||||
// KVSDelete is used to delete a KVS entry
|
// KVSDelete is used to delete a KVS entry
|
||||||
func (s *StateStore) KVSDelete(index uint64, key string) error {
|
func (s *StateStore) KVSDelete(index uint64, key string) error {
|
||||||
return s.kvsDeleteWithIndex(index, "id", key)
|
return s.kvsDeleteWithIndex(index, "id", key)
|
||||||
|
|
|
@ -1401,6 +1401,106 @@ func TestKVS_List(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestKVS_ListKeys(t *testing.T) {
|
||||||
|
store, err := testStateStore()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
defer store.Close()
|
||||||
|
|
||||||
|
// Should not exist
|
||||||
|
idx, keys, err := store.KVSListKeys("", "/")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
if idx != 0 {
|
||||||
|
t.Fatalf("bad: %v", idx)
|
||||||
|
}
|
||||||
|
if len(keys) != 0 {
|
||||||
|
t.Fatalf("bad: %v", keys)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the entries
|
||||||
|
d := &structs.DirEntry{Key: "/web/a", Flags: 42, Value: []byte("test")}
|
||||||
|
if err := store.KVSSet(1000, d); err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
d = &structs.DirEntry{Key: "/web/b", Flags: 42, Value: []byte("test")}
|
||||||
|
if err := store.KVSSet(1001, d); err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
d = &structs.DirEntry{Key: "/web/sub/c", Flags: 42, Value: []byte("test")}
|
||||||
|
if err := store.KVSSet(1002, d); err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should list
|
||||||
|
idx, keys, err = store.KVSListKeys("", "/")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
if idx != 1002 {
|
||||||
|
t.Fatalf("bad: %v", idx)
|
||||||
|
}
|
||||||
|
if len(keys) != 1 {
|
||||||
|
t.Fatalf("bad: %v", keys)
|
||||||
|
}
|
||||||
|
if keys[0] != "/" {
|
||||||
|
t.Fatalf("bad: %v", keys)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should list just web
|
||||||
|
idx, keys, err = store.KVSListKeys("/", "/")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
if idx != 1002 {
|
||||||
|
t.Fatalf("bad: %v", idx)
|
||||||
|
}
|
||||||
|
if len(keys) != 1 {
|
||||||
|
t.Fatalf("bad: %v", keys)
|
||||||
|
}
|
||||||
|
if keys[0] != "/web/" {
|
||||||
|
t.Fatalf("bad: %v", keys)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should list a, b, sub/
|
||||||
|
idx, keys, err = store.KVSListKeys("/web/", "/")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
if idx != 1002 {
|
||||||
|
t.Fatalf("bad: %v", idx)
|
||||||
|
}
|
||||||
|
if len(keys) != 3 {
|
||||||
|
t.Fatalf("bad: %v", keys)
|
||||||
|
}
|
||||||
|
if keys[0] != "/web/a" {
|
||||||
|
t.Fatalf("bad: %v", keys)
|
||||||
|
}
|
||||||
|
if keys[1] != "/web/b" {
|
||||||
|
t.Fatalf("bad: %v", keys)
|
||||||
|
}
|
||||||
|
if keys[2] != "/web/sub/" {
|
||||||
|
t.Fatalf("bad: %v", keys)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should list c
|
||||||
|
idx, keys, err = store.KVSListKeys("/web/sub/", "/")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
if idx != 1002 {
|
||||||
|
t.Fatalf("bad: %v", idx)
|
||||||
|
}
|
||||||
|
if len(keys) != 1 {
|
||||||
|
t.Fatalf("bad: %v", keys)
|
||||||
|
}
|
||||||
|
if keys[0] != "/web/sub/c" {
|
||||||
|
t.Fatalf("bad: %v", keys)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestKVSDeleteTree(t *testing.T) {
|
func TestKVSDeleteTree(t *testing.T) {
|
||||||
store, err := testStateStore()
|
store, err := testStateStore()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
Loading…
Reference in New Issue