mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
add list feature
This commit is contained in:
parent
5ee976da76
commit
93c96b3813
15
command.go
15
command.go
@ -61,6 +61,21 @@ func (c *GetCommand) GeneratePath() string {
|
||||
return "get/" + c.Key
|
||||
}
|
||||
|
||||
// List command
|
||||
type ListCommand struct {
|
||||
Prefix string `json:"prefix"`
|
||||
}
|
||||
|
||||
// The name of the command in the log
|
||||
func (c *ListCommand) CommandName() string {
|
||||
return "list"
|
||||
}
|
||||
|
||||
// Set the value of key to value
|
||||
func (c *ListCommand) Apply(server *raft.Server) (interface{}, error) {
|
||||
return store.List(c.Prefix)
|
||||
}
|
||||
|
||||
// Delete command
|
||||
type DeleteCommand struct {
|
||||
Key string `json:"key"`
|
||||
|
1
etcd.go
1
etcd.go
@ -318,6 +318,7 @@ func startClientTransport(port int, st int) {
|
||||
// external commands
|
||||
http.HandleFunc("/v1/keys/", Multiplexer)
|
||||
http.HandleFunc("/v1/watch/", WatchHttpHandler)
|
||||
http.HandleFunc("/v1/list/", ListHttpHandler)
|
||||
http.HandleFunc("/master", MasterHttpHandler)
|
||||
|
||||
switch st {
|
||||
|
26
handlers.go
26
handlers.go
@ -231,6 +231,32 @@ func GetHttpHandler(w *http.ResponseWriter, req *http.Request) {
|
||||
|
||||
}
|
||||
|
||||
func ListHttpHandler(w http.ResponseWriter, req *http.Request) {
|
||||
prefix := req.URL.Path[len("/v1/list/"):]
|
||||
|
||||
debug("[recv] GET http://%v/v1/list/%s", server.Name(), prefix)
|
||||
|
||||
command := &ListCommand{}
|
||||
command.Prefix = prefix
|
||||
|
||||
if body, err := command.Apply(server); err != nil {
|
||||
warn("raftd: Unable to write file: %v", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
} else {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
|
||||
body, ok := body.([]byte)
|
||||
if !ok {
|
||||
panic("wrong type")
|
||||
}
|
||||
|
||||
w.Write(body)
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func WatchHttpHandler(w http.ResponseWriter, req *http.Request) {
|
||||
key := req.URL.Path[len("/v1/watch/"):]
|
||||
|
||||
|
@ -70,11 +70,17 @@ type Response struct {
|
||||
Expiration time.Time `json:"expiration"`
|
||||
|
||||
// countdown until expiration in seconds
|
||||
TTL int64 `json:"TTL"`
|
||||
TTL int64 `json:"ttl"`
|
||||
|
||||
Index uint64 `json:"index"`
|
||||
}
|
||||
|
||||
type ListNode struct {
|
||||
Key string
|
||||
Value string
|
||||
Type string
|
||||
}
|
||||
|
||||
// make a new stroe
|
||||
func CreateStore(max int) *Store {
|
||||
s = new(Store)
|
||||
@ -303,6 +309,22 @@ func Get(key string) Response {
|
||||
}
|
||||
}
|
||||
|
||||
// // List all the item in the prefix
|
||||
func List(prefix string) ([]byte, error) {
|
||||
nodes, keys, dirs, ok := s.Tree.list(prefix)
|
||||
|
||||
var ln []ListNode
|
||||
|
||||
if ok {
|
||||
ln = make([]ListNode, len(nodes))
|
||||
for i := 0; i < len(nodes); i++ {
|
||||
ln[i] = ListNode{keys[i], nodes[i].Value, dirs[i]}
|
||||
}
|
||||
}
|
||||
|
||||
return json.Marshal(ln)
|
||||
}
|
||||
|
||||
// delete the key
|
||||
func Delete(key string, index uint64) ([]byte, error) {
|
||||
//update index
|
||||
|
@ -36,7 +36,7 @@ func (s tnWithKeySlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
var emptyNode = Node{".", PERMANENT, nil}
|
||||
|
||||
// set the key to value, return the old value if the key exists
|
||||
func (s *tree) set(key string, value Node) bool {
|
||||
func (t *tree) set(key string, value Node) bool {
|
||||
key = "/" + key
|
||||
key = path.Clean(key)
|
||||
|
||||
@ -45,7 +45,7 @@ func (s *tree) set(key string, value Node) bool {
|
||||
|
||||
//fmt.Println("TreeStore: Nodes ", nodes, " length: ", len(nodes))
|
||||
|
||||
nodeMap := s.Root.NodeMap
|
||||
nodeMap := t.Root.NodeMap
|
||||
|
||||
i := 0
|
||||
newDir := false
|
||||
@ -94,8 +94,8 @@ func (s *tree) set(key string, value Node) bool {
|
||||
|
||||
}
|
||||
|
||||
// get the node of the key
|
||||
func (s *tree) get(key string) (Node, bool) {
|
||||
// use internally to get the internal tree node
|
||||
func (t *tree)internalGet(key string) (*treeNode, bool) {
|
||||
key = "/" + key
|
||||
key = path.Clean(key)
|
||||
|
||||
@ -104,29 +104,67 @@ func (s *tree) get(key string) (Node, bool) {
|
||||
|
||||
//fmt.Println("TreeStore: Nodes ", nodes, " length: ", len(nodes))
|
||||
|
||||
nodeMap := s.Root.NodeMap
|
||||
nodeMap := t.Root.NodeMap
|
||||
|
||||
var i int
|
||||
|
||||
for i = 0; i < len(nodes) - 1; i++ {
|
||||
node, ok := nodeMap[nodes[i]]
|
||||
if !ok || !node.Dir {
|
||||
return emptyNode, false
|
||||
return nil, false
|
||||
}
|
||||
nodeMap = node.NodeMap
|
||||
}
|
||||
|
||||
treeNode, ok := nodeMap[nodes[i]]
|
||||
if ok {
|
||||
return treeNode, ok
|
||||
} else {
|
||||
return nil, ok
|
||||
}
|
||||
}
|
||||
|
||||
// get the node of the key
|
||||
func (t *tree) get(key string) (Node, bool) {
|
||||
treeNode, ok := t.internalGet(key)
|
||||
|
||||
if ok {
|
||||
return treeNode.Value, ok
|
||||
} else {
|
||||
return emptyNode, ok
|
||||
}
|
||||
}
|
||||
|
||||
// return the nodes under the directory
|
||||
func (t *tree) list(prefix string) ([]Node, []string, []string, bool) {
|
||||
treeNode, ok := t.internalGet(prefix)
|
||||
|
||||
if !ok {
|
||||
return nil, nil, nil, ok
|
||||
} else {
|
||||
length := len(treeNode.NodeMap)
|
||||
nodes := make([]Node, length)
|
||||
keys := make([]string, length)
|
||||
dirs := make([]string, length)
|
||||
i := 0
|
||||
|
||||
for key, node := range treeNode.NodeMap {
|
||||
nodes[i] = node.Value
|
||||
keys[i] = key
|
||||
if node.Dir {
|
||||
dirs[i] = "d"
|
||||
} else {
|
||||
dirs[i] = "f"
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
return nodes, keys, dirs, ok
|
||||
}
|
||||
}
|
||||
|
||||
// delete the key, return the old value if the key exists
|
||||
func (s *tree) delete(key string) bool {
|
||||
func (t *tree) delete(key string) bool {
|
||||
key = "/" + key
|
||||
key = path.Clean(key)
|
||||
|
||||
@ -135,7 +173,7 @@ func (s *tree) delete(key string) bool {
|
||||
|
||||
//fmt.Println("TreeStore: Nodes ", nodes, " length: ", len(nodes))
|
||||
|
||||
nodeMap := s.Root.NodeMap
|
||||
nodeMap := t.Root.NodeMap
|
||||
|
||||
var i int
|
||||
|
||||
|
@ -61,6 +61,22 @@ func TestStoreGet(t *testing.T) {
|
||||
}
|
||||
|
||||
|
||||
// test list
|
||||
ts.set("/hello/fooo", CreateTestNode("barbarbar"))
|
||||
ts.set("/hello/foooo/foo", CreateTestNode("barbarbar"))
|
||||
|
||||
nodes, keys, dirs, ok := ts.list("/hello")
|
||||
|
||||
if !ok {
|
||||
t.Fatalf("cannot list!")
|
||||
} else {
|
||||
length := len(nodes)
|
||||
|
||||
for i := 0; i < length; i++ {
|
||||
fmt.Println(keys[i] , "=", nodes[i].Value, "[", dirs[i], "]")
|
||||
}
|
||||
}
|
||||
|
||||
// speed test
|
||||
for i:=0; i < 100; i++ {
|
||||
key := "/"
|
||||
|
Loading…
x
Reference in New Issue
Block a user