internal void CreateNewBatchAndExecutePreviousIfNeeded(RequestBatch <BatchReturnType, RequestResponseType, RequestArgumentType> previousBatch) { if (previousBatch == null) { throw new InvalidOperationException("Trying to start null batch which means it was shutdown already."); } if (Batch.CompareAndSet(previousBatch, new RequestBatch <BatchReturnType, RequestResponseType, RequestArgumentType>(Properties, _commandCollapser, Properties.MaxRequestsInBatch))) { previousBatch.ExecuteBatchIfNotAlreadyStarted(); } }
public void Shutdown() { RequestBatch <BatchReturnType, RequestResponseType, RequestArgumentType> currentBatch = batch.GetAndSet(null); if (currentBatch != null) { currentBatch.Shutdown(); } if (timerListenerReference.Value != null) { // if the timer was started we'll clear it so it stops ticking timerListenerReference.Value.Dispose(); } }
public void Tick() { try { // we fetch current so that when multiple threads race // we can do compareAndSet with the expected/new to ensure only one happens RequestBatch <BatchReturnType, ResponseType, RequestArgumentType> currentBatch = rq.Batch.Value; // 1) it can be null if it got shutdown // 2) we don't execute this batch if it has no requests and let it wait until next tick to be executed if (currentBatch != null && currentBatch.Size > 0) { // do execution within context of wrapped Callable rq.CreateNewBatchAndExecutePreviousIfNeeded(currentBatch); } } catch (Exception) { // logger.error("Error occurred trying to execute callable inside CollapsedTask from Timer.", e); } }
public CollapsedRequest <RequestResponseType, RequestArgumentType> SubmitRequest(RequestArgumentType arg, CancellationToken token) { /* * We only want the timer ticking if there are actually things to do so we register it the first time something is added. */ if (!timerListenerRegistered.Value && timerListenerRegistered.CompareAndSet(false, true)) { /* schedule the collapsing task to be executed every x milliseconds (x defined inside CollapsedTask) */ timerListenerReference.Value = timer.AddListener(new CollapsedTask <BatchReturnType, RequestResponseType, RequestArgumentType>(this)); } // loop until succeed (compare-and-set spin-loop) while (true) { RequestBatch <BatchReturnType, RequestResponseType, RequestArgumentType> b = batch.Value; if (b == null) { throw new InvalidOperationException("Submitting requests after collapser is shutdown"); } CollapsedRequest <RequestResponseType, RequestArgumentType> response = b.Offer(arg, token); // it will always get an CollapsedRequest unless we hit the max batch size if (response != null) { return(response); } else { // this batch can't accept requests so create a new one and set it if another thread doesn't beat us CreateNewBatchAndExecutePreviousIfNeeded(b); } } }