Exemplo n.º 1
0
        public async Task <uint> GetLastKeyAsync(CancellationToken cancel = new CancellationToken())
        {
            // We need to look into the last blob, so we need to list all blobs first
            await RefreshCache(cancel);

            // Look into the last non-empty blob
            if (_firstKey.Count == 0)
            {
                return(0);
            }
            var blob = _blobs[_firstKey.Count - 1];

            // Download one event's worth of data to a local buffer.
            // This will likely truncate an event somewhere at the beginning of the
            // buffer, but we don't care, because looking for the *last* sequence only
            // requires that the last event in the buffer isn't truncated.
            var length = Math.Min(EventFormat.MaxEventFootprint, blob.Properties.Length);
            var bytes  = new byte[length];

            await ReadSubRangeAsync(blob, bytes, blob.Properties.Length - length, 0, length, cancel);

            // Look for the sequence number of the last event.
            using (var stream = new MemoryStream(bytes))
                return(await EventFormat.GetLastSequenceAsync(stream, cancel));
        }
        public Task<DriverReadResult> ReadAsync(long position, long maxBytes, CancellationToken cancel = new CancellationToken())
        {
            var events = new List<RawEvent>();

            if (position >= _file.Length)
                return Task.FromResult(new DriverReadResult(_file.Length, events));

            _file.Seek(position, SeekOrigin.Begin);

            var readBytes = 0L;

            using (var r = new BinaryReader(_file, Encoding.UTF8, true))
            {
                var availableBytes = _file.Length - position;
                while (readBytes < availableBytes)
                {
                    var evt = EventFormat.Read(r);
                    var newReadBytes = _file.Position - position;

                    if (events.Count == 0 || newReadBytes < maxBytes)
                    {
                        events.Add(evt);
                        readBytes = newReadBytes;
                    }

                    if (newReadBytes >= maxBytes)
                        break;
                }
            }

            return Task.FromResult(new DriverReadResult(position + readBytes, events));
        }
        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));
        }
Exemplo n.º 4
0
        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));
        }
Exemplo n.º 5
0
        internal DriverReadResult Read(long position, long maxBytes)
        {
            var events = new List <RawEvent>();

            if (position >= _file.Length)
            {
                return(new DriverReadResult(_file.Length, events));
            }

            _file.Seek(position, SeekOrigin.Begin);

            var readBytes = 0L;

            using (var r = new BinaryReader(_file, Encoding.UTF8, true))
            {
                var availableBytes = _file.Length - position;
                while (readBytes < availableBytes)
                {
                    var evt          = EventFormat.Read(r);
                    var newReadBytes = _file.Position - position;

                    if (events.Count == 0 || newReadBytes < maxBytes)
                    {
                        events.Add(evt);
                        readBytes = newReadBytes;
                    }

                    if (newReadBytes >= maxBytes)
                    {
                        break;
                    }
                }
            }

            return(new DriverReadResult(position + readBytes, events));
        }
Exemplo n.º 6
0
 public async Task <uint> GetLastKeyAsync(CancellationToken cancel = new CancellationToken()) =>
 await EventFormat.GetLastSequenceAsync(_file, cancel);
Exemplo n.º 7
0
        public async Task <DriverReadResult> ReadAsync(long position, long maxBytes, CancellationToken cancel = new CancellationToken())
        {
            // STEP 1: PRELIMINARY CHECKS
            // ==========================

            // The local cache tells us there is no data available at the provided position,
            // so start by refreshing the cache.
            if (_blobs.Count == 0 || position >= _lastKnownPosition)
            {
                await RefreshCache(cancel);
            }

            // Even with a fresh cache, our position is beyond any available data:
            // return that there is no more data available.
            if (_blobs.Count == 0 || position >= _lastKnownPosition)
            {
                return(new DriverReadResult(_lastKnownPosition, new RawEvent[0]));
            }

            // STEP 2: IDENTIFY BLOB
            // =====================

            CloudAppendBlob blob          = null;
            long            firstPosition = 0;
            long            blobSize      = 0;

            for (var i = _blobs.Count - 1; i >= 0; --i)
            {
                if (_firstPosition[i] <= position)
                {
                    blob          = _blobs[i];
                    firstPosition = _firstPosition[i];
                    blobSize      = (i == _blobs.Count - 1 ? _lastKnownPosition : _firstPosition[i + 1]) - firstPosition;
                    break;
                }
            }

            if (blob == null)
            {
                // Since _firstPosition[0] == 0, this means the position is negative
                throw new ArgumentOutOfRangeException("Invalid position:" + position, "position");
            }

            // STEP 3: READ RAW DATA
            // =====================

            var startPos = position - firstPosition;

            maxBytes = Math.Min(maxBytes, Math.Min(_buffer.Length, blobSize - startPos));

            if (maxBytes == 0)
            {
                return(new DriverReadResult(_lastKnownPosition, new RawEvent[0]));
            }

            var length = await ReadRangeAsync(blob, startPos, maxBytes, cancel);

            // STEP 4: PARSE DATA
            // ==================

            var events    = new List <RawEvent>();
            var readBytes = 0L;

            using (var ms = new MemoryStream(_buffer, 0, length))
                using (var reader = new BinaryReader(ms))
                {
                    while (true)
                    {
                        try
                        {
                            events.Add(EventFormat.Read(reader));

                            // Only update after finishing a full read !
                            readBytes = ms.Position;
                        }
                        catch (EndOfStreamException)
                        {
                            break;
                        }
                        catch (InvalidDataException e)
                        {
                            throw new InvalidDataException($"{e.Message} at {position + readBytes}");
                        }
                    }
                }

            return(new DriverReadResult(position + readBytes, events));
        }
Exemplo n.º 8
0
        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));
        }