Package freenet.client.async

Source Code of freenet.client.async.BinaryBlobInserter$MySendableInsert

package freenet.client.async;

import java.io.DataInputStream;
import java.io.IOException;
import java.util.ArrayList;

import freenet.client.FailureCodeTracker;
import freenet.client.InsertContext;
import freenet.client.InsertException;
import freenet.client.InsertException.InsertExceptionMode;
import freenet.keys.CHKBlock;
import freenet.keys.ClientKey;
import freenet.keys.Key;
import freenet.keys.KeyBlock;
import freenet.keys.SSKBlock;
import freenet.node.LowLevelPutException;
import freenet.node.RequestClient;
import freenet.node.SendableRequestItem;
import freenet.node.SimpleSendableInsert;
import freenet.support.Logger;
import freenet.support.Logger.LogLevel;
import freenet.support.api.Bucket;

public class BinaryBlobInserter implements ClientPutState {

  final ClientPutter parent;
  final RequestClient clientContext;
  final MySendableInsert[] inserters;
  final FailureCodeTracker errors;
  final int maxRetries;
  final int consecutiveRNFsCountAsSuccess;
  private boolean logMINOR;
  private int completedBlocks;
  private int succeededBlocks;
  private boolean fatal;
  final InsertContext ctx;
  final boolean realTimeFlag;

  BinaryBlobInserter(Bucket blob, ClientPutter parent, RequestClient clientContext, boolean tolerant, short prioClass, InsertContext ctx, ClientContext context)
  throws IOException, BinaryBlobFormatException {
    logMINOR = Logger.shouldLog(LogLevel.MINOR, this);
    this.ctx = ctx;
    this.maxRetries = ctx.maxInsertRetries;
    this.consecutiveRNFsCountAsSuccess = ctx.consecutiveRNFsCountAsSuccess;
    this.parent = parent;
    this.clientContext = clientContext;
    this.errors = new FailureCodeTracker(true);
    this.realTimeFlag = clientContext.realTimeFlag();
    DataInputStream dis = new DataInputStream(blob.getInputStream());

    BlockSet blocks = new SimpleBlockSet();

    try {
      BinaryBlob.readBinaryBlob(dis, blocks, tolerant);
    } finally {
      dis.close();
    }

    ArrayList<MySendableInsert> myInserters = new ArrayList<MySendableInsert>();
    int x=0;
    for(Key key: blocks.keys()) {
      KeyBlock block = blocks.get(key);
      MySendableInsert inserter =
        new MySendableInsert(x++, block, prioClass, getScheduler(block, context), clientContext);
      myInserters.add(inserter);
    }

    inserters = myInserters.toArray(new MySendableInsert[myInserters.size()]);
    parent.addMustSucceedBlocks(inserters.length);
    parent.notifyClients(context);
  }

  private ClientRequestScheduler getScheduler(KeyBlock block, ClientContext context) {
    if(block instanceof CHKBlock)
      return context.getChkInsertScheduler(realTimeFlag);
    else if(block instanceof SSKBlock)
      return context.getSskInsertScheduler(realTimeFlag);
    else throw new IllegalArgumentException("Unknown block type "+block.getClass()+" : "+block);
  }

  @Override
  public void cancel(ClientContext context) {
    for(MySendableInsert inserter: inserters) {
      if(inserter != null)
        inserter.cancel(context);
    }
    parent.onFailure(new InsertException(InsertExceptionMode.CANCELLED), this, context);
  }

  @Override
  public BaseClientPutter getParent() {
    return parent;
  }

  @Override
  public Object getToken() {
    return clientContext;
  }

  @Override
  public void schedule(ClientContext context) throws InsertException {
    for(MySendableInsert inserter: inserters) {
      inserter.schedule();
    }
  }

  class MySendableInsert extends SimpleSendableInsert {

        private static final long serialVersionUID = 1L;
        final int blockNum;
    private int consecutiveRNFs;
    private int retries;

    public MySendableInsert(int i, KeyBlock block, short prioClass, ClientRequestScheduler scheduler, RequestClient client) {
      super(block, prioClass, client, scheduler);
      this.blockNum = i;
    }

