diff --git a/store/tree.go b/store/tree.go index 34c34ce26..4ff77eef2 100644 --- a/store/tree.go +++ b/store/tree.go @@ -6,138 +6,149 @@ import ( "sort" ) +//------------------------------------------------------------------------------ +// +// Typedefs +// +//------------------------------------------------------------------------------ + +// A file system like tree structure. Each non-leaf node of the tree has a hashmap to +// store its children nodes. Leaf nodes has no hashmap (a nil pointer) type tree struct { Root *treeNode } +// A treeNode wraps a Node. It has a hashmap to keep records of its children treeNodes. type treeNode struct { - - Value Node - - Dir bool //for clearity - + InternalNode Node + Dir bool NodeMap map[string]*treeNode - } +// TreeNode with its key. We use it when we need to sort the treeNodes. type tnWithKey struct{ key string tn *treeNode } +// Define type and functions to match sort interface type tnWithKeySlice []tnWithKey func (s tnWithKeySlice) Len() int { return len(s) } func (s tnWithKeySlice) Less(i, j int) bool { return s[i].key < s[j].key } func (s tnWithKeySlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +// CONSTANT VARIABLE - +// Represent an empty node var emptyNode = Node{".", PERMANENT, nil} -// set the key to value, return the old value if the key exists +//------------------------------------------------------------------------------ +// +// Methods +// +//------------------------------------------------------------------------------ + +// Set the key to the given value, return true if success +// If any intermidate path of the key is not a directory type, it will fail +// For example if the /foo = Node(bar) exists, set /foo/foo = Node(barbar) +// will fail. func (t *tree) set(key string, value Node) bool { - key = "/" + key - key = path.Clean(key) - nodes := strings.Split(key, "/") - nodes = nodes[1:] - - //fmt.Println("TreeStore: Nodes ", nodes, " length: ", len(nodes)) + nodesName := split(key) nodeMap := t.Root.NodeMap i := 0 newDir := false - for i = 0; i < len(nodes) - 1; i++ { + // go through all the path + for i = 0; i < len(nodesName) - 1; i++ { + // if we meet a new directory, all the directory after it must be new if newDir { - node := &treeNode{emptyNode, true, make(map[string]*treeNode)} - nodeMap[nodes[i]] = node - nodeMap = node.NodeMap + tn := &treeNode{emptyNode, true, make(map[string]*treeNode)} + nodeMap[nodesName[i]] = tn + nodeMap = tn.NodeMap continue } - node, ok := nodeMap[nodes[i]] - // add new dir + // get the node from the nodeMap of the current level + tn, ok := nodeMap[nodesName[i]] + if !ok { - //fmt.Println("TreeStore: Add a dir ", nodes[i]) + // add a new directory and set newDir to true newDir = true - node := &treeNode{emptyNode, true, make(map[string]*treeNode)} - nodeMap[nodes[i]] = node - nodeMap = node.NodeMap + tn := &treeNode{emptyNode, true, make(map[string]*treeNode)} + nodeMap[nodesName[i]] = tn + nodeMap = tn.NodeMap - } else if ok && !node.Dir { + } else if ok && !tn.Dir { + // if we meet a non-directory node, we cannot set the key return false } else { - //fmt.Println("TreeStore: found dir ", nodes[i]) - nodeMap = node.NodeMap + // update the nodeMap to next level + nodeMap = tn.NodeMap } } - // add the last node and value - node, ok := nodeMap[nodes[i]] + // Add the last node + tn, ok := nodeMap[nodesName[i]] if !ok { - node := &treeNode{value, false, nil} - nodeMap[nodes[i]] = node - //fmt.Println("TreeStore: Add a new Node ", key, "=", value) + // we add a new treeNode + tn := &treeNode{value, false, nil} + nodeMap[nodesName[i]] = tn + } else { - node.Value = value - //fmt.Println("TreeStore: Update a Node ", key, "=", value, "[", oldValue, "]") + // we change the value of a old Treenode + tn.InternalNode = value } return true } -// use internally to get the internal tree node +// Get the tree node of the key func (t *tree)internalGet(key string) (*treeNode, bool) { - key = "/" + key - key = path.Clean(key) - - nodes := strings.Split(key, "/") - nodes = nodes[1:] - - //fmt.Println("TreeStore: Nodes ", nodes, " length: ", len(nodes)) + nodesName := split(key) nodeMap := t.Root.NodeMap var i int - for i = 0; i < len(nodes) - 1; i++ { - node, ok := nodeMap[nodes[i]] + for i = 0; i < len(nodesName) - 1; i++ { + node, ok := nodeMap[nodesName[i]] if !ok || !node.Dir { return nil, false } nodeMap = node.NodeMap } - treeNode, ok := nodeMap[nodes[i]] + tn, ok := nodeMap[nodesName[i]] if ok { - return treeNode, ok + return tn, ok } else { return nil, ok } } -// get the node of the key +// get the internalNode of the key func (t *tree) get(key string) (Node, bool) { - treeNode, ok := t.internalGet(key) + tn, ok := t.internalGet(key) if ok { - return treeNode.Value, ok + return tn.InternalNode, 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) +// return the nodes information under the directory +func (t *tree) list(directory string) ([]Node, []string, []string, bool) { + treeNode, ok := t.internalGet(directory) if !ok { return nil, nil, nil, ok @@ -149,7 +160,7 @@ func (t *tree) list(prefix string) ([]Node, []string, []string, bool) { i := 0 for key, node := range treeNode.NodeMap { - nodes[i] = node.Value + nodes[i] = node.InternalNode keys[i] = key if node.Dir { dirs[i] = "d" @@ -163,36 +174,31 @@ func (t *tree) list(prefix string) ([]Node, []string, []string, bool) { } } -// delete the key, return the old value if the key exists +// delete the key, return true if success func (t *tree) delete(key string) bool { - key = "/" + key - key = path.Clean(key) - - nodes := strings.Split(key, "/") - nodes = nodes[1:] - - //fmt.Println("TreeStore: Nodes ", nodes, " length: ", len(nodes)) + nodesName := split(key) nodeMap := t.Root.NodeMap var i int - for i = 0; i < len(nodes) - 1; i++ { - node, ok := nodeMap[nodes[i]] + for i = 0; i < len(nodesName) - 1; i++ { + node, ok := nodeMap[nodesName[i]] if !ok || !node.Dir { return false } nodeMap = node.NodeMap } - node, ok := nodeMap[nodes[i]] + node, ok := nodeMap[nodesName[i]] if ok && !node.Dir{ - delete(nodeMap, nodes[i]) + delete(nodeMap, nodesName[i]) return true } return false } +// traverse wrapper func (t *tree) traverse(f func(string, *Node), sort bool) { if sort { sortDfs("", t.Root, f) @@ -201,24 +207,29 @@ func (t *tree) traverse(f func(string, *Node), sort bool) { } } +// deep first search to traverse the tree +// apply the func f to each internal node func dfs(key string, t *treeNode, f func(string, *Node)) { + // base case if len(t.NodeMap) == 0{ - f(key, &t.Value) + f(key, &t.InternalNode) // recursion } else { - for nodeKey, _treeNode := range t.NodeMap { - newKey := key + "/" + nodeKey - dfs(newKey, _treeNode, f) + for tnKey, tn := range t.NodeMap { + tnKey := key + "/" + tnKey + dfs(tnKey, tn, f) } } } +// sort deep first search to traverse the tree +// apply the func f to each internal node func sortDfs(key string, t *treeNode, f func(string, *Node)) { // base case if len(t.NodeMap) == 0{ - f(key, &t.Value) + f(key, &t.InternalNode) // recursion } else { @@ -227,9 +238,9 @@ func sortDfs(key string, t *treeNode, f func(string, *Node)) { i := 0 // copy - for nodeKey, _treeNode := range t.NodeMap { - newKey := key + "/" + nodeKey - s[i] = tnWithKey{newKey, _treeNode} + for tnKey, tn := range t.NodeMap { + tnKey := key + "/" + tnKey + s[i] = tnWithKey{tnKey, tn} i++ } @@ -243,4 +254,14 @@ func sortDfs(key string, t *treeNode, f func(string, *Node)) { } } +// split the key by '/', get the intermediate node name +func split(key string) []string { + key = "/" + key + key = path.Clean(key) + // get the intermidate nodes name + nodesName := strings.Split(key, "/") + // we do not need the root node, since we start with it + nodesName = nodesName[1:] + return nodesName +}