Пример #1
0
        void AppendToStream(IIdentity id, string envelopeId, Applied then, string explanation)
        {
            var stream = _factory.GetOrCreateStream(IdentityConvert.ToStream(id));
            var b      = new EnvelopeBuilder("unknown");

            b.AddString("caused-by", envelopeId);

            if (!String.IsNullOrEmpty(explanation))
            {
                b.AddString("explain", explanation);
            }
            foreach (var e in then.Events)
            {
                b.AddItem((object)e);
            }
            var data = _streamer.SaveEnvelopeData(b.Build());

            Context.Debug("?? Append {0} at v{3} to '{1}' in thread {2}", then.Events.Count,
                          IdentityConvert.ToStream(id),
                          Thread.CurrentThread.ManagedThreadId,
                          then.Version);

            if (!stream.TryAppend(data, TapeAppendCondition.VersionIs(then.Version)))
            {
                throw new InvalidOperationException("Failed to update the stream - it has been changed concurrently");
            }
        }
        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;
            }
        }
Пример #3
0
        void Dispatch(string id, IEnumerable <ICommand> commands)
        {
            var stream = _factory.GetOrCreateStream(id);

            var records = stream.ReadRecords(0, int.MaxValue).ToList();
            var events  = records
                          .Select(tr => _streamer.ReadAsEnvelopeData(tr.Data))
                          .SelectMany(i => i.Items)
                          .Select(i => (IEvent)i.Content)
                          .ToList();

            var then = AggregateFactory
                       .LoadProject(events, commands)
                       .Select(e => new MessageBuilder(e.GetType(), e)).ToList();

            if (then.Count == 0)
            {
                return;
            }


            // events are stored here as envelopes )
            var b = new EnvelopeBuilder("unknown");

            foreach (var e in then)
            {
                b.Items.Add(e);
            }

            var version = records.Count == 0 ? 0 : records.Last().Version;

            var data   = _streamer.SaveEnvelopeData(b.Build());
            var result = stream.TryAppend(data, TapeAppendCondition.VersionIs(version));

            if (!result)
            {
                throw new InvalidOperationException(
                          "Data was modified concurrently, and we don't have merging implemented, yet");
            }

            var args = _path.Split(':');
            IQueueWriterFactory factory;

            if (!_queue.TryGet(args[0], out factory))
            {
                throw new InvalidOperationException("Not found " + _path);
            }


            var arVersion = events.Count + 1;
            var arName    = id;

            for (int i = 0; i < then.Count; i++)
            {
                var name    = string.Format("{0}/{1}/{2}", arName, arVersion, i);
                var builder = new EnvelopeBuilder(name);


                builder.Items.Add(then[i]);
                builder.AddString("from-entity", arName);

                factory.GetWriteQueue(args[1]).PutMessage(builder.Build());
            }
        }