/** Called by RequestStarter to find a request to run. */ @Override public ChosenBlock grabRequest() { boolean needsRefill = true; while (true) { PersistentChosenRequest reqGroup = null; synchronized (starterQueue) { short bestPriority = Short.MAX_VALUE; for (PersistentChosenRequest req : starterQueue) { if (req.prio == RequestStarter.MINIMUM_PRIORITY_CLASS) { if (logDEBUG) Logger.debug( this, "Ignoring paused persistent request: " + req + " prio: " + req.prio); continue; // Ignore paused requests } if (req.prio < bestPriority) { bestPriority = req.prio; reqGroup = req; } } } if (reqGroup != null) { // Try to find a better non-persistent request if (logMINOR) Logger.minor(this, "Persistent request: " + reqGroup + " prio " + reqGroup.prio); ChosenBlock better = getBetterNonPersistentRequest(reqGroup.prio); if (better != null) { if (better.getPriority() > reqGroup.prio) { Logger.error( this, "Selected " + better + " as better than " + reqGroup + " but isn't better!"); } if (logMINOR) Logger.minor(this, "Returning better: " + better); return better; } } if (reqGroup == null) { queueFillRequestStarterQueue(); return getBetterNonPersistentRequest(Short.MAX_VALUE); } ChosenBlock block; synchronized (starterQueue) { block = reqGroup.grabNotStarted(clientContext.fastWeakRandom, this); if (block == null) { if (logMINOR) Logger.minor(this, "No block found on " + reqGroup); int finalLength = 0; for (int i = 0; i < starterQueue.size(); i++) { if (starterQueue.get(i) == reqGroup) { starterQueue.remove(i); if (logMINOR) Logger.minor(this, "Removed " + reqGroup + " from starter queue because is empty"); i--; } else { finalLength += starterQueue.get(i).sizeNotStarted(); } } needsRefill = finalLength < MAX_STARTER_QUEUE_SIZE; continue; } else { // Prevent this request being selected, even though we may remove the PCR from the starter // queue // in the very near future. When the PCR finishes, the requests will be un-blocked. if (!runningPersistentRequests.contains(reqGroup.request)) runningPersistentRequests.add(reqGroup.request); } } if (needsRefill) queueFillRequestStarterQueue(); if (logMINOR) Logger.minor(this, "grabRequest() returning " + block + " for " + reqGroup); return block; } }
public boolean send( NodeClientCore core, RequestScheduler sched, final ClientContext context, ChosenBlock req) { // Ignore keyNum, key, since we're only sending one block. ClientKeyBlock b; ClientKey key = null; if (SingleBlockInserter.logMINOR) Logger.minor(this, "Starting request: " + SingleBlockInserter.this); BlockItem block = (BlockItem) req.token; try { try { b = innerEncode( context.random, block.uri, block.copyBucket, block.isMetadata, block.compressionCodec, block.sourceLength, compressorDescriptor); } catch (CHKEncodeException e) { throw new LowLevelPutException( LowLevelPutException.INTERNAL_ERROR, e.toString() + ":" + e.getMessage(), e); } catch (SSKEncodeException e) { throw new LowLevelPutException( LowLevelPutException.INTERNAL_ERROR, e.toString() + ":" + e.getMessage(), e); } catch (MalformedURLException e) { throw new LowLevelPutException( LowLevelPutException.INTERNAL_ERROR, e.toString() + ":" + e.getMessage(), e); } catch (InsertException e) { throw new LowLevelPutException( LowLevelPutException.INTERNAL_ERROR, e.toString() + ":" + e.getMessage(), e); } catch (IOException e) { throw new LowLevelPutException( LowLevelPutException.INTERNAL_ERROR, e.toString() + ":" + e.getMessage(), e); } catch (InvalidCompressionCodecException e) { throw new LowLevelPutException( LowLevelPutException.INTERNAL_ERROR, e.toString() + ":" + e.getMessage(), e); } if (b == null) { Logger.error( this, "Asked to send empty block on " + SingleBlockInserter.this, new Exception("error")); return false; } key = b.getClientKey(); final ClientKey k = key; if (block.persistent) { context.jobRunner.queue( new DBJob() { public boolean run(ObjectContainer container, ClientContext context) { if (!container.ext().isStored(SingleBlockInserter.this)) return false; container.activate(SingleBlockInserter.this, 1); onEncode(k, container, context); container.deactivate(SingleBlockInserter.this, 1); return false; } }, NativeThread.NORM_PRIORITY + 1, false); } else { context.mainExecutor.execute( new Runnable() { public void run() { onEncode(k, null, context); } }, "Got URI"); } if (req.localRequestOnly) try { core.node.store(b, false, req.canWriteClientCache, true, false); } catch (KeyCollisionException e) { throw new LowLevelPutException(LowLevelPutException.COLLISION); } else core.realPut(b, req.canWriteClientCache, req.forkOnCacheable); } catch (LowLevelPutException e) { if (e.code == LowLevelPutException.COLLISION) { // Collision try { ClientSSKBlock collided = (ClientSSKBlock) core.node.fetch((ClientSSK) key, true, true, req.canWriteClientCache); byte[] data = collided.memoryDecode(true); byte[] inserting = BucketTools.toByteArray(block.copyBucket); if (collided.isMetadata() == block.isMetadata && collided.getCompressionCodec() == block.compressionCodec && Arrays.equals(data, inserting)) { if (SingleBlockInserter.logMINOR) Logger.minor(this, "Collided with identical data: " + SingleBlockInserter.this); req.onInsertSuccess(context); return true; } } catch (KeyVerifyException e1) { Logger.error(this, "Caught " + e1 + " when checking collision!", e1); } catch (KeyDecodeException e1) { Logger.error(this, "Caught " + e1 + " when checking collision!", e1); } catch (IOException e1) { Logger.error(this, "Caught " + e1 + " when checking collision!", e1); } } req.onFailure(e, context); if (SingleBlockInserter.logMINOR) Logger.minor(this, "Request failed: " + SingleBlockInserter.this + " for " + e); return true; } catch (DatabaseDisabledException e) { // Impossible, and nothing to do. Logger.error(this, "Running persistent insert but database is disabled!"); } finally { block.copyBucket.free(); } if (SingleBlockInserter.logMINOR) Logger.minor(this, "Request succeeded: " + SingleBlockInserter.this); req.onInsertSuccess(context); return true; }