add list feature

release-0.4
Xiang Li 2013-07-05 16:22:45 -07:00
parent 5ee976da76
commit 93c96b3813
6 changed files with 127 additions and 9 deletions

View File

@ -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"`

View File

@ -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 {

View File

@ -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/"):]

View File

@ -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

View File

@ -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

View File

@ -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 := "/"