Browse Source

tree store init commit

Xiang Li 12 years ago
parent
commit
c5901f4b88
6 changed files with 233 additions and 86 deletions
  1. 1 1
      etcd.go
  2. 0 0
      store/store_test.bak
  3. 0 85
      store/tree_store.bak
  4. 150 0
      store/tree_store.go
  5. 82 0
      store/tree_store_test.go
  6. 0 0
      store/watcher_test.bak

+ 1 - 1
etcd.go

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

+ 0 - 0
store/store_test.go → store/store_test.bak


+ 0 - 85
store/tree_store.bak

@@ -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 - 0
store/tree_store.go

@@ -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 - 0
store/tree_store_test.go

@@ -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)
+		}
+
+	}
+
+}

+ 0 - 0
store/watcher_test.go → store/watcher_test.bak