public void onFailure(
     FetchException e, Object token, ObjectContainer container, ClientContext context) {
   if (persistent) {
     container.activate(segment, 1);
     container.activate(parent, 1);
     container.activate(segment.errors, 1);
   }
   boolean forceFatal = false;
   if (parent.isCancelled()) {
     if (logMINOR) Logger.minor(this, "Failing: cancelled");
     e = new FetchException(FetchException.CANCELLED);
     forceFatal = true;
   }
   segment.errors.inc(e.getMode());
   if (persistent) segment.errors.storeTo(container);
   if (e.isFatal() && token == null) {
     segment.fail(e, container, context, false);
   } else if (e.isFatal() || forceFatal) {
     segment.onFatalFailure(
         e, ((SplitFileFetcherSegmentSendableRequestItem) token).blockNum, container, context);
   } else {
     segment.onNonFatalFailure(
         e, ((SplitFileFetcherSegmentSendableRequestItem) token).blockNum, container, context);
   }
   if (persistent) {
     container.deactivate(segment, 1);
     container.deactivate(parent, 1);
     container.deactivate(segment.errors, 1);
   }
 }
 // Real onFailure
 protected void onFailure(
     FetchException e, Object token, ObjectContainer container, ClientContext context) {
   if (persistent) {
     container.activate(segment, 1);
     container.activate(parent, 1);
     container.activate(segment.errors, 1);
   }
   boolean forceFatal = false;
   if (parent.isCancelled()) {
     if (Logger.shouldLog(Logger.MINOR, this)) Logger.minor(this, "Failing: cancelled");
     e = new FetchException(FetchException.CANCELLED);
     forceFatal = true;
   }
   segment.errors.inc(e.getMode());
   if (e.isFatal() && token == null) {
     segment.fail(e, container, context, false);
   } else if (e.isFatal() || forceFatal) {
     segment.onFatalFailure(e, ((MySendableRequestItem) token).x, this, container, context);
   } else {
     segment.onNonFatalFailure(e, ((MySendableRequestItem) token).x, this, container, context);
   }
   removeBlockNum(((MySendableRequestItem) token).x, container, false);
   if (persistent) {
     container.deactivate(segment, 1);
     container.deactivate(parent, 1);
     container.deactivate(segment.errors, 1);
   }
 }
 @Override
 public ClientKey getKey(Object token, ObjectContainer container) {
   if (persistent) {
     container.activate(this, 1);
     container.activate(segment, 1);
   }
   synchronized (segment) {
     if (cancelled) {
       if (logMINOR)
         Logger.minor(this, "Segment is finishing when getting key " + token + " on " + this);
       return null;
     }
     ClientKey key = segment.getBlockKey(((MySendableRequestItem) token).x, container);
     if (key == null) {
       if (segment.isFinished(container)) {
         Logger.error(this, "Segment finished but didn't tell us! " + this);
       } else if (segment.isFinishing(container)) {
         Logger.error(this, "Segment finishing but didn't tell us! " + this);
       } else {
         Logger.error(
             this,
             "Segment not finishing yet still returns null for getKey()!: "
                 + token
                 + " for "
                 + this,
             new Exception("debug"));
       }
     }
     return key;
   }
 }
  public void onFailure(
      BulkCallFailureItem[] items, ObjectContainer container, ClientContext context) {
    FetchException[] fetchExceptions = new FetchException[items.length];
    int countFatal = 0;
    if (persistent) {
      container.activate(blockNums, 2);
    }
    for (int i = 0; i < items.length; i++) {
      fetchExceptions[i] = translateException(items[i].e);
      if (fetchExceptions[i].isFatal()) countFatal++;
      removeBlockNum(((MySendableRequestItem) items[i].token).x, container, true);
    }
    if (persistent) {
      container.store(blockNums);
      container.deactivate(blockNums, 2);
      container.activate(segment, 1);
      container.activate(parent, 1);
      container.activate(segment.errors, 1);
    }
    if (parent.isCancelled()) {
      if (Logger.shouldLog(Logger.MINOR, this)) Logger.minor(this, "Failing: cancelled");
      // Fail the segment.
      segment.fail(new FetchException(FetchException.CANCELLED), container, context, false);
      // FIXME do we need to free the keyNum's??? Or will that happen later anyway?
      return;
    }
    for (int i = 0; i < fetchExceptions.length; i++)
      segment.errors.inc(fetchExceptions[i].getMode());
    int nonFatalExceptions = items.length - countFatal;
    int[] blockNumbers = new int[nonFatalExceptions];
    if (countFatal > 0) {
      FetchException[] newFetchExceptions = new FetchException[items.length - countFatal];
      // Call the fatal callbacks directly.
      int x = 0;
      for (int i = 0; i < items.length; i++) {
        int blockNum = ((MySendableRequestItem) items[i].token).x;
        if (fetchExceptions[i].isFatal()) {
          segment.onFatalFailure(fetchExceptions[i], blockNum, this, container, context);
        } else {
          blockNumbers[x] = blockNum;
          newFetchExceptions[x] = fetchExceptions[i];
          x++;
        }
      }
      fetchExceptions = newFetchExceptions;
    } else {
      for (int i = 0; i < blockNumbers.length; i++)
        blockNumbers[i] = ((MySendableRequestItem) items[i].token).x;
    }
    segment.onNonFatalFailure(fetchExceptions, blockNumbers, this, container, context);

    if (persistent) {
      container.deactivate(segment, 1);
      container.deactivate(parent, 1);
      container.deactivate(segment.errors, 1);
    }
  }
 @Override
 public boolean hasValidKeys(
     KeysFetchingLocally keys, ObjectContainer container, ClientContext context) {
   if (persistent) {
     container.activate(this, 1);
     container.activate(blockNums, 1);
     container.activate(segment, 1);
   }
   boolean hasSet = false;
   boolean retval = false;
   synchronized (segment) {
     for (int i = 0; i < 10; i++) {
       Integer ret;
       int x;
       if (blockNums.isEmpty()) {
         break;
       }
       x = context.random.nextInt(blockNums.size());
       ret = blockNums.get(x);
       int block = ret;
       Key key = segment.getBlockNodeKey(block, container);
       if (key == null) {
         if (segment.isFinishing(container) || segment.isFinished(container)) return false;
         if (segment.haveBlock(block, container))
           Logger.error(
               this,
               "Already have block "
                   + ret
                   + " but was in blockNums on "
                   + this
                   + " in hasValidKeys");
         else
           Logger.error(
               this, "Key is null for block " + ret + " for " + this + " in hasValidKeys");
         blockNums.remove(x);
         if (persistent) {
           container.delete(ret);
           if (!hasSet) {
             hasSet = true;
             container.store(blockNums);
           }
         }
         continue;
       }
       if (keys.hasKey(key)) {
         continue;
       }
       retval = true;
       break;
     }
   }
   if (persistent) {
     container.deactivate(blockNums, 5);
     container.deactivate(segment, 1);
   }
   return retval;
 }
 @Override
 public long getCooldownWakeup(Object token, ObjectContainer container, ClientContext context) {
   if (persistent) container.activate(segment, 1);
   return segment.getCooldownWakeup(
       ((SplitFileFetcherSegmentSendableRequestItem) token).blockNum,
       segment.getMaxRetries(container),
       container,
       context);
 }
  public void onGotKey(Key key, KeyBlock block, ObjectContainer container, ClientContext context) {
    if (persistent) {
      container.activate(this, 1);
      container.activate(segment, 1);
      container.activate(blockNums, 1);
    }
    if (logMINOR) Logger.minor(this, "onGotKey(" + key + ")");
    // Find and remove block if it is on this subsegment. However it may have been
    // removed already.
    int blockNo;
    synchronized (segment) {
      for (int i = 0; i < blockNums.size(); i++) {
        Integer token = blockNums.get(i);
        int num = token;
        Key k = segment.getBlockNodeKey(num, container);
        if (k != null && k.equals(key)) {
          blockNums.remove(i);
          if (persistent) container.delete(token);
          break;
        }
      }
      blockNo = segment.getBlockNumber(key, container);
    }
    if (blockNo == -1) {
      Logger.minor(this, "No block found for key " + key + " on " + this);
      return;
    }
    Integer token = Integer.valueOf(blockNo);
    ClientCHK ckey = segment.getBlockKey(blockNo, container);
    ClientCHKBlock cb;
    try {
      cb = new ClientCHKBlock((CHKBlock) block, ckey);
    } catch (CHKVerifyException e) {
      onFailure(
          new FetchException(FetchException.BLOCK_DECODE_ERROR, e), token, container, context);
      return;
    }
    Bucket data = extract(cb, token, container, context);
    if (data == null) return;

    if (!cb.isMetadata()) {
      onSuccess(data, false, token, (token).intValue(), cb, container, context);
    } else {
      onFailure(
          new FetchException(FetchException.INVALID_METADATA, "Metadata where expected data"),
          token,
          container,
          context);
    }
  }
 @Override
 public ClientKey getKey(Object token, ObjectContainer container) {
   SplitFileFetcherSegmentSendableRequestItem req =
       (SplitFileFetcherSegmentSendableRequestItem) token;
   if (persistent) container.activate(segment, 1);
   return segment.getBlockKey(req.blockNum, container);
 }
 private SendableRequestItem getRandomBlockNum(
     KeysFetchingLocally keys, ClientContext context, ObjectContainer container) {
   if (persistent) {
     container.activate(this, 1);
     container.activate(blockNums, 1);
     container.activate(segment, 1);
   }
   logMINOR = Logger.shouldLog(Logger.MINOR, this);
   synchronized (segment) {
     if (blockNums.isEmpty()) {
       if (logMINOR) Logger.minor(this, "No blocks to remove");
       return null;
     }
     for (int i = 0; i < 10; i++) {
       Integer ret;
       int x;
       if (blockNums.size() == 0) return null;
       x = context.random.nextInt(blockNums.size());
       ret = blockNums.get(x);
       int num = ret;
       Key key = segment.getBlockNodeKey(num, container);
       if (key == null) {
         if (segment.isFinishing(container) || segment.isFinished(container)) return null;
         if (segment.haveBlock(num, container))
           Logger.error(this, "Already have block " + ret + " but was in blockNums on " + this);
         else Logger.error(this, "Key is null for block " + ret + " for " + this);
         continue;
       }
       if (keys.hasKey(key)) {
         continue;
       }
       if (logMINOR)
         Logger.minor(
             this,
             "Removing block "
                 + x
                 + " of "
                 + (blockNums.size() + 1)
                 + " : "
                 + ret
                 + " on "
                 + this);
       return new MySendableRequestItem(num);
     }
     return null;
   }
 }
 @Override
 public void requeueAfterCooldown(
     Key key, long time, ObjectContainer container, ClientContext context) {
   if (persistent) container.activate(segment, 1);
   int blockNum = segment.getBlockNumber(key, container);
   if (blockNum == -1) return;
   reschedule(container, context);
 }
 @Override
 public SendableRequestItem chooseKey(
     KeysFetchingLocally keys, ObjectContainer container, ClientContext context) {
   if (persistent) container.activate(segment, 1);
   ArrayList<Integer> possibles = segment.validBlockNumbers(keys, true, container, context);
   if (possibles == null || possibles.isEmpty()) return null;
   return new SplitFileFetcherSegmentSendableRequestItem(
       possibles.get(context.random.nextInt(possibles.size())));
 }
 @Override
 public long getCooldownWakeup(Object token, ObjectContainer container) {
   if (persistent) {
     container.activate(this, 1);
     container.activate(segment, 1);
   }
   long ret = segment.getCooldownWakeup(((MySendableRequestItem) token).x);
   return ret;
 }
 public long getCooldownTime(ObjectContainer container, ClientContext context, long now) {
   if (persistent) container.activate(segment, 1);
   HasCooldownCacheItem parentRGA = getParentGrabArray();
   long wakeTime = segment.getCooldownTime(container, context, parentRGA, now);
   if (wakeTime > 0)
     context.cooldownTracker.setCachedWakeup(
         wakeTime, this, parentRGA, persistent, container, context, true);
   return wakeTime;
 }
 @Override
 public void resetCooldownTimes(ObjectContainer container) {
   if (persistent) {
     container.activate(this, 1);
     container.activate(segment, 1);
   }
   synchronized (segment) {
     segment.resetCooldownTimes(blockNums.toArray(new Integer[blockNums.size()]));
   }
 }
 @Override
 public Key[] listKeys(ObjectContainer container) {
   boolean activated = false;
   if (persistent) {
     activated = container.ext().isActive(segment);
     if (!activated) container.activate(segment, 1);
   }
   Key[] keys = segment.listKeys(container);
   if (persistent && !activated) container.deactivate(segment, 1);
   return keys;
 }
 /**
  * Fetch the array from the segment because we need to include *ALL* keys, especially those on
  * cooldown queues. This is important when unregistering.
  */
 @Override
 public long countAllKeys(ObjectContainer container, ClientContext context) {
   if (persistent) {
     container.activate(this, 1);
     container.activate(segment, 1);
   }
   // j16sdiz (22-DEC-2008):
   // ClientRequestSchedular.removePendingKeys() call this to get a list of request to be removed
   // FIXME ClientRequestSchedular.removePendingKeys() is leaking, what's missing here?
   return segment.getKeyNumbersAtRetryLevel(retryCount).length;
 }
 @Override
 public List<PersistentChosenBlock> makeBlocks(
     PersistentChosenRequest request,
     RequestScheduler sched,
     ObjectContainer container,
     ClientContext context) {
   if (persistent) container.activate(segment, 1);
   // FIXME why is the fetching keys list not passed in? We could at least check for other fetchers
   // for the same key??? Need to modify the parameters ...
   List<PersistentChosenBlock> blocks = segment.makeBlocks(request, sched, container, context);
   if (persistent) container.deactivate(segment, 1);
   return blocks;
 }
 @Override
 public long getCooldownWakeupByKey(Key key, ObjectContainer container, ClientContext context) {
   /* Only deactivate if was deactivated in the first place.
    * See the removePendingKey() stack trace: Segment is the listener (getter) ! */
   boolean activated = false;
   if (persistent) {
     activated = container.ext().isActive(segment);
     if (!activated) container.activate(segment, 1);
   }
   long ret = segment.getCooldownWakeupByKey(key, container, context);
   if (persistent) {
     if (!activated) container.deactivate(segment, 1);
   }
   return ret;
 }
 @Override
 public List<PersistentChosenBlock> makeBlocks(
     PersistentChosenRequest request,
     RequestScheduler sched,
     ObjectContainer container,
     ClientContext context) {
   if (persistent) {
     container.activate(segment, 1);
     container.activate(blockNums, 1);
   }
   Integer[] blockNumbers;
   synchronized (this) {
     blockNumbers = blockNums.toArray(new Integer[blockNums.size()]);
   }
   ArrayList<PersistentChosenBlock> blocks = new ArrayList<PersistentChosenBlock>();
   Arrays.sort(blockNumbers);
   int prevBlockNumber = -1;
   for (int i = 0; i < blockNumbers.length; i++) {
     int blockNumber = blockNumbers[i];
     if (blockNumber == prevBlockNumber) {
       Logger.error(
           this,
           "Duplicate block number in makeBlocks() in " + this + ": two copies of " + blockNumber);
       continue;
     }
     prevBlockNumber = blockNumber;
     ClientKey key = segment.getBlockKey(blockNumber, container);
     if (key == null) {
       if (logMINOR) Logger.minor(this, "Block " + blockNumber + " is null, maybe race condition");
       continue;
     }
     key = key.cloneKey();
     Key k = key.getNodeKey(true);
     PersistentChosenBlock block =
         new PersistentChosenBlock(
             false, request, new MySendableRequestItem(blockNumber), k, key, sched);
     if (logMINOR)
       Logger.minor(
           this, "Created block " + block + " for block number " + blockNumber + " on " + this);
     blocks.add(block);
   }
   blocks.trimToSize();
   if (persistent) {
     container.deactivate(segment, 1);
     container.deactivate(blockNums, 1);
   }
   return blocks;
 }
 protected void onSuccess(
     Bucket data,
     boolean fromStore,
     Integer token,
     int blockNo,
     ClientKeyBlock block,
     ObjectContainer container,
     ClientContext context) {
   if (persistent) {
     container.activate(this, 1);
     container.activate(segment, 1);
     container.activate(parent, 1);
   }
   if (parent.isCancelled()) {
     data.free();
     if (persistent) data.removeFrom(container);
     onFailure(new FetchException(FetchException.CANCELLED), token, container, context);
     return;
   }
   segment.onSuccess(data, blockNo, block, container, context, this);
 }
 /**
  * If there are no more blocks, cancel the SubSegment, remove it from the segment, and return
  * true; the caller must call kill(,,true,true). Else return false.
  *
  * @param container
  * @param context
  * @return
  */
 public boolean possiblyRemoveFromParent(ObjectContainer container, ClientContext context) {
   if (persistent) {
     container.activate(this, 1);
     container.activate(segment, 1);
     container.activate(blockNums, 1);
   }
   if (logMINOR) Logger.minor(this, "Possibly removing from parent: " + this);
   synchronized (segment) {
     if (!blockNums.isEmpty()) {
       if (persistent) container.deactivate(blockNums, 1);
       return false;
     }
     if (logMINOR) Logger.minor(this, "Definitely removing from parent: " + this);
     if (!segment.maybeRemoveSeg(this, container)) {
       if (persistent) container.deactivate(blockNums, 1);
       return false;
     }
     cancelled = true;
   }
   return true;
 }
 @Override
 public void requeueAfterCooldown(
     Key key, long time, ObjectContainer container, ClientContext context) {
   if (persistent) {
     container.activate(segment, 1);
   }
   if (cancelled) {
     if (Logger.shouldLog(Logger.MINOR, this))
       Logger.minor(this, "Not requeueing as already cancelled");
     return;
   }
   if (Logger.shouldLog(Logger.MINOR, this))
     Logger.minor(this, "Requeueing after cooldown " + key + " for " + this);
   if (!segment.requeueAfterCooldown(key, time, container, context, this)) {
     Logger.error(
         this,
         "Key was not wanted after cooldown: "
             + key
             + " for "
             + this
             + " in requeueAfterCooldown");
   }
   if (persistent) container.deactivate(segment, 1);
 }
 public boolean isEmpty(ObjectContainer container) {
   if (persistent) container.activate(segment, 1);
   return segment.isFinishing(container);
 }
 @Override
 public long countSendableKeys(ObjectContainer container, ClientContext context) {
   if (persistent) container.activate(segment, 1);
   return segment.countSendableKeys(container, context);
 }