You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

163 lines
3.6 KiB

5 years ago
5 years ago
  1. package bounded_tree
  2. import (
  3. "github.com/chrislusf/seaweedfs/weed/glog"
  4. "github.com/chrislusf/seaweedfs/weed/util"
  5. )
  6. type Node struct {
  7. Parent *Node
  8. Name string
  9. Children map[string]*Node
  10. }
  11. type BoundedTree struct {
  12. root *Node
  13. }
  14. func NewBoundedTree() *BoundedTree {
  15. return &BoundedTree{
  16. root: &Node{
  17. Name: "/",
  18. },
  19. }
  20. }
  21. type VisitNodeFunc func(path util.FullPath) (childDirectories []string, err error)
  22. // If the path is not visited, call the visitFn for each level of directory
  23. // No action if the directory has been visited before or does not exist.
  24. // A leaf node, which has no children, represents a directory not visited.
  25. // A non-leaf node or a non-existing node represents a directory already visited, or does not need to visit.
  26. func (t *BoundedTree) EnsureVisited(p util.FullPath, visitFn VisitNodeFunc) {
  27. // println()
  28. // println("EnsureVisited", p)
  29. if t.root == nil {
  30. return
  31. }
  32. components := p.Split()
  33. // fmt.Printf("components %v %d\n", components, len(components))
  34. if canDelete := t.ensureVisited(t.root, util.FullPath("/"), components, 0, visitFn); canDelete {
  35. t.root = nil
  36. }
  37. }
  38. func (t *BoundedTree) ensureVisited(n *Node, currentPath util.FullPath, components []string, i int, visitFn VisitNodeFunc) (canDeleteNode bool) {
  39. // println("ensureVisited", currentPath, i)
  40. if n == nil {
  41. // fmt.Printf("%s null\n", currentPath)
  42. return
  43. }
  44. if n.isVisited() {
  45. // fmt.Printf("%s visited %v\n", currentPath, n.Name)
  46. } else {
  47. // fmt.Printf("ensure %v\n", currentPath)
  48. children, err := visitFn(currentPath)
  49. if err != nil {
  50. glog.V(0).Infof("failed to visit %s: %v", currentPath, err)
  51. return
  52. }
  53. if len(children) == 0 {
  54. // fmt.Printf(" canDelete %v without children\n", currentPath)
  55. return true
  56. }
  57. n.Children = make(map[string]*Node)
  58. for _, child := range children {
  59. // fmt.Printf(" add child %v %v\n", currentPath, child)
  60. n.Children[child] = &Node{
  61. Name: child,
  62. }
  63. }
  64. }
  65. if i >= len(components) {
  66. return
  67. }
  68. // fmt.Printf(" check child %v %v\n", currentPath, components[i])
  69. toVisitNode, found := n.Children[components[i]]
  70. if !found {
  71. // fmt.Printf(" did not find child %v %v\n", currentPath, components[i])
  72. return
  73. }
  74. // fmt.Printf(" ensureVisited %v %v\n", currentPath, toVisitNode.Name)
  75. if canDelete := t.ensureVisited(toVisitNode, currentPath.Child(components[i]), components, i+1, visitFn); canDelete {
  76. // fmt.Printf(" delete %v %v\n", currentPath, components[i])
  77. delete(n.Children, components[i])
  78. if len(n.Children) == 0 {
  79. // fmt.Printf(" canDelete %v\n", currentPath)
  80. return true
  81. }
  82. }
  83. return false
  84. }
  85. func (n *Node) isVisited() bool {
  86. if n == nil {
  87. return true
  88. }
  89. if len(n.Children) > 0 {
  90. return true
  91. }
  92. return false
  93. }
  94. func (n *Node) getChild(childName string) *Node {
  95. if n == nil {
  96. return nil
  97. }
  98. if len(n.Children) > 0 {
  99. return n.Children[childName]
  100. }
  101. return nil
  102. }
  103. func (t *BoundedTree) HasVisited(p util.FullPath) bool {
  104. if t.root == nil {
  105. return true
  106. }
  107. components := p.Split()
  108. // fmt.Printf("components %v %d\n", components, len(components))
  109. return t.hasVisited(t.root, util.FullPath("/"), components, 0)
  110. }
  111. func (t *BoundedTree) hasVisited(n *Node, currentPath util.FullPath, components []string, i int) bool {
  112. if n == nil {
  113. return true
  114. }
  115. if !n.isVisited() {
  116. return false
  117. }
  118. // fmt.Printf(" hasVisited child %v %+v %d\n", currentPath, components, i)
  119. if i >= len(components) {
  120. return true
  121. }
  122. toVisitNode, found := n.Children[components[i]]
  123. if !found {
  124. return true
  125. }
  126. return t.hasVisited(toVisitNode, currentPath.Child(components[i]), components, i+1)
  127. }