public AsyncSubject <Unit> Vacuum() { // Vacuum is a special snowflake. We want to delete all the expired rows before // actually vacuuming. Unfortunately vacuum can't be run in a transaction so we'll // claim an exclusive lock on the queue, drain it and run the delete first before // running our vacuum op without any transactions. var ret = new AsyncSubject <Unit>(); Task.Run(async() => { IDisposable @lock = null; try { // NB. While the documentation for SemaphoreSlim (which powers AsyncLock) // doesn't guarantee ordering the actual (current) implementation[1] // uses a linked list to queue incoming requests so by adding ourselves // to the queue first and then sending a no-op to the main queue to // force it to finish up and release the lock we avoid any potential // race condition where the main queue reclaims the lock before we // have had a chance to acquire it. // // 1. http://referencesource.microsoft.com/#mscorlib/system/threading/SemaphoreSlim.cs,d57f52e0341a581f var lockTask = flushLock.LockAsync(shouldQuit.Token); operationQueue.Add(OperationQueueItem.CreateUnit(OperationType.DoNothing)); try { @lock = await lockTask; } catch (OperationCanceledException) { } var deleteOp = OperationQueueItem.CreateUnit(OperationType.DeleteExpiredSqliteOperation); operationQueue.Add(deleteOp); FlushInternal(); await deleteOp.CompletionAsUnit; var vacuumOp = OperationQueueItem.CreateUnit(OperationType.VacuumSqliteOperation); MarshalCompletion(vacuumOp.Completion, vacuum.Value.PrepareToExecute(), Observable.Return(Unit.Default)); await vacuumOp.CompletionAsUnit; } finally { if (@lock != null) { @lock.Dispose(); } } }) .ToObservable() .ObserveOn(scheduler) .Multicast(ret) .PermaRef(); return(ret); }
public AsyncSubject <Unit> InvalidateAll() { var ret = OperationQueueItem.CreateUnit(OperationType.InvalidateAllSqliteOperation); _operationQueue.Add(ret); return(ret.CompletionAsUnit); }
public IObservable <Unit> Flush() { var noop = OperationQueueItem.CreateUnit(OperationType.DoNothing); _operationQueue.Add(noop); return(noop.CompletionAsUnit); }
public AsyncSubject <Unit> Vacuum() { var ret = OperationQueueItem.CreateUnit(OperationType.VacuumSqliteOperation); operationQueue.Add(ret); return(ret.CompletionAsUnit); }
public IObservable <Unit> Flush() { var ret = new AsyncSubject <Unit>(); return(Task.Run(async() => { // NB: We add a "DoNothing" operation so that the thread waiting // on an item will always have one instead of waiting the full timeout // before we can run the flush operationQueue.Add(OperationQueueItem.CreateUnit(OperationType.DoNothing)); using (await flushLock.LockAsync()) { FlushInternal(); } }).ToObservable()); }
public IObservable <Unit> Flush() { var ret = new AsyncSubject <Unit>(); return(Task.Run(async() => { // NB: We add a "DoNothing" operation so that the thread waiting // on an item will always have one instead of waiting the full timeout // before we can run the flush operationQueue.Add(OperationQueueItem.CreateUnit(OperationType.DoNothing)); using (await flushLock.LockAsync()) { var newQueue = new BlockingCollection <OperationQueueItem>(); var existingItems = Interlocked.Exchange(ref operationQueue, newQueue).ToList(); ProcessItems(CoalesceOperations(existingItems)); } }).ToObservable()); }
public AsyncSubject <Unit> Vacuum() { // Vacuum is a special snowflake. We want to delete all the expired rows before // actually vacuuming. Unfortunately vacuum can't be run in a transaction so we'll // claim an exclusive lock on the queue, drain it and run the delete first before // running our vacuum op without any transactions. var ret = new AsyncSubject <Unit>(); Task.Run(async() => { // NB: We add a "DoNothing" operation so that the thread waiting // on an item will always have one instead of waiting the full timeout // before we can run the flush operationQueue.Add(OperationQueueItem.CreateUnit(OperationType.DoNothing)); using (await flushLock.LockAsync()) { var deleteOp = OperationQueueItem.CreateUnit(OperationType.DeleteExpiredSqliteOperation); operationQueue.Add(deleteOp); FlushInternal(); await deleteOp.CompletionAsUnit; var vacuumOp = OperationQueueItem.CreateUnit(OperationType.VacuumSqliteOperation); MarshalCompletion(vacuumOp.Completion, vacuum.PrepareToExecute(), Observable.Return(Unit.Default)); await vacuumOp.CompletionAsUnit; } }) .ToObservable() .ObserveOn(scheduler) .Multicast(ret) .PermaRef(); return(ret); }