   constructor: (@exclusive) ->
     @operations = []
     @locks = []
-  lock: (strata, mutation, tier, callback) ->
-    locks = (strata.locks[tier.address] or= [ [] ])
-    if @exclusive
-      throw new Error "already locked" if @locks.length
-      lock = [ callback, strata, mutation ]
-      lock.address = tier.address
-      @locks.push lock
-      locks.push [ lock ]
-      locks.push []
-      if locks[0].length is 0
-        locks.shift()
-        callback.call strata, mutation
-    else
-      lock = [ callback, strata, mutation ]
-      lock.address = tier.address
-      @locks.push lock
-      locks[locks.length - 1].push lock
-      if locks.length is 1
-        callback.call strata, mutation
+  lock: (strata, mutation, address, callback) ->
+    # TODO Will it matter if we load before we lock? We probably have to.
+    strata.io.load strata, mutation, address, (mutation, tier) =>
+      locks = (strata.locks[tier.address] or= [ [] ])
+      if @exclusive
+        throw new Error "already locked" if @locks.length
+        lock = [ callback, strata, mutation, tier ]
+        lock.address = tier.address
+        @locks.push lock
+        locks.push [ lock ]
+        locks.push []
+        if locks[0].length is 0
+          locks.shift()
+          callback.call strata, mutation, tier
+      else
+        lock = [ callback, strata, mutation, tier ]
+        lock.address = tier.address
+        @locks.push lock
+        locks[locks.length - 1].push lock
+        if locks.length is 1
+          callback.call strata, mutation, tier
 
   # Remove the lock callback from the callback list..
   release: (strata) ->

        low--
      return low
    return low - 1
    
  _testInnerTier: (mutation, decision, leaveExclusive, next) ->
    tiers = decision.call @, mutation
    keys = mutation.decisions.swap.call @, mutation
    if tiers or keys
      if not (mutation.parentLevel.exclusive and mutation.childLevel.exclusive)
        mutation.parentLevel.upgrade mutation.childLevel, =>
          mutation.parentLevel.operations.clear()
          mutation.childLevel.operations.clear()
          @_testInnerTier mutation, leaveExclusive, next
      else if not tiers
        mutation.rewind leaveExclusive
        next.call @, mutation
      else
        next.call @, mutation
    else
      @_rewind mutation, leaveExclusive
      next.call @, mutation

  _rewind: (mutation, leaveExclusive) ->
    count = mutation.levels.length - leaveExclusive
    if count > 0
      unlock = true
      index = 0
      for ignored in  [0...count]
        level = mutation.levels[index]
        level.operations = level.operations.filter (operation) ->
          not operation.isSplitOrMerge
        unlock = unlock or level.operations.length is 0
        if unlock
          if mutation.levels.length <= 3
            level.downgrade(@)
            index++
          else
            level.release()
            levels.splice(index, 1)
        else
          index++

  # If the root is full, we add a root split operation to the operation stack.
  _shouldDrainRoot: (mutation) ->
    if @innerSize is mutation.parentLevel.tier.size()
      mutation.parentLevel.operations.add @_splitRoot
      true
    else
      false

  # Shorthand to allocate a new inner tier.
  _newInnerTier: (mutation, penultimate) ->

  #
  # This generalized mutation will insert or remove a single item.
  _generalized: (mutation) ->
    mutation.levels.unshift new Level
    mutation.levels[0].lock @, mutation, @rootAddress, @_rootLoaded

  # Perform the root decision with only a read lock obtained.
  _rootLoaded: (mutation, root) ->
    mutation.levels[0].tier = root
    mutation.decisions.initial.call @, mutation
    @_tierDecision mutation

  # Determine if we need to lock a tier. We have different criteria for inner
  # tiers with inner tier children then for penultimate inner tiers with leaf
  # tier children.
  _tierDecision: (mutation) ->
    if mutation.level[0].tier.penultimate
      @_testInnerTier mutation, mutation.decisions.penultimate, @_operate
    else
      @_testInnerTier mutation, mutation.decisions.subsequent, @_tierDescend

  # Perform decisions related to the inner tier.
  _testInnerTier: (mutation, decision, next) ->
    mutation.decisions.swap.call @, mutation
    if not decision.call @, mutation
      for level in mutation.levels
        level.operations = level.operations.filter (operation) ->
          operation isnt "swap"
    next.call @, mutation

  _tierDescend: (mutation) ->
    branch = @_find(mutation.parentLevel.tier, mutation.sought)
    @io.load mutation.parent, branch, (child) =>
      mutation.parent = child
      mutation.parentLevel = mutation.childLevel
      mutation.childLevel = new Level()
      mutation.levels.push mutation.childLevel
      @_tierDecision mutation

  # When `_operate` is invoked, all the necessary locks have been obtained and
  # we are able to mutate the tree with impunity.
