Ejemplo n.º 1
0
        /// <summary>
        /// Commits the header information which essentially commits any transactions that occured
        /// related to that header.
        /// </summary>
        /// <param name="newCommit">the new commit to write</param>
        /// <param name="headerStartOffsetBytes">where in the blob the new commit will be written</param>
        /// <param name="blob">blob header applies to</param>
        /// <param name="header">the new header data</param>
        /// <returns></returns>
        private void CommitNewMessage(WrappedPageBlob blob, byte[] newCommit, StreamBlobHeader header, int offsetBytes)
        {
            newCommit = newCommit ?? new byte[0];
            var serializedHeader          = _serializer.Serialize(header);
            var writeStartLocationAligned = GetPageAlignedSize(offsetBytes);
            var amountToWriteAligned      = GetPageAlignedSize(serializedHeader.Length + newCommit.Length);
            var totalSpaceNeeded          = writeStartLocationAligned + amountToWriteAligned;

            var totalBlobLength = blob.Properties.Length;

            if (totalBlobLength < totalSpaceNeeded)
            {
                blob.Resize(totalSpaceNeeded);
                totalBlobLength = blob.Properties.Length;
            }

            // set the header definition to make it all official
            var headerDefinitionMetadata = new HeaderDefinitionMetadata();

            headerDefinitionMetadata.HeaderSizeInBytes = serializedHeader.Length;
            headerDefinitionMetadata.HeaderStartLocationOffsetBytes = writeStartLocationAligned + newCommit.Length;
            blob.Metadata[_isEventStreamAggregateKey] = "yes";
            blob.Metadata[_hasUndispatchedCommitsKey] = header.PageBlobCommitDefinitions.Any((x) => !x.IsDispatched).ToString();
            if (blob.Metadata.ContainsKey(_primaryHeaderDefinitionKey))
            {
                blob.Metadata[_fallbackHeaderDefinitionKey] = blob.Metadata[_primaryHeaderDefinitionKey];
            }
            blob.Metadata[_primaryHeaderDefinitionKey] = Convert.ToBase64String(headerDefinitionMetadata.GetRaw());
            blob.SetMetadata();

            using (var ms = new MemoryStream(amountToWriteAligned))
            {
                ms.Write(newCommit, 0, newCommit.Length);
                ms.Write(serializedHeader, 0, serializedHeader.Length);

                var remainder = (ms.Position % _blobPageSize);
                var fillSpace = amountToWriteAligned - newCommit.Length - serializedHeader.Length;

                if (fillSpace != 0)
                {
                    ms.Position += fillSpace - 1;
                    ms.WriteByte(0);
                }

                ms.Position = 0;
                blob.Write(ms, writeStartLocationAligned);
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Commits the header information which essentially commits any transactions that occurred
        /// related to that header.
        /// </summary>
        /// <param name="newCommit">the new commit to write</param>
        /// <param name="blob">blob header applies to</param>
        /// <param name="updatedHeader">the new header to be serialized out</param>
        /// <param name="currentGoodHeaderDefinition">the definition for the current header, before this change is committed</param>
        /// <param name="nonAlignedBytesUsedAlready">non aligned offset of index where last commit data is stored (not inclusive of header)</param>
        /// <returns></returns>
        private void CommitNewMessage(WrappedPageBlob blob, byte[] newCommit,
                                      StreamBlobHeader updatedHeader, HeaderDefinitionMetadata currentGoodHeaderDefinition,
                                      int nonAlignedBytesUsedAlready)
        {
            newCommit = newCommit ?? new byte[0];
            var serializedHeader                 = _serializer.Serialize(updatedHeader);
            var writeStartLocationAligned        = GetPageAlignedSize(nonAlignedBytesUsedAlready);
            var amountToWriteAligned             = GetPageAlignedSize(serializedHeader.Length + newCommit.Length);
            var totalSpaceNeeded                 = writeStartLocationAligned + amountToWriteAligned;
            var newHeaderStartLocationNonAligned = writeStartLocationAligned + newCommit.Length;

            var totalBlobLength = blob.Properties.Length;

            if (totalBlobLength < totalSpaceNeeded)
            {
                blob.Resize(totalSpaceNeeded);
                totalBlobLength = blob.Properties.Length;
            }

            // set the header definition to make it all official
            bool isFirstWrite             = currentGoodHeaderDefinition.HeaderSizeInBytes == 0;
            var  headerDefinitionMetadata = new HeaderDefinitionMetadata();

            headerDefinitionMetadata.HeaderSizeInBytes = serializedHeader.Length;
            headerDefinitionMetadata.HeaderStartLocationOffsetBytes = writeStartLocationAligned + newCommit.Length;
            blob.Metadata[_isEventStreamAggregateKey] = "yes";
            blob.Metadata[_hasUndispatchedCommitsKey] = updatedHeader.PageBlobCommitDefinitions.Any((x) => !x.IsDispatched).ToString();

            if (!isFirstWrite)
            {
                blob.Metadata[_secondaryHeaderDefinitionKey] = Convert.ToBase64String(currentGoodHeaderDefinition.GetRaw());

                // this is a thirt layer backup in the case we have a issue in the middle of this upcoming write operation.
                var tempHeaderDefinition = currentGoodHeaderDefinition.Clone();
                tempHeaderDefinition.HeaderStartLocationOffsetBytes = newHeaderStartLocationNonAligned;
                blob.Metadata[_terciaryHeaderDefintionKey]          = Convert.ToBase64String(tempHeaderDefinition.GetRaw());
                blob.Metadata[_firstWriteCompletedKey] = "t";
            }
            else
            {
                blob.Metadata[_firstWriteCompletedKey] = "f";
            }

            blob.Metadata[_primaryHeaderDefinitionKey] = Convert.ToBase64String(headerDefinitionMetadata.GetRaw());
            blob.SetMetadata();

            using (var ms = CreateAndFillStreamAligned(amountToWriteAligned, newCommit, serializedHeader))
            { blob.Write(ms, writeStartLocationAligned, newHeaderStartLocationNonAligned, currentGoodHeaderDefinition); }

            // we pay the cost of an extra call for our first ever write (this is effectively creation of the aggregate.
            // we do this because we actually host our header in the blob, but the reference to that header in our metadata.
            // we set the metadata with the potential states prior to actually writing the new header.  If this was the first
            // ever write and we set the metadata, but then fail to write the header, we can get in a state where the aggregate
            // becomes unusable because it believes there should be a header according to the metadata.
            // For that reason we must record when our first write completes
            if (isFirstWrite)
            {
                blob.Metadata[_firstWriteCompletedKey] = "t";
                blob.SetMetadata();
            }
        }