package freenet.client.async; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.Random; import freenet.client.async.SplitFileInserterSegmentStorage.BlockInsert; import freenet.node.KeysFetchingLocally; import freenet.support.io.StorageFormatException; /** Tracks retry count and completion status for blocks in an insert segment. */ public class SplitFileInserterSegmentBlockChooser extends SimpleBlockChooser { final SplitFileInserterSegmentStorage segment; final KeysFetchingLocally keysFetching; final int[] consecutiveRNFs; /** If positive, this many RNFs count as success. */ final int consecutiveRNFsCountAsSuccess; public SplitFileInserterSegmentBlockChooser(SplitFileInserterSegmentStorage segment, int blocks, Random random, int maxRetries, KeysFetchingLocally keysFetching, int consecutiveRNFsCountAsSuccess) { super(blocks, random, maxRetries); this.segment = segment; this.keysFetching = keysFetching; this.consecutiveRNFsCountAsSuccess = consecutiveRNFsCountAsSuccess; if(consecutiveRNFsCountAsSuccess > 0) consecutiveRNFs = new int[blocks]; else consecutiveRNFs = null; } protected int getMaxBlockNumber() { // Ignore cross-segment: We either send all blocks, if the segment has been encoded, or // only the data blocks, if it hasn't (even if the cross-segment blocks have been encoded). if(segment.hasEncoded()) return segment.totalBlockCount; else return segment.dataBlockCount; } protected void onCompletedAll() { segment.onInsertedAllBlocks(); } protected boolean checkValid(int chosen) { if(!super.checkValid(chosen)) return false; return !keysFetching.hasInsert(new BlockInsert(segment, chosen)); } /** Handle an RNF if the n-consecutive-RNFs-count-as-success hack is enabled. * Must only be called if consecutiveRNFsCountAsSuccess > 0 */ public void onRNF(int blockNo) { synchronized(this) { assert(consecutiveRNFsCountAsSuccess > 0); if(++consecutiveRNFs[blockNo] < consecutiveRNFsCountAsSuccess) return; } onSuccess(blockNo); } /** Count the previous RNFs towards the retry limit, when the following error wasn't an RNF. */ public synchronized boolean pushRNFs(int blockNo) { int ret = consecutiveRNFs[blockNo]; consecutiveRNFs[blockNo] = 0; for(int i=0;i<ret;i++) if(onNonFatalFailure(blockNo)) return true; return false; } public void write(DataOutputStream dos) throws IOException { super.write(dos); if(consecutiveRNFsCountAsSuccess > 0) { for(int i : consecutiveRNFs) dos.writeInt(i); } } public void read(DataInputStream dis) throws IOException, StorageFormatException { super.read(dis); if(consecutiveRNFsCountAsSuccess > 0) { for(int i=0;i<consecutiveRNFs.length;i++) { consecutiveRNFs[i] = dis.readInt(); } } } }