/// <summary> /// Returns the hosts to use for a new query. <p> The returned plan will first /// return replicas (whose <code>HostDistance</code> for the child policy is /// <code>Local</code>) for the query if it can determine them (i.e. mainly if /// <code>query.getRoutingKey()</code> is not <code>null</code>). Following what /// it will return the plan of the child policy.</p> /// </summary> /// <param name="query"> the query for which to build the plan. </param> /// /// <returns>the new query plan.</returns> public IEnumerable<Host> NewQueryPlan(Query query) { var routingKey = query.RoutingKey; if (routingKey == null) { foreach (var iter in _childPolicy.NewQueryPlan(null)) yield return iter; yield break; } var replicas = _cluster.Metadata.GetReplicas(routingKey.RawRoutingKey); if (replicas.Count == 0) { foreach (var iter in _childPolicy.NewQueryPlan(query)) yield return iter; yield break; } var iterator = replicas.GetEnumerator(); while (iterator.MoveNext()) { var host = _cluster.Metadata.GetHost(iterator.Current); if (host != null && host.IsConsiderablyUp && _childPolicy.Distance(host) == HostDistance.Local) yield return host; } foreach (var host in _childPolicy.NewQueryPlan(query)) { if (!replicas.Contains(host.Address) || _childPolicy.Distance(host) != HostDistance.Local) yield return host; } }
public IEnumerable<Host> NewQueryPlan(Query query) { var schedule = _reconnectionPolicy.NewSchedule(); while (true) { List<Host> copyOfHosts = new List<Host>(_cluster.Metadata.AllHosts()); for (int i = 0; i < copyOfHosts.Count; i++) { if (_startidx == -1 || _startidx >= copyOfHosts.Count - 1) _startidx = StaticRandom.Instance.Next(copyOfHosts.Count); var h = copyOfHosts[_startidx]; if (h.IsConsiderablyUp) yield return h; _startidx++; _startidx = _startidx % copyOfHosts.Count; } if (ReconnectionEvent != null) { var ea = new RoundRobinPolicyWithReconnectionRetriesEventArgs(schedule.NextDelayMs()); ReconnectionEvent(this, ea); if (ea.Cancel) break; } else Thread.Sleep((int)schedule.NextDelayMs()); } }
public RetryDecision onWriteTimeout(Query query, ConsistencyLevel cl, String writeType, int requiredAcks, int receivedAcks, int nbRetry) { int hour = DateTime.Now.Hour; if (hour >= nonRetryStartHour && hour <= nonRetryEndHour) { return RetryDecision.Rethrow(); } return policy.OnWriteTimeout(query, cl, writeType, requiredAcks, receivedAcks, nbRetry); }
public RetryDecision onUnavailable(Query query, ConsistencyLevel cl, int requiredReplica, int aliveReplica, int nbRetry) { int hour = DateTime.Now.Hour; if (hour >= nonRetryStartHour && hour <= nonRetryEndHour) { return RetryDecision.Rethrow(); } return policy.OnUnavailable(query, cl, requiredReplica, aliveReplica, nbRetry); }
public RetryDecision onReadTimeout(Query query, ConsistencyLevel cl, int requiredResponses, int receivedResponses, Boolean dataRetrieved, int nbRetry) { int hour = DateTime.Now.Hour; if (hour >= nonRetryStartHour && hour <= nonRetryEndHour) { return RetryDecision.Rethrow(); } return policy.OnReadTimeout(query, cl, requiredResponses, receivedResponses, dataRetrieved, nbRetry); }
public RetryDecision OnWriteTimeout(Query query, ConsistencyLevel cl, string writeType, int requiredAcks, int receivedAcks, int nbRetry) { RetryDecision decision = _policy.OnWriteTimeout(query,cl, writeType, requiredAcks, receivedAcks, nbRetry); switch (decision.DecisionType) { case RetryDecision.RetryDecisionType.Ignore: _logger.Info(string.Format("Ignoring write timeout (initial consistency: {0}, write type: {1} required acknowledgments: {2}, received acknowledgments: {3}, retries: {4})", cl, writeType, requiredAcks, receivedAcks, nbRetry)); break; case RetryDecision.RetryDecisionType.Retry: _logger.Info(string.Format("Retrying on write timeout at consistency {0}(initial consistency: {1}, write type: {2}, required acknowledgments: {3}, received acknowledgments: {4}, retries: {5})", CL(cl, decision), cl, writeType, requiredAcks, receivedAcks, nbRetry)); break; } return decision; }
public RetryDecision OnUnavailable(Query query, ConsistencyLevel cl, int requiredReplica, int aliveReplica, int nbRetry) { RetryDecision decision = _policy.OnUnavailable(query,cl, requiredReplica, aliveReplica, nbRetry); switch (decision.DecisionType) { case RetryDecision.RetryDecisionType.Ignore: _logger.Info(string.Format("Ignoring unavailable exception (initial consistency: {0}, required replica: {1}, alive replica: {2}, retries: {3})", cl, requiredReplica, aliveReplica, nbRetry)); break; case RetryDecision.RetryDecisionType.Retry: _logger.Info(string.Format("Retrying on unavailable exception at consistency {0} (initial consistency: {1}, required replica: {2}, alive replica: {3}, retries: {4})", CL(cl, decision), cl, requiredReplica, aliveReplica, nbRetry)); break; } return decision; }
public RetryDecision OnReadTimeout(Query query, ConsistencyLevel cl, int requiredResponses, int receivedResponses, bool dataRetrieved, int nbRetry) { RetryDecision decision = _policy.OnReadTimeout(query, cl, requiredResponses, receivedResponses, dataRetrieved, nbRetry); switch (decision.DecisionType) { case RetryDecision.RetryDecisionType.Ignore: _logger.Info(string.Format("Ignoring read timeout (initial consistency: {0}, required responses: {1}, received responses: {2}, data retrieved: {3}, retries: {4})",cl, requiredResponses, receivedResponses, dataRetrieved, nbRetry)); break; case RetryDecision.RetryDecisionType.Retry: _logger.Info(string.Format("Retrying on read timeout at consistency {0} (initial consistency: {1}, required responses: {2}, received responses: {3}, data retrieved: {4}, retries: {5})", CL(cl, decision), cl, requiredResponses, receivedResponses, dataRetrieved, nbRetry)); break; } return decision; }
/// <summary> /// Returns the hosts to use for a new query. <p> The returned plan will try each /// known host of the cluster. Upon each call to this method, the ith host of the /// plans returned will cycle over all the host of the cluster in a round-robin /// fashion.</p> /// </summary> /// <param name="query"> the query for which to build the plan. </param> /// /// <returns>a new query plan, i.e. an iterator indicating which host to try /// first for querying, which one to use as failover, etc...</returns> public IEnumerable<Host> NewQueryPlan(Query query) { List<Host> copyOfHosts = new List<Host>(_cluster.Metadata.AllHosts()); for (int i = 0; i < copyOfHosts.Count; i++) { if (_startidx == -1 || _startidx >= copyOfHosts.Count - 1) _startidx = StaticRandom.Instance.Next(copyOfHosts.Count - 1); var h = copyOfHosts[_startidx]; if (h.IsConsiderablyUp) yield return h; _startidx++; _startidx = _startidx % copyOfHosts.Count; } }
public IEnumerable<Host> NewQueryPlan(Query query) { var schedule = _reconnectionPolicy.NewSchedule(); while (true) { var childQueryPlan = _loadBalancingPolicy.NewQueryPlan(query); foreach (var host in childQueryPlan) yield return host; if (ReconnectionEvent != null) { var ea = new RetryLoadBalancingPolicyEventArgs(schedule.NextDelayMs()); ReconnectionEvent(this, ea); if (ea.Cancel) break; } else Thread.Sleep((int)schedule.NextDelayMs()); } }
static RetryDecision GetRetryDecision(Query query, QueryValidationException exc, IRetryPolicy policy, int queryRetries) { if (exc is OverloadedException) return RetryDecision.Retry(null); else if (exc is IsBootstrappingException) return RetryDecision.Retry(null); else if (exc is TruncateException) return RetryDecision.Retry(null); else if (exc is ReadTimeoutException) { var e = exc as ReadTimeoutException; return policy.OnReadTimeout(query, e.ConsistencyLevel, e.RequiredAcknowledgements, e.ReceivedAcknowledgements, e.WasDataRetrieved, queryRetries); } else if (exc is WriteTimeoutException) { var e = exc as WriteTimeoutException; return policy.OnWriteTimeout(query, e.ConsistencyLevel, e.WriteType, e.RequiredAcknowledgements, e.ReceivedAcknowledgements, queryRetries); } else if (exc is UnavailableException) { var e = exc as UnavailableException; return policy.OnUnavailable(query, e.Consistency, e.RequiredReplicas, e.AliveReplicas, queryRetries); } else if (exc is AlreadyExistsException) return RetryDecision.Rethrow(); else if (exc is InvalidConfigurationInQueryException) return RetryDecision.Rethrow(); else if (exc is PreparedQueryNotFoundException) return RetryDecision.Rethrow(); else if (exc is ProtocolErrorException) return RetryDecision.Rethrow(); else if (exc is InvalidQueryException) return RetryDecision.Rethrow(); else if (exc is UnauthorizedException) return RetryDecision.Rethrow(); else if (exc is SyntaxError) return RetryDecision.Rethrow(); else if (exc is ServerErrorException) return null; else return null; }
internal RowSet Query(string cqlQuery, ConsistencyLevel consistency = ConsistencyLevel.Default, bool isTracing = false, Query query = null) { return EndQuery(BeginQuery(cqlQuery, null, null, consistency,isTracing, query)); }
internal RowSet ExecuteQuery(byte[] id, RowSetMetadata metadata, object[] values, ConsistencyLevel consistency = ConsistencyLevel.Default, Query query = null, bool isTracing=false) { var ar = BeginExecuteQuery(id,metadata,values, null, null, consistency, query, isTracing); return EndExecuteQuery(ar); }
internal IAsyncResult BeginQuery(string cqlQuery, AsyncCallback callback, object state, ConsistencyLevel consistency = ConsistencyLevel.Default, bool isTracing=false, Query query = null, object sender = null, object tag = null) { var longActionAc = new AsyncResult<RowSet>(-1, callback, state, this, "SessionQuery", sender, tag); var token = new LongQueryToken() { Consistency = consistency, CqlQuery = cqlQuery, Query = query, LongActionAc = longActionAc, IsTracing = isTracing }; ExecConn(token, false); return longActionAc; }
internal IAsyncResult BeginSetKeyspace(string cqlQuery, AsyncCallback callback, object state, ConsistencyLevel consistency = ConsistencyLevel.Default, Query query = null) { var longActionAc = new AsyncResult<string>(callback, state, this, "SessionSetKeyspace", null, null,_clientOptions.AsyncCallAbortTimeout); var token = new LongSetKeyspaceToken() { Consistency = consistency, CqlQuery = cqlQuery, Query = query, LongActionAc = longActionAc }; ExecConn(token, false); return longActionAc; }
/// <summary> /// Returns the hosts to use for a new query. <p> The returned plan will always /// try each known host in the local datacenter first, and then, if none of the /// local host is reacheable, will try up to a configurable number of other host /// per remote datacenter. The order of the local node in the returned query plan /// will follow a Round-robin algorithm.</p> /// </summary> /// <param name="query"> the query for which to build the plan. </param> /// <returns>a new query plan, i.e. an iterator indicating which host to try /// first for querying, which one to use as failover, etc...</returns> public IEnumerable<Host> NewQueryPlan(Query query) { foreach (var h in _cluster.Metadata.AllHosts()) { if (_localDc.Equals(DC(h))) { if (h.IsConsiderablyUp) yield return h; } } var ixes = new Dictionary<string, int>(); foreach (var h in _cluster.Metadata.AllHosts()) { if (!_localDc.Equals(DC(h))) { if (h.IsConsiderablyUp && (!ixes.ContainsKey(DC(h)) || ixes[DC(h)] < _usedHostsPerRemoteDc)) { yield return h; if (!ixes.ContainsKey(DC(h))) ixes.Add(DC(h), 1); else ixes[DC(h)] = ixes[DC(h)] + 1; } } } }
internal CassandraConnection Connect(Query query, IEnumerator<Host> hostsIter, List<IPAddress> triedHosts, Dictionary<IPAddress, List<Exception>> innerExceptions) { CheckDisposed(); lock (_trashcan) { foreach (var conn in _trashcan) { if (conn.IsEmpty()) { _logger.Error("Connection trashed"); conn.Dispose(); } } } lock (_connectionPool) { while (true) { var currentHost = hostsIter.Current; if (currentHost == null) { var ex = new NoHostAvailableException(innerExceptions); _logger.Error("All hosts are not responding.", ex); throw ex; } if (currentHost.IsConsiderablyUp) { triedHosts.Add(currentHost.Address); var hostDistance = _policies.LoadBalancingPolicy.Distance(currentHost); if (!_connectionPool.ContainsKey(currentHost.Address)) _connectionPool.Add(currentHost.Address, new List<CassandraConnection>()); var pool = _connectionPool[currentHost.Address]; var poolCpy = new List<CassandraConnection>(pool); CassandraConnection toReturn = null; foreach (var conn in poolCpy) { if (!conn.IsHealthy) { pool.Remove(conn); conn.Dispose(); } else { if (toReturn == null) { if (!conn.IsBusy(_poolingOptions.GetMaxSimultaneousRequestsPerConnectionTreshold(hostDistance))) toReturn = conn; } else { if (pool.Count > _poolingOptions.GetCoreConnectionsPerHost(hostDistance)) { if (conn.IsFree(_poolingOptions.GetMinSimultaneousRequestsPerConnectionTreshold(hostDistance))) { lock (_trashcan) _trashcan.Add(conn); pool.Remove(conn); } } } } } if (toReturn != null) return toReturn; if (pool.Count < _poolingOptions.GetMaxConnectionPerHost(hostDistance) - 1) { bool error = false; CassandraConnection conn = null; do { Exception outExc; conn = AllocateConnection(currentHost.Address, out outExc); if (conn != null) { if (_cluster.Metadata != null) _cluster.Metadata.BringUpHost(currentHost.Address, this); pool.Add(conn); } else { if (!innerExceptions.ContainsKey(currentHost.Address)) innerExceptions.Add(currentHost.Address, new List<Exception>()); innerExceptions[currentHost.Address].Add(outExc); _logger.Info("New connection attempt failed - goto another host."); error = true; break; } } while (pool.Count < _poolingOptions.GetCoreConnectionsPerHost(hostDistance)); if (!error) return conn; } } if (!hostsIter.MoveNext()) { var ex = new NoHostAvailableException(innerExceptions); _logger.Error("Cannot connect to any host from pool.", ex); throw ex; } } } }
public IAsyncResult BeginExecute(Query query, AsyncCallback callback, object state) { return query.BeginSessionExecute(this, null, callback, state); }
internal CassandraConnection Connect(Query query, IEnumerator<Host> hostsIter, List<IPAddress> triedHosts, Dictionary<IPAddress, List<Exception>> innerExceptions, out int streamId) { CheckDisposed(); while (true) { var currentHost = hostsIter.Current; if (currentHost == null) { var ex = new NoHostAvailableException(innerExceptions); _logger.Error("All hosts are not responding.", ex); throw ex; } if (currentHost.IsConsiderablyUp) { triedHosts.Add(currentHost.Address); var hostDistance = _policies.LoadBalancingPolicy.Distance(currentHost); RETRY_GET_POOL: if (!_connectionPool.ContainsKey(currentHost.Address)) _connectionPool.TryAdd(currentHost.Address, new ConcurrentDictionary<Guid, CassandraConnection>()); ConcurrentDictionary<Guid, CassandraConnection> pool; if (!_connectionPool.TryGetValue(currentHost.Address, out pool)) goto RETRY_GET_POOL; // CassandraCounters.SetConnectionsCount(currentHost.Address, pool.Count); foreach (var kv in pool) { CassandraConnection conn = kv.Value; if (!conn.IsHealthy) { CassandraConnection cc; if(pool.TryRemove(conn.Guid, out cc)) FreeConnection(cc); } else { if (!conn.IsBusy(_poolingOptions.GetMaxSimultaneousRequestsPerConnectionTreshold(hostDistance))) { streamId = conn.AllocateStreamId(); return conn; } else { if (pool.Count > _poolingOptions.GetCoreConnectionsPerHost(hostDistance)) { if (conn.IsFree(_poolingOptions.GetMinSimultaneousRequestsPerConnectionTreshold(hostDistance))) { CassandraConnection cc; if (pool.TryRemove(conn.Guid, out cc)) TrashcanPut(cc); } } } } } { var conn = TrashcanRecycle(currentHost.Address); if (conn != null) { if (!conn.IsHealthy) FreeConnection(conn); else { pool.TryAdd(conn.Guid, conn); streamId = conn.AllocateStreamId(); return conn; } } // if not recycled { Exception outExc; conn = AllocateConnection(currentHost.Address, hostDistance, out outExc); if (conn != null) { if (_cluster.Metadata != null) _cluster.Metadata.BringUpHost(currentHost.Address, this); pool.TryAdd(conn.Guid, conn); streamId = conn.AllocateStreamId(); return conn; } else { if (!innerExceptions.ContainsKey(currentHost.Address)) innerExceptions.Add(currentHost.Address, new List<Exception>()); innerExceptions[currentHost.Address].Add(outExc); _logger.Info("New connection attempt failed - goto another host."); } } } } _logger.Verbose(string.Format("Currently tried host: {0} have all of connections busy. Switching to the next host.", currentHost.Address)); if (!hostsIter.MoveNext()) { var ex = new NoHostAvailableException(innerExceptions); _logger.Error("Cannot connect to any host from pool.", ex); throw ex; } } }
/// <summary> /// Returns the hosts to use for a new query. <p> The returned plan will try each /// known host of the cluster. Upon each call to this method, the ith host of the /// plans returned will cycle over all the host of the cluster in a round-robin /// fashion.</p> /// </summary> /// <param name="query"> the query for which to build the plan. </param> /// /// <returns>a new query plan, i.e. an iterator indicating which host to try /// first for querying, which one to use as failover, etc...</returns> public IEnumerable<Host> NewQueryPlan(Query query) { int startidx = Interlocked.Increment(ref _index); // Overflow protection; not theoretically thread safe but should be good enough if (startidx > int.MaxValue - 10000) Thread.VolatileWrite(ref _index, 0); var copyOfHosts = (from h in _cluster.Metadata.AllHosts() where h.IsConsiderablyUp select h).ToArray(); for (int i = 0; i < copyOfHosts.Length; i++) { startidx %= copyOfHosts.Length; var h = copyOfHosts[startidx]; startidx++; if (h.IsConsiderablyUp) yield return h; } }
/// <summary> /// Returns the hosts to use for a new query. <p> The returned plan will try each /// known host of the cluster. Upon each call to this method, the ith host of the /// plans returned will cycle over all the host of the cluster in a round-robin /// fashion.</p> /// </summary> /// <param name="query"> the query for which to build the plan. </param> /// /// <returns>a new query plan, i.e. an iterator indicating which host to try /// first for querying, which one to use as failover, etc...</returns> public IEnumerable<Host> NewQueryPlan(Query query) { List<Host> copyOfHosts = new List<Host>(_cluster.Metadata.AllHosts()); for (int i = 0; i < copyOfHosts.Count; i++) { int startidx = Interlocked.Increment(ref _index); // Overflow protection; not theoretically thread safe but should be good enough if (startidx > int.MaxValue - 10000) Thread.VolatileWrite(ref _index, 0); startidx %= copyOfHosts.Count; var h = copyOfHosts[startidx]; startidx++; if (h.IsConsiderablyUp) yield return h; } }
/// <summary> /// Returns the hosts to use for a new query. <p> The returned plan will always /// try each known host in the local datacenter first, and then, if none of the /// local host is reacheable, will try up to a configurable number of other host /// per remote datacenter. The order of the local node in the returned query plan /// will follow a Round-robin algorithm.</p> /// </summary> /// <param name="query"> the query for which to build the plan. </param> /// <returns>a new query plan, i.e. an iterator indicating which host to try /// first for querying, which one to use as failover, etc...</returns> public IEnumerable<Host> NewQueryPlan(Query query) { int startidx = Interlocked.Increment(ref _index); // Overflow protection; not theoretically thread safe but should be good enough if (startidx > int.MaxValue - 10000) Thread.VolatileWrite(ref _index, 0); var copyOfHosts = (from h in _cluster.Metadata.AllHosts() where h.IsConsiderablyUp select h).ToArray(); var localHosts = new List<Host>(); for (int i = 0; i < copyOfHosts.Length; i++) { var h = copyOfHosts[i]; if (h.IsConsiderablyUp) if (_localDc.Equals(DC(h))) localHosts.Add(h); } for (int i = 0; i < localHosts.Count; i++) { startidx %= localHosts.Count; var h = localHosts[startidx]; startidx++; yield return h; } var remoteHosts = new List<Host>(); var ixes = new Dictionary<string, int>(); for (int i = 0; i < copyOfHosts.Length; i++) { var h = copyOfHosts[i]; if (h.IsConsiderablyUp) if (!_localDc.Equals(DC(h))) if (!ixes.ContainsKey(DC(h)) || ixes[DC(h)] < _usedHostsPerRemoteDc) { remoteHosts.Add(h); if (!ixes.ContainsKey(DC(h))) ixes.Add(DC(h), 1); else ixes[DC(h)] = ixes[DC(h)] + 1; } } for (int i = 0; i < remoteHosts.Count; i++) { startidx %= remoteHosts.Count; var h = remoteHosts[startidx]; startidx++; yield return h; } }
public IAsyncResult BeginExecute(Query query, AsyncCallback callback, object state) { var ar = query.BeginSessionExecute(this, null, callback, state) as AsyncResultNoResult; _startedActons.TryAdd(ar.Id, ar) ; return ar; }
public RowSet Execute(Query query) { return EndExecute(BeginExecute(query, null, null)); }
internal IAsyncResult BeginExecuteQuery(byte[] id, RowSetMetadata metadata, object[] values, AsyncCallback callback, object state, ConsistencyLevel consistency = ConsistencyLevel.Default, Query query = null, object sender = null, object tag = null, bool isTracing=false) { var longActionAc = new AsyncResult<RowSet>(-1, callback, state, this, "SessionExecuteQuery", sender, tag); var token = new LongExecuteQueryToken() { Consistency = consistency, Id = id, cql= _preparedQueries[id], Metadata = metadata, Values = values, Query = query, LongActionAc = longActionAc, IsTracinig = isTracing}; ExecConn(token, false); return longActionAc; }
/// <summary> /// Returns the hosts to use for a new query. <p> The returned plan will always /// try each known host in the local datacenter first, and then, if none of the /// local host is reacheable, will try up to a configurable number of other host /// per remote datacenter. The order of the local node in the returned query plan /// will follow a Round-robin algorithm.</p> /// </summary> /// <param name="query"> the query for which to build the plan. </param> /// <returns>a new query plan, i.e. an iterator indicating which host to try /// first for querying, which one to use as failover, etc...</returns> public IEnumerable<Host> NewQueryPlan(Query query) { List<Host> copyOfHosts = new List<Host>(_cluster.Metadata.AllHosts()); for (int i = 0; i < copyOfHosts.Count; i++) { if (_startidx == -1) _startidx = StaticRandom.Instance.Next(copyOfHosts.Count); _startidx %= copyOfHosts.Count; var h = copyOfHosts[_startidx]; _startidx++; if (h.IsConsiderablyUp) if (_localDc.Equals(DC(h))) yield return h; } var remoteHosts = new List<Host>(); var ixes = new Dictionary<string, int>(); for (int i = 0; i < copyOfHosts.Count; i++) { var h = copyOfHosts[i]; if (h.IsConsiderablyUp) if (!_localDc.Equals(DC(h))) if (!ixes.ContainsKey(DC(h)) || ixes[DC(h)] < _usedHostsPerRemoteDc) { remoteHosts.Add(h); if (!ixes.ContainsKey(DC(h))) ixes.Add(DC(h), 1); else ixes[DC(h)] = ixes[DC(h)] + 1; } } for (int i = 0; i < remoteHosts.Count; i++) { if (_startidx == -1) _startidx = StaticRandom.Instance.Next(copyOfHosts.Count); _startidx %= remoteHosts.Count; var h = remoteHosts[_startidx]; _startidx++; yield return h; } }
internal object SetKeyspace(string cqlQuery, ConsistencyLevel consistency = ConsistencyLevel.Default, Query query = null) { var ar = BeginSetKeyspace(cqlQuery, null, null, consistency, query); return EndSetKeyspace(ar); }