public async Task <IEnumerable <(long, T)> > GetBatch(long startingOffset, int batchSize, CancellationToken cancellationToken) { Preconditions.CheckRange(batchSize, 1, nameof(batchSize)); if (startingOffset < this.headOffset) { startingOffset = this.headOffset; } if (this.IsEmpty() || this.tailOffset < startingOffset) { return(Enumerable.Empty <(long, T)>()); } var batch = new List <(long, T)>(); byte[] startingKey = StoreUtils.GetKeyFromOffset(startingOffset); await this.entityStore.IterateBatch( startingKey, batchSize, (k, v) => { long offsetFromKey = StoreUtils.GetOffsetFromKey(k); batch.Add((offsetFromKey, v)); return(Task.CompletedTask); }, cancellationToken); return(batch); }
private async Task <bool> RemoveEnd(Func <long, T, Task <bool> > predicate, CancellationToken cancellationToken, bool head) { long offset = head ? this.headOffset : this.tailOffset; byte[] key = StoreUtils.GetKeyFromOffset(offset); Option <T> value = await this.entityStore.Get(key, cancellationToken); bool result = await value .Match( async v => { if (await predicate(offset, v)) { await this.entityStore.Remove(key, cancellationToken); if (head) { this.headOffset++; } else { this.tailOffset--; } return(true); } return(false); }, () => Task.FromResult(false)); return(result); }
public async Task <bool> RemoveFirst(Func <long, T, Task <bool> > predicate, CancellationToken cancellationToken) { using (await this.headLockObject.LockAsync(cancellationToken)) { // Tail offset could change here, but not holding a lock for efficiency. if (this.IsEmpty()) { return(false); } byte[] key = StoreUtils.GetKeyFromOffset(this.headOffset); Option <T> value = await this.entityStore.Get(key, cancellationToken); bool result = await value .Match( async v => { if (await predicate(this.headOffset, v)) { await this.entityStore.Remove(key, cancellationToken); this.headOffset++; return(true); } return(false); }, () => Task.FromResult(false)); return(result); } }
public async Task <long> Append(T item, CancellationToken cancellationToken) { using (await this.tailLockObject.LockAsync(cancellationToken)) { long currentOffset = this.tailOffset + 1; byte[] key = StoreUtils.GetKeyFromOffset(currentOffset); await this.entityStore.Put(key, item, cancellationToken); this.tailOffset = currentOffset; return(currentOffset); } }
public async Task <bool> RemoveOffset(Func <long, T, Task <bool> > predicate, long offset, CancellationToken cancellationToken) { if (offset == this.headOffset) { return(await this.RemoveFirst(predicate, cancellationToken)); } if (this.IsEmpty()) { return(false); } if (offset == this.tailOffset) { using (await this.tailLockObject.LockAsync(cancellationToken)) { return(await this.RemoveEnd(predicate, cancellationToken, false)); } } byte[] key = StoreUtils.GetKeyFromOffset(offset); Option <T> value = await this.entityStore.Get(key, cancellationToken); bool result = await value .Match( async v => { if (await predicate(offset, v)) { await this.entityStore.Remove(key, cancellationToken); return(true); } return(false); }, () => Task.FromResult(false)); return(result); }
public Task <ulong> GetCountFromOffset(long offset) => this.entityStore.GetCountFromOffset(StoreUtils.GetKeyFromOffset(offset));