예제 #1
0
        public bool 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.");
            }

            try
            {
                _storage.AddOrUpdate(_name, s =>
                {
                    condition.Enforce(0);
                    return(new List <byte[]>
                    {
                        buffer
                    });
                }, (s, list) =>
                {
                    condition.Enforce(list.Count);
                    list.Add(buffer);
                    return(list);
                });
                return(true);
            }
            catch (TapeAppendConditionException)
            {
                return(false);
            }
        }
예제 #2
0
        public bool 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 = ReadVersionFromTheEnd(file);

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

                var versionToWrite = version + 1;
                using (var writer = new BinaryWriter(file))
                {
                    WriteBlockInner(writer, buffer, versionToWrite);
                }

                return(true);
            }
        }
예제 #3
0
        public bool AppendNonAtomic(IEnumerable <byte[]> records, TapeAppendCondition condition = default(TapeAppendCondition))
        {
            if (records == null)
            {
                throw new ArgumentNullException("records");
            }

            return(Write(w =>
            {
                var version = w.IndexWriter.BaseStream.Position / sizeof(long);

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

                var recordsArray = records.ToArray();

                if (version > long.MaxValue - 1)
                {
                    throw new IndexOutOfRangeException("Version is more than long.MaxValue.");
                }

                Append(w, recordsArray, version + 1);

                return true;
            }));
        }
예제 #4
0
        public bool 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 connection = new SqlConnection(_connectionString))
            {
                connection.Open();

                var version = GetCurrentVersion(connection);

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

                if (version > long.MaxValue - 1)
                {
                    throw new IndexOutOfRangeException("Version is more than long.MaxValue.");
                }
                version++;

                Append(connection, version, buffer);
            }

            return(true);
        }
예제 #5
0
        public bool 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.");

            try
            {
                _storage.AddOrUpdate(_name, s =>
                    {
                        condition.Enforce(0);
                        return new List<byte[]>
                            {
                                buffer
                            };
                    }, (s, list) =>
                        {
                            condition.Enforce(list.Count);
                            list.Add(buffer);
                            return list;
                        });
                return true;
            }
            catch (TapeAppendConditionException)
            {
                return false;
            }
        }
예제 #6
0
        public void Specified_condition_is_matched_for_empty_storage()
        {
            var version = _stream.GetCurrentVersion();

            var success = _stream.TryAppend(_batch[0], TapeAppendCondition.VersionIs(version));

            Assert.IsTrue(success, "Appending records should succeed");

            var currentVersion = _stream.GetCurrentVersion();

            Assert.Greater(currentVersion, version, "Version should change");
        }
예제 #7
0
        public void Specified_condition_is_verified_for_empty_storage()
        {
            var previousVersion = _stream.GetCurrentVersion();

            Assert.AreEqual(0, previousVersion, "Version should be zero");

            var result = _stream.TryAppend(_batch[0], TapeAppendCondition.VersionIs(1));

            Assert.IsFalse(result, "Appending records should fail");

            var currentVersion = _stream.GetCurrentVersion();

            Assert.AreEqual(previousVersion, currentVersion, "Version should not change");
        }
예제 #8
0
        public bool 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.");
            }

            return(Write(w => TryAppendInternal(w, buffer, condition)));
        }
예제 #9
0
        public void Specified_condition_is_verified_for_non_empty_storage()
        {
            var previousVersion = _stream.GetCurrentVersion();

            _stream.TryAppend(_batch[0]);

            var currentVersion1 = _stream.GetCurrentVersion();

            Assert.Greater(currentVersion1, previousVersion, "Version should be equal to one");

            var result = _stream.TryAppend(_batch[1], TapeAppendCondition.VersionIs(previousVersion));

            Assert.IsFalse(result, "Appending records should fail");

            var currentVersion2 = _stream.GetCurrentVersion();

            Assert.AreEqual(currentVersion1, currentVersion2, "Version should not change");
        }
예제 #10
0
        static bool TryAppendInternal(Writers writers, byte[] buffer, TapeAppendCondition condition)
        {
            var version = writers.IndexWriter.BaseStream.Position / sizeof(long);

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

            if (version > long.MaxValue - 1)
            {
                throw new IndexOutOfRangeException("Version is more than long.MaxValue.");
            }

            Append(writers, new[] { buffer }, version + 1);

            return(true);
        }
예제 #11
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);
            }
        }
예제 #12
0
        public bool 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 = ReadVersionFromTheEnd(file);

                if (!condition.Satisfy(version))
                    return false;

                var versionToWrite = version + 1;
                using (var writer = new BinaryWriter(file))
                {
                    WriteBlockInner(writer, buffer, versionToWrite);
                }

                return true;
            }
        }