|
| 1 | +package iavl |
| 2 | + |
| 3 | +// NOTE: This file favors int64 as opposed to int for size/counts. |
| 4 | +// The Tree on the other hand favors int. This is intentional. |
| 5 | + |
| 6 | +import ( |
| 7 | + "bytes" |
| 8 | + |
| 9 | + dbm "github.com/tendermint/tm-db" |
| 10 | +) |
| 11 | + |
| 12 | +type traversal struct { |
| 13 | + tree *ImmutableTree |
| 14 | + start, end []byte // iteration domain |
| 15 | + ascending bool // ascending traversal |
| 16 | + inclusive bool // end key inclusiveness |
| 17 | + post bool // postorder traversal |
| 18 | + delayedNodes *delayedNodes // delayed nodes to be traversed |
| 19 | +} |
| 20 | + |
| 21 | +func (node *Node) newTraversal(tree *ImmutableTree, start, end []byte, ascending bool, inclusive bool, post bool) *traversal { |
| 22 | + return &traversal{ |
| 23 | + tree: tree, |
| 24 | + start: start, |
| 25 | + end: end, |
| 26 | + ascending: ascending, |
| 27 | + inclusive: inclusive, |
| 28 | + post: post, |
| 29 | + delayedNodes: &delayedNodes{{node, true}}, // set initial traverse to the node |
| 30 | + } |
| 31 | +} |
| 32 | + |
| 33 | +// delayedNode represents the delayed iteration on the nodes. |
| 34 | +// When delayed is set to true, the delayedNode should be expanded, and their |
| 35 | +// children should be traversed. When delayed is set to false, the delayedNode is |
| 36 | +// already have expanded, and it could be immediately returned. |
| 37 | +type delayedNode struct { |
| 38 | + node *Node |
| 39 | + delayed bool |
| 40 | +} |
| 41 | + |
| 42 | +type delayedNodes []delayedNode |
| 43 | + |
| 44 | +func (nodes *delayedNodes) pop() (*Node, bool) { |
| 45 | + node := (*nodes)[len(*nodes)-1] |
| 46 | + *nodes = (*nodes)[:len(*nodes)-1] |
| 47 | + return node.node, node.delayed |
| 48 | +} |
| 49 | + |
| 50 | +func (nodes *delayedNodes) push(node *Node, delayed bool) { |
| 51 | + *nodes = append(*nodes, delayedNode{node, delayed}) |
| 52 | +} |
| 53 | + |
| 54 | +func (nodes *delayedNodes) length() int { |
| 55 | + return len(*nodes) |
| 56 | +} |
| 57 | + |
| 58 | +// `traversal` returns the delayed execution of recursive traversal on a tree. |
| 59 | +// |
| 60 | +// `traversal` will traverse the tree in a depth-first manner. To handle locating |
| 61 | +// the next element, and to handle unwinding, the traversal maintains its future |
| 62 | +// iteration under `delayedNodes`. At each call of `next()`, it will retrieve the |
| 63 | +// next element from the `delayedNodes` and acts accordingly. The `next()` itself |
| 64 | +// defines how to unwind the delayed nodes stack. The caller can either call the |
| 65 | +// next traversal to proceed, or simply discard the `traversal` struct to stop iteration. |
| 66 | +// |
| 67 | +// At the each step of `next`, the `delayedNodes` can have one of the three states: |
| 68 | +// 1. It has length of 0, meaning that their is no more traversable nodes. |
| 69 | +// 2. It has length of 1, meaning that the traverse is being started from the initial node. |
| 70 | +// 3. It has length of 2>=, meaning that there are delayed nodes to be traversed. |
| 71 | +// |
| 72 | +// When the `delayedNodes` are not empty, `next` retrieves the first `delayedNode` and initially check: |
| 73 | +// 1. If it is not an delayed node (node.delayed == false) it immediately returns it. |
| 74 | +// |
| 75 | +// A. If the `node` is a branch node: |
| 76 | +// 1. If the traversal is postorder, then append the current node to the t.delayedNodes, |
| 77 | +// with `delayed` set to false. This makes the current node returned *after* all the children |
| 78 | +// are traversed, without being expanded. |
| 79 | +// 2. Append the traversable children nodes into the `delayedNodes`, with `delayed` set to true. This |
| 80 | +// makes the children nodes to be traversed, and expanded with their respective children. |
| 81 | +// 3. If the traversal is preorder, (with the children to be traversed already pushed to the |
| 82 | +// `delayedNodes`), returns the current node. |
| 83 | +// 4. Call `traversal.next()` to further traverse through the `delayedNodes`. |
| 84 | +// |
| 85 | +// B. If the `node` is a leaf node, it will be returned without expand, by the following process: |
| 86 | +// 1. If the traversal is postorder, the current node will be append to the `delayedNodes` with `delayed` |
| 87 | +// set to false, and immediately returned at the subsequent call of `traversal.next()` at the last line. |
| 88 | +// 2. If the traversal is preorder, the current node will be returned. |
| 89 | +func (t *traversal) next() *Node { |
| 90 | + // End of traversal. |
| 91 | + if t.delayedNodes.length() == 0 { |
| 92 | + return nil |
| 93 | + } |
| 94 | + |
| 95 | + node, delayed := t.delayedNodes.pop() |
| 96 | + |
| 97 | + // Already expanded, immediately return. |
| 98 | + if !delayed || node == nil { |
| 99 | + return node |
| 100 | + } |
| 101 | + |
| 102 | + afterStart := t.start == nil || bytes.Compare(t.start, node.key) < 0 |
| 103 | + startOrAfter := afterStart || bytes.Equal(t.start, node.key) |
| 104 | + beforeEnd := t.end == nil || bytes.Compare(node.key, t.end) < 0 |
| 105 | + if t.inclusive { |
| 106 | + beforeEnd = beforeEnd || bytes.Equal(node.key, t.end) |
| 107 | + } |
| 108 | + |
| 109 | + // case of postorder. A-1 and B-1 |
| 110 | + // Recursively process left sub-tree, then right-subtree, then node itself. |
| 111 | + if t.post && (!node.isLeaf() || (startOrAfter && beforeEnd)) { |
| 112 | + t.delayedNodes.push(node, false) |
| 113 | + } |
| 114 | + |
| 115 | + // case of branch node, traversing children. A-2. |
| 116 | + if !node.isLeaf() { |
| 117 | + // if node is a branch node and the order is ascending, |
| 118 | + // We traverse through the left subtree, then the right subtree. |
| 119 | + if t.ascending { |
| 120 | + if beforeEnd { |
| 121 | + // push the delayed traversal for the right nodes, |
| 122 | + t.delayedNodes.push(node.getRightNode(t.tree), true) |
| 123 | + } |
| 124 | + if afterStart { |
| 125 | + // push the delayed traversal for the left nodes, |
| 126 | + t.delayedNodes.push(node.getLeftNode(t.tree), true) |
| 127 | + } |
| 128 | + } else { |
| 129 | + // if node is a branch node and the order is not ascending |
| 130 | + // We traverse through the right subtree, then the left subtree. |
| 131 | + if afterStart { |
| 132 | + // push the delayed traversal for the left nodes, |
| 133 | + t.delayedNodes.push(node.getLeftNode(t.tree), true) |
| 134 | + } |
| 135 | + if beforeEnd { |
| 136 | + // push the delayed traversal for the right nodes, |
| 137 | + t.delayedNodes.push(node.getRightNode(t.tree), true) |
| 138 | + } |
| 139 | + } |
| 140 | + } |
| 141 | + |
| 142 | + // case of preorder traversal. A-3 and B-2. |
| 143 | + // Process root then (recursively) processing left child, then process right child |
| 144 | + if !t.post && (!node.isLeaf() || (startOrAfter && beforeEnd)) { |
| 145 | + return node |
| 146 | + } |
| 147 | + |
| 148 | + // Keep traversing and expanding the remaning delayed nodes. A-4. |
| 149 | + return t.next() |
| 150 | +} |
| 151 | + |
| 152 | +// Iterator is a dbm.Iterator for ImmutableTree |
| 153 | +type Iterator struct { |
| 154 | + start, end []byte |
| 155 | + |
| 156 | + key, value []byte |
| 157 | + |
| 158 | + valid bool |
| 159 | + |
| 160 | + t *traversal |
| 161 | +} |
| 162 | + |
| 163 | +func (t *ImmutableTree) Iterator(start, end []byte, ascending bool) *Iterator { |
| 164 | + iter := &Iterator{ |
| 165 | + start: start, |
| 166 | + end: end, |
| 167 | + valid: true, |
| 168 | + t: t.root.newTraversal(t, start, end, ascending, false, false), |
| 169 | + } |
| 170 | + |
| 171 | + iter.Next() |
| 172 | + return iter |
| 173 | +} |
| 174 | + |
| 175 | +var _ dbm.Iterator = &Iterator{} |
| 176 | + |
| 177 | +// Domain implements dbm.Iterator. |
| 178 | +func (iter *Iterator) Domain() ([]byte, []byte) { |
| 179 | + return iter.start, iter.end |
| 180 | +} |
| 181 | + |
| 182 | +// Valid implements dbm.Iterator. |
| 183 | +func (iter *Iterator) Valid() bool { |
| 184 | + return iter.valid |
| 185 | +} |
| 186 | + |
| 187 | +// Key implements dbm.Iterator |
| 188 | +func (iter *Iterator) Key() []byte { |
| 189 | + return iter.key |
| 190 | +} |
| 191 | + |
| 192 | +// Value implements dbm.Iterator |
| 193 | +func (iter *Iterator) Value() []byte { |
| 194 | + return iter.value |
| 195 | +} |
| 196 | + |
| 197 | +// Next implements dbm.Iterator |
| 198 | +func (iter *Iterator) Next() { |
| 199 | + if iter.t == nil { |
| 200 | + return |
| 201 | + } |
| 202 | + |
| 203 | + node := iter.t.next() |
| 204 | + if node == nil { |
| 205 | + iter.t = nil |
| 206 | + iter.valid = false |
| 207 | + return |
| 208 | + } |
| 209 | + |
| 210 | + if node.height == 0 { |
| 211 | + iter.key, iter.value = node.key, node.value |
| 212 | + return |
| 213 | + } |
| 214 | + |
| 215 | + iter.Next() |
| 216 | +} |
| 217 | + |
| 218 | +// Close implements dbm.Iterator |
| 219 | +func (iter *Iterator) Close() error { |
| 220 | + iter.t = nil |
| 221 | + iter.valid = false |
| 222 | + return nil |
| 223 | +} |
| 224 | + |
| 225 | +// Error implements dbm.Iterator |
| 226 | +func (iter *Iterator) Error() error { |
| 227 | + return nil |
| 228 | +} |
0 commit comments