예제 #1
0
        public void AppendNonAtomic(IEnumerable <TapeRecord> records)
        {
            if (records == null)
            {
                throw new ArgumentNullException("records");
            }

            // if enumeration is lazy, then this would cause another enum
            //if (!records.Any())
            //    return;

            using (var file = OpenForWrite())
            {
                file.Seek(0, SeekOrigin.End);

                foreach (var record in records)
                {
                    if (record.Data.Length == 0)
                    {
                        throw new ArgumentException("Record must contain at least one byte.");
                    }

                    var versionToWrite = record.Version;
                    TapeStreamSerializer.WriteRecord(file, record.Data, versionToWrite);
                }
            }
        }
예제 #2
0
        public long TryAppend(byte[] buffer, TapeAppendCondition condition)
        {
            if (buffer == null)
            {
                throw new ArgumentNullException("buffer");
            }

            if (buffer.Length == 0)
            {
                throw new ArgumentException("Buffer must contain at least one byte.");
            }

            using (var file = OpenForWrite())
            {
                // we need to know version first.
                file.Seek(0, SeekOrigin.End);
                var version = TapeStreamSerializer.ReadVersionFromTheEnd(file);

                if (!condition.Satisfy(version))
                {
                    return(0);
                }

                var versionToWrite = version + 1;
                TapeStreamSerializer.WriteRecord(file, buffer, versionToWrite);

                return(versionToWrite);
            }
        }
        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);
                    }
                }
            }
        }
예제 #4
0
        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.");
            }

            if (!_data.Exists)
            {
                // file could've been created since the last check
                _data.Refresh();
                if (!_data.Exists)
                {
                    yield break;
                }
            }

            using (var file = OpenForRead())
            {
                if (!TapeStreamSerializer.SkipRecords(afterVersion, file))
                {
                    yield break;
                }

                for (var i = 0; i < maxCount; i++)
                {
                    if (file.Position == file.Length)
                    {
                        yield break;
                    }

                    var record = TapeStreamSerializer.ReadRecord(file);

                    yield return(record);
                }
            }
        }
예제 #5
0
 public long GetCurrentVersion()
 {
     try
     {
         using (var s = OpenForRead())
         {
             // seek end
             s.Seek(0, SeekOrigin.End);
             return(TapeStreamSerializer.ReadVersionFromTheEnd(s));
         }
     }
     catch (FileNotFoundException)
     {
         return(0);
     }
     catch (DirectoryNotFoundException)
     {
         return(0);
     }
 }
        public long 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(0);
            }

            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(version + 1);
            }
        }