spill writes the nodes to dirty pages and splits nodes as it goes. Returns an error if dirty pages cannot be allocated.
()
| 293 | // spill writes the nodes to dirty pages and splits nodes as it goes. |
| 294 | // Returns an error if dirty pages cannot be allocated. |
| 295 | func (n *node) spill() error { |
| 296 | var tx = n.bucket.tx |
| 297 | if n.spilled { |
| 298 | return nil |
| 299 | } |
| 300 | |
| 301 | // Spill child nodes first. Child nodes can materialize sibling nodes in |
| 302 | // the case of split-merge so we cannot use a range loop. We have to check |
| 303 | // the children size on every loop iteration. |
| 304 | sort.Sort(n.children) |
| 305 | for i := 0; i < len(n.children); i++ { |
| 306 | if err := n.children[i].spill(); err != nil { |
| 307 | return err |
| 308 | } |
| 309 | } |
| 310 | |
| 311 | // We no longer need the child list because it's only used for spill tracking. |
| 312 | n.children = nil |
| 313 | |
| 314 | // Split nodes into appropriate sizes. The first node will always be n. |
| 315 | var nodes = n.split(uintptr(tx.db.pageSize)) |
| 316 | for _, node := range nodes { |
| 317 | // Add node's page to the freelist if it's not new. |
| 318 | if node.pgid > 0 { |
| 319 | tx.db.freelist.Free(tx.meta.Txid(), tx.page(node.pgid)) |
| 320 | node.pgid = 0 |
| 321 | } |
| 322 | |
| 323 | // Allocate contiguous space for the node. |
| 324 | p, err := tx.allocate((node.size() + tx.db.pageSize - 1) / tx.db.pageSize) |
| 325 | if err != nil { |
| 326 | return err |
| 327 | } |
| 328 | |
| 329 | // Write the node. |
| 330 | if p.Id() >= tx.meta.Pgid() { |
| 331 | panic(fmt.Sprintf("pgid (%d) above high water mark (%d)", p.Id(), tx.meta.Pgid())) |
| 332 | } |
| 333 | node.pgid = p.Id() |
| 334 | node.write(p) |
| 335 | node.spilled = true |
| 336 | |
| 337 | // Insert into parent inodes. |
| 338 | if node.parent != nil { |
| 339 | var key = node.key |
| 340 | if key == nil { |
| 341 | key = node.inodes[0].Key() |
| 342 | } |
| 343 | |
| 344 | node.parent.put(key, node.inodes[0].Key(), nil, node.pgid, 0) |
| 345 | node.key = node.inodes[0].Key() |
| 346 | common.Assert(len(node.key) > 0, "spill: zero-length node key") |
| 347 | } |
| 348 | |
| 349 | // Update the statistics. |
| 350 | tx.stats.IncSpill(1) |
| 351 | } |
| 352 |