@Override
 public void onSuccess(Object keyNum, ObjectContainer container, ClientContext context) {
   if (logMINOR) Logger.minor(this, "Succeeded (" + this + "): " + token);
   if (persistent) container.activate(parent, 1);
   if (parent.isCancelled()) {
     fail(new InsertException(InsertException.CANCELLED), container, context);
     return;
   }
   synchronized (this) {
     if (extraInserts > 0) {
       if (++completedInserts <= extraInserts) {
         if (logMINOR)
           Logger.minor(
               this,
               "Completed inserts "
                   + completedInserts
                   + " of extra inserts "
                   + extraInserts
                   + " on "
                   + this);
         if (persistent) container.store(this);
         return; // Let it repeat until we've done enough inserts. It hasn't been unregistered yet.
       }
     }
     if (finished) {
       // Normal with persistence.
       Logger.normal(this, "Block already completed: " + this);
       return;
     }
     finished = true;
   }
   if (persistent) {
     container.store(this);
     container.activate(sourceData, 1);
   }
   if (freeData) {
     sourceData.free();
     if (persistent) sourceData.removeFrom(container);
     sourceData = null;
     if (persistent) container.store(this);
   }
   parent.completedBlock(false, container, context);
   unregister(container, context, getPriorityClass(container));
   if (persistent) container.activate(cb, 1);
   if (logMINOR) Logger.minor(this, "Calling onSuccess for " + cb);
   cb.onSuccess(this, container, context);
   if (persistent) container.deactivate(cb, 1);
 }
 public void schedule(ObjectContainer container, ClientContext context) throws InsertException {
   synchronized (this) {
     if (finished) {
       if (logMINOR) Logger.minor(this, "Finished already: " + this);
       return;
     }
   }
   if (getCHKOnly) {
     boolean deactivateCB = false;
     if (persistent) {
       deactivateCB = !container.ext().isActive(cb);
       if (deactivateCB) container.activate(cb, 1);
       container.activate(parent, 1);
     }
     ClientKeyBlock block = encode(container, context, true);
     cb.onEncode(block.getClientKey(), this, container, context);
     parent.completedBlock(false, container, context);
     cb.onSuccess(this, container, context);
     finished = true;
     if (persistent) {
       container.store(this);
       if (deactivateCB) container.deactivate(cb, 1);
     }
   } else {
     getScheduler(context).registerInsert(this, persistent, true, container);
   }
 }
 /**
  * Create a SingleBlockInserter.
  *
  * @param parent
  * @param data
  * @param compressionCodec The compression codec.
  * @param uri
  * @param ctx
  * @param cb
  * @param isMetadata
  * @param sourceLength The length of the original, uncompressed data.
  * @param token
  * @param getCHKOnly
  * @param addToParent
  * @param dontSendEncoded
  * @param tokenObject
  * @param container
  * @param context
  * @param persistent
  * @param freeData
  */
 public SingleBlockInserter(
     BaseClientPutter parent,
     Bucket data,
     short compressionCodec,
     FreenetURI uri,
     InsertContext ctx,
     PutCompletionCallback cb,
     boolean isMetadata,
     int sourceLength,
     int token,
     boolean getCHKOnly,
     boolean addToParent,
     boolean dontSendEncoded,
     Object tokenObject,
     ObjectContainer container,
     ClientContext context,
     boolean persistent,
     boolean freeData,
     int extraInserts) {
   super(persistent);
   assert (persistent == parent.persistent());
   this.consecutiveRNFs = 0;
   this.tokenObject = tokenObject;
   this.token = token;
   this.parent = parent;
   this.dontSendEncoded = dontSendEncoded;
   this.retries = 0;
   this.finished = false;
   this.ctx = ctx;
   this.freeData = freeData;
   errors = new FailureCodeTracker(true);
   this.cb = cb;
   this.uri = uri;
   this.compressionCodec = compressionCodec;
   this.sourceData = data;
   if (sourceData == null) throw new NullPointerException();
   this.isMetadata = isMetadata;
   this.sourceLength = sourceLength;
   this.getCHKOnly = getCHKOnly;
   isSSK = uri.getKeyType().toUpperCase().equals("SSK");
   if (addToParent) {
     parent.addMustSucceedBlocks(1, container);
     parent.notifyClients(container, context);
   }
   this.extraInserts = extraInserts;
 }
 private void fail(
     InsertException e, boolean forceFatal, ObjectContainer container, ClientContext context) {
   synchronized (this) {
     if (finished) return;
     finished = true;
   }
   if (persistent) container.store(this);
   if (e.isFatal() || forceFatal) parent.fatallyFailedBlock(container, context);
   else parent.failedBlock(container, context);
   unregister(container, context, getPriorityClass(container));
   if (freeData) {
     if (persistent) container.activate(sourceData, 1);
     sourceData.free();
     if (persistent) sourceData.removeFrom(container);
     sourceData = null;
     if (persistent) container.store(this);
   }
   if (persistent) container.activate(cb, 1);
   cb.onFailure(e, this, container, context);
 }
 @Override
 public RequestClient getClient(ObjectContainer container) {
   if (persistent) container.activate(parent, 1);
   return parent.getClient();
 }
  @Override
  public void onFailure(
      LowLevelPutException e, Object keyNum, ObjectContainer container, ClientContext context) {
    synchronized (this) {
      if (finished) return;
    }
    if (persistent) container.activate(errors, 1);
    if (parent.isCancelled()) {
      fail(new InsertException(InsertException.CANCELLED), container, context);
      return;
    }
    if (logMINOR) Logger.minor(this, "onFailure() on " + e + " for " + this);

    switch (e.code) {
      case LowLevelPutException.COLLISION:
        fail(new InsertException(InsertException.COLLISION), container, context);
        return;
      case LowLevelPutException.INTERNAL_ERROR:
        fail(new InsertException(InsertException.INTERNAL_ERROR), container, context);
        return;
      case LowLevelPutException.REJECTED_OVERLOAD:
        errors.inc(InsertException.REJECTED_OVERLOAD);
        break;
      case LowLevelPutException.ROUTE_NOT_FOUND:
        errors.inc(InsertException.ROUTE_NOT_FOUND);
        break;
      case LowLevelPutException.ROUTE_REALLY_NOT_FOUND:
        errors.inc(InsertException.ROUTE_REALLY_NOT_FOUND);
        break;
      default:
        Logger.error(this, "Unknown LowLevelPutException code: " + e.code);
        errors.inc(InsertException.INTERNAL_ERROR);
    }
    if (persistent) container.activate(ctx, 1);
    if (e.code == LowLevelPutException.ROUTE_NOT_FOUND
        || e.code == LowLevelPutException.ROUTE_REALLY_NOT_FOUND) {
      consecutiveRNFs++;
      if (logMINOR)
        Logger.minor(
            this,
            "Consecutive RNFs: " + consecutiveRNFs + " / " + ctx.consecutiveRNFsCountAsSuccess);
      if (consecutiveRNFs == ctx.consecutiveRNFsCountAsSuccess) {
        if (logMINOR)
          Logger.minor(this, "Consecutive RNFs: " + consecutiveRNFs + " - counting as success");
        onSuccess(keyNum, container, context);
        return;
      }
    } else consecutiveRNFs = 0;
    if (logMINOR) Logger.minor(this, "Failed: " + e);
    retries++;
    if ((retries > ctx.maxInsertRetries) && (ctx.maxInsertRetries != -1)) {
      fail(InsertException.construct(persistent ? errors.clone() : errors), container, context);
      if (persistent) container.deactivate(ctx, 1);
      return;
    }
    if (persistent) {
      container.store(this);
      container.deactivate(ctx, 1);
    }
    getScheduler(context).registerInsert(this, persistent, false, container);
  }
 @Override
 public short getPriorityClass(ObjectContainer container) {
   if (persistent) container.activate(parent, 1);
   return parent.getPriorityClass(); // Not much point deactivating
 }