/// <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 void WaitForSchemaAgreement(Connection connection) { if (Hosts.Count == 1) { //If there is just one node, the schema is up to date in all nodes :) return; } var start = DateTime.Now; var waitSeconds = _config.ProtocolOptions.MaxSchemaAgreementWaitSeconds; Logger.Info("Waiting for schema agreement"); try { var totalVersions = 0; while (DateTime.Now.Subtract(start).TotalSeconds < waitSeconds) { var schemaVersionLocalQuery = new QueryRequest(connection.ProtocolVersion, SelectSchemaVersionLocal, false, QueryProtocolOptions.Default); var schemaVersionPeersQuery = new QueryRequest(connection.ProtocolVersion, SelectSchemaVersionPeers, false, QueryProtocolOptions.Default); var queries = new [] { connection.Send(schemaVersionLocalQuery), connection.Send(schemaVersionPeersQuery) }; // ReSharper disable once CoVariantArrayConversion Task.WaitAll(queries, _config.ClientOptions.QueryAbortTimeout); var versions = new HashSet<Guid> { ControlConnection.GetRowSet(queries[0].Result).First().GetValue<Guid>("schema_version") }; var peerVersions = ControlConnection.GetRowSet(queries[1].Result).Select(r => r.GetValue<Guid>("schema_version")); foreach (var v in peerVersions) { versions.Add(v); } totalVersions = versions.Count; if (versions.Count == 1) { return; } Thread.Sleep(500); } Logger.Info(String.Format("Waited for schema agreement, still {0} schema versions in the cluster.", totalVersions)); } catch (Exception ex) { //Exceptions are not fatal Logger.Error("There was an exception while trying to retrieve schema versions", ex); } }
/// <summary> /// Sets the keyspace of the connection. /// If the keyspace is different from the current value, it sends a Query request to change it /// </summary> public Task <bool> SetKeyspace(string value) { if (String.IsNullOrEmpty(value) || _keyspace == value) { //No need to switch return(TaskHelper.Completed); } Task <bool> keyspaceSwitch; try { if (!_keyspaceSwitchSemaphore.Wait(0)) { //Could not enter semaphore //It is very likely that the connection is already switching keyspace keyspaceSwitch = _keyspaceSwitchTask; if (keyspaceSwitch != null) { return(keyspaceSwitch.Then(_ => { //validate if the new keyspace is the expected if (_keyspace != value) { //multiple concurrent switches to different keyspace return SetKeyspace(value); } return TaskHelper.Completed; })); } _keyspaceSwitchSemaphore.Wait(); } } catch (ObjectDisposedException) { //The semaphore was disposed, this connection is closed return(TaskHelper.FromException <bool>(new SocketException((int)SocketError.NotConnected))); } //Semaphore entered if (_keyspace == value) { //While waiting to enter the semaphore, the connection switched keyspace try { _keyspaceSwitchSemaphore.Release(); } catch (ObjectDisposedException) { //this connection is now closed but the switch completed successfully } return(TaskHelper.Completed); } var request = new QueryRequest(_serializer.ProtocolVersion, string.Format("USE \"{0}\"", value), false, QueryProtocolOptions.Default); Logger.Info("Connection to host {0} switching to keyspace {1}", Address, value); keyspaceSwitch = _keyspaceSwitchTask = Send(request).ContinueSync(r => { _keyspace = value; try { _keyspaceSwitchSemaphore.Release(); } catch (ObjectDisposedException) { //this connection is now closed but the switch completed successfully } _keyspaceSwitchTask = null; return(true); }); return(keyspaceSwitch); }
private RowSet Query(string cqlQuery) { var request = new QueryRequest(ControlConnectionProtocolVersion, cqlQuery, false, QueryProtocolOptions.Default); var task = _activeConnection.Value.Send(request); TaskHelper.WaitToComplete(task, 10000); if (!(task.Result is ResultResponse) && !(((ResultResponse)task.Result).Output is OutputRows)) { throw new DriverInternalError("Expected rows " + task.Result); } return ((task.Result as ResultResponse).Output as OutputRows).RowSet; }
/// <summary> /// Uses the active connection to execute a query /// </summary> public RowSet Query(string cqlQuery, bool retry = false) { var request = new QueryRequest(ProtocolVersion, 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> /// Gets the Request to send to a cassandra node based on the statement type /// </summary> internal IRequest GetRequest(IStatement statement) { ICqlRequest request = null; if (statement is RegularStatement) { var s = (RegularStatement)statement; s.ProtocolVersion = BinaryProtocolVersion; var options = QueryProtocolOptions.CreateFromQuery(s, Configuration.QueryOptions); options.ValueNames = s.QueryValueNames; request = new QueryRequest(BinaryProtocolVersion, s.QueryString, s.IsTracing, options); } if (statement is BoundStatement) { var s = (BoundStatement)statement; var options = QueryProtocolOptions.CreateFromQuery(s, Configuration.QueryOptions); request = new ExecuteRequest(BinaryProtocolVersion, s.PreparedStatement.Id, null, s.IsTracing, options); } if (statement is BatchStatement) { var s = (BatchStatement)statement; s.ProtocolVersion = BinaryProtocolVersion; var consistency = Configuration.QueryOptions.GetConsistencyLevel(); if (s.ConsistencyLevel != null) { consistency = s.ConsistencyLevel.Value; } request = new BatchRequest(BinaryProtocolVersion, s, consistency); } if (request == null) { throw new NotSupportedException("Statement of type " + statement.GetType().FullName + " not supported"); } //Set the outgoing payload for the request request.Payload = statement.OutgoingPayload; return request; }
/// <summary> /// Sets the keyspace of the connection. /// If the keyspace is different from the current value, it sends a Query request to change it /// </summary> public Task<bool> SetKeyspace(string value) { if (String.IsNullOrEmpty(value) || _keyspace == value) { //No need to switch return TaskHelper.Completed; } Task<bool> keyspaceSwitch; try { if (!_keyspaceSwitchSemaphore.Wait(0)) { //Could not enter semaphore //It is very likely that the connection is already switching keyspace keyspaceSwitch = _keyspaceSwitchTask; if (keyspaceSwitch != null) { return keyspaceSwitch.Then(_ => { //validate if the new keyspace is the expected if (_keyspace != value) { //multiple concurrent switches to different keyspace return SetKeyspace(value); } return TaskHelper.Completed; }); } _keyspaceSwitchSemaphore.Wait(); } } catch (ObjectDisposedException) { //The semaphore was disposed, this connection is closed return TaskHelper.FromException<bool>(new SocketException((int) SocketError.NotConnected)); } //Semaphore entered if (_keyspace == value) { //While waiting to enter the semaphore, the connection switched keyspace try { _keyspaceSwitchSemaphore.Release(); } catch (ObjectDisposedException) { //this connection is now closed but the switch completed successfully } return TaskHelper.Completed; } var request = new QueryRequest(ProtocolVersion, string.Format("USE \"{0}\"", value), false, QueryProtocolOptions.Default); _logger.Info("Connection to host {0} switching to keyspace {1}", Address, value); keyspaceSwitch = _keyspaceSwitchTask = Send(request).ContinueSync(r => { _keyspace = value; try { _keyspaceSwitchSemaphore.Release(); } catch (ObjectDisposedException) { //this connection is now closed but the switch completed successfully } _keyspaceSwitchTask = null; return true; }); return keyspaceSwitch; }
/// <summary> /// Gets executed once the idle timeout has passed /// </summary> private void IdleTimeoutHandler(object state) { //Ensure there are no more idle timeouts until the query finished sending if (_isCanceled) { if (!IsDisposed) { //If it was not manually disposed _logger.Warning("Can not issue an heartbeat request as connection is closed"); if (OnIdleRequestException != null) { OnIdleRequestException(new SocketException((int)SocketError.NotConnected)); } } return; } _logger.Verbose("Connection idling, issuing a Request to prevent idle disconnects"); var request = new QueryRequest(ProtocolVersion, IdleQuery, false, QueryProtocolOptions.Default); Send(request, (ex, response) => { if (ex == null) { //The send succeeded //There is a valid response but we don't care about the response return; } _logger.Warning("Received heartbeat request exception " + ex.ToString()); if (ex is SocketException && OnIdleRequestException != null) { OnIdleRequestException(ex); } }); }