    @Override
    public void onSuccess(SendableRequestItem keyNum, ClientKey key, ClientContext context) {
      synchronized(this) {
        if(inserters[blockNum] == null) return;
        inserters[blockNum] = null;
        completedBlocks++;
        succeededBlocks++;
      }
      parent.completedBlock(false, context);
      maybeFinish(context);
    }

    // FIXME duplicated code from SingleBlockInserter
    // FIXME combine it somehow
    @Override
    public void onFailure(LowLevelPutException e, SendableRequestItem keyNum, ClientContext context) {
      synchronized(BinaryBlobInserter.this) {
        if(inserters[blockNum] == null) return;
      }
      if(parent.isCancelled()) {
        fail(new InsertException(InsertExceptionMode.CANCELLED), true, context);
        return;
      }
      logMINOR = Logger.shouldLog(LogLevel.MINOR, BinaryBlobInserter.this);
      switch(e.code) {
      case LowLevelPutException.COLLISION:
        fail(new InsertException(InsertExceptionMode.COLLISION), false, context);
        break;
      case LowLevelPutException.INTERNAL_ERROR:
        errors.inc(InsertExceptionMode.INTERNAL_ERROR);
        break;
      case LowLevelPutException.REJECTED_OVERLOAD:
        errors.inc(InsertExceptionMode.REJECTED_OVERLOAD);
        break;
      case LowLevelPutException.ROUTE_NOT_FOUND:
        errors.inc(InsertExceptionMode.ROUTE_NOT_FOUND);
        break;
      case LowLevelPutException.ROUTE_REALLY_NOT_FOUND:
        errors.inc(InsertExceptionMode.ROUTE_REALLY_NOT_FOUND);
        break;
      default:
        Logger.error(this, "Unknown LowLevelPutException code: "+e.code);
        errors.inc(InsertExceptionMode.INTERNAL_ERROR);
      }
      if(e.code == LowLevelPutException.ROUTE_NOT_FOUND) {
        consecutiveRNFs++;
        if(logMINOR) Logger.minor(this, "Consecutive RNFs: "+consecutiveRNFs+" / "+consecutiveRNFsCountAsSuccess);
        if(consecutiveRNFs == consecutiveRNFsCountAsSuccess) {
          if(logMINOR) Logger.minor(this, "Consecutive RNFs: "+consecutiveRNFs+" - counting as success");
          onSuccess(keyNum, null, context);
          return;
        }
      } else
        consecutiveRNFs = 0;
      if(logMINOR) Logger.minor(this, "Failed: "+e);
      retries++;
      if((retries > maxRetries) && (maxRetries != -1)) {
        fail(InsertException.construct(errors), false, context);
        return;
      }
      this.clearWakeupTime(context);
      // Retry *this block*
      this.schedule();
    }

    private void fail(InsertException e, boolean fatal, ClientContext context) {
      synchronized(BinaryBlobInserter.this) {
        if(inserters[blockNum] == null) return;
        inserters[blockNum] = null;
        completedBlocks++;
        if(fatal) BinaryBlobInserter.this.fatal = true;
      }
      if(fatal)
        parent.fatallyFailedBlock(context);
      else
        parent.failedBlock(context);
      maybeFinish(context);
    }

  }

  public void maybeFinish(ClientContext context) {
    boolean success;
    boolean wasFatal;
    synchronized(this) {
      if(completedBlocks != inserters.length)
        return;
      success = completedBlocks == succeededBlocks;
      wasFatal = fatal;
    }
    if(success) {
      parent.onSuccess(this, context);
    } else if(wasFatal)
      parent.onFailure(new InsertException(InsertExceptionMode.FATAL_ERRORS_IN_BLOCKS, errors, null), this, context);
    else
      parent.onFailure(new InsertException(InsertExceptionMode.TOO_MANY_RETRIES_IN_BLOCKS, errors, null), this, context);
  }

    @Override
    public void onResume(ClientContext context) throws InsertException {
        // TODO binary blob inserter isn't persistent yet, right?
        throw new InsertException(InsertExceptionMode.INTERNAL_ERROR, "Persistence not supported yet", null);
    }

    @Override
    public void onShutdown(ClientContext context) {
        // Ignore.
    }

}
TOP

Related Classes of freenet.client.async.BinaryBlobInserter$MySendableInsert

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.