diff --git a/store/store.go b/store/store.go index c10a93848..e78ea6381 100644 --- a/store/store.go +++ b/store/store.go @@ -22,9 +22,11 @@ const ( var PERMANENT = time.Unix(0, 0) type Store struct { - // use the build-in hash map as the key-value store structure - Nodes map[string]Node `json:"nodes"` + // // use the build-in hash map as the key-value store structure + // Nodes map[string]Node `json:"nodes"` + // use treeMap as the key-value stroe structure + Tree *tree // the string channel to send messages to the outside world // now we use it to send changes to the hub of the web service messager *chan string @@ -77,11 +79,23 @@ type Response struct { func CreateStore(max int) *Store { s = new(Store) s.messager = nil - s.Nodes = make(map[string]Node) s.ResponseMap = make(map[string]Response) s.ResponseStartIndex = 0 s.ResponseMaxSize = max s.ResponseCurrSize = 0 + + s.Tree = &tree{ + &treeNode{ + Node { + "/", + time.Unix(0,0), + nil, + }, + true, + make(map[string]*treeNode), + }, + } + return s } @@ -125,7 +139,7 @@ func Set(key string, value string, expireTime time.Time, index uint64) ([]byte, } // get the node - node, ok := s.Nodes[key] + node, ok := s.Tree.get(key) if ok { // if node is not permanent before @@ -145,7 +159,7 @@ func Set(key string, value string, expireTime time.Time, index uint64) ([]byte, } // update the information of the node - s.Nodes[key] = Node{value, expireTime, node.update} + s.Tree.set(key, Node{value, expireTime, node.update}) resp := Response{SET, key, node.Value, value, true, expireTime, TTL, index} @@ -168,7 +182,7 @@ func Set(key string, value string, expireTime time.Time, index uint64) ([]byte, update := make(chan time.Time) - s.Nodes[key] = Node{value, expireTime, update} + s.Tree.set(key, Node{value, expireTime, update}) if isExpire { go expire(key, update, expireTime) @@ -200,12 +214,12 @@ func expire(key string, update chan time.Time, expireTime time.Time) { select { // timeout delete the node case <-time.After(duration): - node, ok := s.Nodes[key] + node, ok := s.Tree.get(key) if !ok { return } else { - delete(s.Nodes, key) + s.Tree.delete(key) resp := Response{DELETE, key, node.Value, "", true, node.ExpireTime, 0, s.Index} @@ -267,7 +281,7 @@ func Get(key string) Response { key = path.Clean(key) - node, ok := s.Nodes[key] + node, ok := s.Tree.get(key) if ok { var TTL int64 @@ -298,19 +312,19 @@ func Delete(key string, index uint64) ([]byte, error) { key = path.Clean(key) - node, ok := s.Nodes[key] + node, ok := s.Tree.get(key) if ok { if node.ExpireTime.Equal(PERMANENT) { - delete(s.Nodes, key) + s.Tree.delete(key) } else { // kill the expire go routine node.update <- PERMANENT - delete(s.Nodes, key) + s.Tree.delete(key) } @@ -361,21 +375,21 @@ func (s *Store) Recovery(state []byte) error { // clean all expired keys func clean() { - for key, node := range s.Nodes { + // for key, node := range s.Nodes { - if node.ExpireTime.Equal(PERMANENT) { - continue - } else { + // if node.ExpireTime.Equal(PERMANENT) { + // continue + // } else { - if node.ExpireTime.Sub(time.Now()) >= time.Second { - node.update = make(chan time.Time) - go expire(key, node.update, node.ExpireTime) + // if node.ExpireTime.Sub(time.Now()) >= time.Second { + // node.update = make(chan time.Time) + // go expire(key, node.update, node.ExpireTime) - } else { - // we should delete this node - delete(s.Nodes, key) - } - } + // } else { + // // we should delete this node + // delete(s.Nodes, key) + // } + // } - } + // } } diff --git a/store/tree_store.go b/store/tree_store.go index b84ec3ad1..336d2cf02 100644 --- a/store/tree_store.go +++ b/store/tree_store.go @@ -3,31 +3,26 @@ package store import ( "path" "strings" - "errors" - //"fmt" ) -type treeStore struct { +type tree struct { Root *treeNode } type treeNode struct { - Value string + + Value Node Dir bool //for clearity NodeMap map[string]*treeNode - // if the node is a permanent one the ExprieTime will be Unix(0,0) - // Otherwise after the expireTime, the node will be deleted - ExpireTime time.Time `json:"expireTime"` - - // a channel to update the expireTime of the node - update chan time.Time `json:"-"` } +var emptyNode = Node{".", PERMANENT, nil} + // set the key to value, return the old value if the key exists -func (s *treeStore) set(key string, value string, expireTime time.Time, index uint64) (string, error) { +func (s *tree) set(key string, value Node) bool { key = "/" + key key = path.Clean(key) @@ -44,7 +39,7 @@ func (s *treeStore) set(key string, value string, expireTime time.Time, index ui for i = 0; i < len(nodes) - 1; i++ { if newDir { - node := &treeNode{".", true, make(map[string]*treeNode)} + node := &treeNode{emptyNode, true, make(map[string]*treeNode)} nodeMap[nodes[i]] = node nodeMap = node.NodeMap continue @@ -55,13 +50,13 @@ func (s *treeStore) set(key string, value string, expireTime time.Time, index ui if !ok { //fmt.Println("TreeStore: Add a dir ", nodes[i]) newDir = true - node := &treeNode{".", true, make(map[string]*treeNode)} + node := &treeNode{emptyNode, true, make(map[string]*treeNode)} nodeMap[nodes[i]] = node nodeMap = node.NodeMap } else if ok && !node.Dir { - return "", errors.New("Try to add a key under a file") + return false } else { //fmt.Println("TreeStore: found dir ", nodes[i]) @@ -77,18 +72,16 @@ func (s *treeStore) set(key string, value string, expireTime time.Time, index ui node := &treeNode{value, false, nil} nodeMap[nodes[i]] = node //fmt.Println("TreeStore: Add a new Node ", key, "=", value) - return "", nil } else { - oldValue := node.Value node.Value = value //fmt.Println("TreeStore: Update a Node ", key, "=", value, "[", oldValue, "]") - return oldValue ,nil } + return true } // get the node of the key -func (s *treeStore) get(key string) *treeNode { +func (s *tree) get(key string) (Node, bool) { key = "/" + key key = path.Clean(key) @@ -104,21 +97,22 @@ func (s *treeStore) get(key string) *treeNode { for i = 0; i < len(nodes) - 1; i++ { node, ok := nodeMap[nodes[i]] if !ok || !node.Dir { - return nil + return emptyNode, false } nodeMap = node.NodeMap } - node, ok := nodeMap[nodes[i]] + treeNode, ok := nodeMap[nodes[i]] if ok { - return node + return treeNode.Value, ok + } else { + return emptyNode, ok } - return nil } // delete the key, return the old value if the key exists -func (s *treeStore) delete(key string) string { +func (s *tree) delete(key string) bool { key = "/" + key key = path.Clean(key) @@ -134,17 +128,16 @@ func (s *treeStore) delete(key string) string { for i = 0; i < len(nodes) - 1; i++ { node, ok := nodeMap[nodes[i]] if !ok || !node.Dir { - return "" + return false } nodeMap = node.NodeMap } node, ok := nodeMap[nodes[i]] if ok && !node.Dir{ - oldValue := node.Value delete(nodeMap, nodes[i]) - return oldValue + return true } - return "" + return false } diff --git a/store/tree_store_test.go b/store/tree_store_test.go index 562e5bfeb..b356d1f8d 100644 --- a/store/tree_store_test.go +++ b/store/tree_store_test.go @@ -8,7 +8,7 @@ import ( func TestStoreGet(t *testing.T) { - ts := &treeStore{ + ts := &tree{ &treeNode{ "/", true, diff --git a/web/web.go b/web/web.go index f57c51c8c..610310fa3 100644 --- a/web/web.go +++ b/web/web.go @@ -4,10 +4,10 @@ import ( "code.google.com/p/go.net/websocket" "fmt" "github.com/xiangli-cmu/go-raft" - "github.com/xiangli-cmu/raft-etcd/store" + //"github.com/xiangli-cmu/raft-etcd/store" "html/template" "net/http" - "time" + //"time" ) var s *raft.Server @@ -28,15 +28,15 @@ func handler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Data\n") - s := store.GetStore() + //s := store.GetStore() - for key, node := range s.Nodes { - if node.ExpireTime.Equal(time.Unix(0, 0)) { - fmt.Fprintf(w, "%s %s\n", key, node.Value) - } else { - fmt.Fprintf(w, "%s %s %s\n", key, node.Value, node.ExpireTime) - } - } + // for key, node := range s.Nodes { + // if node.ExpireTime.Equal(time.Unix(0, 0)) { + // fmt.Fprintf(w, "%s %s\n", key, node.Value) + // } else { + // fmt.Fprintf(w, "%s %s %s\n", key, node.Value, node.ExpireTime) + // } + // } }