/// <summary> /// Gets the next connection and setup the event listener for the host and connection. /// Not thread-safe. /// </summary> private void SubscribeEventHandlers() { _host.Down += OnHostDown; _connection.CassandraEventResponse += OnConnectionCassandraEvent; //Register to events on the connection var registerTask = _connection.Send(new RegisterForEventRequest(CassandraEventTypes)); TaskHelper.WaitToComplete(registerTask, 10000); if (!(registerTask.Result is ReadyResponse)) { throw new DriverInternalError("Expected ReadyResponse, obtained " + registerTask.Result.GetType().Name); } }
private void DoFetchTrace() { try { TaskHelper.WaitToComplete(LoadAsync(), _metadataFetchSyncTimeout); } catch (Exception ex) { throw new TraceRetrievalException("Unexpected exception while fetching query trace", ex); } finally { _isDisconnected = false; } }
private Cluster(IEnumerable <object> contactPoints, Configuration configuration) { Configuration = configuration; _metadata = new Metadata(configuration); TaskHelper.WaitToComplete(AddHosts(contactPoints)); var protocolVersion = _maxProtocolVersion; if (Configuration.ProtocolOptions.MaxProtocolVersionValue != null && Configuration.ProtocolOptions.MaxProtocolVersionValue.Value.IsSupported()) { protocolVersion = Configuration.ProtocolOptions.MaxProtocolVersionValue.Value; } _controlConnection = new ControlConnection(protocolVersion, Configuration, _metadata); _metadata.ControlConnection = _controlConnection; _serializer = _controlConnection.Serializer; }
/// <summary> /// Updates the keyspace and token information /// </summary> public bool RefreshSchema(string keyspace = null, string table = null) { if (table == null) { //Refresh all the keyspaces and tables information return(TaskHelper.WaitToComplete(RefreshKeyspaces(true), Configuration.ClientOptions.QueryAbortTimeout)); } var ks = GetKeyspace(keyspace); if (ks == null) { return(false); } ks.ClearTableMetadata(table); return(true); }
/// <summary> /// Tries to create a connection to any of the contact points and retrieve cluster metadata for the first time. Not thread-safe. /// </summary> /// <exception cref="NoHostAvailableException" /> /// <exception cref="DriverInternalError" /> internal void Init() { _logger.Info("Trying to connect the ControlConnection"); TaskHelper.WaitToComplete(Connect(true), _config.SocketOptions.ConnectTimeoutMillis); try { SubscribeEventHandlers(); RefreshNodeList(); Metadata.RefreshKeyspaces(false); } catch (SocketException ex) { //There was a problem using the connection obtained //It is not usual but can happen _logger.Error("An error occurred when trying to retrieve the cluster metadata, retrying.", ex); //Retry one more time and throw if there is problem TaskHelper.WaitToComplete(Reconnect(), _config.SocketOptions.ConnectTimeoutMillis); } }
/// <summary> /// Waits until that the schema version in all nodes is the same or the waiting time passed. /// This method blocks the calling thread. /// </summary> internal bool WaitForSchemaAgreement(IConnection connection) { if (Hosts.Count == 1) { //If there is just one node, the schema is up to date in all nodes :) return(true); } var start = DateTime.Now; var waitSeconds = Configuration.ProtocolOptions.MaxSchemaAgreementWaitSeconds; Metadata.Logger.Info("Waiting for schema agreement"); try { var totalVersions = 0; while (DateTime.Now.Subtract(start).TotalSeconds < waitSeconds) { var schemaVersionLocalQuery = new QueryRequest(ControlConnection.ProtocolVersion, Metadata.SelectSchemaVersionLocal, false, QueryProtocolOptions.Default); var schemaVersionPeersQuery = new QueryRequest(ControlConnection.ProtocolVersion, Metadata.SelectSchemaVersionPeers, false, QueryProtocolOptions.Default); var queries = new[] { connection.Send(schemaVersionLocalQuery), connection.Send(schemaVersionPeersQuery) }; // ReSharper disable once CoVariantArrayConversion Task.WaitAll(queries, Configuration.ClientOptions.QueryAbortTimeout); if (Metadata.CheckSchemaVersionResults( Cassandra.ControlConnection.GetRowSet(queries[0].Result), Cassandra.ControlConnection.GetRowSet(queries[1].Result))) { return(true); } Thread.Sleep(500); } Metadata.Logger.Info($"Waited for schema agreement, still {totalVersions} schema versions in the cluster."); TaskHelper.WaitToComplete(RefreshPartitionMap(), Configuration.ClientOptions.QueryAbortTimeout); } catch (Exception ex) { //Exceptions are not fatal Metadata.Logger.Error("There was an exception while trying to retrieve schema versions", ex); } return(false); }
/// <summary> /// Starts the authentication flow /// </summary> /// <exception cref="AuthenticationException" /> private void Authenticate() { //Determine which authentication flow to use. //Check if its using a C* 1.2 with authentication patched version (like DSE 3.1) var isPatchedVersion = ProtocolVersion == 1 && !(Configuration.AuthProvider is NoneAuthProvider) && Configuration.AuthInfoProvider == null; if (ProtocolVersion >= 2 || isPatchedVersion) { //Use protocol v2+ authentication flow //NewAuthenticator will throw AuthenticationException when NoneAuthProvider var authenticator = Configuration.AuthProvider.NewAuthenticator(Address); var initialResponse = authenticator.InitialResponse() ?? new byte[0]; Authenticate(initialResponse, authenticator); } else { //Use protocol v1 authentication flow if (Configuration.AuthInfoProvider == null) { throw new AuthenticationException( String.Format("Host {0} requires authentication, but no credentials provided in Cluster configuration", Address), Address); } var credentialsProvider = Configuration.AuthInfoProvider; var credentials = credentialsProvider.GetAuthInfos(Address); var request = new CredentialsRequest(ProtocolVersion, credentials); var response = TaskHelper.WaitToComplete(this.Send(request), Configuration.SocketOptions.ConnectTimeoutMillis); //If Cassandra replied with a auth response error //The task already is faulted and the exception was already thrown. if (response is ReadyResponse) { return; } throw new ProtocolErrorException("Expected SASL response, obtained " + response.GetType().Name); } }
private Cluster(IEnumerable <object> contactPoints, Configuration configuration, IClusterLifecycleManager lifecycleManager) { Configuration = configuration; _metadata = new Metadata(configuration); TaskHelper.WaitToComplete(AddHosts(contactPoints)); var protocolVersion = _maxProtocolVersion; if (Configuration.ProtocolOptions.MaxProtocolVersionValue != null && Configuration.ProtocolOptions.MaxProtocolVersionValue.Value.IsSupported()) { protocolVersion = Configuration.ProtocolOptions.MaxProtocolVersionValue.Value; } _protocolEventDebouncer = new ProtocolEventDebouncer( configuration.TimerFactory, TimeSpan.FromMilliseconds(configuration.MetadataSyncOptions.RefreshSchemaDelayIncrement), TimeSpan.FromMilliseconds(configuration.MetadataSyncOptions.MaxTotalRefreshSchemaDelay)); _controlConnection = configuration.ControlConnectionFactory.Create(_protocolEventDebouncer, protocolVersion, Configuration, _metadata); _metadata.ControlConnection = _controlConnection; _serializer = _controlConnection.Serializer; _sessionFactory = configuration.SessionFactoryBuilder.BuildWithCluster(this); _lifecycleManager = lifecycleManager ?? new ClusterLifecycleManager(this); }
/// <summary> /// Uses the active connection to execute a query /// </summary> public RowSet Query(string cqlQuery, bool retry = false) { var request = new QueryRequest(_controlConnectionProtocolVersion, cqlQuery, false, QueryProtocolOptions.Default); var task = _connection.Send(request); try { TaskHelper.WaitToComplete(task, 10000); } catch (SocketException ex) { const string message = "There was an error while executing on the host {0} the query '{1}'"; _logger.Error(String.Format(message, cqlQuery, _connection.Address), ex); if (retry) { //Try to connect to another host Refresh(reconnect: true, throwExceptions: true); //Try to execute again without retry return(Query(cqlQuery, false)); } throw; } return(GetRowSet(task.Result)); }
/// <summary> /// Fills the common properties of the RowSet /// </summary> private RowSet FillRowSet(RowSet rs) { rs.Info.SetTriedHosts(_triedHosts.Keys.ToList()); if (_request is ICqlRequest) { rs.Info.SetAchievedConsistency(((ICqlRequest)_request).Consistency); } if (rs.PagingState != null && _request is IQueryRequest && typeof(T) == typeof(RowSet)) { rs.FetchNextPage = (pagingState) => { if (_session.IsDisposed) { _logger.Warning("Trying to page results using a Session already disposed."); return(new RowSet()); } ((IQueryRequest)_request).PagingState = pagingState; var task = new RequestHandler <RowSet>(_session, _request, _statement).Send(); TaskHelper.WaitToComplete(task, _session.Configuration.ClientOptions.QueryAbortTimeout); return((RowSet)(object)task.Result); }; } return(rs); }
/// <exception cref="AuthenticationException" /> private void Authenticate(byte[] token, IAuthenticator authenticator) { var request = new AuthResponseRequest(this.ProtocolVersion, token); var response = TaskHelper.WaitToComplete(this.Send(request), Configuration.SocketOptions.ConnectTimeoutMillis); if (response is AuthSuccessResponse) { //It is now authenticated return; } if (response is AuthChallengeResponse) { token = authenticator.EvaluateChallenge((response as AuthChallengeResponse).Token); if (token == null) { // If we get a null response, then authentication has completed //return without sending a further response back to the server. return; } Authenticate(token, authenticator); return; } throw new ProtocolErrorException("Expected SASL response, obtained " + response.GetType().Name); }
/// <summary> /// Gets the definition associated with a User Defined Type from Cassandra /// </summary> public UdtColumnInfo GetUdtDefinition(string keyspace, string typeName) { return(TaskHelper.WaitToComplete(GetUdtDefinitionAsync(keyspace, typeName), _queryAbortTimeout)); }
/// <summary> /// Updates the keyspace and token information /// </summary> public bool RefreshSchema(string keyspace = null, string table = null) { return(TaskHelper.WaitToComplete(RefreshSchemaAsync(keyspace, table), Configuration.DefaultRequestOptions.QueryAbortTimeout * 2)); }
/// <summary> /// Returns metadata of specified view in this keyspace. /// </summary> /// <param name="viewName">the name of view to retrieve </param> /// <returns>the metadata for view <c>viewName</c> in this keyspace if it /// exists, <c>null</c> otherwise.</returns> public MaterializedViewMetadata GetMaterializedViewMetadata(string viewName) { return(TaskHelper.WaitToComplete( GetMaterializedViewMetadataAsync(viewName), _parent.Configuration.DefaultRequestOptions.GetQueryAbortTimeout(2))); }
/// <summary> /// Returns metadata of specified table in this keyspace. /// </summary> /// <param name="tableName"> the name of table to retrieve </param> /// <returns>the metadata for table <c>tableName</c> in this keyspace if it /// exists, <c>null</c> otherwise.</returns> public TableMetadata GetTableMetadata(string tableName) { return(TaskHelper.WaitToComplete( GetTableMetadataAsync(tableName), _parent.Configuration.ClientOptions.GetQueryAbortTimeout(2))); }
/// <summary> /// Gets the definition of a User defined type /// </summary> internal UdtColumnInfo GetUdtDefinition(string typeName) { return(TaskHelper.WaitToComplete(GetUdtDefinitionAsync(typeName), _parent.Configuration.ClientOptions.QueryAbortTimeout)); }
/// <summary> /// Returns names of all tables defined in this keyspace. /// </summary> /// /// <returns>a collection of all, defined in this /// keyspace tables names.</returns> public ICollection <string> GetTablesNames() { return(TaskHelper.WaitToComplete(_parent.SchemaParser.GetTableNames(Name))); }
/// <summary> /// Add mapping definition(s) for UDTs, specifying how UDTs should be mapped to .NET types and vice versa. /// </summary> /// <exception cref="ArgumentException" /> public void Define(params UdtMap[] udtMaps) { TaskHelper.WaitToComplete(DefineAsync(udtMaps), _cluster.Configuration.ClientOptions.QueryAbortTimeout); }
internal Task <bool> Reconnect() { //If there is another thread reconnecting, use the same task var tcs = new TaskCompletionSource <bool>(); var currentTask = Interlocked.CompareExchange(ref _reconnectTask, tcs.Task, null); if (currentTask != null) { return(currentTask); } Unsubscribe(); Connect(false).ContinueWith(t => { if (Interlocked.Read(ref _isShutdown) > 0L) { if (t.Exception != null) { t.Exception.Handle(e => true); } return; } if (t.Exception != null) { t.Exception.Handle(e => true); Interlocked.Exchange(ref _reconnectTask, null); tcs.TrySetException(t.Exception.InnerException); var delay = _reconnectionSchedule.NextDelayMs(); _logger.Error("ControlConnection was not able to reconnect: " + t.Exception.InnerException); try { _reconnectionTimer.Change((int)delay, Timeout.Infinite); } catch (ObjectDisposedException) { //Control connection is being disposed } return; } try { RefreshNodeList(); TaskHelper.WaitToComplete(_metadata.RefreshKeyspaces(false), MetadataAbortTimeout); _reconnectionSchedule = _reconnectionPolicy.NewSchedule(); tcs.TrySetResult(true); Interlocked.Exchange(ref _reconnectTask, null); _logger.Info("ControlConnection reconnected to host {0}", _host.Address); } catch (Exception ex) { Interlocked.Exchange(ref _reconnectTask, null); _logger.Error("There was an error when trying to refresh the ControlConnection", ex); tcs.TrySetException(ex); try { _reconnectionTimer.Change((int)_reconnectionSchedule.NextDelayMs(), Timeout.Infinite); } catch (ObjectDisposedException) { //Control connection is being disposed } } }); return(tcs.Task); }
/// <summary> /// Returns TableMetadata for specified table in specified keyspace. /// </summary> /// <param name="keyspace">name of the keyspace within specified table is defined.</param> /// <param name="tableName">name of table for which metadata should be returned.</param> /// <returns>a TableMetadata for the specified table in the specified keyspace.</returns> public TableMetadata GetTable(string keyspace, string tableName) { return(TaskHelper.WaitToComplete(GetTableAsync(keyspace, tableName), _queryAbortTimeout * 2)); }
/// <summary> /// Gets a CQL function by name and signature /// </summary> /// <returns>The function metadata or null if not found.</returns> public FunctionMetadata GetFunction(string functionName, string[] signature) { return(TaskHelper.WaitToComplete( GetFunctionAsync(functionName, signature), _parent.Configuration.DefaultRequestOptions.QueryAbortTimeout)); }
internal async Task <bool> Reconnect() { var tcs = new TaskCompletionSource <bool>(); var currentTask = Interlocked.CompareExchange(ref _reconnectTask, tcs.Task, null); if (currentTask != null) { // If there is another thread reconnecting, use the same task return(await currentTask.ConfigureAwait(false)); } Unsubscribe(); try { await Connect(false).ConfigureAwait(false); } catch (Exception ex) { // It failed to reconnect, schedule the timer for next reconnection and let go. Interlocked.Exchange(ref _reconnectTask, null).Forget(); tcs.TrySetException(ex); var delay = _reconnectionSchedule.NextDelayMs(); _logger.Error("ControlConnection was not able to reconnect: " + ex); try { _reconnectionTimer.Change((int)delay, Timeout.Infinite); } catch (ObjectDisposedException) { //Control connection is being disposed } // It will throw the same exception that it was set in the TCS throw; } if (Interlocked.Read(ref _isShutdown) > 0L) { return(false); } try { await RefreshNodeList().ConfigureAwait(false); TaskHelper.WaitToComplete(_metadata.RefreshKeyspaces(false), MetadataAbortTimeout); _reconnectionSchedule = _reconnectionPolicy.NewSchedule(); tcs.TrySetResult(true); Interlocked.Exchange(ref _reconnectTask, null).Forget(); _logger.Info("ControlConnection reconnected to host {0}", _host.Address); } catch (Exception ex) { Interlocked.Exchange(ref _reconnectTask, null).Forget(); _logger.Error("There was an error when trying to refresh the ControlConnection", ex); tcs.TrySetException(ex); try { _reconnectionTimer.Change((int)_reconnectionSchedule.NextDelayMs(), Timeout.Infinite); } catch (ObjectDisposedException) { //Control connection is being disposed } } return(await tcs.Task.ConfigureAwait(false)); }
/// <summary> /// Creates a new session on this cluster and using a keyspace an existing keyspace. /// </summary> /// <param name="keyspace">Case-sensitive keyspace name to use</param> public ISession Connect(string keyspace) { return(TaskHelper.WaitToComplete(ConnectAsync(keyspace))); }
/// <summary> /// Uses the active connection to execute a query /// </summary> public IEnumerable <Row> Query(string cqlQuery, bool retry = false) { return(TaskHelper.WaitToComplete(QueryAsync(cqlQuery, retry), MetadataAbortTimeout)); }
/// <summary> /// Gets the definition of a User defined type /// </summary> internal UdtColumnInfo GetUdtDefinition(string typeName) { return(TaskHelper.WaitToComplete(GetUdtDefinitionAsync(typeName), ControlConnection.MetadataAbortTimeout)); }
/// <summary> /// Gets a CQL aggregate by name and signature /// </summary> /// <returns>The aggregate metadata or null if not found.</returns> public AggregateMetadata GetAggregate(string aggregateName, string[] signature) { return(TaskHelper.WaitToComplete( GetAggregateAsync(aggregateName, signature), _parent.Configuration.DefaultRequestOptions.QueryAbortTimeout)); }