private TcpPackage WrapDataChunkBulk(ReplicationMessage.DataChunkBulk msg)
        {
            var dto = new ReplicationMessageDto.DataChunkBulk(msg.LeaderId.ToByteArray(),
                                                              msg.SubscriptionId.ToByteArray(),
                                                              msg.ChunkStartNumber,
                                                              msg.ChunkEndNumber,
                                                              msg.SubscriptionPosition,
                                                              msg.DataBytes,
                                                              msg.CompleteChunk);

            return(new TcpPackage(TcpCommand.DataChunkBulk, Guid.NewGuid(), dto.Serialize()));
        }
        public void Handle(ReplicationMessage.DataChunkBulk message)
        {
            Interlocked.Decrement(ref FlushMessagesInQueue);
            try
            {
                if (_subscriptionId != message.SubscriptionId)
                {
                    return;
                }
                if (_activeChunk != null)
                {
                    ReplicationFail("Data chunk bulk received, but we have active chunk for receiving raw chunk bulks.");
                }

                var chunk = Writer.CurrentChunk;
                if (chunk.ChunkHeader.ChunkStartNumber != message.ChunkStartNumber || chunk.ChunkHeader.ChunkEndNumber != message.ChunkEndNumber)
                {
                    Log.Error("Received DataChunkBulk for TFChunk {0}-{1}, but active chunk is {2}-{3}.",
                              message.ChunkStartNumber, message.ChunkEndNumber, chunk.ChunkHeader.ChunkStartNumber, chunk.ChunkHeader.ChunkEndNumber);
                    return;
                }

                if (_subscriptionPos != message.SubscriptionPosition)
                {
                    Log.Error("Received DataChunkBulk at SubscriptionPosition {0} (0x{0:X}) while current SubscriptionPosition is {1} (0x{1:X}).",
                              message.SubscriptionPosition, _subscriptionPos);
                    return;
                }

                _framer.UnFrameData(new ArraySegment <byte>(message.DataBytes));
                _subscriptionPos += message.DataBytes.Length;

                if (message.CompleteChunk)
                {
                    Log.Trace("Completing data chunk {0}-{1}...", message.ChunkStartNumber, message.ChunkEndNumber);
                    Writer.CompleteChunk();

                    if (_framer.HasData)
                    {
                        ReplicationFail("There is some data left in framer when completing chunk.");
                    }

                    _subscriptionPos = chunk.ChunkHeader.ChunkEndPosition;
                    _framer.Reset();
                }
            }
            catch (Exception exc)
            {
                Log.ErrorException(exc, "Exception in writer.");
                throw;
            }
            finally
            {
                Flush();
            }

            if (message.CompleteChunk || _subscriptionPos - _ackedSubscriptionPos >= MasterReplicationService.ReplicaAckWindow)
            {
                _ackedSubscriptionPos = _subscriptionPos;
                Bus.Publish(new ReplicationMessage.AckLogPosition(_subscriptionId, _ackedSubscriptionPos));
            }
        }
Exemple #3
0
        private bool TrySendLogBulk(ReplicaSubscription subscription, long masterCheckpoint)
        {
            /*
             * if (subscription == null) throw new Exception("subscription == null");
             * if (subscription.BulkReader == null) throw new Exception("subscription.BulkReader == null");
             * if (subscription.BulkReader.Chunk == null) throw new Exception("subscription.BulkReader.Chunk == null");
             * if (subscription.DataBuffer == null) throw new Exception("subscription.DataBuffer == null");
             */

            var bulkReader  = subscription.BulkReader;
            var chunkHeader = bulkReader.Chunk.ChunkHeader;

            BulkReadResult bulkResult;

            if (subscription.RawSend)
            {
                bulkResult = bulkReader.ReadNextRawBytes(subscription.DataBuffer.Length, subscription.DataBuffer);
            }
            else
            {
                var bytesToRead = (int)Math.Min(subscription.DataBuffer.Length, masterCheckpoint - subscription.LogPosition);
                bulkResult = bulkReader.ReadNextDataBytes(bytesToRead, subscription.DataBuffer);
            }

            bool dataFound = false;

            // for logical send we can get 0 at the end multiple time, but we need to get EOF exactly once
            if (bulkResult.BytesRead > 0 || (bulkResult.IsEOF && !subscription.RawSend && !subscription.EOFSent))
            {
                var data = new byte[bulkResult.BytesRead];
                Buffer.BlockCopy(subscription.DataBuffer, 0, data, 0, bulkResult.BytesRead);

                dataFound            = true;
                subscription.EOFSent = bulkResult.IsEOF;

                if (subscription.RawSend)
                {
                    var msg = new ReplicationMessage.RawChunkBulk(
                        _instanceId, subscription.SubscriptionId, chunkHeader.ChunkStartNumber, chunkHeader.ChunkEndNumber,
                        bulkResult.OldPosition, data, bulkResult.IsEOF);
                    subscription.SendMessage(msg);
                }
                else
                {
                    if (chunkHeader.GetLocalLogPosition(subscription.LogPosition) != bulkResult.OldPosition)
                    {
                        throw new Exception(string.Format("Replication invariant failure. SubscriptionPosition {0}, bulkResult.OldPosition {1}",
                                                          subscription.LogPosition, bulkResult.OldPosition));
                    }
                    var msg = new ReplicationMessage.DataChunkBulk(
                        _instanceId, subscription.SubscriptionId, chunkHeader.ChunkStartNumber, chunkHeader.ChunkEndNumber,
                        subscription.LogPosition, data, bulkResult.IsEOF);
                    subscription.LogPosition += bulkResult.BytesRead;
                    subscription.SendMessage(msg);
                }
            }

            if (bulkResult.IsEOF)
            {
                var newLogPosition = chunkHeader.ChunkEndPosition;
                if (newLogPosition < masterCheckpoint)
                {
                    dataFound = true;
                    SetSubscriptionPosition(subscription, newLogPosition, Guid.Empty, replicationStart: false, verbose: true, trial: 0);
                }
            }
            return(dataFound);
        }