| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589 |
- // Copyright 2018 The Cockroach Authors.
- // Copyright 2021 Andrew Werner.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- // implied. See the License for the specific language governing
- // permissions and limitations under the License.
- package abstract
- import (
- "fmt"
- "strings"
- "sync/atomic"
- )
- // Node represents a node in the tree.
- type Node[K, V, A any] struct {
- ref int32
- count int16
- aug A
- keys [MaxEntries]K
- values [MaxEntries]V
- children *[MaxEntries + 1]*Node[K, V, A]
- }
- type interiorNode[K, V, A any] struct {
- Node[K, V, A]
- children [MaxEntries + 1]*Node[K, V, A]
- }
- func (n *Node[K, V, A]) GetA() *A {
- return &n.aug
- }
- func (n *Node[K, V, A]) IsLeaf() bool {
- return n.children == nil
- }
- func (n *Node[K, V, A]) Count() int16 {
- return n.count
- }
- func (n *Node[K, V, A]) GetKey(i int16) K {
- return n.keys[i]
- }
- func (n *Node[K, V, A]) GetChild(i int16) *A {
- if !n.IsLeaf() && n.children[i] != nil {
- return &n.children[i].aug
- }
- return nil
- }
- // mut creates and returns a mutable node reference. If the node is not shared
- // with any other trees then it can be modified in place. Otherwise, it must be
- // cloned to ensure unique ownership. In this way, we enforce a copy-on-write
- // policy which transparently incorporates the idea of local mutations, like
- // Clojure's transients or Haskell's ST monad, where nodes are only copied
- // during the first time that they are modified between Clone operations.
- //
- // When a node is cloned, the provided pointer will be redirected to the new
- // mutable node.
- func mut[K, V, A any](
- np *nodePool[K, V, A],
- n **Node[K, V, A],
- ) *Node[K, V, A] {
- if atomic.LoadInt32(&(*n).ref) == 1 {
- // Exclusive ownership. Can mutate in place.
- return *n
- }
- // If we do not have unique ownership over the node then we
- // clone it to gain unique ownership. After doing so, we can
- // release our reference to the old node. We pass recursive
- // as true because even though we just observed the node's
- // reference count to be greater than 1, we might be racing
- // with another call to decRef on this node.
- c := (*n).clone(np)
- (*n).decRef(np, true /* recursive */)
- *n = c
- return *n
- }
- // incRef acquires a reference to the node.
- func (n *Node[K, V, A]) incRef() {
- atomic.AddInt32(&n.ref, 1)
- }
- // decRef releases a reference to the node. If requested, the method
- // will recurse into child nodes and decrease their refcounts as well.
- func (n *Node[K, V, A]) decRef(
- np *nodePool[K, V, A], recursive bool,
- ) {
- if atomic.AddInt32(&n.ref, -1) > 0 {
- // Other references remain. Can't free.
- return
- }
- // Clear and release node into memory pool.
- if n.IsLeaf() {
- np.putLeafNode(n)
- } else {
- // Release child references first, if requested.
- if recursive {
- for i := int16(0); i <= n.count; i++ {
- n.children[i].decRef(np, true /* recursive */)
- }
- }
- np.putInteriorNode(n)
- }
- }
- // clone creates a clone of the receiver with a single reference count.
- func (n *Node[K, V, A]) clone(
- np *nodePool[K, V, A],
- ) *Node[K, V, A] {
- var c *Node[K, V, A]
- if n.IsLeaf() {
- c = np.getLeafNode()
- } else {
- c = np.getInteriorNode()
- }
- // NB: copy field-by-field without touching N.N.ref to avoid
- // triggering the race detector and looking like a data race.
- c.count = n.count
- n.aug = c.aug
- c.keys = n.keys
- if !c.IsLeaf() {
- // Copy children and increase each refcount.
- *c.children = *n.children
- for i := int16(0); i <= c.count; i++ {
- c.children[i].incRef()
- }
- }
- return c
- }
- func (n *Node[K, V, A]) insertAt(index int, item K, value V, nd *Node[K, V, A]) {
- if index < int(n.count) {
- copy(n.keys[index+1:n.count+1], n.keys[index:n.count])
- copy(n.values[index+1:n.count+1], n.values[index:n.count])
- if !n.IsLeaf() {
- copy(n.children[index+2:n.count+2], n.children[index+1:n.count+1])
- }
- }
- n.keys[index] = item
- n.values[index] = value
- if !n.IsLeaf() {
- n.children[index+1] = nd
- }
- n.count++
- }
- func (n *Node[K, V, A]) pushBack(item K, value V, nd *Node[K, V, A]) {
- n.keys[n.count] = item
- n.values[n.count] = value
- if !n.IsLeaf() {
- n.children[n.count+1] = nd
- }
- n.count++
- }
- func (n *Node[K, V, A]) pushFront(item K, value V, nd *Node[K, V, A]) {
- if !n.IsLeaf() {
- copy(n.children[1:n.count+2], n.children[:n.count+1])
- n.children[0] = nd
- }
- copy(n.keys[1:n.count+1], n.keys[:n.count])
- copy(n.values[1:n.count+1], n.values[:n.count])
- n.keys[0] = item
- n.values[0] = value
- n.count++
- }
- // removeAt removes a value at a given index, pulling all subsequent values
- // back.
- func (n *Node[K, V, A]) removeAt(index int) (K, V, *Node[K, V, A]) {
- var child *Node[K, V, A]
- if !n.IsLeaf() {
- child = n.children[index+1]
- copy(n.children[index+1:n.count], n.children[index+2:n.count+1])
- n.children[n.count] = nil
- }
- n.count--
- outK := n.keys[index]
- outV := n.values[index]
- copy(n.keys[index:n.count], n.keys[index+1:n.count+1])
- copy(n.values[index:n.count], n.values[index+1:n.count+1])
- var rk K
- var rv V
- n.keys[n.count] = rk
- n.values[n.count] = rv
- return outK, outV, child
- }
- // popBack removes and returns the last element in the list.
- func (n *Node[K, V, A]) popBack() (K, V, *Node[K, V, A]) {
- n.count--
- outK := n.keys[n.count]
- outV := n.values[n.count]
- var rK K
- var rV V
- n.keys[n.count] = rK
- n.values[n.count] = rV
- if n.IsLeaf() {
- return outK, outV, nil
- }
- child := n.children[n.count+1]
- n.children[n.count+1] = nil
- return outK, outV, child
- }
- // popFront removes and returns the first element in the list.
- func (n *Node[K, V, A]) popFront() (K, V, *Node[K, V, A]) {
- n.count--
- var child *Node[K, V, A]
- if !n.IsLeaf() {
- child = n.children[0]
- copy(n.children[:n.count+1], n.children[1:n.count+2])
- n.children[n.count+1] = nil
- }
- outK := n.keys[0]
- outV := n.values[0]
- copy(n.keys[:n.count], n.keys[1:n.count+1])
- copy(n.values[:n.count], n.values[1:n.count+1])
- var rK K
- var rV V
- n.keys[n.count] = rK
- n.values[n.count] = rV
- return outK, outV, child
- }
- // find returns the index where the given item should be inserted into this
- // list. 'found' is true if the item already exists in the list at the given
- // index.
- func (n *Node[K, V, A]) find(cmp func(K, K) int, item K) (index int, found bool) {
- // Logic copied from sort.Search. Inlining this gave
- // an 11% speedup on BenchmarkBTreeDeleteInsert.
- i, j := 0, int(n.count)
- for i < j {
- h := int(uint(i+j) >> 1) // avoid overflow when computing h
- // i ≤ h < j
- c := cmp(item, n.keys[h])
- if c < 0 {
- j = h
- } else if c > 0 {
- i = h + 1
- } else {
- return h, true
- }
- }
- return i, false
- }
- // split splits the given node at the given index. The current node shrinks,
- // and this function returns the item that existed at that index and a new
- // node containing all keys/children after it.
- //
- // Before:
- //
- // +-----------+
- // | x y z |
- // +--/-/-\-\--+
- //
- // After:
- //
- // +-----------+
- // | y |
- // +----/-\----+
- // / \
- // v v
- // +-----------+ +-----------+
- // | x | | z |
- // +-----------+ +-----------+
- //
- func (n *Node[K, V, A]) split(cfg *config[K, V, A], i int) (K, V, *Node[K, V, A]) {
- outK := n.keys[i]
- outV := n.values[i]
- var next *Node[K, V, A]
- if n.IsLeaf() {
- next = cfg.np.getLeafNode()
- } else {
- next = cfg.np.getInteriorNode()
- }
- next.count = n.count - int16(i+1)
- copy(next.keys[:], n.keys[i+1:n.count])
- copy(next.values[:], n.values[i+1:n.count])
- var rK K
- var rV V
- for j := int16(i); j < n.count; j++ {
- n.keys[j] = rK
- n.values[j] = rV
- }
- if !n.IsLeaf() {
- copy(next.children[:], n.children[i+1:n.count+1])
- for j := int16(i + 1); j <= n.count; j++ {
- n.children[j] = nil
- }
- }
- n.count = int16(i)
- next.update(&cfg.Config)
- n.updateOn(&cfg.Config, Split, outK, next)
- return outK, outV, next
- }
- func (n *Node[K, V, A]) update(cfg *Config[K, V, A]) bool {
- return n.updateWithMeta(cfg, UpdateInfo[K, A]{})
- }
- func (n *Node[K, V, A]) updateWithMeta(cfg *Config[K, V, A], md UpdateInfo[K, A]) bool {
- if cfg.Updater == nil {
- return false
- }
- return cfg.Updater.Update(n, md)
- }
- func (n *Node[K, V, A]) updateOn(cfg *Config[K, V, A], action Action, k K, affected *Node[K, V, A]) bool {
- if cfg.Updater == nil {
- return false
- }
- var a *A
- if affected != nil {
- a = &affected.aug
- }
- return n.updateWithMeta(cfg, UpdateInfo[K, A]{
- Action: action,
- RelevantKey: k,
- ModifiedOther: a,
- })
- }
- // insert inserts an item into the suAugBTree rooted at this node, making sure no
- // nodes in the suAugBTree exceed MaxEntries keys. Returns true if an existing item
- // was replaced and false if an item was inserted. Also returns whether the
- // node's upper bound changes.
- func (n *Node[K, V, A]) insert(cfg *config[K, V, A], item K, value V) (replacedK K, replacedV V, replaced, newBound bool) {
- i, found := n.find(cfg.cmp, item)
- if found {
- replacedV = n.values[i]
- replacedK = n.keys[i]
- n.keys[i] = item
- n.values[i] = value
- return replacedK, replacedV, true, false
- }
- if n.IsLeaf() {
- n.insertAt(i, item, value, nil)
- return replacedK, replacedV, false, n.updateOn(&cfg.Config, Insertion, item, nil)
- }
- if n.children[i].count >= MaxEntries {
- splitLK, splitLV, splitNode := mut(cfg.np, &n.children[i]).
- split(cfg, MaxEntries/2)
- n.insertAt(i, splitLK, splitLV, splitNode)
- if c := cfg.cmp(item, n.keys[i]); c < 0 {
- // no change, we want first split node
- } else if c > 0 {
- i++ // we want second split node
- } else {
- // TODO(ajwerner): add something to the augmentation api to
- // deal with replacement.
- replacedV = n.values[i]
- replacedK = n.keys[i]
- n.keys[i] = item
- n.values[i] = value
- return replacedK, replacedV, true, false
- }
- }
- replacedK, replacedV, replaced, newBound =
- mut(cfg.np, &n.children[i]).insert(cfg, item, value)
- if newBound {
- newBound = n.updateOn(&cfg.Config, Insertion, item, nil)
- }
- return replacedK, replacedV, replaced, newBound
- }
- // removeMax removes and returns the maximum item from the suAugBTree rooted at
- // this node.
- func (n *Node[K, V, A]) removeMax(cfg *config[K, V, A]) (K, V) {
- if n.IsLeaf() {
- n.count--
- outK := n.keys[n.count]
- outV := n.values[n.count]
- var rK K
- var rV V
- n.keys[n.count] = rK
- n.values[n.count] = rV
- n.updateOn(&cfg.Config, Removal, outK, nil)
- return outK, outV
- }
- // Recurse into max child.
- i := int(n.count)
- if n.children[i].count <= MinEntries {
- // Child not large enough to remove from.
- n.rebalanceOrMerge(cfg, i)
- return n.removeMax(cfg) // redo
- }
- child := mut(cfg.np, &n.children[i])
- outK, outV := child.removeMax(cfg)
- n.updateOn(&cfg.Config, Removal, outK, nil)
- return outK, outV
- }
- // rebalanceOrMerge grows child 'i' to ensure it has sufficient room to remove
- // an item from it while keeping it at or above MinItems.
- func (n *Node[K, V, A]) rebalanceOrMerge(
- cfg *config[K, V, A], i int,
- ) {
- switch {
- case i > 0 && n.children[i-1].count > MinEntries:
- // Rebalance from left sibling.
- //
- // +-----------+
- // | y |
- // +----/-\----+
- // / \
- // v v
- // +-----------+ +-----------+
- // | x | | |
- // +----------\+ +-----------+
- // \
- // v
- // a
- //
- // After:
- //
- // +-----------+
- // | x |
- // +----/-\----+
- // / \
- // v v
- // +-----------+ +-----------+
- // | | | y |
- // +-----------+ +/----------+
- // /
- // v
- // a
- //
- left := mut(cfg.np, &n.children[i-1])
- child := mut(cfg.np, &n.children[i])
- xLaK, xLaV, grandChild := left.popBack()
- yLaK, yLaV := n.keys[i-1], n.values[i-1]
- child.pushFront(yLaK, yLaV, grandChild)
- n.keys[i-1], n.values[i-1] = xLaK, xLaV
- left.updateOn(&cfg.Config, Removal, xLaK, grandChild)
- child.updateOn(&cfg.Config, Insertion, yLaK, grandChild)
- case i < int(n.count) && n.children[i+1].count > MinEntries:
- // Rebalance from right sibling.
- //
- // +-----------+
- // | y |
- // +----/-\----+
- // / \
- // v v
- // +-----------+ +-----------+
- // | | | x |
- // +-----------+ +/----------+
- // /
- // v
- // a
- //
- // After:
- //
- // +-----------+
- // | x |
- // +----/-\----+
- // / \
- // v v
- // +-----------+ +-----------+
- // | y | | |
- // +----------\+ +-----------+
- // \
- // v
- // a
- //
- right := mut(cfg.np, &n.children[i+1])
- child := mut(cfg.np, &n.children[i])
- xLaK, xLaV, grandChild := right.popFront()
- yLaK, yLaV := n.keys[i], n.values[i]
- child.pushBack(yLaK, yLaV, grandChild)
- n.keys[i], n.values[i] = xLaK, xLaV
- right.updateOn(&cfg.Config, Removal, xLaK, grandChild)
- child.updateOn(&cfg.Config, Insertion, yLaK, grandChild)
- default:
- // Merge with either the left or right sibling.
- //
- // +-----------+
- // | u y v |
- // +----/-\----+
- // / \
- // v v
- // +-----------+ +-----------+
- // | x | | z |
- // +-----------+ +-----------+
- //
- // After:
- //
- // +-----------+
- // | u v |
- // +-----|-----+
- // |
- // v
- // +-----------+
- // | x y z |
- // +-----------+
- //
- if i >= int(n.count) {
- i = int(n.count - 1)
- }
- child := mut(cfg.np, &n.children[i])
- // Make mergeChild mutable, bumping the refcounts on its children if necessary.
- _ = mut(cfg.np, &n.children[i+1])
- mergeLaK, mergeLaV, mergeChild := n.removeAt(i)
- child.keys[child.count] = mergeLaK
- child.values[child.count] = mergeLaV
- copy(child.keys[child.count+1:], mergeChild.keys[:mergeChild.count])
- copy(child.values[child.count+1:], mergeChild.values[:mergeChild.count])
- if !child.IsLeaf() {
- copy(child.children[child.count+1:], mergeChild.children[:mergeChild.count+1])
- }
- child.count += mergeChild.count + 1
- child.updateOn(&cfg.Config, Insertion, mergeLaK, mergeChild)
- mergeChild.decRef(cfg.np, false /* recursive */)
- }
- }
- // remove removes an item from the suAugBTree rooted at this node. Returns the item
- // that was removed or nil if no matching item was found. Also returns whether
- // the node's upper bound changes.
- func (n *Node[K, V, A]) remove(
- cfg *config[K, V, A], item K,
- ) (outK K, outV V, found, newBound bool) {
- i, found := n.find(cfg.cmp, item)
- if n.IsLeaf() {
- if found {
- outK, outV, _ = n.removeAt(i)
- return outK, outV, true, n.updateOn(&cfg.Config, Removal, outK, nil)
- }
- var rK K
- var rV V
- return rK, rV, false, false
- }
- if n.children[i].count <= MinEntries {
- // Child not large enough to remove from.
- n.rebalanceOrMerge(cfg, i)
- return n.remove(cfg, item) // redo
- }
- child := mut(cfg.np, &n.children[i])
- if found {
- // Replace the item being removed with the max item in our left child.
- outK = n.keys[i]
- outV = n.values[i]
- n.keys[i], n.values[i] = child.removeMax(cfg)
- return outK, outV, true, n.updateOn(&cfg.Config, Removal, outK, nil)
- }
- // Latch is not in this node and child is large enough to remove from.
- outK, outV, found, newBound = child.remove(cfg, item)
- if newBound {
- newBound = n.updateOn(&cfg.Config, Removal, outK, nil)
- }
- return outK, outV, found, newBound
- }
- func (n *Node[K, V, A]) writeString(b *strings.Builder) {
- if n.IsLeaf() {
- for i := int16(0); i < n.count; i++ {
- if i != 0 {
- b.WriteString(",")
- }
- fmt.Fprintf(b, "%v:%v", n.keys[i], n.values[i])
- }
- return
- }
- for i := int16(0); i <= n.count; i++ {
- b.WriteString("(")
- n.children[i].writeString(b)
- b.WriteString(")")
- if i < n.count {
- fmt.Fprintf(b, "%v:%v", n.keys[i], n.values[i])
- }
- }
- }
|