treeStruct first commit

This commit is contained in:
Xiang Li 2013-07-03 12:57:23 -07:00
parent c5901f4b88
commit 6e3379c3ef
4 changed files with 70 additions and 63 deletions

View File

@ -22,9 +22,11 @@ const (
var PERMANENT = time.Unix(0, 0) var PERMANENT = time.Unix(0, 0)
type Store struct { type Store struct {
// use the build-in hash map as the key-value store structure // // use the build-in hash map as the key-value store structure
Nodes map[string]Node `json:"nodes"` // 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 // the string channel to send messages to the outside world
// now we use it to send changes to the hub of the web service // now we use it to send changes to the hub of the web service
messager *chan string messager *chan string
@ -77,11 +79,23 @@ type Response struct {
func CreateStore(max int) *Store { func CreateStore(max int) *Store {
s = new(Store) s = new(Store)
s.messager = nil s.messager = nil
s.Nodes = make(map[string]Node)
s.ResponseMap = make(map[string]Response) s.ResponseMap = make(map[string]Response)
s.ResponseStartIndex = 0 s.ResponseStartIndex = 0
s.ResponseMaxSize = max s.ResponseMaxSize = max
s.ResponseCurrSize = 0 s.ResponseCurrSize = 0
s.Tree = &tree{
&treeNode{
Node {
"/",
time.Unix(0,0),
nil,
},
true,
make(map[string]*treeNode),
},
}
return s return s
} }
@ -125,7 +139,7 @@ func Set(key string, value string, expireTime time.Time, index uint64) ([]byte,
} }
// get the node // get the node
node, ok := s.Nodes[key] node, ok := s.Tree.get(key)
if ok { if ok {
// if node is not permanent before // 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 // 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} 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) update := make(chan time.Time)
s.Nodes[key] = Node{value, expireTime, update} s.Tree.set(key, Node{value, expireTime, update})
if isExpire { if isExpire {
go expire(key, update, expireTime) go expire(key, update, expireTime)
@ -200,12 +214,12 @@ func expire(key string, update chan time.Time, expireTime time.Time) {
select { select {
// timeout delete the node // timeout delete the node
case <-time.After(duration): case <-time.After(duration):
node, ok := s.Nodes[key] node, ok := s.Tree.get(key)
if !ok { if !ok {
return return
} else { } else {
delete(s.Nodes, key) s.Tree.delete(key)
resp := Response{DELETE, key, node.Value, "", true, node.ExpireTime, 0, s.Index} 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) key = path.Clean(key)
node, ok := s.Nodes[key] node, ok := s.Tree.get(key)
if ok { if ok {
var TTL int64 var TTL int64
@ -298,19 +312,19 @@ func Delete(key string, index uint64) ([]byte, error) {
key = path.Clean(key) key = path.Clean(key)
node, ok := s.Nodes[key] node, ok := s.Tree.get(key)
if ok { if ok {
if node.ExpireTime.Equal(PERMANENT) { if node.ExpireTime.Equal(PERMANENT) {
delete(s.Nodes, key) s.Tree.delete(key)
} else { } else {
// kill the expire go routine // kill the expire go routine
node.update <- PERMANENT 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 // clean all expired keys
func clean() { func clean() {
for key, node := range s.Nodes { // for key, node := range s.Nodes {
if node.ExpireTime.Equal(PERMANENT) { // if node.ExpireTime.Equal(PERMANENT) {
continue // continue
} else { // } else {
if node.ExpireTime.Sub(time.Now()) >= time.Second { // if node.ExpireTime.Sub(time.Now()) >= time.Second {
node.update = make(chan time.Time) // node.update = make(chan time.Time)
go expire(key, node.update, node.ExpireTime) // go expire(key, node.update, node.ExpireTime)
} else { // } else {
// we should delete this node // // we should delete this node
delete(s.Nodes, key) // delete(s.Nodes, key)
} // }
} // }
} // }
} }

View File

@ -3,31 +3,26 @@ package store
import ( import (
"path" "path"
"strings" "strings"
"errors"
//"fmt"
) )
type treeStore struct { type tree struct {
Root *treeNode Root *treeNode
} }
type treeNode struct { type treeNode struct {
Value string
Value Node
Dir bool //for clearity Dir bool //for clearity
NodeMap map[string]*treeNode 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 // 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 = "/" + key
key = path.Clean(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++ { for i = 0; i < len(nodes) - 1; i++ {
if newDir { if newDir {
node := &treeNode{".", true, make(map[string]*treeNode)} node := &treeNode{emptyNode, true, make(map[string]*treeNode)}
nodeMap[nodes[i]] = node nodeMap[nodes[i]] = node
nodeMap = node.NodeMap nodeMap = node.NodeMap
continue continue
@ -55,13 +50,13 @@ func (s *treeStore) set(key string, value string, expireTime time.Time, index ui
if !ok { if !ok {
//fmt.Println("TreeStore: Add a dir ", nodes[i]) //fmt.Println("TreeStore: Add a dir ", nodes[i])
newDir = true newDir = true
node := &treeNode{".", true, make(map[string]*treeNode)} node := &treeNode{emptyNode, true, make(map[string]*treeNode)}
nodeMap[nodes[i]] = node nodeMap[nodes[i]] = node
nodeMap = node.NodeMap nodeMap = node.NodeMap
} else if ok && !node.Dir { } else if ok && !node.Dir {
return "", errors.New("Try to add a key under a file") return false
} else { } else {
//fmt.Println("TreeStore: found dir ", nodes[i]) //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} node := &treeNode{value, false, nil}
nodeMap[nodes[i]] = node nodeMap[nodes[i]] = node
//fmt.Println("TreeStore: Add a new Node ", key, "=", value) //fmt.Println("TreeStore: Add a new Node ", key, "=", value)
return "", nil
} else { } else {
oldValue := node.Value
node.Value = value node.Value = value
//fmt.Println("TreeStore: Update a Node ", key, "=", value, "[", oldValue, "]") //fmt.Println("TreeStore: Update a Node ", key, "=", value, "[", oldValue, "]")
return oldValue ,nil
} }
return true
} }
// get the node of the key // get the node of the key
func (s *treeStore) get(key string) *treeNode { func (s *tree) get(key string) (Node, bool) {
key = "/" + key key = "/" + key
key = path.Clean(key) key = path.Clean(key)
@ -104,21 +97,22 @@ func (s *treeStore) get(key string) *treeNode {
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 nil return emptyNode, false
} }
nodeMap = node.NodeMap nodeMap = node.NodeMap
} }
node, ok := nodeMap[nodes[i]] treeNode, ok := nodeMap[nodes[i]]
if ok { 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 // 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 = "/" + key
key = path.Clean(key) key = path.Clean(key)
@ -134,17 +128,16 @@ func (s *treeStore) delete(key string) string {
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 "" return false
} }
nodeMap = node.NodeMap nodeMap = node.NodeMap
} }
node, ok := nodeMap[nodes[i]] node, ok := nodeMap[nodes[i]]
if ok && !node.Dir{ if ok && !node.Dir{
oldValue := node.Value
delete(nodeMap, nodes[i]) delete(nodeMap, nodes[i])
return oldValue return true
} }
return "" return false
} }

View File

@ -8,7 +8,7 @@ import (
func TestStoreGet(t *testing.T) { func TestStoreGet(t *testing.T) {
ts := &treeStore{ ts := &tree{
&treeNode{ &treeNode{
"/", "/",
true, true,

View File

@ -4,10 +4,10 @@ import (
"code.google.com/p/go.net/websocket" "code.google.com/p/go.net/websocket"
"fmt" "fmt"
"github.com/xiangli-cmu/go-raft" "github.com/xiangli-cmu/go-raft"
"github.com/xiangli-cmu/raft-etcd/store" //"github.com/xiangli-cmu/raft-etcd/store"
"html/template" "html/template"
"net/http" "net/http"
"time" //"time"
) )
var s *raft.Server var s *raft.Server
@ -28,15 +28,15 @@ func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Data\n") fmt.Fprintf(w, "Data\n")
s := store.GetStore() //s := store.GetStore()
for key, node := range s.Nodes { // for key, node := range s.Nodes {
if node.ExpireTime.Equal(time.Unix(0, 0)) { // if node.ExpireTime.Equal(time.Unix(0, 0)) {
fmt.Fprintf(w, "%s %s\n", key, node.Value) // fmt.Fprintf(w, "%s %s\n", key, node.Value)
} else { // } else {
fmt.Fprintf(w, "%s %s %s\n", key, node.Value, node.ExpireTime) // fmt.Fprintf(w, "%s %s %s\n", key, node.Value, node.ExpireTime)
} // }
} // }
} }