public IEnumerable <TapeRecord> ReadRecords(long afterVersion, int maxCount) { if (afterVersion < 0) { throw new ArgumentOutOfRangeException("afterVersion", "Must be zero or greater."); } if (maxCount <= 0) { throw new ArgumentOutOfRangeException("maxCount", "Must be more than zero."); } // afterVersion + maxCount > long.MaxValue, but transformed to avoid overflow if (afterVersion > long.MaxValue - maxCount) { throw new ArgumentOutOfRangeException("maxCount", "Version will exceed long.MaxValue."); } var blob = _container.GetBlockBlobReference(_blobName); var dataExists = blob.Exists(); // we return empty result if writer didn't even start writing to the storage. if (!dataExists) { return(Enumerable.Empty <TapeRecord>()); } var blockList = blob.DownloadBlockList(); var range = GetReadRange(blockList, afterVersion, maxCount); if (range.Item4 == 0) { return(new TapeRecord[0]); } using (var s = blob.OpenRead()) { s.ReadAheadSize = range.Item2; s.Seek(range.Item1, SeekOrigin.Begin); using (var reader = new BinaryReader(s)) { var bytes = reader.ReadBytes(range.Item2); using (var ms = new MemoryStream(bytes)) { TapeStreamSerializer.SkipRecords(range.Item3, ms); var records = Enumerable.Range(0, range.Item4) .Select(i => TapeStreamSerializer.ReadRecord(ms)) .ToArray(); return(records); } } } }
public void WriteRecordTest() { byte[] expecteddata = Encoding.UTF8.GetBytes("TEST"); const long expectedversion = 3L; var expectedrecord = new TapeRecord(expectedversion, expecteddata); using (MemoryStream ms = new MemoryStream()) { new TapeStreamSerializer().WriteRecord(ms, expecteddata, expectedversion); ms.Seek(0, SeekOrigin.Begin); var actual = new TapeStreamSerializer().ReadRecord(ms); Assert.AreEqual(expectedrecord.Version, actual.Version); Assert.AreEqual(expectedrecord.Data[0], actual.Data[0]); } }
public bool TryAppend(byte[] buffer, TapeAppendCondition appendCondition = new TapeAppendCondition()) { if (buffer == null) { throw new ArgumentNullException("buffer"); } if (buffer.Length == 0) { throw new ArgumentException("Buffer must contain at least one byte."); } long version; int lastBlockSize; long offset; long firstVersion; long count; List <string> blockNames; var blob = _container.GetBlockBlobReference(_blobName); if (blob.Exists()) { var blockList = blob.DownloadBlockList().ToArray(); blockNames = blockList.Select(bl => bl.Name).ToList(); var lastBlock = blockList.LastOrDefault(); if (default(ListBlockItem) == lastBlock) { version = 0; lastBlockSize = int.MaxValue; offset = 0; firstVersion = 1; count = 0; } else { var nameInfo = Naming.GetInfo(DecodeName(lastBlock.Name)); firstVersion = nameInfo.FirstVersion; version = nameInfo.FirstVersion - 1 + nameInfo.Count; count = nameInfo.Count; if (lastBlock.Size > int.MaxValue) { throw new InvalidOperationException("last block size must be in 'int' range"); } lastBlockSize = (int)lastBlock.Size; offset = blockList.Reverse().Skip(1).Sum(l => l.Size); } } else { version = 0; lastBlockSize = int.MaxValue; offset = 0; firstVersion = 1; count = 0; blockNames = new List <string>(); } if (!appendCondition.Satisfy(version)) { return(false); } if (version > long.MaxValue - 1) { throw new IndexOutOfRangeException("Version is more than long.MaxValue."); } if (buffer.Length > FourMb) { throw new ArgumentException("buffer size must be less than or equal to 4 Mb", "buffer"); } using (var outStream = new MemoryStream()) { if (buffer.Length < MaxBlockSize && lastBlockSize <= MaxBlockSize - buffer.Length) { // read old block using (var s = blob.OpenRead()) { s.Seek(offset, SeekOrigin.Begin); s.CopyTo(outStream); TapeStreamSerializer.WriteRecord(outStream, buffer, version + 1); count++; blockNames.RemoveAt(blockNames.Count - 1); } } else { TapeStreamSerializer.WriteRecord(outStream, buffer, version + 1); firstVersion = version + 1; count = 1; } var blockId = EncodeName(Naming.GetName(firstVersion, count)); string md5Hash; outStream.Seek(0, SeekOrigin.Begin); using (var md5 = MD5.Create()) { md5Hash = Convert.ToBase64String(md5.ComputeHash(outStream)); } outStream.Seek(0, SeekOrigin.Begin); blob.PutBlock(blockId, outStream, md5Hash); blockNames.Add(blockId); blob.PutBlockList(blockNames); return(true); } }