/// <inheritdoc /> protected override void MessageReceived(Message message) { if (message.Data is JoinAttempt) { JoinAttempt attempt = (JoinAttempt)message.Data; if (attempt.Type != NodeType.Api) { SendMessage(new Message(message, new JoinFailure("Only an API node can send a join attempt to a query node."), false) { SendWithoutConfirmation = true }); } if (attempt.Settings != _settings.ConnectionString) { SendMessage(new Message(message, new JoinFailure("The connection strings do not match."), false) { SendWithoutConfirmation = true }); } Connections[message.Address].ConnectionEstablished(message.Address, attempt.Type); var response = new Message(message, new JoinSuccess(new Document()), true); SendMessage(response); response.BlockUntilDone(); } 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 NodeList) { lock (_connectedStorageNodes) { _connectedStorageNodes.Clear(); _connectedStorageNodes.AddRange(((NodeList)message.Data).Nodes.Select(e => new NodeDefinition(e.Split(':')[0], int.Parse(e.Split(':')[1])))); var connections = GetConnectedNodes(); foreach (var item in _connectedStorageNodes) { if (!connections.Any(e => Equals(e.Item1, item))) { Message attempt = new Message(item, new JoinAttempt(NodeType.Query, _settings.NodeName, _settings.Port, _settings.ConnectionString), true) { SendWithoutConfirmation = true }; SendMessage(attempt); attempt.BlockUntilDone(); if (attempt.Success) { if (attempt.Response.Data is JoinFailure) { Logger.Log("Failed to join storage node: " + ((JoinFailure)attempt.Response.Data).Reason, LogLevel.Error); } else { Connections[item].ConnectionEstablished(item, NodeType.Storage); SendMessage(new Message(attempt.Response, new Acknowledgement(), false)); } } } } } } else if (message.Data is DataOperation) { DataOperation op = (DataOperation)message.Data; Document dataOperation = new Document(op.Json); if (!dataOperation.Valid) { SendMessage(new Message(message, new DataOperationResult(ErrorCodes.InvalidDocument, "The document is invalid."), false)); return; } try { ProcessDataOperation(dataOperation, message); } catch (Exception e) { Logger.Log(e.Message + "\nStackTrace:" + e.StackTrace, LogLevel.Error); SendMessage(new Message(message, new DataOperationResult(ErrorCodes.FailedMessage, "An exception occurred while processing the operation."), false)); } } else if (message.Data is ChunkListUpdate) { _chunkListLock.EnterWriteLock(); _chunkList = ((ChunkListUpdate)message.Data).ChunkList; _chunkListLock.ExitWriteLock(); SendMessage(new Message(message, new Acknowledgement(), false)); } }
/// <inheritdoc /> protected override void MessageReceived(Message message) { if (message.Data is JoinAttempt) { JoinAttempt attempt = (JoinAttempt)message.Data; if (attempt.Type != NodeType.Query && attempt.Type != NodeType.Storage) { SendMessage(new Message(message, new JoinFailure("Only a query node can send a join attempt to a storage node."), false) { SendWithoutConfirmation = true }); } if (attempt.Settings != _settings.ConnectionString) { SendMessage(new Message(message, new JoinFailure("The connection strings do not match."), false) { SendWithoutConfirmation = true }); } NodeDefinition nodeDef = new NodeDefinition(attempt.Name, attempt.Port); RenameConnection(message.Address, nodeDef); Connections[nodeDef].ConnectionEstablished(nodeDef, attempt.Type); Message response = new Message(message, new JoinSuccess(new Document()), true) { Address = nodeDef }; SendMessage(response); response.BlockUntilDone(); } 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 DataOperation) { DataOperationResult result; try { result = _database.ProcessOperation((DataOperation)message.Data); } catch (ChunkMovedException) { result = new DataOperationResult(ErrorCodes.ChunkMoved, "The chunk has been moved."); } catch (Exception e) { Logger.Log(e.Message + "\nStackTrace:" + e.StackTrace, LogLevel.Error); result = new DataOperationResult(ErrorCodes.FailedMessage, "An exception occurred while processing the operation."); } SendMessage(new Message(message, result, false)); } else if (message.Data is DatabaseCreate) { _database.Create(); SendMessage(new Message(message, new Acknowledgement(), false)); } else if (message.Data is ChunkTransfer) { var transfer = (ChunkTransfer)message.Data; MessageReceivedThreadPool.QueueWorkItem(TransferChunk, transfer); } else if (message.Data is ChunkDataRequest) { _database.ProcessChunkDataRequest((ChunkDataRequest)message.Data, message); } else if (message.Data is ChunkListRequest) { _database.ProcessChunkListRequest(message, (ChunkListRequest)message.Data); } }
/// <summary> /// Handles a <see cref="JoinAttempt"/> message. /// </summary> /// <param name="message">The message that was received.</param> /// <param name="joinAttemptData">The <see cref="JoinAttempt"/> that was received.</param> private void HandleJoinAttemptMessage(Message message, JoinAttempt joinAttemptData) { switch (joinAttemptData.Type) { case NodeType.Controller: ControllerNodeSettings joinSettings = new ControllerNodeSettings(joinAttemptData.Settings); if (joinSettings.ConnectionString != _settings.ConnectionString) { SendMessage(new Message(message, new JoinFailure("Connection strings do not match."), false) { SendWithoutConfirmation = true }); } else if (joinSettings.MaxChunkItemCount != _settings.MaxChunkItemCount) { SendMessage(new Message(message, new JoinFailure("Max chunk item counts do not match."), false) { SendWithoutConfirmation = true }); } else if (joinSettings.RedundantNodesPerLocation != _settings.RedundantNodesPerLocation) { SendMessage(new Message(message, new JoinFailure("Redundent nodes per location do not match."), false) { SendWithoutConfirmation = true }); } else { NodeDefinition nodeDef = new NodeDefinition(joinAttemptData.Name, joinAttemptData.Port); if (Equals(message.Address, nodeDef)) { Logger.Log("Duplicate connection found. Not recognizing new connection in favor of the old one.", LogLevel.Info); } RenameConnection(message.Address, nodeDef); Connections[nodeDef].ConnectionEstablished(nodeDef, joinAttemptData.Type); Message response = new Message(message, new JoinSuccess(new Document("{\"PrimaryController\":" + Equals(Primary, Self).ToString().ToLower() + "}")), true) { Address = nodeDef }; SendMessage(response); response.BlockUntilDone(); if (response.Success) { if (joinAttemptData.Primary) { Logger.Log("Connection to primary controller established, setting primary to " + message.Address.ConnectionName, LogLevel.Info); Primary = nodeDef; } SendChunkList(); } } break; case NodeType.Query: QueryNodeSettings queryJoinSettings = new QueryNodeSettings(joinAttemptData.Settings); if (queryJoinSettings.ConnectionString != _settings.ConnectionString) { SendMessage(new Message(message, new JoinFailure("Connection strings do not match."), false) { SendWithoutConfirmation = true }); } else { NodeDefinition nodeDef = new NodeDefinition(joinAttemptData.Name, joinAttemptData.Port); RenameConnection(message.Address, nodeDef); Connections[nodeDef].ConnectionEstablished(nodeDef, joinAttemptData.Type); Message response = new Message(message, new JoinSuccess(new Document("{\"PrimaryController\":" + Equals(Primary, Self).ToString().ToLower() + "}")), true) { Address = nodeDef }; SendMessage(response); response.BlockUntilDone(); if (response.Success) { SendStorageNodeConnectionMessage(); SendQueryNodeConnectionMessage(); SendChunkList(); } } break; case NodeType.Storage: StorageNodeSettings storageJoinSettings = new StorageNodeSettings(joinAttemptData.Settings); if (storageJoinSettings.ConnectionString != _settings.ConnectionString) { SendMessage(new Message(message, new JoinFailure("Connection strings do not match."), false) { SendWithoutConfirmation = true }); } else { NodeDefinition nodeDef = new NodeDefinition(joinAttemptData.Name, joinAttemptData.Port); RenameConnection(message.Address, nodeDef); Connections[nodeDef].ConnectionEstablished(nodeDef, joinAttemptData.Type); var responseData = new Document(); responseData["PrimaryController"] = new DocumentEntry("PrimaryController", DocumentEntryType.Boolean, Equals(Primary, Self)); responseData["MaxChunkItemCount"] = new DocumentEntry("MaxChunkItemCount", DocumentEntryType.Integer, _settings.MaxChunkItemCount); Message response = new Message(message, new JoinSuccess(responseData), true) { Address = nodeDef }; SendMessage(response); response.BlockUntilDone(); if (response.Success) { lock (_storageNodes) { _storageNodes.Add(new Tuple <NodeDefinition, int>(nodeDef, storageJoinSettings.Weight)); } SendStorageNodeConnectionMessage(); TryCreateDatabase(); } } break; case NodeType.Api: if (joinAttemptData.Settings != _settings.ConnectionString) { SendMessage(new Message(message, new JoinFailure("Connection strings do not match."), false) { SendWithoutConfirmation = true }); } else { Connections[message.Address].ConnectionEstablished(message.Address, joinAttemptData.Type); var apiResponse = new Message(message, new JoinSuccess(new Document("{\"PrimaryController\":" + Equals(Primary, Self).ToString().ToLower() + "}")), true); SendMessage(apiResponse); apiResponse.BlockUntilDone(); if (apiResponse.Success) { SendQueryNodeConnectionMessage(); } } break; } }