public PutSubscriptionCommand(string databaseName, string query, string mentor, string uniqueRequestId) : base(databaseName, uniqueRequestId) { Query = query; MentorNode = mentor; // this verifies that the query is a valid subscription query SubscriptionConnection.ParseSubscriptionQuery(query); }
public SubscriptionConnectionState OpenSubscription(SubscriptionConnection connection) { var subscriptionState = _subscriptionConnectionStates.GetOrAdd(connection.SubscriptionId, subscriptionId => new SubscriptionConnectionState(subscriptionId, this)); return(subscriptionState); }
private async Task <bool> DispatchDatabaseTcpConnection(TcpConnectionOptions tcp, TcpConnectionHeaderMessage header) { var databaseLoadingTask = ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(header.DatabaseName); if (databaseLoadingTask == null) { DatabaseDoesNotExistException.Throw(header.DatabaseName); return(true); } var databaseLoadTimeout = ServerStore.DatabasesLandlord.DatabaseLoadTimeout; if (databaseLoadingTask.IsCompleted == false) { var resultingTask = await Task.WhenAny(databaseLoadingTask, Task.Delay(databaseLoadTimeout)); if (resultingTask != databaseLoadingTask) { ThrowTimeoutOnDatabaseLoad(header); } } tcp.DocumentDatabase = await databaseLoadingTask; if (tcp.DocumentDatabase == null) { DatabaseDoesNotExistException.Throw(header.DatabaseName); } Debug.Assert(tcp.DocumentDatabase != null); if (tcp.DocumentDatabase.DatabaseShutdown.IsCancellationRequested) { ThrowDatabaseShutdown(tcp.DocumentDatabase); } tcp.DocumentDatabase.RunningTcpConnections.Add(tcp); switch (header.Operation) { case TcpConnectionHeaderMessage.OperationTypes.Subscription: SubscriptionConnection.SendSubscriptionDocuments(tcp); break; case TcpConnectionHeaderMessage.OperationTypes.Replication: var documentReplicationLoader = tcp.DocumentDatabase.ReplicationLoader; documentReplicationLoader.AcceptIncomingConnection(tcp); break; default: throw new InvalidOperationException("Unknown operation for TCP " + header.Operation); } //since the responses to TCP connections mostly continue to run //beyond this point, no sense to dispose the connection now, so set it to null. //this way the responders are responsible to dispose the connection and the context // ReSharper disable once RedundantAssignment tcp = null; return(false); }
private void OnEndConnection(SubscriptionConnection connection) { var subscriptionName = connection.SubscriptionState.SubscriptionName; if (_perSubscriptionConnectionStats.TryGetValue(subscriptionName, out var subscriptionAndStats)) { var aggregatorToAdd = connection.GetPerformanceStats(); subscriptionAndStats.Performance.TryAdd(aggregatorToAdd); } }
private void SetSubscriptionConnectionStats(SubscriptionConnection connection, DynamicJsonValue config) { config["ClientUri"] = connection.TcpConnection.TcpClient.Client.RemoteEndPoint.ToString(); config["ConnectedAt"] = connection.Stats.ConnectedAt; config["ConnectionException"] = connection.ConnectionException; config["LastMessageSentAt"] = connection.Stats.LastMessageSentAt; config["LastAckReceivedAt"] = connection.Stats.LastAckReceivedAt; config["DocsRate"] = connection.Stats.DocsRate.CreateMeterData(); config["BytesRate"] = connection.Stats.BytesRate.CreateMeterData(); config["AckRate"] = connection.Stats.AckRate.CreateMeterData(); }
public void RegisterRejectedConnection(SubscriptionConnection connection, SubscriptionException exception = null) { if (exception != null && connection.ConnectionException == null) { connection.ConnectionException = exception; } while (_rejectedConnections.Count > 10) { _rejectedConnections.TryDequeue(out SubscriptionConnection _); } _rejectedConnections.Enqueue(connection); }
private async Task CreateInternal(BlittableJsonReaderObject bjro, SubscriptionCreationOptions options, DocumentsOperationContext context, long?id, bool?disabled) { if (TrafficWatchManager.HasRegisteredClients) { AddStringToHttpContext(bjro.ToString(), TrafficWatchChangeType.Subscriptions); } var sub = SubscriptionConnection.ParseSubscriptionQuery(options.Query); if (Enum.TryParse(options.ChangeVector, out Constants.Documents.SubscriptionChangeVectorSpecialStates changeVectorSpecialValue)) { switch (changeVectorSpecialValue) { case Constants.Documents.SubscriptionChangeVectorSpecialStates.BeginningOfTime: options.ChangeVector = null; break; case Constants.Documents.SubscriptionChangeVectorSpecialStates.LastDocument: options.ChangeVector = Database.DocumentsStorage.GetLastDocumentChangeVector(context.Transaction.InnerTransaction, context, sub.Collection); break; } } var mentor = options.MentorNode; var subscriptionId = await Database.SubscriptionStorage.PutSubscription(options, GetRaftRequestIdFromQuery(), id, disabled, mentor); var name = options.Name ?? subscriptionId.ToString(); using (ServerStore.ContextPool.AllocateOperationContext(out TransactionOperationContext serverContext)) using (serverContext.OpenReadTransaction()) { // need to wait on the relevant remote node var node = Database.SubscriptionStorage.GetResponsibleNode(serverContext, name); if (node != null && node != ServerStore.NodeTag) { await WaitForExecutionOnSpecificNode(serverContext, ServerStore.GetClusterTopology(serverContext), node, subscriptionId); } } HttpContext.Response.StatusCode = (int)HttpStatusCode.Created; await using (var writer = new AsyncBlittableJsonTextWriter(context, ResponseBodyStream())) { context.Write(writer, new DynamicJsonValue { [nameof(CreateSubscriptionResult.Name)] = name }); } }
private static DynamicJsonValue GetSubscriptionConnectionDJV(SubscriptionConnection x) { if (x == null) { return(new DynamicJsonValue()); } return(new DynamicJsonValue() { [nameof(SubscriptionConnection.ClientUri)] = x.ClientUri, [nameof(SubscriptionConnection.Strategy)] = x.Strategy, [nameof(SubscriptionConnection.Stats)] = GetConnectionStatsDJV(x.Stats), [nameof(SubscriptionConnection.ConnectionException)] = x.ConnectionException?.Message }); }
public async Task Create() { using (ContextPool.AllocateOperationContext(out DocumentsOperationContext context)) using (context.OpenReadTransaction()) { var json = await context.ReadForMemoryAsync(RequestBodyStream(), null); var options = JsonDeserializationServer.SubscriptionCreationParams(json); if (TrafficWatchManager.HasRegisteredClients) { AddStringToHttpContext(json.ToString(), TrafficWatchChangeType.Subscriptions); } var sub = SubscriptionConnection.ParseSubscriptionQuery(options.Query); if (Enum.TryParse( options.ChangeVector, out Constants.Documents.SubscriptionChangeVectorSpecialStates changeVectorSpecialValue)) { switch (changeVectorSpecialValue) { case Constants.Documents.SubscriptionChangeVectorSpecialStates.BeginningOfTime: options.ChangeVector = null; break; case Constants.Documents.SubscriptionChangeVectorSpecialStates.LastDocument: options.ChangeVector = Database.DocumentsStorage.GetLastDocumentChangeVector(context, sub.Collection); break; } } var id = GetLongQueryString("id", required: false); var disabled = GetBoolValueQueryString("disabled", required: false); var mentor = options.MentorNode; var subscriptionId = await Database.SubscriptionStorage.PutSubscription(options, id, disabled, mentor : mentor); HttpContext.Response.StatusCode = (int)HttpStatusCode.Created; // Created using (var writer = new BlittableJsonTextWriter(context, ResponseBodyStream())) { context.Write(writer, new DynamicJsonValue { ["Name"] = options.Name ?? subscriptionId.ToString() }); } } }
private static DynamicJsonValue GetSubscriptionConnectionJson(SubscriptionConnection x) { if (x == null) { return(new DynamicJsonValue()); } return(new DynamicJsonValue() { [nameof(SubscriptionConnection.ClientUri)] = x.ClientUri, [nameof(SubscriptionConnection.Strategy)] = x.Strategy, [nameof(SubscriptionConnection.Stats)] = GetConnectionStatsJson(x.Stats), [nameof(SubscriptionConnection.ConnectionException)] = x.ConnectionException?.Message, ["TcpConnectionStats"] = x.TcpConnection.GetConnectionStats(), [nameof(SubscriptionConnection.RecentSubscriptionStatuses)] = new DynamicJsonArray(x.RecentSubscriptionStatuses?.ToArray() ?? Array.Empty <string>()) }); }
public void HandleDatabaseRecordChange(DatabaseRecord databaseRecord) { using (_serverStore.ContextPool.AllocateOperationContext(out TransactionOperationContext context)) using (context.OpenReadTransaction()) { foreach (var subscriptionStateKvp in _subscriptionConnectionStates) { var subscriptionName = subscriptionStateKvp.Value.Connection?.Options?.SubscriptionName; if (subscriptionName == null) { continue; } var subscriptionBlittable = _serverStore.Cluster.Read(context, SubscriptionState.GenerateSubscriptionItemKeyName(databaseRecord.DatabaseName, subscriptionName)); if (subscriptionBlittable == null) { DropSubscriptionConnection(subscriptionStateKvp.Key, new SubscriptionDoesNotExistException($"The subscription {subscriptionName} had been deleted")); continue; } var subscriptionState = JsonDeserializationClient.SubscriptionState(subscriptionBlittable); if (subscriptionState.Disabled) { DropSubscriptionConnection(subscriptionStateKvp.Key, new SubscriptionClosedException($"The subscription {subscriptionName} is disabled and cannot be used until enabled")); continue; } SubscriptionConnection connection = subscriptionStateKvp.Value.Connection; if (connection != null && subscriptionState.Query != connection.SubscriptionState.Query) { DropSubscriptionConnection(subscriptionStateKvp.Key, new SubscriptionClosedException($"The subscription {subscriptionName} query has been modified, connection must be restarted")); continue; } var whoseTaskIsIt = _db.WhoseTaskIsIt(databaseRecord.Topology, subscriptionState, subscriptionState); if (whoseTaskIsIt != _serverStore.NodeTag) { DropSubscriptionConnection(subscriptionStateKvp.Key, new SubscriptionDoesNotBelongToNodeException("Subscription operation was stopped, because it's now under different server's responsibility")); } } } }
public bool TryGetRunningSubscriptionConnection(long subscriptionId, out SubscriptionConnection connection) { connection = null; if (_subscriptionConnectionStates.TryGetValue(subscriptionId, out var state) == false) { return(false); } var stateConnection = state.Connection; if (stateConnection == null) { return(false); } connection = stateConnection; return(true); }
public DocumentsSubscriptionProcessor(ServerStore server, DocumentDatabase database, SubscriptionConnection connection) : base(server, database, connection) { }
public async Task Try() { using (ContextPool.AllocateOperationContext(out DocumentsOperationContext context)) { var json = await context.ReadForMemoryAsync(RequestBodyStream(), null); var tryout = JsonDeserializationServer.SubscriptionTryout(json); var(collection, (script, functions), revisions) = SubscriptionConnection.ParseSubscriptionQuery(tryout.Query); SubscriptionPatchDocument patch = null; if (string.IsNullOrEmpty(script) == false) { patch = new SubscriptionPatchDocument(script, functions); } if (collection == null) { throw new ArgumentException("Collection must be specified"); } var pageSize = GetIntValueQueryString("pageSize") ?? 1; var state = new SubscriptionState { ChangeVectorForNextBatchStartingPoint = tryout.ChangeVector, Query = tryout.Query }; var fetcher = new SubscriptionDocumentsFetcher(Database, pageSize, -0x42, new IPEndPoint(HttpContext.Connection.RemoteIpAddress, HttpContext.Connection.RemotePort), collection, revisions, state, patch); if (Enum.TryParse( tryout.ChangeVector, out Constants.Documents.SubscriptionChangeVectorSpecialStates changeVectorSpecialValue)) { switch (changeVectorSpecialValue) { case Constants.Documents.SubscriptionChangeVectorSpecialStates.BeginningOfTime: case Constants.Documents.SubscriptionChangeVectorSpecialStates.DoNotChange: state.ChangeVectorForNextBatchStartingPoint = null; break; case Constants.Documents.SubscriptionChangeVectorSpecialStates.LastDocument: state.ChangeVectorForNextBatchStartingPoint = Database.DocumentsStorage.GetLastDocumentChangeVector(context, collection); break; } } using (var writer = new BlittableJsonTextWriter(context, ResponseBodyStream())) { writer.WriteStartObject(); writer.WritePropertyName("Results"); writer.WriteStartArray(); using (context.OpenReadTransaction()) { var first = true; foreach (var itemDetails in fetcher.GetDataToSend(context, 0)) { if (itemDetails.Doc.Data == null) { continue; } if (first == false) { writer.WriteComma(); } if (itemDetails.Exception == null) { writer.WriteDocument(context, itemDetails.Doc, metadataOnly: false); } else { var docWithExcepton = new DocumentWithException { Exception = itemDetails.Exception.ToString(), ChangeVector = itemDetails.Doc.ChangeVector, Id = itemDetails.Doc.Id, DocumentData = itemDetails.Doc.Data }; writer.WriteObject(context.ReadObject(docWithExcepton.ToJson(), "")); } first = false; } } writer.WriteEndArray(); writer.WriteEndObject(); } } }
// we should have two locks: one lock for a connection and one lock for operations // remember to catch ArgumentOutOfRangeException for timeout problems public async Task <IDisposable> RegisterSubscriptionConnection( SubscriptionConnection incomingConnection, TimeSpan timeToWait) { try { if (await ConnectionInUse.WaitAsync(timeToWait) == false) { switch (incomingConnection.Strategy) { // we try to connect, if the resource is occupied, we will throw an exception // this piece of code could have been upper, but we choose to have it here, for better readability case SubscriptionOpeningStrategy.WaitForFree: throw new TimeoutException(); case SubscriptionOpeningStrategy.OpenIfFree: throw new SubscriptionInUseException( $"Subscription {incomingConnection.SubscriptionId} is occupied, connection cannot be opened"); case SubscriptionOpeningStrategy.TakeOver: if (_currentConnection?.Strategy == SubscriptionOpeningStrategy.TakeOver) { throw new SubscriptionInUseException( $"Subscription {incomingConnection.SubscriptionId} is already occupied by a TakeOver connection, connection cannot be opened"); } if (_currentConnection != null) { _storage.DropSubscriptionConnection(_currentConnection.SubscriptionId, new SubscriptionInUseException("Closed by TakeOver")); } throw new TimeoutException(); default: throw new InvalidOperationException("Unknown subscription open strategy: " + incomingConnection.Strategy); } } } catch (SubscriptionException e) { RegisterRejectedConnection(incomingConnection, e); throw; } var subscriptionConnection = Interlocked.CompareExchange(ref _currentConnection, incomingConnection, null); if (subscriptionConnection != null && subscriptionConnection != incomingConnection) { throw new TimeoutException(); } ConnectionInUse.Reset(); return(new DisposableAction(() => { while (_recentConnections.Count > 10) { _recentConnections.TryDequeue(out SubscriptionConnection _); } _recentConnections.Enqueue(incomingConnection); Interlocked.CompareExchange(ref _currentConnection, null, incomingConnection); ConnectionInUse.Set(); })); }
public SubscriptionState(SubscriptionConnection currentConnection) { _currentConnection = currentConnection; _connectionInUse.Set(); }
public PutSubscriptionCommand(string databaseName, string query) : base(databaseName) { Query = query; // this verifies that the query is a valid subscription query SubscriptionConnection.ParseSubscriptionQuery(query); }
protected SubscriptionProcessor(ServerStore server, DocumentDatabase database, SubscriptionConnection connection) : base(server, database, connection) { Logger = LoggingSource.Instance.GetLogger <SubscriptionProcessor <T> >(Database.Name); }
// we should have two locks: one lock for a connection and one lock for operations // remember to catch ArgumentOutOfRangeException for timeout problems public async Task <IDisposable> RegisterSubscriptionConnection( SubscriptionConnection incomingConnection, int timeToWait) { try { if (await _connectionInUse.WaitAsync(TimeSpan.FromMilliseconds(timeToWait)) == false) { switch (incomingConnection.Strategy) { // we try to connect, if the resource is occupied, we will throw an exception // this piece of code could have been upper, but we choose to have it here, for better readability case SubscriptionOpeningStrategy.WaitForFree: throw new TimeoutException(); case SubscriptionOpeningStrategy.OpenIfFree: throw new SubscriptionInUseException( $"Subscription {incomingConnection.SubscriptionId} is occupied, connection cannot be opened"); case SubscriptionOpeningStrategy.TakeOver: if (_currentConnection?.Strategy == SubscriptionOpeningStrategy.ForceAndKeep) { throw new SubscriptionInUseException( $"Subscription {incomingConnection.SubscriptionId} is occupied by a ForceAndKeep connection, connectionId cannot be opened"); } if (_currentConnection != null) { _currentConnection.ConnectionException = new SubscriptionClosedException("Closed by Takeover"); } _currentConnection?.CancellationTokenSource.Cancel(); throw new TimeoutException(); case SubscriptionOpeningStrategy.ForceAndKeep: _currentConnection.ConnectionException = new SubscriptionClosedException("Closed by ForceAndKeep"); _currentConnection?.CancellationTokenSource.Cancel(); throw new TimeoutException(); default: throw new InvalidOperationException("Unknown subscription open strategy: " + incomingConnection.Strategy); } } } catch (SubscriptionException e) { RegisterRejectedConnection(incomingConnection, e); throw; } _connectionInUse.Reset(); _currentConnection = incomingConnection; return(new DisposableAction(() => { while (_recentConnections.Count > 10) { SubscriptionConnection options; _recentConnections.TryDequeue(out options); } _recentConnections.Enqueue(incomingConnection); _connectionInUse.SetByAsyncCompletion(); _currentConnection = null; })); }
public async Task Create() { using (ContextPool.AllocateOperationContext(out DocumentsOperationContext context)) using (context.OpenReadTransaction()) { var json = await context.ReadForMemoryAsync(RequestBodyStream(), null); var options = JsonDeserializationServer.SubscriptionCreationParams(json); if (TrafficWatchManager.HasRegisteredClients) { AddStringToHttpContext(json.ToString(), TrafficWatchChangeType.Subscriptions); } var sub = SubscriptionConnection.ParseSubscriptionQuery(options.Query); if (Enum.TryParse( options.ChangeVector, out Constants.Documents.SubscriptionChangeVectorSpecialStates changeVectorSpecialValue)) { switch (changeVectorSpecialValue) { case Constants.Documents.SubscriptionChangeVectorSpecialStates.BeginningOfTime: options.ChangeVector = null; break; case Constants.Documents.SubscriptionChangeVectorSpecialStates.LastDocument: options.ChangeVector = Database.DocumentsStorage.GetLastDocumentChangeVector(context.Transaction.InnerTransaction, context, sub.Collection); break; } } var id = GetLongQueryString("id", required: false); var disabled = GetBoolValueQueryString("disabled", required: false); var mentor = options.MentorNode; var subscriptionId = await Database.SubscriptionStorage.PutSubscription(options, GetRaftRequestIdFromQuery(), id, disabled, mentor : mentor); var name = options.Name ?? subscriptionId.ToString(); using (ServerStore.ContextPool.AllocateOperationContext(out TransactionOperationContext serverContext)) using (serverContext.OpenReadTransaction()) { // need to wait on the relevant remote node var node = Database.SubscriptionStorage.GetResponsibleNode(serverContext, name); if (node != null && node != ServerStore.NodeTag) { await WaitForExecutionOnSpecificNode(serverContext, ServerStore.GetClusterTopology(serverContext), node, subscriptionId); } } HttpContext.Response.StatusCode = (int)HttpStatusCode.Created; // Created using (var writer = new BlittableJsonTextWriter(context, ResponseBodyStream())) { context.Write(writer, new DynamicJsonValue { ["Name"] = name }); } } }
public async Task Try() { using (ContextPool.AllocateOperationContext(out DocumentsOperationContext context)) { BlittableJsonReaderObject json = await context.ReadForMemoryAsync(RequestBodyStream(), null); SubscriptionTryout tryout = JsonDeserializationServer.SubscriptionTryout(json); SubscriptionConnection.ParsedSubscription sub = SubscriptionConnection.ParseSubscriptionQuery(tryout.Query); SubscriptionPatchDocument patch = null; if (string.IsNullOrEmpty(sub.Script) == false) { patch = new SubscriptionPatchDocument(sub.Script, sub.Functions); } if (sub.Collection == null) { throw new ArgumentException("Collection must be specified"); } const int maxPageSize = 1024; var pageSize = GetIntValueQueryString("pageSize") ?? 1; if (pageSize > maxPageSize) { throw new ArgumentException($"Cannot gather more than {maxPageSize} results during tryouts, but requested number was {pageSize}."); } var state = new SubscriptionState { ChangeVectorForNextBatchStartingPoint = tryout.ChangeVector, Query = tryout.Query }; var fetcher = new SubscriptionDocumentsFetcher(Database, int.MaxValue, -0x42, new IPEndPoint(HttpContext.Connection.RemoteIpAddress, HttpContext.Connection.RemotePort), sub.Collection, sub.Revisions, state, patch); var includeCmd = new IncludeDocumentsCommand(Database.DocumentsStorage, context, sub.Includes, isProjection: patch != null); if (Enum.TryParse( tryout.ChangeVector, out Constants.Documents.SubscriptionChangeVectorSpecialStates changeVectorSpecialValue)) { switch (changeVectorSpecialValue) { case Constants.Documents.SubscriptionChangeVectorSpecialStates.BeginningOfTime: case Constants.Documents.SubscriptionChangeVectorSpecialStates.DoNotChange: state.ChangeVectorForNextBatchStartingPoint = null; break; case Constants.Documents.SubscriptionChangeVectorSpecialStates.LastDocument: using (context.OpenReadTransaction()) { state.ChangeVectorForNextBatchStartingPoint = Database.DocumentsStorage.GetLastDocumentChangeVector(context.Transaction.InnerTransaction, context, sub.Collection); } break; } } else { state.ChangeVectorForNextBatchStartingPoint = tryout.ChangeVector; } var changeVector = state.ChangeVectorForNextBatchStartingPoint.ToChangeVector(); var cv = changeVector.FirstOrDefault(x => x.DbId == Database.DbBase64Id); var sp = Stopwatch.StartNew(); var timeLimit = TimeSpan.FromSeconds(GetIntValueQueryString("timeLimit", false) ?? 15); var startEtag = cv.Etag; await using (var writer = new AsyncBlittableJsonTextWriter(context, ResponseBodyStream())) using (context.OpenReadTransaction()) { writer.WriteStartObject(); writer.WritePropertyName("Results"); writer.WriteStartArray(); var numberOfDocs = 0; while (numberOfDocs == 0 && sp.Elapsed < timeLimit) { var first = true; var lastEtag = startEtag; foreach (var itemDetails in fetcher.GetDataToSend(context, includeCmd, startEtag)) { if (itemDetails.Doc.Data != null) { using (itemDetails.Doc.Data) { includeCmd.Gather(itemDetails.Doc); if (first == false) { writer.WriteComma(); } if (itemDetails.Exception == null) { writer.WriteDocument(context, itemDetails.Doc, metadataOnly: false); } else { var documentWithException = new DocumentWithException { Exception = itemDetails.Exception.ToString(), ChangeVector = itemDetails.Doc.ChangeVector, Id = itemDetails.Doc.Id, DocumentData = itemDetails.Doc.Data }; writer.WriteObject(context.ReadObject(documentWithException.ToJson(), "")); } first = false; if (++numberOfDocs >= pageSize) { break; } } } if (sp.Elapsed >= timeLimit) { break; } lastEtag = itemDetails.Doc.Etag; } if (startEtag == lastEtag) { break; } startEtag = lastEtag; } writer.WriteEndArray(); writer.WriteComma(); writer.WritePropertyName("Includes"); var includes = new List <Document>(); includeCmd.Fill(includes); await writer.WriteIncludesAsync(context, includes); writer.WriteEndObject(); } } }
private void ListenToNewTcpConnection(TcpListener listener) { Task.Run(async() => { TcpClient tcpClient; try { tcpClient = await listener.AcceptTcpClientAsync(); } catch (ObjectDisposedException) { // shutting down return; } catch (Exception e) { if (_tcpLogger.IsInfoEnabled) { _tcpLogger.Info("Failed to accept new tcp connection", e); } return; } ListenToNewTcpConnection(listener); TcpConnectionOptions tcp = null; try { tcpClient.NoDelay = true; tcpClient.ReceiveBufferSize = 32 * 1024; tcpClient.SendBufferSize = 4096; var stream = tcpClient.GetStream(); tcp = new TcpConnectionOptions() { Stream = stream, TcpClient = tcpClient, DisposeOnConnectionClose = { stream, tcpClient } }; tcp.DisposeOnConnectionClose.Add( _tcpContextPool.AllocateOperationContext(out tcp.Context) ); tcp.MultiDocumentParser = tcp.Context.ParseMultiFrom(stream); try { TcpConnectionHeaderMessage header; using (var headerJson = await tcp.MultiDocumentParser.ParseToMemoryAsync()) { header = JsonDeserializationClient.TcpConnectionHeaderMessage(headerJson); if (_logger.IsInfoEnabled) { _logger.Info($"New {header.Operation} TCP connection to {header.DatabaseName} from {tcpClient.Client.RemoteEndPoint}"); } } tcp.Operation = header.Operation; var databaseLoadingTask = ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(header.DatabaseName); if (databaseLoadingTask == null) { ThrowNoSuchDatabase(header); return;// never hit } var databaseLoadTimeout = ServerStore.DatabasesLandlord.DatabaseLoadTimeout; if (databaseLoadingTask.IsCompleted == false) { var resultingTask = await Task.WhenAny(databaseLoadingTask, Task.Delay(databaseLoadTimeout)); if (resultingTask != databaseLoadingTask) { ThrowTimeoutOnDatbaseLoad(header); } } tcp.DocumentDatabase = await databaseLoadingTask; tcp.DocumentDatabase.RunningTcpConnections.Add(tcp); switch (header.Operation) { case TcpConnectionHeaderMessage.OperationTypes.BulkInsert: BulkInsertConnection.Run(tcp); break; case TcpConnectionHeaderMessage.OperationTypes.Subscription: SubscriptionConnection.SendSubscriptionDocuments(tcp); break; case TcpConnectionHeaderMessage.OperationTypes.Replication: var documentReplicationLoader = tcp.DocumentDatabase.DocumentReplicationLoader; documentReplicationLoader.AcceptIncomingConnection(tcp); break; default: throw new InvalidOperationException("Unknown operation for tcp " + header.Operation); } tcp = null; } catch (Exception e) { if (_tcpLogger.IsInfoEnabled) { _tcpLogger.Info("Failed to process TCP connection run", e); } if (tcp != null) { using (var errorWriter = new BlittableJsonTextWriter(tcp.Context, tcp.Stream)) { tcp.Context.Write(errorWriter, new DynamicJsonValue { ["Type"] = "Error", ["Exception"] = e.ToString() }); } } } } catch (Exception e) { if (_tcpLogger.IsInfoEnabled) { _tcpLogger.Info("Failure when processing tcp connection", e); } } finally { tcp?.Dispose(); } }); }