tree store init commit

This commit is contained in:
Xiang Li 2013-07-02 18:09:54 -07:00
parent ab285a90bb
commit c5901f4b88
6 changed files with 233 additions and 86 deletions

View File

@ -212,7 +212,7 @@ func main() {
}
// open the snapshot
go server.Snapshot()
//go server.Snapshot()
if webPort != -1 {
// start web

View File

@ -1,85 +0,0 @@
package main
import (
"path"
"strings"
)
type store struct {
nodes map[string]node
}
type node struct {
value string
dir bool // just for clearity
nodes map[string]node
}
// set the key to value, return the old value if the key exists
func (s *store) set(key string, value string) string, error {
key = path.Clean(key)
nodeNames := strings.Split(key, "/")
levelNodes := s.nodes
for i = 0; i < len(nodes) - 1; ++i {
node, ok := levelNodes[nodeNames[i]]
// add new dir
if !ok {
node := Node{nodeNames[i], true, make(map[string]node)}
levelNodes[nodeNames[i]] := node
} else if ok && !node.dir {
return nil, errors.New("The key is a directory")
}
else {
levelNodes = levelNodes.nodes
}
}
// add the last node and value
node, ok := levelNodes[nodeNames[i]]
if !ok {
node := Node{nodeNames[i], false, nil}
levelNodes[nodeNames] = node
return nil, nil
} else {
oldValue := node.value
node.value = value
return oldValue ,nil
}
}
// get the node of the key
func (s *store) get(key string) node {
key = path.Clean(key)
nodeNames := strings.Split(key, "/")
levelNodes := s.nodes
for i = 0; i < len(nodes) - 1; ++i {
node, ok := levelNodes[nodeNames[i]]
if !ok || !node.dir {
return nil
}
levelNodes = levelNodes.nodes
}
node, ok := levelNodes[nodeNames[i]]
if ok {
return node
}
return nil
}
// delete the key, return the old value if the key exists
func (s *store) delete(key string) string {
return nil
}
func (n *node) Value() string{
return n.value
}

150
store/tree_store.go Normal file
View File

@ -0,0 +1,150 @@
package store
import (
"path"
"strings"
"errors"
//"fmt"
)
type treeStore struct {
Root *treeNode
}
type treeNode struct {
Value string
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:"-"`
}
// 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) {
key = "/" + key
key = path.Clean(key)
nodes := strings.Split(key, "/")
nodes = nodes[1:]
//fmt.Println("TreeStore: Nodes ", nodes, " length: ", len(nodes))
nodeMap := s.Root.NodeMap
i := 0
newDir := false
for i = 0; i < len(nodes) - 1; i++ {
if newDir {
node := &treeNode{".", true, make(map[string]*treeNode)}
nodeMap[nodes[i]] = node
nodeMap = node.NodeMap
continue
}
node, ok := nodeMap[nodes[i]]
// add new dir
if !ok {
//fmt.Println("TreeStore: Add a dir ", nodes[i])
newDir = true
node := &treeNode{".", 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")
} else {
//fmt.Println("TreeStore: found dir ", nodes[i])
nodeMap = node.NodeMap
}
}
// add the last node and value
node, ok := nodeMap[nodes[i]]
if !ok {
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
}
}
// get the node of the key
func (s *treeStore) get(key string) *treeNode {
key = "/" + key
key = path.Clean(key)
nodes := strings.Split(key, "/")
nodes = nodes[1:]
//fmt.Println("TreeStore: Nodes ", nodes, " length: ", len(nodes))
nodeMap := s.Root.NodeMap
var i int
for i = 0; i < len(nodes) - 1; i++ {
node, ok := nodeMap[nodes[i]]
if !ok || !node.Dir {
return nil
}
nodeMap = node.NodeMap
}
node, ok := nodeMap[nodes[i]]
if ok {
return node
}
return nil
}
// delete the key, return the old value if the key exists
func (s *treeStore) delete(key string) string {
key = "/" + key
key = path.Clean(key)
nodes := strings.Split(key, "/")
nodes = nodes[1:]
//fmt.Println("TreeStore: Nodes ", nodes, " length: ", len(nodes))
nodeMap := s.Root.NodeMap
var i int
for i = 0; i < len(nodes) - 1; i++ {
node, ok := nodeMap[nodes[i]]
if !ok || !node.Dir {
return ""
}
nodeMap = node.NodeMap
}
node, ok := nodeMap[nodes[i]]
if ok && !node.Dir{
oldValue := node.Value
delete(nodeMap, nodes[i])
return oldValue
}
return ""
}

82
store/tree_store_test.go Normal file
View File

@ -0,0 +1,82 @@
package store
import (
"testing"
"math/rand"
"strconv"
)
func TestStoreGet(t *testing.T) {
ts := &treeStore{
&treeNode{
"/",
true,
make(map[string]*treeNode),
},
}
// create key
ts.set("/foo", "bar")
// change value
ts.set("/foo", "barbar")
// create key
ts.set("/hello/foo", "barbarbar")
treeNode := ts.get("/foo")
if treeNode == nil {
t.Fatalf("Expect to get node, but not")
}
if treeNode.Value != "barbar" {
t.Fatalf("Expect value barbar, but got %s", treeNode.Value)
}
// create key
treeNode = ts.get("/hello/foo")
if treeNode == nil {
t.Fatalf("Expect to get node, but not")
}
if treeNode.Value != "barbarbar" {
t.Fatalf("Expect value barbarbar, but got %s", treeNode.Value)
}
// create a key under other key
_, err := ts.set("/foo/foo", "bar")
if err == nil {
t.Fatalf("shoud not add key under a exisiting key")
}
// delete a key
oldValue := ts.delete("/foo")
if oldValue != "barbar" {
t.Fatalf("Expect Oldvalue bar, but got %s", oldValue)
}
// delete a directory
oldValue = ts.delete("/hello")
if oldValue != "" {
t.Fatalf("Expect cannot delet /hello, but deleted! %s", oldValue)
}
// speed test
for i:=0; i < 10000; i++ {
key := "/"
depth := rand.Intn(10)
for j := 0; j < depth; j++ {
key += "/" + strconv.Itoa(rand.Int())
}
value := strconv.Itoa(rand.Int())
ts.set(key, value)
treeNode := ts.get(key)
if treeNode == nil {
t.Fatalf("Expect to get node, but not")
}
if treeNode.Value != value {
t.Fatalf("Expect value %s, but got %s", value, treeNode.Value)
}
}
}