add list feature
parent
5ee976da76
commit
93c96b3813
15
command.go
15
command.go
|
@ -61,6 +61,21 @@ func (c *GetCommand) GeneratePath() string {
|
||||||
return "get/" + c.Key
|
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
|
// Delete command
|
||||||
type DeleteCommand struct {
|
type DeleteCommand struct {
|
||||||
Key string `json:"key"`
|
Key string `json:"key"`
|
||||||
|
|
1
etcd.go
1
etcd.go
|
@ -318,6 +318,7 @@ func startClientTransport(port int, st int) {
|
||||||
// external commands
|
// external commands
|
||||||
http.HandleFunc("/v1/keys/", Multiplexer)
|
http.HandleFunc("/v1/keys/", Multiplexer)
|
||||||
http.HandleFunc("/v1/watch/", WatchHttpHandler)
|
http.HandleFunc("/v1/watch/", WatchHttpHandler)
|
||||||
|
http.HandleFunc("/v1/list/", ListHttpHandler)
|
||||||
http.HandleFunc("/master", MasterHttpHandler)
|
http.HandleFunc("/master", MasterHttpHandler)
|
||||||
|
|
||||||
switch st {
|
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) {
|
func WatchHttpHandler(w http.ResponseWriter, req *http.Request) {
|
||||||
key := req.URL.Path[len("/v1/watch/"):]
|
key := req.URL.Path[len("/v1/watch/"):]
|
||||||
|
|
||||||
|
|
|
@ -70,11 +70,17 @@ type Response struct {
|
||||||
Expiration time.Time `json:"expiration"`
|
Expiration time.Time `json:"expiration"`
|
||||||
|
|
||||||
// countdown until expiration in seconds
|
// countdown until expiration in seconds
|
||||||
TTL int64 `json:"TTL"`
|
TTL int64 `json:"ttl"`
|
||||||
|
|
||||||
Index uint64 `json:"index"`
|
Index uint64 `json:"index"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ListNode struct {
|
||||||
|
Key string
|
||||||
|
Value string
|
||||||
|
Type string
|
||||||
|
}
|
||||||
|
|
||||||
// make a new stroe
|
// make a new stroe
|
||||||
func CreateStore(max int) *Store {
|
func CreateStore(max int) *Store {
|
||||||
s = new(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
|
// delete the key
|
||||||
func Delete(key string, index uint64) ([]byte, error) {
|
func Delete(key string, index uint64) ([]byte, error) {
|
||||||
//update index
|
//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}
|
var emptyNode = Node{".", PERMANENT, nil}
|
||||||
|
|
||||||
// set the key to value, return the old value if the key exists
|
// 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 = "/" + key
|
||||||
key = path.Clean(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))
|
//fmt.Println("TreeStore: Nodes ", nodes, " length: ", len(nodes))
|
||||||
|
|
||||||
nodeMap := s.Root.NodeMap
|
nodeMap := t.Root.NodeMap
|
||||||
|
|
||||||
i := 0
|
i := 0
|
||||||
newDir := false
|
newDir := false
|
||||||
|
@ -94,8 +94,8 @@ func (s *tree) set(key string, value Node) bool {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the node of the key
|
// use internally to get the internal tree node
|
||||||
func (s *tree) get(key string) (Node, bool) {
|
func (t *tree)internalGet(key string) (*treeNode, bool) {
|
||||||
key = "/" + key
|
key = "/" + key
|
||||||
key = path.Clean(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))
|
//fmt.Println("TreeStore: Nodes ", nodes, " length: ", len(nodes))
|
||||||
|
|
||||||
nodeMap := s.Root.NodeMap
|
nodeMap := t.Root.NodeMap
|
||||||
|
|
||||||
var i int
|
var i int
|
||||||
|
|
||||||
for i = 0; i < len(nodes) - 1; i++ {
|
for i = 0; i < len(nodes) - 1; i++ {
|
||||||
node, ok := nodeMap[nodes[i]]
|
node, ok := nodeMap[nodes[i]]
|
||||||
if !ok || !node.Dir {
|
if !ok || !node.Dir {
|
||||||
return emptyNode, false
|
return nil, false
|
||||||
}
|
}
|
||||||
nodeMap = node.NodeMap
|
nodeMap = node.NodeMap
|
||||||
}
|
}
|
||||||
|
|
||||||
treeNode, ok := nodeMap[nodes[i]]
|
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 {
|
if ok {
|
||||||
return treeNode.Value, ok
|
return treeNode.Value, ok
|
||||||
} else {
|
} else {
|
||||||
return emptyNode, ok
|
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
|
// 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 = "/" + key
|
||||||
key = path.Clean(key)
|
key = path.Clean(key)
|
||||||
|
|
||||||
|
@ -135,7 +173,7 @@ func (s *tree) delete(key string) bool {
|
||||||
|
|
||||||
//fmt.Println("TreeStore: Nodes ", nodes, " length: ", len(nodes))
|
//fmt.Println("TreeStore: Nodes ", nodes, " length: ", len(nodes))
|
||||||
|
|
||||||
nodeMap := s.Root.NodeMap
|
nodeMap := t.Root.NodeMap
|
||||||
|
|
||||||
var i int
|
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
|
// speed test
|
||||||
for i:=0; i < 100; i++ {
|
for i:=0; i < 100; i++ {
|
||||||
key := "/"
|
key := "/"
|
||||||
|
|
Loading…
Reference in New Issue