public Task<DriverWriteResult> WriteAsync(long position, IEnumerable<RawEvent> events, CancellationToken cancel = new CancellationToken()) { var written = false; if (_file.Length == position) { written = true; _file.Seek(0, SeekOrigin.End); using (var w = new BinaryWriter(_file, Encoding.UTF8, true)) foreach (var e in events) EventFormat.Write(w, e); } return Task.FromResult(new DriverWriteResult(_file.Length, written)); }
internal DriverWriteResult Write(long position, IEnumerable <RawEvent> events) { var written = false; if (_file.Length == position) { written = true; _file.Seek(0, SeekOrigin.End); using (var w = new BinaryWriter(_file, Encoding.UTF8, true)) foreach (var e in events) { EventFormat.Write(w, e); } } return(new DriverWriteResult(_file.Length, written)); }
public async Task <DriverWriteResult> WriteAsync(long position, IEnumerable <RawEvent> events, CancellationToken cancel = new CancellationToken()) { // Caller knows something we don't? Refresh! if (position > _lastKnownPosition) { _lastKnownPosition = await RefreshCache(cancel); } // Quick early-out with no Azure request involved. if (position < _lastKnownPosition) { return(new DriverWriteResult(_lastKnownPosition, false)); } // This should only happen very rarely, but it still needs to be done. if (_blobs.Count == 0) { await CreateLastBlob(cancel); } // Generate appended payload byte[] payload; using (var stream = new MemoryStream()) using (var writer = new BinaryWriter(stream)) { foreach (var e in events) { EventFormat.Write(writer, e); } payload = stream.ToArray(); } // Nothing to write, but still check position if (payload.Length == 0) { _lastKnownPosition = await RefreshCache(cancel); return(new DriverWriteResult(_lastKnownPosition, position == _lastKnownPosition)); } // Attempt write to last blob. bool collision; try { var offset = _firstPosition[_blobs.Count - 1]; await _blobs[_blobs.Count - 1].AppendTransactionalAsync(payload, position - offset, cancel); _lastKnownPosition = position + payload.Length; return(new DriverWriteResult(_lastKnownPosition, true)); } catch (StorageException e) { if (!e.IsCollision() && !e.IsMaxReached()) { throw; } collision = e.IsCollision(); } // Collision means we do not have the proper _lastKnownPosition, so refresh // the cache and return a failure. if (collision) { return(new DriverWriteResult(await RefreshCache(cancel), false)); } // Too many appends can be solved by creating a new blob and appending to it. // The append code is similar but subtly different, so we just rewrite it // below. await CreateLastBlob(cancel); try { await _blobs[_blobs.Count - 1].AppendTransactionalAsync(payload, 0, cancel); _lastKnownPosition = position + payload.Length; return(new DriverWriteResult(_lastKnownPosition, true)); } catch (StorageException e) { // Only a collision can stop us here, no max-appends-reached should // happen when appending at position 0. if (!e.IsCollision()) { throw; } } // Collision here means someone else already created the new blob and appended // to it, so refresh everything and report failure. return(new DriverWriteResult(await RefreshCache(cancel), false)); }