rebalance attempts to combine the node with sibling nodes if the node fill size is below a threshold or if there are not enough keys.
()
| 363 | // rebalance attempts to combine the node with sibling nodes if the node fill |
| 364 | // size is below a threshold or if there are not enough keys. |
| 365 | func (n *node) rebalance() { |
| 366 | if !n.unbalanced { |
| 367 | return |
| 368 | } |
| 369 | n.unbalanced = false |
| 370 | |
| 371 | // Update statistics. |
| 372 | n.bucket.tx.stats.IncRebalance(1) |
| 373 | |
| 374 | // Ignore if node is above threshold (25% when FillPercent is set to DefaultFillPercent) and has enough keys. |
| 375 | var threshold = int(float64(n.bucket.tx.db.pageSize)*n.bucket.FillPercent) / 2 |
| 376 | if n.size() > threshold && len(n.inodes) > n.minKeys() { |
| 377 | return |
| 378 | } |
| 379 | |
| 380 | // Root node has special handling. |
| 381 | if n.parent == nil { |
| 382 | // If root node is a branch and only has one node then collapse it. |
| 383 | if !n.isLeaf && len(n.inodes) == 1 { |
| 384 | // Move root's child up. |
| 385 | child := n.bucket.node(n.inodes[0].Pgid(), n) |
| 386 | n.isLeaf = child.isLeaf |
| 387 | n.inodes = child.inodes[:] |
| 388 | n.children = child.children |
| 389 | |
| 390 | // Reparent all child nodes being moved. |
| 391 | for _, inode := range n.inodes { |
| 392 | if child, ok := n.bucket.nodes[inode.Pgid()]; ok { |
| 393 | child.parent = n |
| 394 | } |
| 395 | } |
| 396 | |
| 397 | // Remove old child. |
| 398 | child.parent = nil |
| 399 | delete(n.bucket.nodes, child.pgid) |
| 400 | child.free() |
| 401 | } |
| 402 | |
| 403 | return |
| 404 | } |
| 405 | |
| 406 | // If node has no keys then just remove it. |
| 407 | if n.numChildren() == 0 { |
| 408 | n.parent.del(n.key) |
| 409 | n.parent.removeChild(n) |
| 410 | delete(n.bucket.nodes, n.pgid) |
| 411 | n.free() |
| 412 | n.parent.rebalance() |
| 413 | return |
| 414 | } |
| 415 | |
| 416 | common.Assert(n.parent.numChildren() > 1, "parent must have at least 2 children") |
| 417 | |
| 418 | // Merge with right sibling if idx == 0, otherwise left sibling. |
| 419 | var leftNode, rightNode *node |
| 420 | var useNextSibling = n.parent.childIndex(n) == 0 |
| 421 | if useNextSibling { |
| 422 | leftNode = n |
no test coverage detected