Beispiel #1
0
        /// <summary>
        /// Attempts to merge the database chunks.
        /// </summary>
        private void AttemptMerge()
        {
            BaseMessageData message = null;

            _checkForMerge = false;

            _lock.EnterUpgradeableReadLock();

            for (int i = 0; i < _chunks.Count - 1; ++i)
            {
                if (_chunks[i].Count + _chunks[i + 1].Count < _maxChunkItemCount / 2 &&
                    Equals(_chunks[i].End, _chunks[i + 1].Start))
                {
                    _checkForMerge = true;

                    if (_node.Primary == null)
                    {
                        break;
                    }

                    Message canMerge = new Message(_node.Primary, new ChunkManagementRequest(), true);
                    _node.SendDatabaseMessage(canMerge);
                    canMerge.BlockUntilDone();
                    if (canMerge.Success && ((ChunkManagementResponse)canMerge.Response.Data).Result)
                    {
                        _lock.EnterWriteLock();

                        // Merging two chunks, do the merge and then alert the primary controller before doing anything else.
                        _chunks[i].Merge(_chunks[i + 1]);
                        _chunks.RemoveAt(i + 1);
                        message = new ChunkMerge(_chunks[i].Start, _chunks[i].End);

                        _lock.ExitWriteLock();
                    }

                    break;
                }
            }

            _lock.ExitUpgradeableReadLock();

            if (message != null)
            {
                Message sentMessage = new Message(_node.Primary, message, true);
                _node.SendDatabaseMessage(sentMessage);
                sentMessage.BlockUntilDone();
            }
        }
Beispiel #2
0
        /// <inheritdoc />
        protected override void MessageReceived(Message message)
        {
            if (Equals(message.Address, Primary))
            {
                _lastPrimaryMessageId = Math.Max(_lastPrimaryMessageId, message.ID);
            }

            if (message.Data is JoinAttempt)
            {
                HandleJoinAttemptMessage(message, (JoinAttempt)message.Data);
            }
            else if (message.Data is VotingRequest)
            {
                if (Primary != null)
                {
                    SendMessage(new Message(message, new VotingResponse(false), false));
                }
                else
                {
                    uint max = 0;
                    List <Tuple <NodeDefinition, uint> > votingIds = new List <Tuple <NodeDefinition, uint> >();
                    foreach (var def in _controllerNodes)
                    {
                        if (Equals(def, Self))
                        {
                            continue;
                        }

                        Message idRequest = new Message(def, new LastPrimaryMessageIdRequest(), true);
                        SendMessage(idRequest);
                        idRequest.BlockUntilDone();

                        if (idRequest.Success)
                        {
                            uint votingId = ((LastPrimaryMessageIdResponse)idRequest.Response.Data).LastMessageId;
                            max = Math.Max(max, votingId);
                            votingIds.Add(new Tuple <NodeDefinition, uint>(def, votingId));
                        }
                    }

                    bool votingResponse = false;
                    if (votingIds.Count > 0)
                    {
                        var top = votingIds.Where(e => e.Item2 == max).OrderBy(e => e.Item1.ConnectionName);

                        if (Equals(top.First().Item1, message.Address))
                        {
                            votingResponse = true;
                        }
                    }

                    SendMessage(new Message(message, new VotingResponse(votingResponse), false));
                }
            }
            else if (message.Data is LastPrimaryMessageIdRequest)
            {
                SendMessage(new Message(message, new LastPrimaryMessageIdResponse(_lastPrimaryMessageId), false));
            }
            else if (message.Data is PrimaryAnnouncement)
            {
                Logger.Log("Setting the primary controller to " + message.Address.ConnectionName, LogLevel.Info);
                Primary = message.Address;
            }
            else if (message.Data is ChunkListUpdate)
            {
                lock (_chunkList)
                {
                    _chunkList.Clear();
                    _chunkList.AddRange(((ChunkListUpdate)message.Data).ChunkList);
                }

                SendMessage(new Message(message, new Acknowledgement(), false));
            }
            else if (message.Data is ChunkSplit)
            {
                ChunkSplit splitData = (ChunkSplit)message.Data;
                lock (_chunkList)
                {
                    _chunkList.Remove(_chunkList.Find(e => Equals(e.Start, splitData.Start1)));
                    _chunkList.Add(new ChunkDefinition(splitData.Start1, splitData.End1, message.Address));
                    _chunkList.Add(new ChunkDefinition(splitData.Start2, splitData.End2, message.Address));
                }

                SendMessage(new Message(message, new Acknowledgement(), false));

                lock (_balancingLockObject)
                {
                    _balancing         = BalancingState.None;
                    _nodeManagingChunk = null;

                    Logger.Log("Committing chunk split.", LogLevel.Debug);
                }

                SendChunkList();
            }
            else if (message.Data is ChunkMerge)
            {
                ChunkMerge mergeData = (ChunkMerge)message.Data;
                lock (_chunkList)
                {
                    _chunkList.Remove(_chunkList.Find(e => Equals(e.Start, mergeData.Start)));
                    _chunkList.Remove(_chunkList.Find(e => Equals(e.End, mergeData.End)));
                    _chunkList.Add(new ChunkDefinition(mergeData.Start, mergeData.End, message.Address));
                }

                SendMessage(new Message(message, new Acknowledgement(), false));

                lock (_balancingLockObject)
                {
                    _balancing         = BalancingState.None;
                    _nodeManagingChunk = null;

                    Logger.Log("Committing chunk merge.", LogLevel.Debug);
                }

                SendChunkList();
            }
            else if (message.Data is ChunkManagementRequest)
            {
                bool success = false;
                lock (_balancingLockObject)
                {
                    if (_balancing == BalancingState.None)
                    {
                        _balancing         = BalancingState.ChunkManagement;
                        success            = true;
                        _nodeManagingChunk = message.Address;

                        Logger.Log("Granting chunk management request.", LogLevel.Debug);
                    }
                }

                SendMessage(new Message(message, new ChunkManagementResponse(success), false));
            }
            else if (message.Data is ChunkTransferComplete)
            {
                if (((ChunkTransferComplete)message.Data).Success)
                {
                    lock (_chunkList)
                    {
                        int index = _chunkList.IndexOf(_chunkBeingTransfered);
                        _chunkList[index] = new ChunkDefinition(_chunkBeingTransfered.Start, _chunkBeingTransfered.End, message.Address);
                    }

                    Logger.Log("Chunk transfer completed successfully.", LogLevel.Info);
                    SendChunkList();
                    BalanceChunks();
                }
                else
                {
                    Logger.Log("Chunk transfer failed.", LogLevel.Info);

                    lock (_balancingLockObject)
                    {
                        _nodeTransferingChunk = null;
                        _chunkBeingTransfered = null;
                        _balancing            = BalancingState.None;
                    }
                }
            }
        }