       page.balancers++
 
   last: -> @queue[@queue.length - 1]
+
   # Increment or decrement the difference of the page since the last balance.
   difference: (page, difference) ->
     if not @differences[page.address]?

    @io         = @strata._io
    @options    = @strata._io.options

    @parent     = { operations: [], locks: [] }
    @child      = { operations: [], locks: [] }
    @exclusive  = []
    @shared     = []
    @pivots     = []
    @stack      = []

    { @extractor, @comparator } = @options

    @key        = @extractor @object if @object? and not @key?

  # Going forward, every will story keys, so that when we encounter a record, we
  # don't have to run the extractor, plus we get some caching.
  #
  # Or maybe just three arrays, key, object and address? I'm talking about using
  # each key as an object cache, by adding an object member to the key. But,
  # they cache container is a hash table, which is a compactish representation,
  # so why not make it yet anohter hash table? The logic gets a lot easier.
  #
  # TODO None of this is right.
  record: (page, index, _) ->
    position = page.positions[index]
    if not record = page.cache[position]
      record = page.cache[position] = @readRecord page, position, _
    record
  
  # Descend the tree, optionally starting an exclusive descent. Once the descent
  # is exclusive, all subsequent descents are exclusive.

  # `mutation.descend(exclusive)` 
  _descend: (exclusive) ->
    # Add a new level to the plan.
    @plan.unshift { operations: [], addresses: [] }

    # Two or more exclusive levels mean that the parent is exclusive.
    if @exclusive.length < 1
      @strata._release @parent

    # Any items in the exclusive level array means we are now locking exclusive.
    exclusive or= @exclusive.length > 0

    # Make child a parent.
    @parent = @child
    @child = { operations: [], locks: [], exclusive }

    # Add the new child to the list of exclusive levels.
    if exclusive
      @exclusive.push(@child)

  # Aching to get rid of duplicates. We need to support them here, when
  # searching for a leaf page partition at split, and when determining whether
  # to split a leaf page.
  #
  # This will rewind to the place before the key.

  #
  first: (page, index, key, _) ->
    while index != 0 && comparator(key, io.key(page, index - 1, _)) == 0
      index--

  hasKey: (tier, _) ->
    for key in @operation.keys or []
      branch = @find(tier, key, _)
      if tier.cache[branch] is key
        return true
    false

  # TODO: We are always allowed to get a shared lock on any leaf page and read a
  # value, as long as we let go of it immediately. This allows us to read from
  # leaf pages to get branch values.

  descend: (_) ->
    parent = null

    @shared.push child = @io.lock 0, false, false, _
    if @operation.keys and (child.addresses.length is 1 or @hasKey(child, _))
      @exclusive.push @io.upgrade @shared.pop(), _

    # TODO: Flag for go left.
    while not child.penultimate or child.address is @soughtAddress
      process.exit 1

    # TODO: Flag for shared or exclusive. If exclusive, leave parent locked, if
    # shared, then unlock parent.

    descent = @[@operation.method].call this, parent, child, _

    @io.unlock page for page in @shared
    @io.unlock page for page in @exclusive

    descent.descend _ if descent

  cursor: (exclusive, _) ->
    @shared.push page = @io.lock 0, false, false, _


    cursor

  get: (parent, child, _) ->
    branch = @find child, @key, _
    @shared.push leaves = @io.lock child.addresses[branch], false, true, _
    address = @find leaves, @key, _
    leaves.cache[leaves.addresses[address]]


  mergeLeaf: (parent, child, _) ->
    [ key, rightKey ] = @operation.keys
    compare = @comparator(full, leftKey = @io.key(child, 0, _))
    if compare is 0
      return if leftKey isnt key
class exports.Strata
  # Construct the Strata from the options.
  constructor: (options) ->
