mirror of https://github.com/apache/cassandra
Merge branch 'cassandra-4.1' into cassandra-5.0
This commit is contained in:
commit
617a75843c
|
|
@ -5686,7 +5686,7 @@ Merged from 1.0:
|
|||
* avoid recursion in leveled compaction (CASSANDRA-4587)
|
||||
* increase stack size under Java7 to 180K
|
||||
* Log(info) schema changes (CASSANDRA-4547)
|
||||
* Change nodetool setcachecapcity to manipulate global caches (CASSANDRA-4563)
|
||||
* Change nodetool setcachecapacity to manipulate global caches (CASSANDRA-4563)
|
||||
* (cql3) fix setting compaction strategy (CASSANDRA-4597)
|
||||
* fix broken system.schema_* timestamps on system startup (CASSANDRA-4561)
|
||||
* fix wrong skip of cache saving (CASSANDRA-4533)
|
||||
|
|
|
|||
|
|
@ -47,14 +47,13 @@ import org.apache.cassandra.db.marshal.TupleType;
|
|||
import org.apache.cassandra.exceptions.RequestExecutionException;
|
||||
import org.apache.cassandra.schema.SchemaConstants;
|
||||
import org.apache.cassandra.service.ClientState;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.transport.messages.ResultMessage;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.MBeanWrapper;
|
||||
import org.apache.cassandra.utils.Pair;
|
||||
|
||||
import static org.apache.cassandra.service.QueryState.forInternalCalls;
|
||||
import static org.apache.cassandra.utils.Clock.Global.nanoTime;
|
||||
|
||||
|
||||
public class CIDRGroupsMappingManager implements CIDRGroupsMappingManagerMBean
|
||||
{
|
||||
|
|
@ -89,7 +88,7 @@ public class CIDRGroupsMappingManager implements CIDRGroupsMappingManagerMBean
|
|||
@VisibleForTesting
|
||||
ResultMessage.Rows select(SelectStatement statement, QueryOptions options)
|
||||
{
|
||||
return statement.execute(forInternalCalls(), options, nanoTime());
|
||||
return statement.execute(forInternalCalls(), options, Dispatcher.RequestTime.forImmediateExecution());
|
||||
}
|
||||
|
||||
UntypedResultSet process(String query, ConsistencyLevel cl) throws RequestExecutionException
|
||||
|
|
|
|||
|
|
@ -41,12 +41,12 @@ import org.apache.cassandra.exceptions.RequestExecutionException;
|
|||
import org.apache.cassandra.schema.SchemaConstants;
|
||||
import org.apache.cassandra.service.ClientState;
|
||||
import org.apache.cassandra.service.reads.range.RangeCommands;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.transport.messages.ResultMessage;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.MBeanWrapper;
|
||||
|
||||
import static org.apache.cassandra.service.QueryState.forInternalCalls;
|
||||
import static org.apache.cassandra.utils.Clock.Global.nanoTime;
|
||||
|
||||
/**
|
||||
* Provides functionality to list/update/drop CIDR permissions of a role
|
||||
|
|
@ -76,7 +76,7 @@ public class CIDRPermissionsManager implements CIDRPermissionsManagerMBean, Auth
|
|||
@VisibleForTesting
|
||||
ResultMessage.Rows select(SelectStatement statement, QueryOptions options)
|
||||
{
|
||||
return statement.execute(forInternalCalls(), options, nanoTime());
|
||||
return statement.execute(forInternalCalls(), options, Dispatcher.RequestTime.forImmediateExecution());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
|
|
|
|||
|
|
@ -46,12 +46,11 @@ import org.apache.cassandra.schema.SchemaConstants;
|
|||
import org.apache.cassandra.cql3.statements.SelectStatement;
|
||||
import org.apache.cassandra.service.ClientState;
|
||||
import org.apache.cassandra.service.QueryState;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.transport.messages.ResultMessage;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.Pair;
|
||||
|
||||
import static org.apache.cassandra.utils.Clock.Global.nanoTime;
|
||||
|
||||
/**
|
||||
* CassandraAuthorizer is an IAuthorizer implementation that keeps
|
||||
* user permissions internally in C* using the system_auth.role_permissions
|
||||
|
|
@ -421,7 +420,7 @@ public class CassandraAuthorizer implements IAuthorizer
|
|||
|
||||
ResultMessage.Rows select(SelectStatement statement, QueryOptions options)
|
||||
{
|
||||
return statement.execute(QueryState.forInternalCalls(), options, nanoTime());
|
||||
return statement.execute(QueryState.forInternalCalls(), options, Dispatcher.RequestTime.forImmediateExecution());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -439,7 +438,7 @@ public class CassandraAuthorizer implements IAuthorizer
|
|||
QueryProcessor.instance.processBatch(statement,
|
||||
QueryState.forInternalCalls(),
|
||||
BatchQueryOptions.withoutPerStatementVariables(options),
|
||||
nanoTime());
|
||||
Dispatcher.RequestTime.forImmediateExecution());
|
||||
}
|
||||
|
||||
public static ConsistencyLevel authWriteConsistencyLevel()
|
||||
|
|
|
|||
|
|
@ -39,11 +39,11 @@ import org.apache.cassandra.db.marshal.UTF8Type;
|
|||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
import org.apache.cassandra.schema.SchemaConstants;
|
||||
import org.apache.cassandra.service.ClientState;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.transport.messages.ResultMessage;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
|
||||
import static org.apache.cassandra.service.QueryState.forInternalCalls;
|
||||
import static org.apache.cassandra.utils.Clock.Global.nanoTime;
|
||||
|
||||
public class CassandraNetworkAuthorizer implements INetworkAuthorizer
|
||||
{
|
||||
|
|
@ -61,7 +61,7 @@ public class CassandraNetworkAuthorizer implements INetworkAuthorizer
|
|||
@VisibleForTesting
|
||||
ResultMessage.Rows select(SelectStatement statement, QueryOptions options)
|
||||
{
|
||||
return statement.execute(forInternalCalls(), options, nanoTime());
|
||||
return statement.execute(forInternalCalls(), options, Dispatcher.RequestTime.forImmediateExecution());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ import org.apache.cassandra.exceptions.*;
|
|||
import org.apache.cassandra.service.ClientState;
|
||||
import org.apache.cassandra.service.StorageProxy;
|
||||
import org.apache.cassandra.service.StorageService;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.transport.messages.ResultMessage;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.NoSpamLogger;
|
||||
|
|
@ -52,7 +53,6 @@ import org.mindrot.jbcrypt.BCrypt;
|
|||
|
||||
import static org.apache.cassandra.config.CassandraRelevantProperties.AUTH_BCRYPT_GENSALT_LOG2_ROUNDS;
|
||||
import static org.apache.cassandra.service.QueryState.forInternalCalls;
|
||||
import static org.apache.cassandra.utils.Clock.Global.nanoTime;
|
||||
|
||||
/**
|
||||
* Responsible for the creation, maintenance and deletion of roles
|
||||
|
|
@ -678,7 +678,7 @@ public class CassandraRoleManager implements IRoleManager
|
|||
@VisibleForTesting
|
||||
ResultMessage.Rows select(SelectStatement statement, QueryOptions options)
|
||||
{
|
||||
return statement.execute(forInternalCalls(), options, nanoTime());
|
||||
return statement.execute(forInternalCalls(), options, Dispatcher.RequestTime.forImmediateExecution());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -43,12 +43,12 @@ import org.apache.cassandra.exceptions.AuthenticationException;
|
|||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
import org.apache.cassandra.service.ClientState;
|
||||
import org.apache.cassandra.service.QueryState;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.transport.messages.ResultMessage;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.mindrot.jbcrypt.BCrypt;
|
||||
|
||||
import static org.apache.cassandra.auth.CassandraRoleManager.consistencyForRoleRead;
|
||||
import static org.apache.cassandra.utils.Clock.Global.nanoTime;
|
||||
|
||||
/**
|
||||
* PasswordAuthenticator is an IAuthenticator implementation
|
||||
|
|
@ -198,7 +198,7 @@ public class PasswordAuthenticator implements IAuthenticator, AuthCache.BulkLoad
|
|||
@VisibleForTesting
|
||||
ResultMessage.Rows select(SelectStatement statement, QueryOptions options)
|
||||
{
|
||||
return statement.execute(QueryState.forInternalCalls(), options, nanoTime());
|
||||
return statement.execute(QueryState.forInternalCalls(), options, Dispatcher.RequestTime.forImmediateExecution());
|
||||
}
|
||||
|
||||
public Set<DataResource> protectedResources()
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ import com.google.common.annotations.VisibleForTesting;
|
|||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.util.concurrent.RateLimiter;
|
||||
import org.apache.cassandra.concurrent.ScheduledExecutorPlus;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.utils.TimeUUID;
|
||||
import org.apache.cassandra.utils.concurrent.Future;
|
||||
import org.slf4j.Logger;
|
||||
|
|
@ -82,7 +83,6 @@ import static org.apache.cassandra.cql3.QueryProcessor.executeInternal;
|
|||
import static org.apache.cassandra.cql3.QueryProcessor.executeInternalWithPaging;
|
||||
import static org.apache.cassandra.net.Verb.MUTATION_REQ;
|
||||
import static org.apache.cassandra.utils.Clock.Global.currentTimeMillis;
|
||||
import static org.apache.cassandra.utils.Clock.Global.nanoTime;
|
||||
|
||||
public class BatchlogManager implements BatchlogManagerMBean
|
||||
{
|
||||
|
|
@ -503,7 +503,7 @@ public class BatchlogManager implements BatchlogManagerMBean
|
|||
|
||||
ReplicaPlan.ForWrite replicaPlan = new ReplicaPlan.ForWrite(keyspace, liveAndDown.replicationStrategy(),
|
||||
ConsistencyLevel.ONE, liveRemoteOnly.pending(), liveRemoteOnly.all(), liveRemoteOnly.all(), liveRemoteOnly.all());
|
||||
ReplayWriteResponseHandler<Mutation> handler = new ReplayWriteResponseHandler<>(replicaPlan, mutation, nanoTime());
|
||||
ReplayWriteResponseHandler<Mutation> handler = new ReplayWriteResponseHandler<>(replicaPlan, mutation, Dispatcher.RequestTime.forImmediateExecution());
|
||||
Message<Mutation> message = Message.outWithFlag(MUTATION_REQ, mutation, MessageFlag.CALL_BACK_ON_FAILURE);
|
||||
for (Replica replica : liveRemoteOnly.all())
|
||||
MessagingService.instance().sendWriteWithCallback(message, replica, handler);
|
||||
|
|
@ -527,9 +527,9 @@ public class BatchlogManager implements BatchlogManagerMBean
|
|||
private final Set<InetAddressAndPort> undelivered = Collections.newSetFromMap(new ConcurrentHashMap<>());
|
||||
|
||||
// TODO: should we be hinting here, since presumably batch log will retry? Maintaining historical behaviour for the moment.
|
||||
ReplayWriteResponseHandler(ReplicaPlan.ForWrite replicaPlan, Supplier<Mutation> hintOnFailure, long queryStartNanoTime)
|
||||
ReplayWriteResponseHandler(ReplicaPlan.ForWrite replicaPlan, Supplier<Mutation> hintOnFailure, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
super(replicaPlan, null, WriteType.UNLOGGED_BATCH, hintOnFailure, queryStartNanoTime);
|
||||
super(replicaPlan, null, WriteType.UNLOGGED_BATCH, hintOnFailure, requestTime);
|
||||
Iterables.addAll(undelivered, replicaPlan.contacts().endpoints());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,9 @@
|
|||
*/
|
||||
package org.apache.cassandra.concurrent;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.apache.cassandra.utils.MonotonicClock;
|
||||
import org.apache.cassandra.utils.Shared;
|
||||
|
||||
import static org.apache.cassandra.utils.Shared.Recursive.INTERFACES;
|
||||
|
|
@ -29,6 +32,11 @@ import static org.apache.cassandra.utils.Shared.Scope.SIMULATION;
|
|||
@Shared(scope = SIMULATION, inner = INTERFACES)
|
||||
public interface DebuggableTask
|
||||
{
|
||||
public default long elapsedSinceCreation()
|
||||
{
|
||||
return MonotonicClock.Global.approxTime.now() - creationTimeNanos();
|
||||
}
|
||||
|
||||
public long creationTimeNanos();
|
||||
|
||||
public long startTimeNanos();
|
||||
|
|
@ -36,6 +44,7 @@ public interface DebuggableTask
|
|||
public String description();
|
||||
|
||||
interface RunnableDebuggableTask extends Runnable, DebuggableTask {}
|
||||
interface CallableDebuggableTask<T> extends Callable<T>, DebuggableTask {}
|
||||
|
||||
/**
|
||||
* Wraps a {@link DebuggableTask} to include the name of the thread running it.
|
||||
|
|
|
|||
|
|
@ -89,6 +89,34 @@ public class FutureTask<V> extends AsyncFuture<V> implements RunnableFuture<V>
|
|||
|
||||
public static <T> Callable<T> callable(Runnable run)
|
||||
{
|
||||
if (run instanceof DebuggableTask.RunnableDebuggableTask)
|
||||
{
|
||||
return new DebuggableTask.CallableDebuggableTask<T>()
|
||||
{
|
||||
final RunnableDebuggableTask task = (RunnableDebuggableTask) run;
|
||||
public T call()
|
||||
{
|
||||
run.run();
|
||||
return null;
|
||||
}
|
||||
|
||||
public long creationTimeNanos()
|
||||
{
|
||||
return task.creationTimeNanos();
|
||||
}
|
||||
|
||||
public long startTimeNanos()
|
||||
{
|
||||
return task.startTimeNanos();
|
||||
}
|
||||
|
||||
public String description()
|
||||
{
|
||||
return task.description();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return new Callable<T>()
|
||||
{
|
||||
public T call()
|
||||
|
|
|
|||
|
|
@ -79,4 +79,9 @@ public interface ResizableThreadPool
|
|||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
default long oldestTaskQueueTime()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,6 +84,21 @@ public class SEPExecutor implements LocalAwareExecutorPlus, SEPExecutorMBean
|
|||
completedTasks.incrementAndGet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long oldestTaskQueueTime()
|
||||
{
|
||||
Runnable task = tasks.peek();
|
||||
if (!(task instanceof FutureTask))
|
||||
return 0L;
|
||||
|
||||
FutureTask<?> futureTask = (FutureTask<?>) task;
|
||||
DebuggableTask debuggableTask = futureTask.debuggableTask();
|
||||
if (debuggableTask == null)
|
||||
return 0L;
|
||||
|
||||
return debuggableTask.elapsedSinceCreation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxTasksQueued()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1283,4 +1283,24 @@ public class Config
|
|||
public double severity_during_decommission = 0;
|
||||
|
||||
public StorageCompatibilityMode storage_compatibility_mode;
|
||||
|
||||
/**
|
||||
* Which timestamp should be used to represent a base for replica-side timeouts.
|
||||
* Client-side timeout is always based on the QUEUE, and is controlled by native_transport_timeout.
|
||||
*/
|
||||
public enum CQLStartTime
|
||||
{
|
||||
REQUEST, // uses a timestamp that represent the start of processing of the request
|
||||
QUEUE // uses a timestamp that represents when the request was enqueued
|
||||
}
|
||||
public volatile CQLStartTime cql_start_time = CQLStartTime.REQUEST;
|
||||
|
||||
public boolean native_transport_throw_on_overload = false;
|
||||
public double native_transport_queue_max_item_age_threshold = Double.MAX_VALUE;
|
||||
public DurationSpec.LongMillisecondsBound native_transport_min_backoff_on_queue_overload = new DurationSpec.LongMillisecondsBound("10ms");
|
||||
public DurationSpec.LongMillisecondsBound native_transport_max_backoff_on_queue_overload = new DurationSpec.LongMillisecondsBound("200ms");
|
||||
|
||||
// 3.x Cassandra Driver has its "read" timeout set to 12 seconds, default matches this.
|
||||
public DurationSpec.LongMillisecondsBound native_transport_timeout = new DurationSpec.LongMillisecondsBound("12s");
|
||||
public boolean enforce_native_deadline_for_hints = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -990,6 +990,15 @@ public class DatabaseDescriptor
|
|||
throw new ConfigurationException(String.format("Invalid configuration. Heap dump is enabled but cannot create heap dump output path: %s.", conf.heap_dump_path != null ? conf.heap_dump_path : "null"));
|
||||
|
||||
conf.sai_options.validate();
|
||||
|
||||
if (conf.native_transport_min_backoff_on_queue_overload.toMilliseconds() <= 0)
|
||||
throw new ConfigurationException("native_transport_min_backoff_on_queue_overload should be strictly positive");
|
||||
|
||||
if (conf.native_transport_min_backoff_on_queue_overload.toMilliseconds() >= conf.native_transport_max_backoff_on_queue_overload.toMilliseconds())
|
||||
throw new ConfigurationException(String.format("native_transport_min_backoff_on_queue_overload should be strictly less than native_transport_max_backoff_on_queue_overload, but %s >= %s",
|
||||
conf.native_transport_min_backoff_on_queue_overload,
|
||||
conf.native_transport_max_backoff_on_queue_overload));
|
||||
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
|
|
@ -2238,6 +2247,100 @@ public class DatabaseDescriptor
|
|||
getTruncateRpcTimeout(unit));
|
||||
}
|
||||
|
||||
public static Config.CQLStartTime getCQLStartTime()
|
||||
{
|
||||
return conf.cql_start_time;
|
||||
}
|
||||
|
||||
public static void setCQLStartTime(Config.CQLStartTime value)
|
||||
{
|
||||
conf.cql_start_time = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* How much time the item is allowed to spend in (currently only Native) queue, compared to {@link #nativeTransportIdleTimeout()},
|
||||
* before backpressure starts being applied.
|
||||
*
|
||||
* For example, setting this value to 0.5 means and having the largest of read/range/write/counter timeouts to 10 seconds
|
||||
* means that if any item spends more than 5 seconds in the queue, backpressure will be applied to the socket associated
|
||||
* with this queue.
|
||||
*
|
||||
* Set to 0 or any negative value to fully disable.
|
||||
*/
|
||||
public static double getNativeTransportQueueMaxItemAgeThreshold()
|
||||
{
|
||||
return conf.native_transport_queue_max_item_age_threshold;
|
||||
}
|
||||
|
||||
public static void setNativeTransportMaxQueueItemAgeThreshold(double threshold)
|
||||
{
|
||||
conf.native_transport_queue_max_item_age_threshold = threshold;
|
||||
}
|
||||
|
||||
public static long getNativeTransportMinBackoffOnQueueOverload(TimeUnit timeUnit)
|
||||
{
|
||||
return conf.native_transport_min_backoff_on_queue_overload.to(timeUnit);
|
||||
}
|
||||
|
||||
public static long getNativeTransportMaxBackoffOnQueueOverload(TimeUnit timeUnit)
|
||||
{
|
||||
return conf.native_transport_max_backoff_on_queue_overload.to(timeUnit);
|
||||
}
|
||||
|
||||
public static void setNativeTransportBackoffOnQueueOverload(long minBackoffMillis,
|
||||
long maxBackoffMillis,
|
||||
TimeUnit timeUnit)
|
||||
{
|
||||
if (minBackoffMillis <= 0)
|
||||
throw new IllegalArgumentException("native_transport_min_backoff_on_queue_overload should be positive");
|
||||
|
||||
if (minBackoffMillis >= maxBackoffMillis)
|
||||
throw new IllegalArgumentException(String.format("native_transport_max_backoff_on_queue_overload should be greater than native_transport_min_backoff_on_queue_overload, but %s >= %s", minBackoffMillis, maxBackoffMillis));
|
||||
|
||||
|
||||
conf.native_transport_min_backoff_on_queue_overload = new DurationSpec.LongMillisecondsBound(minBackoffMillis, timeUnit);
|
||||
conf.native_transport_max_backoff_on_queue_overload = new DurationSpec.LongMillisecondsBound(maxBackoffMillis, timeUnit);
|
||||
}
|
||||
|
||||
private static long native_transport_timeout_nanos_cached = -1;
|
||||
|
||||
public static long getNativeTransportTimeout(TimeUnit timeUnit)
|
||||
{
|
||||
if (timeUnit == TimeUnit.NANOSECONDS)
|
||||
{
|
||||
if (native_transport_timeout_nanos_cached == -1)
|
||||
native_transport_timeout_nanos_cached = conf.native_transport_timeout.to(TimeUnit.NANOSECONDS);
|
||||
|
||||
return native_transport_timeout_nanos_cached;
|
||||
}
|
||||
return conf.native_transport_timeout.to(timeUnit);
|
||||
}
|
||||
|
||||
public static void setNativeTransportTimeout(long dealine, TimeUnit timeUnit)
|
||||
{
|
||||
conf.native_transport_timeout = new DurationSpec.LongMillisecondsBound(dealine, timeUnit);
|
||||
}
|
||||
|
||||
public static boolean getEnforceNativeDeadlineForHints()
|
||||
{
|
||||
return conf.enforce_native_deadline_for_hints;
|
||||
}
|
||||
|
||||
public static void setEnforceNativeDeadlineForHints(boolean value)
|
||||
{
|
||||
conf.enforce_native_deadline_for_hints = value;
|
||||
}
|
||||
|
||||
public static boolean getNativeTransportThrowOnOverload()
|
||||
{
|
||||
return conf.native_transport_throw_on_overload;
|
||||
}
|
||||
|
||||
public static void setNativeTransportThrowOnOverload(boolean throwOnOverload)
|
||||
{
|
||||
conf.native_transport_throw_on_overload = throwOnOverload;
|
||||
}
|
||||
|
||||
public static long getPingTimeout(TimeUnit unit)
|
||||
{
|
||||
return unit.convert(getBlockForPeersTimeoutInSeconds(), TimeUnit.SECONDS);
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import org.apache.cassandra.audit.AuditLogContext;
|
|||
import org.apache.cassandra.cql3.functions.Function;
|
||||
import org.apache.cassandra.service.ClientState;
|
||||
import org.apache.cassandra.service.QueryState;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.transport.messages.ResultMessage;
|
||||
|
||||
public interface CQLStatement
|
||||
|
|
@ -75,9 +76,9 @@ public interface CQLStatement
|
|||
*
|
||||
* @param state the current query state
|
||||
* @param options options for this query (consistency, variables, pageSize, ...)
|
||||
* @param queryStartNanoTime the timestamp returned by System.nanoTime() when this statement was received
|
||||
* @param requestTime request enqueue / and start times;
|
||||
*/
|
||||
public ResultMessage execute(QueryState state, QueryOptions options, long queryStartNanoTime);
|
||||
public ResultMessage execute(QueryState state, QueryOptions options, Dispatcher.RequestTime requestTime);
|
||||
|
||||
/**
|
||||
* Variant of execute used for internal query against the system tables, and thus only query the local node.
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import org.apache.cassandra.config.CassandraRelevantProperties;
|
|||
import org.apache.cassandra.cql3.statements.BatchStatement;
|
||||
import org.apache.cassandra.service.ClientState;
|
||||
import org.apache.cassandra.service.QueryState;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.transport.messages.ResultMessage;
|
||||
import org.apache.cassandra.utils.MD5Digest;
|
||||
|
||||
|
|
@ -41,13 +42,14 @@ public class CustomPayloadMirroringQueryHandler implements QueryHandler
|
|||
return queryProcessor.parse(query, state, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultMessage process(CQLStatement statement,
|
||||
QueryState state,
|
||||
QueryOptions options,
|
||||
Map<String, ByteBuffer> customPayload,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
ResultMessage result = queryProcessor.process(statement, state, options, customPayload, queryStartNanoTime);
|
||||
ResultMessage result = queryProcessor.process(statement, state, options, customPayload, requestTime);
|
||||
result.setCustomPayload(customPayload);
|
||||
return result;
|
||||
}
|
||||
|
|
@ -64,24 +66,26 @@ public class CustomPayloadMirroringQueryHandler implements QueryHandler
|
|||
return queryProcessor.getPrepared(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultMessage processPrepared(CQLStatement statement,
|
||||
QueryState state,
|
||||
QueryOptions options,
|
||||
Map<String, ByteBuffer> customPayload,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
ResultMessage result = queryProcessor.processPrepared(statement, state, options, customPayload, queryStartNanoTime);
|
||||
ResultMessage result = queryProcessor.processPrepared(statement, state, options, customPayload, requestTime);
|
||||
result.setCustomPayload(customPayload);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultMessage processBatch(BatchStatement statement,
|
||||
QueryState state,
|
||||
BatchQueryOptions options,
|
||||
Map<String, ByteBuffer> customPayload,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
ResultMessage result = queryProcessor.processBatch(statement, state, options, customPayload, queryStartNanoTime);
|
||||
ResultMessage result = queryProcessor.processBatch(statement, state, options, customPayload, requestTime);
|
||||
result.setCustomPayload(customPayload);
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import org.apache.cassandra.exceptions.RequestExecutionException;
|
|||
import org.apache.cassandra.exceptions.RequestValidationException;
|
||||
import org.apache.cassandra.service.ClientState;
|
||||
import org.apache.cassandra.service.QueryState;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.transport.messages.ResultMessage;
|
||||
import org.apache.cassandra.utils.MD5Digest;
|
||||
|
||||
|
|
@ -36,7 +37,7 @@ public interface QueryHandler
|
|||
QueryState state,
|
||||
QueryOptions options,
|
||||
Map<String, ByteBuffer> customPayload,
|
||||
long queryStartNanoTime) throws RequestExecutionException, RequestValidationException;
|
||||
Dispatcher.RequestTime requestTime) throws RequestExecutionException, RequestValidationException;
|
||||
|
||||
ResultMessage.Prepared prepare(String query,
|
||||
ClientState clientState,
|
||||
|
|
@ -48,13 +49,13 @@ public interface QueryHandler
|
|||
QueryState state,
|
||||
QueryOptions options,
|
||||
Map<String, ByteBuffer> customPayload,
|
||||
long queryStartNanoTime) throws RequestExecutionException, RequestValidationException;
|
||||
Dispatcher.RequestTime requestTime) throws RequestExecutionException, RequestValidationException;
|
||||
|
||||
ResultMessage processBatch(BatchStatement statement,
|
||||
QueryState state,
|
||||
BatchQueryOptions options,
|
||||
Map<String, ByteBuffer> customPayload,
|
||||
long queryStartNanoTime) throws RequestExecutionException, RequestValidationException;
|
||||
Dispatcher.RequestTime requestTime) throws RequestExecutionException, RequestValidationException;
|
||||
|
||||
public static class Prepared
|
||||
{
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ import org.apache.cassandra.metrics.CQLMetrics;
|
|||
import org.apache.cassandra.service.*;
|
||||
import org.apache.cassandra.service.pager.QueryPager;
|
||||
import org.apache.cassandra.tracing.Tracing;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
import org.apache.cassandra.transport.messages.ResultMessage;
|
||||
import org.apache.cassandra.utils.*;
|
||||
|
|
@ -243,7 +244,7 @@ public class QueryProcessor implements QueryHandler
|
|||
}
|
||||
}
|
||||
|
||||
public ResultMessage processStatement(CQLStatement statement, QueryState queryState, QueryOptions options, long queryStartNanoTime)
|
||||
public ResultMessage processStatement(CQLStatement statement, QueryState queryState, QueryOptions options, Dispatcher.RequestTime requestTime)
|
||||
throws RequestExecutionException, RequestValidationException
|
||||
{
|
||||
logger.trace("Process {} @CL.{}", statement, options.getConsistency());
|
||||
|
|
@ -253,7 +254,7 @@ public class QueryProcessor implements QueryHandler
|
|||
|
||||
ResultMessage result = options.getConsistency() == ConsistencyLevel.NODE_LOCAL
|
||||
? processNodeLocalStatement(statement, queryState, options)
|
||||
: statement.execute(queryState, options, queryStartNanoTime);
|
||||
: statement.execute(queryState, options, requestTime);
|
||||
|
||||
return result == null ? new ResultMessage.Void() : result;
|
||||
}
|
||||
|
|
@ -314,12 +315,12 @@ public class QueryProcessor implements QueryHandler
|
|||
}
|
||||
}
|
||||
|
||||
public static ResultMessage process(String queryString, ConsistencyLevel cl, QueryState queryState, long queryStartNanoTime)
|
||||
public static ResultMessage process(String queryString, ConsistencyLevel cl, QueryState queryState, Dispatcher.RequestTime requestTime)
|
||||
throws RequestExecutionException, RequestValidationException
|
||||
{
|
||||
QueryOptions options = QueryOptions.forInternalCalls(cl, Collections.<ByteBuffer>emptyList());
|
||||
CQLStatement statement = instance.parse(queryString, queryState, options);
|
||||
return instance.process(statement, queryState, options, queryStartNanoTime);
|
||||
return instance.process(statement, queryState, options, requestTime);
|
||||
}
|
||||
|
||||
public CQLStatement parse(String queryString, QueryState queryState, QueryOptions options)
|
||||
|
|
@ -331,12 +332,12 @@ public class QueryProcessor implements QueryHandler
|
|||
QueryState state,
|
||||
QueryOptions options,
|
||||
Map<String, ByteBuffer> customPayload,
|
||||
long queryStartNanoTime) throws RequestExecutionException, RequestValidationException
|
||||
Dispatcher.RequestTime requestTime) throws RequestExecutionException, RequestValidationException
|
||||
{
|
||||
return process(statement, state, options, queryStartNanoTime);
|
||||
return process(statement, state, options, requestTime);
|
||||
}
|
||||
|
||||
public ResultMessage process(CQLStatement prepared, QueryState queryState, QueryOptions options, long queryStartNanoTime)
|
||||
public ResultMessage process(CQLStatement prepared, QueryState queryState, QueryOptions options, Dispatcher.RequestTime requestTime)
|
||||
throws RequestExecutionException, RequestValidationException
|
||||
{
|
||||
options.prepare(prepared.getBindVariables());
|
||||
|
|
@ -346,7 +347,7 @@ public class QueryProcessor implements QueryHandler
|
|||
if (!queryState.getClientState().isInternal)
|
||||
metrics.regularStatementsExecuted.inc();
|
||||
|
||||
return processStatement(prepared, queryState, options, queryStartNanoTime);
|
||||
return processStatement(prepared, queryState, options, requestTime);
|
||||
}
|
||||
|
||||
public static CQLStatement parseStatement(String queryStr, ClientState clientState) throws RequestValidationException
|
||||
|
|
@ -364,7 +365,7 @@ public class QueryProcessor implements QueryHandler
|
|||
QueryState queryState = QueryState.forInternalCalls();
|
||||
QueryOptions options = QueryOptions.forInternalCalls(cl, values);
|
||||
CQLStatement statement = instance.parse(query, queryState, options);
|
||||
ResultMessage result = instance.process(statement, queryState, options, nanoTime());
|
||||
ResultMessage result = instance.process(statement, queryState, options, Dispatcher.RequestTime.forImmediateExecution());
|
||||
if (result instanceof ResultMessage.Rows)
|
||||
return UntypedResultSet.create(((ResultMessage.Rows)result).result);
|
||||
else
|
||||
|
|
@ -526,7 +527,7 @@ public class QueryProcessor implements QueryHandler
|
|||
try
|
||||
{
|
||||
Prepared prepared = prepareInternal(query);
|
||||
ResultMessage result = prepared.statement.execute(state, makeInternalOptionsWithNowInSec(prepared.statement, state.getNowInSeconds(), values, cl), nanoTime());
|
||||
ResultMessage result = prepared.statement.execute(state, makeInternalOptionsWithNowInSec(prepared.statement, state.getNowInSeconds(), values, cl), Dispatcher.RequestTime.forImmediateExecution());
|
||||
if (result instanceof ResultMessage.Rows)
|
||||
return UntypedResultSet.create(((ResultMessage.Rows)result).result);
|
||||
else
|
||||
|
|
@ -586,12 +587,12 @@ public class QueryProcessor implements QueryHandler
|
|||
* Note that this only make sense for Selects so this only accept SELECT statements and is only useful in rare
|
||||
* cases.
|
||||
*/
|
||||
public static UntypedResultSet executeInternalWithNow(long nowInSec, long queryStartNanoTime, String query, Object... values)
|
||||
public static UntypedResultSet executeInternalWithNow(long nowInSec, Dispatcher.RequestTime requestTime, String query, Object... values)
|
||||
{
|
||||
Prepared prepared = prepareInternal(query);
|
||||
assert prepared.statement instanceof SelectStatement;
|
||||
SelectStatement select = (SelectStatement)prepared.statement;
|
||||
ResultMessage result = select.executeInternal(internalQueryState(), makeInternalOptionsWithNowInSec(prepared.statement, nowInSec, values), nowInSec, queryStartNanoTime);
|
||||
ResultMessage result = select.executeInternal(internalQueryState(), makeInternalOptionsWithNowInSec(prepared.statement, nowInSec, values), nowInSec, requestTime);
|
||||
assert result instanceof ResultMessage.Rows;
|
||||
return UntypedResultSet.create(((ResultMessage.Rows)result).result);
|
||||
}
|
||||
|
|
@ -791,17 +792,18 @@ public class QueryProcessor implements QueryHandler
|
|||
return new ResultMessage.Prepared(statementId, resultMetadata.getResultMetadataId(), preparedMetadata, resultMetadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultMessage processPrepared(CQLStatement statement,
|
||||
QueryState state,
|
||||
QueryOptions options,
|
||||
Map<String, ByteBuffer> customPayload,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
throws RequestExecutionException, RequestValidationException
|
||||
{
|
||||
return processPrepared(statement, state, options, queryStartNanoTime);
|
||||
return processPrepared(statement, state, options, requestTime);
|
||||
}
|
||||
|
||||
public ResultMessage processPrepared(CQLStatement statement, QueryState queryState, QueryOptions options, long queryStartNanoTime)
|
||||
public ResultMessage processPrepared(CQLStatement statement, QueryState queryState, QueryOptions options, Dispatcher.RequestTime requestTime)
|
||||
throws RequestExecutionException, RequestValidationException
|
||||
{
|
||||
List<ByteBuffer> variables = options.getValues();
|
||||
|
|
@ -820,27 +822,27 @@ public class QueryProcessor implements QueryHandler
|
|||
}
|
||||
|
||||
metrics.preparedStatementsExecuted.inc();
|
||||
return processStatement(statement, queryState, options, queryStartNanoTime);
|
||||
return processStatement(statement, queryState, options, requestTime);
|
||||
}
|
||||
|
||||
public ResultMessage processBatch(BatchStatement statement,
|
||||
QueryState state,
|
||||
BatchQueryOptions options,
|
||||
Map<String, ByteBuffer> customPayload,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
throws RequestExecutionException, RequestValidationException
|
||||
{
|
||||
return processBatch(statement, state, options, queryStartNanoTime);
|
||||
return processBatch(statement, state, options, requestTime);
|
||||
}
|
||||
|
||||
public ResultMessage processBatch(BatchStatement batch, QueryState queryState, BatchQueryOptions options, long queryStartNanoTime)
|
||||
public ResultMessage processBatch(BatchStatement batch, QueryState queryState, BatchQueryOptions options, Dispatcher.RequestTime requestTime)
|
||||
throws RequestExecutionException, RequestValidationException
|
||||
{
|
||||
ClientState clientState = queryState.getClientState().cloneWithKeyspaceIfSet(options.getKeyspace());
|
||||
batch.authorize(clientState);
|
||||
batch.validate();
|
||||
batch.validate(clientState);
|
||||
return batch.execute(queryState, options, queryStartNanoTime);
|
||||
return batch.execute(queryState, options, requestTime);
|
||||
}
|
||||
|
||||
public static CQLStatement getStatement(String queryStr, ClientState clientState)
|
||||
|
|
|
|||
|
|
@ -48,12 +48,11 @@ import org.apache.cassandra.schema.ColumnMetadata;
|
|||
import org.apache.cassandra.schema.TableMetadata;
|
||||
import org.apache.cassandra.service.ClientState;
|
||||
import org.apache.cassandra.service.pager.QueryPager;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.utils.AbstractIterator;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.apache.cassandra.utils.TimeUUID;
|
||||
|
||||
import static org.apache.cassandra.utils.Clock.Global.nanoTime;
|
||||
|
||||
/** a utility for doing internal cql-based queries */
|
||||
public abstract class UntypedResultSet implements Iterable<UntypedResultSet.Row>
|
||||
{
|
||||
|
|
@ -291,7 +290,7 @@ public abstract class UntypedResultSet implements Iterable<UntypedResultSet.Row>
|
|||
if (pager.isExhausted())
|
||||
return endOfData();
|
||||
|
||||
try (PartitionIterator iter = pager.fetchPage(pageSize, cl, clientState, nanoTime()))
|
||||
try (PartitionIterator iter = pager.fetchPage(pageSize, cl, clientState, Dispatcher.RequestTime.forImmediateExecution()))
|
||||
{
|
||||
currentPage = select.process(iter, nowInSec, true, clientState).rows.iterator();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import org.apache.cassandra.exceptions.RequestValidationException;
|
|||
import org.apache.cassandra.exceptions.UnauthorizedException;
|
||||
import org.apache.cassandra.service.ClientState;
|
||||
import org.apache.cassandra.service.QueryState;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.transport.messages.ResultMessage;
|
||||
|
||||
public abstract class AuthenticationStatement extends CQLStatement.Raw implements CQLStatement
|
||||
|
|
@ -35,7 +36,8 @@ public abstract class AuthenticationStatement extends CQLStatement.Raw implement
|
|||
return this;
|
||||
}
|
||||
|
||||
public ResultMessage execute(QueryState state, QueryOptions options, long queryStartNanoTime)
|
||||
@Override
|
||||
public ResultMessage execute(QueryState state, QueryOptions options, Dispatcher.RequestTime requestTime)
|
||||
throws RequestExecutionException, RequestValidationException
|
||||
{
|
||||
return execute(state.getClientState());
|
||||
|
|
@ -43,6 +45,7 @@ public abstract class AuthenticationStatement extends CQLStatement.Raw implement
|
|||
|
||||
public abstract ResultMessage execute(ClientState state) throws RequestExecutionException, RequestValidationException;
|
||||
|
||||
@Override
|
||||
public ResultMessage executeLocally(QueryState state, QueryOptions options)
|
||||
{
|
||||
// executeLocally is for local query only, thus altering users doesn't make sense and is not supported
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import org.apache.cassandra.exceptions.RequestExecutionException;
|
|||
import org.apache.cassandra.exceptions.RequestValidationException;
|
||||
import org.apache.cassandra.service.ClientState;
|
||||
import org.apache.cassandra.service.QueryState;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.transport.messages.ResultMessage;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
|
@ -37,7 +38,8 @@ public abstract class AuthorizationStatement extends CQLStatement.Raw implements
|
|||
return this;
|
||||
}
|
||||
|
||||
public ResultMessage execute(QueryState state, QueryOptions options, long queryStartNanoTime)
|
||||
@Override
|
||||
public ResultMessage execute(QueryState state, QueryOptions options, Dispatcher.RequestTime requestTime)
|
||||
throws RequestValidationException, RequestExecutionException
|
||||
{
|
||||
return execute(state.getClientState());
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ import org.apache.cassandra.metrics.BatchMetrics;
|
|||
import org.apache.cassandra.metrics.ClientRequestSizeMetrics;
|
||||
import org.apache.cassandra.service.*;
|
||||
import org.apache.cassandra.tracing.Tracing;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.transport.messages.ResultMessage;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.apache.cassandra.utils.NoSpamLogger;
|
||||
|
|
@ -53,7 +54,6 @@ import org.apache.cassandra.utils.Pair;
|
|||
import static java.util.function.Predicate.isEqual;
|
||||
|
||||
import static org.apache.cassandra.cql3.statements.RequestValidations.checkFalse;
|
||||
import static org.apache.cassandra.utils.Clock.Global.nanoTime;
|
||||
|
||||
/**
|
||||
* A <code>BATCH</code> statement parsed from a CQL query.
|
||||
|
|
@ -272,7 +272,7 @@ public class BatchStatement implements CQLStatement
|
|||
boolean local,
|
||||
long batchTimestamp,
|
||||
long nowInSeconds,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
if (statements.isEmpty())
|
||||
return Collections.emptyList();
|
||||
|
|
@ -309,7 +309,7 @@ public class BatchStatement implements CQLStatement
|
|||
}
|
||||
QueryOptions statementOptions = options.forStatement(i);
|
||||
long timestamp = attrs.getTimestamp(batchTimestamp, statementOptions);
|
||||
statement.addUpdates(collector, partitionKeys.get(i), state, statementOptions, local, timestamp, nowInSeconds, queryStartNanoTime);
|
||||
statement.addUpdates(collector, partitionKeys.get(i), state, statementOptions, local, timestamp, nowInSeconds, requestTime);
|
||||
}
|
||||
|
||||
if (tablesWithZeroGcGs != null)
|
||||
|
|
@ -397,12 +397,12 @@ public class BatchStatement implements CQLStatement
|
|||
}
|
||||
|
||||
|
||||
public ResultMessage execute(QueryState queryState, QueryOptions options, long queryStartNanoTime)
|
||||
public ResultMessage execute(QueryState queryState, QueryOptions options, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
return execute(queryState, BatchQueryOptions.withoutPerStatementVariables(options), queryStartNanoTime);
|
||||
return execute(queryState, BatchQueryOptions.withoutPerStatementVariables(options), requestTime);
|
||||
}
|
||||
|
||||
public ResultMessage execute(QueryState queryState, BatchQueryOptions options, long queryStartNanoTime)
|
||||
public ResultMessage execute(QueryState queryState, BatchQueryOptions options, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
long timestamp = options.getTimestamp(queryState);
|
||||
long nowInSeconds = options.getNowInSeconds(queryState);
|
||||
|
|
@ -420,18 +420,18 @@ public class BatchStatement implements CQLStatement
|
|||
statements.get(i).validateDiskUsage(options.forStatement(i), clientState);
|
||||
|
||||
if (hasConditions)
|
||||
return executeWithConditions(options, queryState, queryStartNanoTime);
|
||||
return executeWithConditions(options, queryState, requestTime);
|
||||
|
||||
if (updatesVirtualTables)
|
||||
executeInternalWithoutCondition(queryState, options, queryStartNanoTime);
|
||||
executeInternalWithoutCondition(queryState, options, requestTime);
|
||||
else
|
||||
executeWithoutConditions(getMutations(clientState, options, false, timestamp, nowInSeconds, queryStartNanoTime),
|
||||
options.getConsistency(), queryStartNanoTime);
|
||||
executeWithoutConditions(getMutations(clientState, options, false, timestamp, nowInSeconds, requestTime),
|
||||
options.getConsistency(), requestTime);
|
||||
|
||||
return new ResultMessage.Void();
|
||||
}
|
||||
|
||||
private void executeWithoutConditions(List<? extends IMutation> mutations, ConsistencyLevel cl, long queryStartNanoTime) throws RequestExecutionException, RequestValidationException
|
||||
private void executeWithoutConditions(List<? extends IMutation> mutations, ConsistencyLevel cl, Dispatcher.RequestTime requestTime) throws RequestExecutionException, RequestValidationException
|
||||
{
|
||||
if (mutations.isEmpty())
|
||||
return;
|
||||
|
|
@ -442,7 +442,7 @@ public class BatchStatement implements CQLStatement
|
|||
updatePartitionsPerBatchMetrics(mutations.size());
|
||||
|
||||
boolean mutateAtomic = (isLogged() && mutations.size() > 1);
|
||||
StorageProxy.mutateWithTriggers(mutations, cl, mutateAtomic, queryStartNanoTime);
|
||||
StorageProxy.mutateWithTriggers(mutations, cl, mutateAtomic, requestTime);
|
||||
ClientRequestSizeMetrics.recordRowAndColumnCountMetrics(mutations);
|
||||
}
|
||||
|
||||
|
|
@ -457,7 +457,7 @@ public class BatchStatement implements CQLStatement
|
|||
}
|
||||
}
|
||||
|
||||
private ResultMessage executeWithConditions(BatchQueryOptions options, QueryState state, long queryStartNanoTime)
|
||||
private ResultMessage executeWithConditions(BatchQueryOptions options, QueryState state, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
Pair<CQL3CasRequest, Set<ColumnMetadata>> p = makeCasRequest(options, state);
|
||||
CQL3CasRequest casRequest = p.left;
|
||||
|
|
@ -474,7 +474,7 @@ public class BatchStatement implements CQLStatement
|
|||
options.getConsistency(),
|
||||
state.getClientState(),
|
||||
options.getNowInSeconds(state),
|
||||
queryStartNanoTime))
|
||||
requestTime))
|
||||
{
|
||||
return new ResultMessage.Rows(ModificationStatement.buildCasResultSet(ksName,
|
||||
tableName,
|
||||
|
|
@ -563,16 +563,16 @@ public class BatchStatement implements CQLStatement
|
|||
if (hasConditions)
|
||||
return executeInternalWithConditions(batchOptions, queryState);
|
||||
|
||||
executeInternalWithoutCondition(queryState, batchOptions, nanoTime());
|
||||
executeInternalWithoutCondition(queryState, batchOptions, Dispatcher.RequestTime.forImmediateExecution());
|
||||
return new ResultMessage.Void();
|
||||
}
|
||||
|
||||
private ResultMessage executeInternalWithoutCondition(QueryState queryState, BatchQueryOptions batchOptions, long queryStartNanoTime)
|
||||
private ResultMessage executeInternalWithoutCondition(QueryState queryState, BatchQueryOptions batchOptions, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
long timestamp = batchOptions.getTimestamp(queryState);
|
||||
long nowInSeconds = batchOptions.getNowInSeconds(queryState);
|
||||
|
||||
for (IMutation mutation : getMutations(queryState.getClientState(), batchOptions, true, timestamp, nowInSeconds, queryStartNanoTime))
|
||||
for (IMutation mutation : getMutations(queryState.getClientState(), batchOptions, true, timestamp, nowInSeconds, requestTime))
|
||||
mutation.apply();
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ import org.apache.cassandra.service.ClientState;
|
|||
import org.apache.cassandra.service.QueryState;
|
||||
import org.apache.cassandra.service.StorageService;
|
||||
import org.apache.cassandra.service.pager.PagingState;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.transport.messages.ResultMessage;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
|
|
@ -124,7 +125,7 @@ public abstract class DescribeStatement<T> extends CQLStatement.Raw implements C
|
|||
}
|
||||
|
||||
@Override
|
||||
public final ResultMessage execute(QueryState state, QueryOptions options, long queryStartNanoTime) throws RequestValidationException, RequestExecutionException
|
||||
public final ResultMessage execute(QueryState state, QueryOptions options, Dispatcher.RequestTime requestTime) throws RequestValidationException, RequestExecutionException
|
||||
{
|
||||
return executeLocally(state, options);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ import org.apache.cassandra.service.disk.usage.DiskUsageBroadcaster;
|
|||
import org.apache.cassandra.service.paxos.Ballot;
|
||||
import org.apache.cassandra.service.paxos.BallotGenerator;
|
||||
import org.apache.cassandra.service.paxos.Commit.Proposal;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.transport.messages.ResultMessage;
|
||||
import org.apache.cassandra.triggers.TriggerExecutor;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
|
|
@ -68,7 +69,6 @@ import org.apache.cassandra.utils.Pair;
|
|||
import static org.apache.cassandra.cql3.statements.RequestValidations.checkFalse;
|
||||
import static org.apache.cassandra.cql3.statements.RequestValidations.checkNull;
|
||||
import static org.apache.cassandra.service.paxos.Ballot.Flag.NONE;
|
||||
import static org.apache.cassandra.utils.Clock.Global.nanoTime;
|
||||
|
||||
/*
|
||||
* Abstract parent class of individual modifications, i.e. INSERT, UPDATE and DELETE.
|
||||
|
|
@ -422,7 +422,7 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
|
|||
boolean local,
|
||||
ConsistencyLevel cl,
|
||||
long nowInSeconds,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
if (!requiresRead())
|
||||
return null;
|
||||
|
|
@ -457,7 +457,7 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
|
|||
}
|
||||
}
|
||||
|
||||
try (PartitionIterator iter = group.execute(cl, null, queryStartNanoTime))
|
||||
try (PartitionIterator iter = group.execute(cl, null, requestTime))
|
||||
{
|
||||
return asMaterializedMap(iter);
|
||||
}
|
||||
|
|
@ -488,7 +488,7 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
|
|||
&& getRestrictions().isColumnRange();
|
||||
}
|
||||
|
||||
public ResultMessage execute(QueryState queryState, QueryOptions options, long queryStartNanoTime)
|
||||
public ResultMessage execute(QueryState queryState, QueryOptions options, Dispatcher.RequestTime requestTime)
|
||||
throws RequestExecutionException, RequestValidationException
|
||||
{
|
||||
if (options.getConsistency() == null)
|
||||
|
|
@ -498,15 +498,15 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
|
|||
queryState.getClientState());
|
||||
|
||||
return hasConditions()
|
||||
? executeWithCondition(queryState, options, queryStartNanoTime)
|
||||
: executeWithoutCondition(queryState, options, queryStartNanoTime);
|
||||
? executeWithCondition(queryState, options, requestTime)
|
||||
: executeWithoutCondition(queryState, options, requestTime);
|
||||
}
|
||||
|
||||
private ResultMessage executeWithoutCondition(QueryState queryState, QueryOptions options, long queryStartNanoTime)
|
||||
private ResultMessage executeWithoutCondition(QueryState queryState, QueryOptions options, Dispatcher.RequestTime requestTime)
|
||||
throws RequestExecutionException, RequestValidationException
|
||||
{
|
||||
if (isVirtual())
|
||||
return executeInternalWithoutCondition(queryState, options, queryStartNanoTime);
|
||||
return executeInternalWithoutCondition(queryState, options, requestTime);
|
||||
|
||||
ConsistencyLevel cl = options.getConsistency();
|
||||
if (isCounter())
|
||||
|
|
@ -523,10 +523,10 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
|
|||
false,
|
||||
options.getTimestamp(queryState),
|
||||
options.getNowInSeconds(queryState),
|
||||
queryStartNanoTime);
|
||||
requestTime);
|
||||
if (!mutations.isEmpty())
|
||||
{
|
||||
StorageProxy.mutateWithTriggers(mutations, cl, false, queryStartNanoTime);
|
||||
StorageProxy.mutateWithTriggers(mutations, cl, false, requestTime);
|
||||
|
||||
if (!SchemaConstants.isSystemKeyspace(metadata.keyspace))
|
||||
ClientRequestSizeMetrics.recordRowAndColumnCountMetrics(mutations);
|
||||
|
|
@ -535,7 +535,7 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
|
|||
return null;
|
||||
}
|
||||
|
||||
private ResultMessage executeWithCondition(QueryState queryState, QueryOptions options, long queryStartNanoTime)
|
||||
private ResultMessage executeWithCondition(QueryState queryState, QueryOptions options, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
CQL3CasRequest request = makeCasRequest(queryState, options);
|
||||
|
||||
|
|
@ -547,7 +547,7 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
|
|||
options.getConsistency(),
|
||||
queryState.getClientState(),
|
||||
options.getNowInSeconds(queryState),
|
||||
queryStartNanoTime))
|
||||
requestTime))
|
||||
{
|
||||
return new ResultMessage.Rows(buildCasResultSet(result, queryState, options));
|
||||
}
|
||||
|
|
@ -680,15 +680,15 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
|
|||
{
|
||||
return hasConditions()
|
||||
? executeInternalWithCondition(queryState, options)
|
||||
: executeInternalWithoutCondition(queryState, options, nanoTime());
|
||||
: executeInternalWithoutCondition(queryState, options, Dispatcher.RequestTime.forImmediateExecution());
|
||||
}
|
||||
|
||||
public ResultMessage executeInternalWithoutCondition(QueryState queryState, QueryOptions options, long queryStartNanoTime)
|
||||
public ResultMessage executeInternalWithoutCondition(QueryState queryState, QueryOptions options, Dispatcher.RequestTime requestTime)
|
||||
throws RequestValidationException, RequestExecutionException
|
||||
{
|
||||
long timestamp = options.getTimestamp(queryState);
|
||||
long nowInSeconds = options.getNowInSeconds(queryState);
|
||||
for (IMutation mutation : getMutations(queryState.getClientState(), options, true, timestamp, nowInSeconds, queryStartNanoTime))
|
||||
for (IMutation mutation : getMutations(queryState.getClientState(), options, true, timestamp, nowInSeconds, requestTime))
|
||||
mutation.apply();
|
||||
return null;
|
||||
}
|
||||
|
|
@ -741,12 +741,12 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
|
|||
boolean local,
|
||||
long timestamp,
|
||||
long nowInSeconds,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
List<ByteBuffer> keys = buildPartitionKeyNames(options, state);
|
||||
HashMultiset<ByteBuffer> perPartitionKeyCounts = HashMultiset.create(keys);
|
||||
SingleTableUpdatesCollector collector = new SingleTableUpdatesCollector(metadata, updatedColumns, perPartitionKeyCounts);
|
||||
addUpdates(collector, keys, state, options, local, timestamp, nowInSeconds, queryStartNanoTime);
|
||||
addUpdates(collector, keys, state, options, local, timestamp, nowInSeconds, requestTime);
|
||||
return collector.toMutations(state);
|
||||
}
|
||||
|
||||
|
|
@ -757,7 +757,7 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
|
|||
boolean local,
|
||||
long timestamp,
|
||||
long nowInSeconds,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
if (hasSlices())
|
||||
{
|
||||
|
|
@ -775,7 +775,7 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
|
|||
local,
|
||||
timestamp,
|
||||
nowInSeconds,
|
||||
queryStartNanoTime);
|
||||
requestTime);
|
||||
for (ByteBuffer key : keys)
|
||||
{
|
||||
Validation.validateKey(metadata(), key);
|
||||
|
|
@ -795,7 +795,7 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
|
|||
if (restrictions.hasClusteringColumnsRestrictions() && clusterings.isEmpty())
|
||||
return;
|
||||
|
||||
UpdateParameters params = makeUpdateParameters(keys, clusterings, state, options, local, timestamp, nowInSeconds, queryStartNanoTime);
|
||||
UpdateParameters params = makeUpdateParameters(keys, clusterings, state, options, local, timestamp, nowInSeconds, requestTime);
|
||||
|
||||
for (ByteBuffer key : keys)
|
||||
{
|
||||
|
|
@ -835,7 +835,7 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
|
|||
boolean local,
|
||||
long timestamp,
|
||||
long nowInSeconds,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
if (clusterings.contains(Clustering.STATIC_CLUSTERING))
|
||||
return makeUpdateParameters(keys,
|
||||
|
|
@ -846,7 +846,7 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
|
|||
local,
|
||||
timestamp,
|
||||
nowInSeconds,
|
||||
queryStartNanoTime);
|
||||
requestTime);
|
||||
|
||||
return makeUpdateParameters(keys,
|
||||
new ClusteringIndexNamesFilter(clusterings, false),
|
||||
|
|
@ -856,7 +856,7 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
|
|||
local,
|
||||
timestamp,
|
||||
nowInSeconds,
|
||||
queryStartNanoTime);
|
||||
requestTime);
|
||||
}
|
||||
|
||||
private UpdateParameters makeUpdateParameters(Collection<ByteBuffer> keys,
|
||||
|
|
@ -867,7 +867,7 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
|
|||
boolean local,
|
||||
long timestamp,
|
||||
long nowInSeconds,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
// Some lists operation requires reading
|
||||
Map<DecoratedKey, Partition> lists =
|
||||
|
|
@ -877,7 +877,7 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
|
|||
local,
|
||||
options.getConsistency(),
|
||||
nowInSeconds,
|
||||
queryStartNanoTime);
|
||||
requestTime);
|
||||
|
||||
return new UpdateParameters(metadata(),
|
||||
updatedColumns(),
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ import org.apache.cassandra.service.StorageProxy;
|
|||
import org.apache.cassandra.service.pager.AggregationQueryPager;
|
||||
import org.apache.cassandra.service.pager.PagingState;
|
||||
import org.apache.cassandra.service.pager.QueryPager;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
import org.apache.cassandra.transport.messages.ResultMessage;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
|
|
@ -92,7 +93,6 @@ import static org.apache.cassandra.cql3.statements.RequestValidations.checkNull;
|
|||
import static org.apache.cassandra.cql3.statements.RequestValidations.checkTrue;
|
||||
import static org.apache.cassandra.cql3.statements.RequestValidations.invalidRequest;
|
||||
import static org.apache.cassandra.utils.ByteBufferUtil.UNSET_BYTE_BUFFER;
|
||||
import static org.apache.cassandra.utils.Clock.Global.nanoTime;
|
||||
|
||||
/**
|
||||
* Encapsulates a completely parsed SELECT query, including the target
|
||||
|
|
@ -277,7 +277,7 @@ public class SelectStatement implements CQLStatement.SingleKeyspaceCqlStatement
|
|||
Guardrails.allowFilteringEnabled.ensureEnabled(state);
|
||||
}
|
||||
|
||||
public ResultMessage.Rows execute(QueryState state, QueryOptions options, long queryStartNanoTime)
|
||||
public ResultMessage.Rows execute(QueryState state, QueryOptions options, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
ConsistencyLevel cl = options.getConsistency();
|
||||
checkNotNull(cl, "Invalid empty consistency level");
|
||||
|
|
@ -337,7 +337,7 @@ public class SelectStatement implements CQLStatement.SingleKeyspaceCqlStatement
|
|||
|
||||
if (aggregationSpec == null && (pageSize <= 0 || (query.limits().count() <= pageSize) || query.isTopK()))
|
||||
{
|
||||
rows = execute(query, options, state.getClientState(), selectors, nowInSec, userLimit, null, queryStartNanoTime, unmask);
|
||||
rows = execute(query, options, state.getClientState(), selectors, nowInSec, userLimit, null, requestTime, unmask);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -351,7 +351,7 @@ public class SelectStatement implements CQLStatement.SingleKeyspaceCqlStatement
|
|||
nowInSec,
|
||||
userLimit,
|
||||
aggregationSpec,
|
||||
queryStartNanoTime,
|
||||
requestTime,
|
||||
unmask);
|
||||
}
|
||||
if (!SchemaConstants.isSystemKeyspace(table.keyspace))
|
||||
|
|
@ -418,10 +418,10 @@ public class SelectStatement implements CQLStatement.SingleKeyspaceCqlStatement
|
|||
long nowInSec,
|
||||
int userLimit,
|
||||
AggregationSpecification aggregationSpec,
|
||||
long queryStartNanoTime,
|
||||
Dispatcher.RequestTime requestTime,
|
||||
boolean unmask)
|
||||
{
|
||||
try (PartitionIterator data = query.execute(options.getConsistency(), state, queryStartNanoTime))
|
||||
try (PartitionIterator data = query.execute(options.getConsistency(), state, requestTime))
|
||||
{
|
||||
return processResults(data, options, selectors, nowInSec, userLimit, aggregationSpec, unmask, state);
|
||||
}
|
||||
|
|
@ -463,7 +463,7 @@ public class SelectStatement implements CQLStatement.SingleKeyspaceCqlStatement
|
|||
return pager.state();
|
||||
}
|
||||
|
||||
public abstract PartitionIterator fetchPage(int pageSize, long queryStartNanoTime);
|
||||
public abstract PartitionIterator fetchPage(int pageSize, Dispatcher.RequestTime requestTime);
|
||||
|
||||
public static class NormalPager extends Pager
|
||||
{
|
||||
|
|
@ -477,9 +477,9 @@ public class SelectStatement implements CQLStatement.SingleKeyspaceCqlStatement
|
|||
this.clientState = clientState;
|
||||
}
|
||||
|
||||
public PartitionIterator fetchPage(int pageSize, long queryStartNanoTime)
|
||||
public PartitionIterator fetchPage(int pageSize, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
return pager.fetchPage(pageSize, consistency, clientState, queryStartNanoTime);
|
||||
return pager.fetchPage(pageSize, consistency, clientState, requestTime);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -493,7 +493,7 @@ public class SelectStatement implements CQLStatement.SingleKeyspaceCqlStatement
|
|||
this.executionController = executionController;
|
||||
}
|
||||
|
||||
public PartitionIterator fetchPage(int pageSize, long queryStartNanoTime)
|
||||
public PartitionIterator fetchPage(int pageSize, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
return pager.fetchPageInternal(pageSize, executionController);
|
||||
}
|
||||
|
|
@ -508,7 +508,7 @@ public class SelectStatement implements CQLStatement.SingleKeyspaceCqlStatement
|
|||
long nowInSec,
|
||||
int userLimit,
|
||||
AggregationSpecification aggregationSpec,
|
||||
long queryStartNanoTime,
|
||||
Dispatcher.RequestTime requestTime,
|
||||
boolean unmask)
|
||||
{
|
||||
Guardrails.pageSize.guard(pageSize, table(), false, state.getClientState());
|
||||
|
|
@ -536,7 +536,7 @@ public class SelectStatement implements CQLStatement.SingleKeyspaceCqlStatement
|
|||
+ " you must either remove the ORDER BY or the IN and sort client side, or disable paging for this query");
|
||||
|
||||
ResultMessage.Rows msg;
|
||||
try (PartitionIterator page = pager.fetchPage(pageSize, queryStartNanoTime))
|
||||
try (PartitionIterator page = pager.fetchPage(pageSize, requestTime))
|
||||
{
|
||||
msg = processResults(page, options, selectors, nowInSec, userLimit, aggregationSpec, unmask, state.getClientState());
|
||||
}
|
||||
|
|
@ -570,13 +570,13 @@ public class SelectStatement implements CQLStatement.SingleKeyspaceCqlStatement
|
|||
|
||||
public ResultMessage.Rows executeLocally(QueryState state, QueryOptions options) throws RequestExecutionException, RequestValidationException
|
||||
{
|
||||
return executeInternal(state, options, options.getNowInSeconds(state), nanoTime());
|
||||
return executeInternal(state, options, options.getNowInSeconds(state), Dispatcher.RequestTime.forImmediateExecution());
|
||||
}
|
||||
|
||||
public ResultMessage.Rows executeInternal(QueryState state,
|
||||
QueryOptions options,
|
||||
long nowInSec,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
int userLimit = getLimit(options);
|
||||
int userPerPartitionLimit = getPerPartitionLimit(options);
|
||||
|
|
@ -614,7 +614,7 @@ public class SelectStatement implements CQLStatement.SingleKeyspaceCqlStatement
|
|||
nowInSec,
|
||||
userLimit,
|
||||
aggregationSpec,
|
||||
queryStartNanoTime,
|
||||
requestTime,
|
||||
unmask);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ import org.apache.cassandra.schema.TableMetadata;
|
|||
import org.apache.cassandra.service.ClientState;
|
||||
import org.apache.cassandra.service.QueryState;
|
||||
import org.apache.cassandra.service.StorageProxy;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.transport.messages.ResultMessage;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
|
@ -61,7 +62,8 @@ public class TruncateStatement extends QualifiedStatement implements CQLStatemen
|
|||
Guardrails.dropTruncateTableEnabled.ensureEnabled(state);
|
||||
}
|
||||
|
||||
public ResultMessage execute(QueryState state, QueryOptions options, long queryStartNanoTime) throws InvalidRequestException, TruncateException
|
||||
@Override
|
||||
public ResultMessage execute(QueryState state, QueryOptions options, Dispatcher.RequestTime requestTime) throws InvalidRequestException, TruncateException
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import org.apache.cassandra.cql3.QueryOptions;
|
|||
import org.apache.cassandra.cql3.QueryProcessor;
|
||||
import org.apache.cassandra.exceptions.InvalidRequestException;
|
||||
import org.apache.cassandra.exceptions.UnauthorizedException;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.transport.messages.ResultMessage;
|
||||
import org.apache.cassandra.service.ClientState;
|
||||
import org.apache.cassandra.service.QueryState;
|
||||
|
|
@ -32,7 +33,6 @@ import org.apache.commons.lang3.builder.ToStringBuilder;
|
|||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
import static org.apache.cassandra.cql3.statements.RequestValidations.checkTrue;
|
||||
import static org.apache.cassandra.utils.Clock.Global.nanoTime;
|
||||
|
||||
public class UseStatement extends CQLStatement.Raw implements CQLStatement
|
||||
{
|
||||
|
|
@ -59,7 +59,8 @@ public class UseStatement extends CQLStatement.Raw implements CQLStatement
|
|||
checkTrue(DatabaseDescriptor.getUseStatementsEnabled(), "USE statements prohibited. (see use_statements_enabled in cassandra.yaml)");
|
||||
}
|
||||
|
||||
public ResultMessage execute(QueryState state, QueryOptions options, long queryStartNanoTime) throws InvalidRequestException
|
||||
@Override
|
||||
public ResultMessage execute(QueryState state, QueryOptions options, Dispatcher.RequestTime requestTime) throws InvalidRequestException
|
||||
{
|
||||
QueryProcessor.metrics.useStatementsExecuted.inc();
|
||||
state.getClientState().setKeyspace(keyspace);
|
||||
|
|
@ -70,7 +71,7 @@ public class UseStatement extends CQLStatement.Raw implements CQLStatement
|
|||
{
|
||||
// In production, internal queries are exclusively on the system keyspace and 'use' is thus useless
|
||||
// but for some unit tests we need to set the keyspace (e.g. for tests with DROP INDEX)
|
||||
return execute(state, options, nanoTime());
|
||||
return execute(state, options, Dispatcher.RequestTime.forImmediateExecution());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ import org.apache.cassandra.schema.Keyspaces.KeyspacesDiff;
|
|||
import org.apache.cassandra.service.ClientState;
|
||||
import org.apache.cassandra.service.ClientWarn;
|
||||
import org.apache.cassandra.service.QueryState;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.transport.Event.SchemaChange;
|
||||
import org.apache.cassandra.transport.messages.ResultMessage;
|
||||
|
||||
|
|
@ -55,7 +56,8 @@ abstract public class AlterSchemaStatement implements CQLStatement.SingleKeyspac
|
|||
this.state = state;
|
||||
}
|
||||
|
||||
public ResultMessage execute(QueryState state, QueryOptions options, long queryStartNanoTime)
|
||||
@Override
|
||||
public ResultMessage execute(QueryState state, QueryOptions options, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
return execute(state, false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,8 +25,7 @@ import org.apache.cassandra.net.IVerbHandler;
|
|||
import org.apache.cassandra.net.Message;
|
||||
import org.apache.cassandra.net.MessagingService;
|
||||
import org.apache.cassandra.service.StorageProxy;
|
||||
|
||||
import static org.apache.cassandra.utils.Clock.Global.nanoTime;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
|
||||
public class CounterMutationVerbHandler implements IVerbHandler<CounterMutation>
|
||||
{
|
||||
|
|
@ -36,7 +35,6 @@ public class CounterMutationVerbHandler implements IVerbHandler<CounterMutation>
|
|||
|
||||
public void doVerb(final Message<CounterMutation> message)
|
||||
{
|
||||
long queryStartNanoTime = nanoTime();
|
||||
final CounterMutation cm = message.payload;
|
||||
logger.trace("Applying forwarded {}", cm);
|
||||
|
||||
|
|
@ -51,6 +49,6 @@ public class CounterMutationVerbHandler implements IVerbHandler<CounterMutation>
|
|||
StorageProxy.applyCounterMutationOnLeader(cm,
|
||||
localDataCenter,
|
||||
() -> MessagingService.instance().send(message.emptyResponse(), message.from()),
|
||||
queryStartNanoTime);
|
||||
Dispatcher.RequestTime.forImmediateExecution());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,9 @@ import org.apache.cassandra.locator.InetAddressAndPort;
|
|||
import org.apache.cassandra.net.*;
|
||||
import org.apache.cassandra.tracing.Tracing;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.NANOSECONDS;
|
||||
import static org.apache.cassandra.db.commitlog.CommitLogSegment.ENTRY_OVERHEAD_SIZE;
|
||||
import static org.apache.cassandra.utils.MonotonicClock.Global.approxTime;
|
||||
|
||||
public class MutationVerbHandler implements IVerbHandler<Mutation>
|
||||
{
|
||||
|
|
@ -41,6 +43,13 @@ public class MutationVerbHandler implements IVerbHandler<Mutation>
|
|||
|
||||
public void doVerb(Message<Mutation> message)
|
||||
{
|
||||
if (approxTime.now() > message.expiresAtNanos())
|
||||
{
|
||||
Tracing.trace("Discarding mutation from {} (timed out)", message.from());
|
||||
MessagingService.instance().metrics.recordDroppedMessage(message, message.elapsedSinceCreated(NANOSECONDS), NANOSECONDS);
|
||||
return;
|
||||
}
|
||||
|
||||
message.payload.validateSize(MessagingService.current_version, ENTRY_OVERHEAD_SIZE);
|
||||
|
||||
// Check if there were any forwarding headers in this message
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ import org.apache.cassandra.schema.TableMetadata;
|
|||
import org.apache.cassandra.service.ClientState;
|
||||
import org.apache.cassandra.service.StorageProxy;
|
||||
import org.apache.cassandra.tracing.Tracing;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
|
||||
/**
|
||||
* A read command that selects a (part of a) range of partitions.
|
||||
|
|
@ -304,9 +305,9 @@ public class PartitionRangeReadCommand extends ReadCommand implements PartitionR
|
|||
return dataRange.isReversed();
|
||||
}
|
||||
|
||||
public PartitionIterator execute(ConsistencyLevel consistency, ClientState state, long queryStartNanoTime) throws RequestExecutionException
|
||||
public PartitionIterator execute(ConsistencyLevel consistency, ClientState state, Dispatcher.RequestTime requestTime) throws RequestExecutionException
|
||||
{
|
||||
return StorageProxy.getRangeSlice(this, consistency, queryStartNanoTime);
|
||||
return StorageProxy.getRangeSlice(this, consistency, requestTime);
|
||||
}
|
||||
|
||||
protected void recordLatency(TableMetrics metric, long latencyNanos)
|
||||
|
|
@ -549,7 +550,7 @@ public class PartitionRangeReadCommand extends ReadCommand implements PartitionR
|
|||
}
|
||||
|
||||
@Override
|
||||
public PartitionIterator execute(ConsistencyLevel consistency, ClientState state, long queryStartNanoTime) throws RequestExecutionException
|
||||
public PartitionIterator execute(ConsistencyLevel consistency, ClientState state, Dispatcher.RequestTime requestTime) throws RequestExecutionException
|
||||
{
|
||||
return executeInternal(executionController());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ import org.apache.cassandra.service.ActiveRepairService;
|
|||
import org.apache.cassandra.service.ClientWarn;
|
||||
import org.apache.cassandra.tracing.Tracing;
|
||||
import org.apache.cassandra.utils.CassandraUInt;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.apache.cassandra.utils.ObjectSizes;
|
||||
import org.apache.cassandra.utils.TimeUUID;
|
||||
|
|
@ -76,8 +77,8 @@ import org.apache.cassandra.utils.TimeUUID;
|
|||
import static com.google.common.collect.Iterables.any;
|
||||
import static com.google.common.collect.Iterables.filter;
|
||||
import static org.apache.cassandra.utils.Clock.Global.nanoTime;
|
||||
import static org.apache.cassandra.utils.MonotonicClock.Global.approxTime;
|
||||
import static org.apache.cassandra.db.partitions.UnfilteredPartitionIterators.MergeListener.NOOP;
|
||||
import static org.apache.cassandra.utils.MonotonicClock.Global.approxTime;
|
||||
|
||||
/**
|
||||
* General interface for storage-engine read commands (common to both range and
|
||||
|
|
@ -789,14 +790,19 @@ public abstract class ReadCommand extends AbstractReadQuery
|
|||
/**
|
||||
* Creates a message for this command.
|
||||
*/
|
||||
public Message<ReadCommand> createMessage(boolean trackRepairedData)
|
||||
public Message<ReadCommand> createMessage(boolean trackRepairedData, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
Message<ReadCommand> msg = trackRepairedData
|
||||
? Message.outWithFlags(verb(), this, MessageFlag.CALL_BACK_ON_FAILURE, MessageFlag.TRACK_REPAIRED_DATA)
|
||||
: Message.outWithFlag(verb(), this, MessageFlag.CALL_BACK_ON_FAILURE);
|
||||
List<MessageFlag> flags = new ArrayList<>(3);
|
||||
flags.add(MessageFlag.CALL_BACK_ON_FAILURE);
|
||||
if (trackWarnings)
|
||||
msg = msg.withFlag(MessageFlag.TRACK_WARNINGS);
|
||||
return msg;
|
||||
flags.add(MessageFlag.TRACK_WARNINGS);
|
||||
if (trackRepairedData)
|
||||
flags.add(MessageFlag.TRACK_REPAIRED_DATA);
|
||||
|
||||
return Message.outWithFlags(verb(),
|
||||
this,
|
||||
requestTime,
|
||||
flags);
|
||||
}
|
||||
|
||||
protected abstract boolean intersects(SSTableReader sstable);
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import org.apache.cassandra.schema.TableMetadata;
|
|||
import org.apache.cassandra.service.ClientState;
|
||||
import org.apache.cassandra.service.pager.QueryPager;
|
||||
import org.apache.cassandra.service.pager.PagingState;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
|
||||
|
|
@ -48,7 +49,7 @@ public interface ReadQuery
|
|||
return ReadExecutionController.empty();
|
||||
}
|
||||
|
||||
public PartitionIterator execute(ConsistencyLevel consistency, ClientState state, long queryStartNanoTime) throws RequestExecutionException
|
||||
public PartitionIterator execute(ConsistencyLevel consistency, ClientState state, Dispatcher.RequestTime requestTime) throws RequestExecutionException
|
||||
{
|
||||
return EmptyIterators.partition();
|
||||
}
|
||||
|
|
@ -141,9 +142,10 @@ public interface ReadQuery
|
|||
*
|
||||
* @param consistency the consistency level to achieve for the query.
|
||||
* @param state client state
|
||||
* @param state request enqueue / and start times
|
||||
* @return the result of the query.
|
||||
*/
|
||||
public PartitionIterator execute(ConsistencyLevel consistency, ClientState state, long queryStartNanoTime) throws RequestExecutionException;
|
||||
public PartitionIterator execute(ConsistencyLevel consistency, ClientState state, Dispatcher.RequestTime requestTime) throws RequestExecutionException;
|
||||
|
||||
/**
|
||||
* Execute the query for internal queries (that is, it basically executes the query locally).
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ import org.apache.cassandra.service.CacheService;
|
|||
import org.apache.cassandra.service.ClientState;
|
||||
import org.apache.cassandra.service.StorageProxy;
|
||||
import org.apache.cassandra.tracing.Tracing;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.apache.cassandra.utils.btree.BTreeSet;
|
||||
|
||||
|
|
@ -462,12 +463,12 @@ public class SinglePartitionReadCommand extends ReadCommand implements SinglePar
|
|||
}
|
||||
|
||||
@Override
|
||||
public PartitionIterator execute(ConsistencyLevel consistency, ClientState state, long queryStartNanoTime) throws RequestExecutionException
|
||||
public PartitionIterator execute(ConsistencyLevel consistency, ClientState state, Dispatcher.RequestTime requestTime) throws RequestExecutionException
|
||||
{
|
||||
if (clusteringIndexFilter.isEmpty(metadata().comparator))
|
||||
return EmptyIterators.partition();
|
||||
|
||||
return StorageProxy.read(Group.one(this), consistency, queryStartNanoTime);
|
||||
return StorageProxy.read(Group.one(this), consistency, requestTime);
|
||||
}
|
||||
|
||||
protected void recordLatency(TableMetrics metric, long latencyNanos)
|
||||
|
|
@ -1273,9 +1274,9 @@ public class SinglePartitionReadCommand extends ReadCommand implements SinglePar
|
|||
new Group(commands, limits);
|
||||
}
|
||||
|
||||
public PartitionIterator execute(ConsistencyLevel consistency, ClientState state, long queryStartNanoTime) throws RequestExecutionException
|
||||
public PartitionIterator execute(ConsistencyLevel consistency, ClientState state, Dispatcher.RequestTime requestTime) throws RequestExecutionException
|
||||
{
|
||||
return StorageProxy.read(this, consistency, queryStartNanoTime);
|
||||
return StorageProxy.read(this, consistency, requestTime);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1287,13 +1288,13 @@ public class SinglePartitionReadCommand extends ReadCommand implements SinglePar
|
|||
}
|
||||
|
||||
@Override
|
||||
public PartitionIterator execute(ConsistencyLevel consistency, ClientState state, long queryStartNanoTime) throws RequestExecutionException
|
||||
public PartitionIterator execute(ConsistencyLevel consistency, ClientState state, Dispatcher.RequestTime requestTime) throws RequestExecutionException
|
||||
{
|
||||
if (queries.size() == 1)
|
||||
return queries.get(0).execute(consistency, state, queryStartNanoTime);
|
||||
return queries.get(0).execute(consistency, state, requestTime);
|
||||
|
||||
return PartitionIterators.concat(queries.stream()
|
||||
.map(q -> q.execute(consistency, state, queryStartNanoTime))
|
||||
.map(q -> q.execute(consistency, state, requestTime))
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
}
|
||||
|
|
@ -1366,7 +1367,7 @@ public class SinglePartitionReadCommand extends ReadCommand implements SinglePar
|
|||
}
|
||||
|
||||
@Override
|
||||
public PartitionIterator execute(ConsistencyLevel consistency, ClientState state, long queryStartNanoTime) throws RequestExecutionException
|
||||
public PartitionIterator execute(ConsistencyLevel consistency, ClientState state, Dispatcher.RequestTime requestTime) throws RequestExecutionException
|
||||
{
|
||||
return executeInternal(executionController());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ import org.apache.cassandra.schema.TableId;
|
|||
import org.apache.cassandra.schema.TableMetadata;
|
||||
import org.apache.cassandra.schema.TableMetadataRef;
|
||||
import org.apache.cassandra.service.StorageProxy;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.apache.cassandra.utils.btree.BTree;
|
||||
import org.apache.cassandra.utils.btree.BTreeSet;
|
||||
|
|
@ -149,7 +150,7 @@ public class TableViews extends AbstractCollection<View>
|
|||
|
||||
// Read modified rows
|
||||
long nowInSec = FBUtilities.nowInSeconds();
|
||||
long queryStartNanoTime = nanoTime();
|
||||
Dispatcher.RequestTime requestTime = Dispatcher.RequestTime.forImmediateExecution();
|
||||
SinglePartitionReadCommand command = readExistingRowsCommand(update, views, nowInSec);
|
||||
if (command == null)
|
||||
return;
|
||||
|
|
@ -166,7 +167,7 @@ public class TableViews extends AbstractCollection<View>
|
|||
Keyspace.openAndGetStore(update.metadata()).metric.viewReadTime.update(nanoTime() - start, TimeUnit.NANOSECONDS);
|
||||
|
||||
if (!mutations.isEmpty())
|
||||
StorageProxy.mutateMV(update.partitionKey().getKey(), mutations, writeCommitLog, baseComplete, queryStartNanoTime);
|
||||
StorageProxy.mutateMV(update.partitionKey().getKey(), mutations, writeCommitLog, baseComplete, requestTime);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -56,11 +56,11 @@ import org.apache.cassandra.gms.Gossiper;
|
|||
import org.apache.cassandra.io.sstable.ReducingKeyIterator;
|
||||
import org.apache.cassandra.io.sstable.format.SSTableReader;
|
||||
import org.apache.cassandra.service.StorageProxy;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.apache.cassandra.utils.TimeUUID;
|
||||
import org.apache.cassandra.utils.concurrent.Refs;
|
||||
|
||||
import static org.apache.cassandra.utils.Clock.Global.nanoTime;
|
||||
import static org.apache.cassandra.utils.TimeUUID.Generator.nextTimeUUID;
|
||||
|
||||
public class ViewBuilderTask extends CompactionInfo.Holder implements Callable<Long>
|
||||
|
|
@ -114,7 +114,7 @@ public class ViewBuilderTask extends CompactionInfo.Holder implements Callable<L
|
|||
.generateViewUpdates(Collections.singleton(view), data, empty, nowInSec, true);
|
||||
|
||||
AtomicLong noBase = new AtomicLong(Long.MAX_VALUE);
|
||||
mutations.forEachRemaining(m -> StorageProxy.mutateMV(key.getKey(), m, true, noBase, nanoTime()));
|
||||
mutations.forEachRemaining(m -> StorageProxy.mutateMV(key.getKey(), m, true, noBase, Dispatcher.RequestTime.forImmediateExecution()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,11 +43,11 @@ import org.apache.cassandra.metrics.CIDRAuthorizerMetrics;
|
|||
import org.apache.cassandra.schema.SchemaConstants;
|
||||
import org.apache.cassandra.schema.TableMetadata;
|
||||
import org.apache.cassandra.service.ClientState;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.transport.messages.ResultMessage;
|
||||
import org.apache.cassandra.utils.MBeanWrapper;
|
||||
|
||||
import static org.apache.cassandra.service.QueryState.forInternalCalls;
|
||||
import static org.apache.cassandra.utils.Clock.Global.nanoTime;
|
||||
|
||||
/**
|
||||
* Virtual tables capturing metrics related to CIDR filtering
|
||||
|
|
@ -196,7 +196,7 @@ public class CIDRFilteringMetricsTable implements CIDRFilteringMetricsTableMBean
|
|||
QueryOptions options = QueryOptions.forInternalCalls(CassandraAuthorizer.authReadConsistencyLevel(),
|
||||
Collections.emptyList());
|
||||
|
||||
ResultMessage.Rows rows = statement.execute(forInternalCalls(), options, nanoTime());
|
||||
ResultMessage.Rows rows = statement.execute(forInternalCalls(), options, Dispatcher.RequestTime.forImmediateExecution());
|
||||
return UntypedResultSet.create(rows.result);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ import org.apache.cassandra.service.ClientState;
|
|||
import org.apache.cassandra.service.DatacenterSyncWriteResponseHandler;
|
||||
import org.apache.cassandra.service.DatacenterWriteResponseHandler;
|
||||
import org.apache.cassandra.service.WriteResponseHandler;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.cliffc.high_scale_lib.NonBlockingHashMap;
|
||||
|
||||
|
|
@ -136,32 +137,32 @@ public abstract class AbstractReplicationStrategy
|
|||
Runnable callback,
|
||||
WriteType writeType,
|
||||
Supplier<Mutation> hintOnFailure,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
return getWriteResponseHandler(replicaPlan, callback, writeType, hintOnFailure,
|
||||
queryStartNanoTime, DatabaseDescriptor.getIdealConsistencyLevel());
|
||||
requestTime, DatabaseDescriptor.getIdealConsistencyLevel());
|
||||
}
|
||||
|
||||
public <T> AbstractWriteResponseHandler<T> getWriteResponseHandler(ReplicaPlan.ForWrite replicaPlan,
|
||||
Runnable callback,
|
||||
WriteType writeType,
|
||||
Supplier<Mutation> hintOnFailure,
|
||||
long queryStartNanoTime,
|
||||
Dispatcher.RequestTime requestTime,
|
||||
ConsistencyLevel idealConsistencyLevel)
|
||||
{
|
||||
AbstractWriteResponseHandler<T> resultResponseHandler;
|
||||
if (replicaPlan.consistencyLevel().isDatacenterLocal())
|
||||
{
|
||||
// block for in this context will be localnodes block.
|
||||
resultResponseHandler = new DatacenterWriteResponseHandler<T>(replicaPlan, callback, writeType, hintOnFailure, queryStartNanoTime);
|
||||
resultResponseHandler = new DatacenterWriteResponseHandler<T>(replicaPlan, callback, writeType, hintOnFailure, requestTime);
|
||||
}
|
||||
else if (replicaPlan.consistencyLevel() == ConsistencyLevel.EACH_QUORUM && (this instanceof NetworkTopologyStrategy))
|
||||
{
|
||||
resultResponseHandler = new DatacenterSyncWriteResponseHandler<T>(replicaPlan, callback, writeType, hintOnFailure, queryStartNanoTime);
|
||||
resultResponseHandler = new DatacenterSyncWriteResponseHandler<T>(replicaPlan, callback, writeType, hintOnFailure, requestTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
resultResponseHandler = new WriteResponseHandler<T>(replicaPlan, callback, writeType, hintOnFailure, queryStartNanoTime);
|
||||
resultResponseHandler = new WriteResponseHandler<T>(replicaPlan, callback, writeType, hintOnFailure, requestTime);
|
||||
}
|
||||
|
||||
//Check if tracking the ideal consistency level is configured
|
||||
|
|
@ -181,7 +182,7 @@ public abstract class AbstractReplicationStrategy
|
|||
callback,
|
||||
writeType,
|
||||
hintOnFailure,
|
||||
queryStartNanoTime,
|
||||
requestTime,
|
||||
idealConsistencyLevel);
|
||||
resultResponseHandler.setIdealCLResponseHandler(idealHandler);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,13 +18,23 @@
|
|||
*/
|
||||
package org.apache.cassandra.metrics;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
import com.codahale.metrics.Gauge;
|
||||
import com.codahale.metrics.Histogram;
|
||||
import com.codahale.metrics.Meter;
|
||||
import com.codahale.metrics.Reservoir;
|
||||
import com.codahale.metrics.Timer;
|
||||
import org.apache.cassandra.transport.*;
|
||||
|
||||
import static org.apache.cassandra.metrics.CassandraMetricsRegistry.Metrics;
|
||||
|
|
@ -41,15 +51,17 @@ public final class ClientMetrics
|
|||
private Meter authSuccess;
|
||||
private Meter authFailure;
|
||||
private AtomicInteger pausedConnections;
|
||||
|
||||
|
||||
@SuppressWarnings({ "unused", "FieldCanBeLocal" })
|
||||
private Gauge<Integer> pausedConnectionsGauge;
|
||||
|
||||
private Meter connectionPaused;
|
||||
private Meter requestDiscarded;
|
||||
private Meter requestDispatched;
|
||||
|
||||
private Meter timedOutBeforeProcessing;
|
||||
private Meter protocolException;
|
||||
private Meter unknownException;
|
||||
private Timer queueTime;
|
||||
|
||||
private ClientMetrics()
|
||||
{
|
||||
|
|
@ -65,11 +77,22 @@ public final class ClientMetrics
|
|||
authFailure.mark();
|
||||
}
|
||||
|
||||
public void pauseConnection() { pausedConnections.incrementAndGet(); }
|
||||
@VisibleForTesting
|
||||
public int getNumberOfPausedConnections()
|
||||
{
|
||||
return (int) connectionPaused.getCount();
|
||||
}
|
||||
|
||||
public void pauseConnection()
|
||||
{
|
||||
connectionPaused.mark();
|
||||
pausedConnections.incrementAndGet();
|
||||
}
|
||||
public void unpauseConnection() { pausedConnections.decrementAndGet(); }
|
||||
|
||||
public void markRequestDiscarded() { requestDiscarded.mark(); }
|
||||
public void markRequestDispatched() { requestDispatched.mark(); }
|
||||
public void markTimedOutBeforeProcessing() { timedOutBeforeProcessing.mark(); }
|
||||
|
||||
public List<ConnectedClient> allConnectedClients()
|
||||
{
|
||||
|
|
@ -120,13 +143,16 @@ public final class ClientMetrics
|
|||
|
||||
pausedConnections = new AtomicInteger();
|
||||
pausedConnectionsGauge = registerGauge("PausedConnections", pausedConnections::get);
|
||||
connectionPaused = registerMeter("ConnectionPaused");
|
||||
requestDiscarded = registerMeter("RequestDiscarded");
|
||||
requestDispatched = registerMeter("RequestDispatched");
|
||||
|
||||
timedOutBeforeProcessing = registerMeter("TimedOutBeforeProcessing");
|
||||
protocolException = registerMeter("ProtocolException");
|
||||
unknownException = registerMeter("UnknownException");
|
||||
|
||||
initialized = true;
|
||||
queueTime = registerTimer("Queued");
|
||||
}
|
||||
|
||||
private int countConnectedClients()
|
||||
|
|
@ -191,4 +217,14 @@ public final class ClientMetrics
|
|||
{
|
||||
return Metrics.meter(factory.createMetricName(name));
|
||||
}
|
||||
|
||||
public Timer registerTimer(String name)
|
||||
{
|
||||
return Metrics.timer(factory.createMetricName(name));
|
||||
}
|
||||
|
||||
public void queueTime(long value, TimeUnit unit)
|
||||
{
|
||||
queueTime.update(value, unit);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ public class ThreadPoolMetrics
|
|||
public static final String TOTAL_BLOCKED_TASKS = "TotalBlockedTasks";
|
||||
public static final String MAX_POOL_SIZE = "MaxPoolSize";
|
||||
public static final String MAX_TASKS_QUEUED = "MaxTasksQueued";
|
||||
public static final String OLDEST_TASK_QUEUE_TIME = "OldestTaskQueueTime";
|
||||
|
||||
/** Number of active tasks. */
|
||||
public final Gauge<Integer> activeTasks;
|
||||
|
|
@ -62,6 +63,9 @@ public class ThreadPoolMetrics
|
|||
/** Maximum number of threads before it will start queuing tasks */
|
||||
public final Gauge<Integer> maxPoolSize;
|
||||
|
||||
/** For how long the oldest task in the queue was queued */
|
||||
public final Gauge<Long> oldestTaskQueueTime;
|
||||
|
||||
/** Maximum number of tasks queued before a task get blocked */
|
||||
public final Gauge<Integer> maxTasksQueued;
|
||||
|
||||
|
|
@ -87,6 +91,7 @@ public class ThreadPoolMetrics
|
|||
completedTasks = executor::getCompletedTaskCount;
|
||||
maxPoolSize = executor::getMaximumPoolSize;
|
||||
maxTasksQueued = executor::getMaxTasksQueued;
|
||||
oldestTaskQueueTime = executor::oldestTaskQueueTime;
|
||||
}
|
||||
|
||||
public ThreadPoolMetrics register()
|
||||
|
|
@ -98,6 +103,7 @@ public class ThreadPoolMetrics
|
|||
Metrics.register(makeMetricName(path, poolName, TOTAL_BLOCKED_TASKS), totalBlocked);
|
||||
Metrics.register(makeMetricName(path, poolName, MAX_POOL_SIZE), maxPoolSize);
|
||||
Metrics.register(makeMetricName(path, poolName, MAX_TASKS_QUEUED), maxTasksQueued);
|
||||
Metrics.register(makeMetricName(path, poolName, OLDEST_TASK_QUEUE_TIME), oldestTaskQueueTime);
|
||||
return Metrics.register(this);
|
||||
}
|
||||
|
||||
|
|
@ -110,6 +116,7 @@ public class ThreadPoolMetrics
|
|||
Metrics.remove(makeMetricName(path, poolName, TOTAL_BLOCKED_TASKS));
|
||||
Metrics.remove(makeMetricName(path, poolName, MAX_POOL_SIZE));
|
||||
Metrics.remove(makeMetricName(path, poolName, MAX_TASKS_QUEUED));
|
||||
Metrics.remove(makeMetricName(path, poolName, OLDEST_TASK_QUEUE_TIME));
|
||||
Metrics.remove(this);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -403,24 +403,24 @@ public class InboundMessageHandler extends AbstractMessageHandler
|
|||
{
|
||||
/**
|
||||
* Actually handle the message. Runs on the appropriate {@link Stage} for the {@link Verb}.
|
||||
*
|
||||
* <p>
|
||||
* Small messages will come pre-deserialized. Large messages will be deserialized on the stage,
|
||||
* just in time, and only then processed.
|
||||
*/
|
||||
public void run()
|
||||
{
|
||||
Header header = header();
|
||||
long currentTimeNanos = approxTime.now();
|
||||
boolean expired = approxTime.isAfter(currentTimeNanos, header.expiresAtNanos);
|
||||
long approxStartTimeNanos = approxTime.now();
|
||||
boolean expired = approxTime.isAfter(approxStartTimeNanos, header.expiresAtNanos);
|
||||
|
||||
boolean processed = false;
|
||||
try
|
||||
{
|
||||
callbacks.onExecuting(size(), header, currentTimeNanos - header.createdAtNanos, NANOSECONDS);
|
||||
callbacks.onExecuting(size(), header, approxStartTimeNanos - header.createdAtNanos, NANOSECONDS);
|
||||
|
||||
if (expired)
|
||||
{
|
||||
callbacks.onExpired(size(), header, currentTimeNanos - header.createdAtNanos, NANOSECONDS);
|
||||
callbacks.onExpired(size(), header, approxStartTimeNanos - header.createdAtNanos, NANOSECONDS);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -441,7 +441,7 @@ public class InboundMessageHandler extends AbstractMessageHandler
|
|||
|
||||
releaseResources();
|
||||
|
||||
callbacks.onExecuted(size(), header, approxTime.now() - currentTimeNanos, NANOSECONDS);
|
||||
callbacks.onExecuted(size(), header, approxTime.now() - approxStartTimeNanos, NANOSECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import java.nio.ByteBuffer;
|
|||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
|
@ -42,6 +43,7 @@ import org.apache.cassandra.io.util.DataOutputPlus;
|
|||
import org.apache.cassandra.locator.InetAddressAndPort;
|
||||
import org.apache.cassandra.tracing.Tracing;
|
||||
import org.apache.cassandra.tracing.Tracing.TraceType;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.utils.MonotonicClockTranslation;
|
||||
import org.apache.cassandra.utils.NoSpamLogger;
|
||||
import org.apache.cassandra.utils.TimeUUID;
|
||||
|
|
@ -217,6 +219,23 @@ public class Message<T>
|
|||
return outWithParam(nextId(), verb, 0, payload, flag2.addTo(flag1.addTo(0)), null, null);
|
||||
}
|
||||
|
||||
public static <T> Message<T> outWithFlags(Verb verb, T payload, Dispatcher.RequestTime requestTime, List<MessageFlag> flags)
|
||||
{
|
||||
assert !verb.isResponse();
|
||||
int encodedFlags = 0;
|
||||
for (MessageFlag flag : flags)
|
||||
encodedFlags = flag.addTo(encodedFlags);
|
||||
|
||||
return new Message<T>(new Header(nextId(),
|
||||
verb,
|
||||
getBroadcastAddressAndPort(),
|
||||
requestTime.startedAtNanos(),
|
||||
requestTime.computeDeadline(verb.expiresAfterNanos()),
|
||||
encodedFlags,
|
||||
buildParams(null, null)),
|
||||
payload);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static <T> Message<T> outWithParam(long id, Verb verb, T payload, ParamType paramType, Object paramValue)
|
||||
{
|
||||
|
|
@ -832,15 +851,13 @@ public class Message<T>
|
|||
Map<ParamType, Object> params = extractParams(buf, index, version);
|
||||
|
||||
long createdAtNanos = calculateCreationTimeNanos(createdAtMillis, timeSnapshot, currentTimeNanos);
|
||||
long expiresAtNanos = getExpiresAtNanos(createdAtNanos, currentTimeNanos, TimeUnit.MILLISECONDS.toNanos(expiresInMillis));
|
||||
long expiresAtNanos = getExpiresAtNanos(createdAtNanos, TimeUnit.MILLISECONDS.toNanos(expiresInMillis));
|
||||
|
||||
return new Header(id, verb, from, createdAtNanos, expiresAtNanos, flags, params);
|
||||
}
|
||||
|
||||
private static long getExpiresAtNanos(long createdAtNanos, long currentTimeNanos, long expirationPeriodNanos)
|
||||
private static long getExpiresAtNanos(long createdAtNanos, long expirationPeriodNanos)
|
||||
{
|
||||
if (!DatabaseDescriptor.hasCrossNodeTimeout() || createdAtNanos > currentTimeNanos)
|
||||
createdAtNanos = currentTimeNanos;
|
||||
return createdAtNanos + expirationPeriodNanos;
|
||||
}
|
||||
|
||||
|
|
@ -862,7 +879,7 @@ public class Message<T>
|
|||
long currentTimeNanos = approxTime.now();
|
||||
MonotonicClockTranslation timeSnapshot = approxTime.translate();
|
||||
long creationTimeNanos = calculateCreationTimeNanos(in.readInt(), timeSnapshot, currentTimeNanos);
|
||||
long expiresAtNanos = getExpiresAtNanos(creationTimeNanos, currentTimeNanos, TimeUnit.MILLISECONDS.toNanos(in.readUnsignedVInt()));
|
||||
long expiresAtNanos = getExpiresAtNanos(creationTimeNanos, TimeUnit.MILLISECONDS.toNanos(in.readUnsignedVInt()));
|
||||
Verb verb = Verb.fromId(in.readUnsignedVInt32());
|
||||
int flags = in.readUnsignedVInt32();
|
||||
Map<ParamType, Object> params = deserializeParams(in, version);
|
||||
|
|
@ -901,6 +918,10 @@ public class Message<T>
|
|||
@VisibleForTesting
|
||||
static long calculateCreationTimeNanos(int messageTimestampMillis, MonotonicClockTranslation timeSnapshot, long currentTimeNanos)
|
||||
{
|
||||
// We do not trust external time source, so we override their value with current time
|
||||
if (!DatabaseDescriptor.hasCrossNodeTimeout())
|
||||
return currentTimeNanos;
|
||||
|
||||
long currentTimeMillis = timeSnapshot.toMillisSinceEpoch(currentTimeNanos);
|
||||
// Reconstruct the message construction time sent by the remote host (we sent only the lower 4 bytes, assuming the
|
||||
// higher 4 bytes wouldn't change between the sender and receiver)
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ import org.apache.cassandra.net.Verb;
|
|||
import org.apache.cassandra.repair.messages.FailSession;
|
||||
import org.apache.cassandra.repair.messages.RepairMessage;
|
||||
import org.apache.cassandra.repair.state.ParticipateState;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.utils.*;
|
||||
import org.apache.cassandra.utils.concurrent.Future;
|
||||
import org.apache.commons.lang3.time.DurationFormatUtils;
|
||||
|
|
@ -551,7 +552,7 @@ public class RepairCoordinator implements Runnable, ProgressEventNotifier, Repai
|
|||
QueryOptions options = QueryOptions.forInternalCalls(ConsistencyLevel.ONE, Lists.newArrayList(sessionIdBytes,
|
||||
tminBytes,
|
||||
tmaxBytes));
|
||||
ResultMessage.Rows rows = statement.execute(forInternalCalls(), options, ctx.clock().nanoTime());
|
||||
ResultMessage.Rows rows = statement.execute(forInternalCalls(), options, new Dispatcher.RequestTime(ctx.clock().nanoTime()));
|
||||
UntypedResultSet result = UntypedResultSet.create(rows.result);
|
||||
|
||||
for (UntypedResultSet.Row r : result)
|
||||
|
|
|
|||
|
|
@ -25,45 +25,42 @@ import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
|
|||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.apache.cassandra.db.ConsistencyLevel;
|
||||
|
||||
import org.apache.cassandra.db.Mutation;
|
||||
import org.apache.cassandra.locator.EndpointsForToken;
|
||||
import org.apache.cassandra.locator.ReplicaPlan;
|
||||
import org.apache.cassandra.locator.ReplicaPlan.ForWrite;
|
||||
import org.apache.cassandra.utils.concurrent.Condition;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.apache.cassandra.db.ColumnFamilyStore;
|
||||
import org.apache.cassandra.db.ConsistencyLevel;
|
||||
import org.apache.cassandra.db.IMutation;
|
||||
import org.apache.cassandra.db.Mutation;
|
||||
import org.apache.cassandra.db.WriteType;
|
||||
import org.apache.cassandra.exceptions.RequestFailureReason;
|
||||
import org.apache.cassandra.exceptions.WriteFailureException;
|
||||
import org.apache.cassandra.exceptions.WriteTimeoutException;
|
||||
import org.apache.cassandra.locator.EndpointsForToken;
|
||||
import org.apache.cassandra.locator.InetAddressAndPort;
|
||||
import org.apache.cassandra.net.RequestCallback;
|
||||
import org.apache.cassandra.locator.ReplicaPlan;
|
||||
import org.apache.cassandra.locator.ReplicaPlan.ForWrite;
|
||||
import org.apache.cassandra.net.Message;
|
||||
import org.apache.cassandra.net.RequestCallback;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.utils.concurrent.Condition;
|
||||
import org.apache.cassandra.utils.concurrent.UncheckedInterruptedException;
|
||||
|
||||
import static java.lang.Long.MAX_VALUE;
|
||||
import static java.lang.Math.min;
|
||||
import static java.util.concurrent.TimeUnit.MICROSECONDS;
|
||||
import static java.util.concurrent.TimeUnit.NANOSECONDS;
|
||||
|
||||
import static org.apache.cassandra.utils.Clock.Global.nanoTime;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
import static org.apache.cassandra.config.DatabaseDescriptor.getCounterWriteRpcTimeout;
|
||||
import static org.apache.cassandra.config.DatabaseDescriptor.getWriteRpcTimeout;
|
||||
import static org.apache.cassandra.db.WriteType.COUNTER;
|
||||
import static org.apache.cassandra.locator.Replicas.countInOurDc;
|
||||
import static org.apache.cassandra.schema.Schema.instance;
|
||||
import static org.apache.cassandra.service.StorageProxy.WritePerformer;
|
||||
import static org.apache.cassandra.utils.Clock.Global.nanoTime;
|
||||
import static org.apache.cassandra.utils.concurrent.Condition.newOneTimeCondition;
|
||||
import static org.apache.cassandra.locator.Replicas.countInOurDc;
|
||||
|
||||
|
||||
public abstract class AbstractWriteResponseHandler<T> implements RequestCallback<T>
|
||||
{
|
||||
|
|
@ -80,7 +77,7 @@ public abstract class AbstractWriteResponseHandler<T> implements RequestCallback
|
|||
AtomicIntegerFieldUpdater.newUpdater(AbstractWriteResponseHandler.class, "failures");
|
||||
private volatile int failures = 0;
|
||||
private final Map<InetAddressAndPort, RequestFailureReason> failureReasonByEndpoint;
|
||||
private final long queryStartNanoTime;
|
||||
private final Dispatcher.RequestTime requestTime;
|
||||
private @Nullable final Supplier<Mutation> hintOnFailure;
|
||||
|
||||
/**
|
||||
|
|
@ -99,17 +96,17 @@ public abstract class AbstractWriteResponseHandler<T> implements RequestCallback
|
|||
/**
|
||||
* @param callback A callback to be called when the write is successful.
|
||||
* @param hintOnFailure
|
||||
* @param queryStartNanoTime
|
||||
* @param requestTime
|
||||
*/
|
||||
protected AbstractWriteResponseHandler(ForWrite replicaPlan, Runnable callback, WriteType writeType,
|
||||
Supplier<Mutation> hintOnFailure, long queryStartNanoTime)
|
||||
Supplier<Mutation> hintOnFailure, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
this.replicaPlan = replicaPlan;
|
||||
this.callback = callback;
|
||||
this.writeType = writeType;
|
||||
this.hintOnFailure = hintOnFailure;
|
||||
this.failureReasonByEndpoint = new ConcurrentHashMap<>();
|
||||
this.queryStartNanoTime = queryStartNanoTime;
|
||||
this.requestTime = requestTime;
|
||||
}
|
||||
|
||||
public void get() throws WriteTimeoutException, WriteFailureException
|
||||
|
|
@ -154,10 +151,11 @@ public abstract class AbstractWriteResponseHandler<T> implements RequestCallback
|
|||
|
||||
public final long currentTimeoutNanos()
|
||||
{
|
||||
long now = nanoTime();
|
||||
long requestTimeout = writeType == COUNTER
|
||||
? getCounterWriteRpcTimeout(NANOSECONDS)
|
||||
: getWriteRpcTimeout(NANOSECONDS);
|
||||
return requestTimeout - (nanoTime() - queryStartNanoTime);
|
||||
return requestTime.computeTimeout(now, requestTimeout);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -292,7 +290,7 @@ public abstract class AbstractWriteResponseHandler<T> implements RequestCallback
|
|||
if (blockFor() + n > candidateReplicaCount())
|
||||
signal();
|
||||
|
||||
if (hintOnFailure != null && StorageProxy.shouldHint(replicaPlan.lookup(from)))
|
||||
if (hintOnFailure != null && StorageProxy.shouldHint(replicaPlan.lookup(from)) && requestTime.shouldSendHints())
|
||||
StorageProxy.submitHint(hintOnFailure.get(), replicaPlan.lookup(from), null);
|
||||
}
|
||||
|
||||
|
|
@ -320,7 +318,7 @@ public abstract class AbstractWriteResponseHandler<T> implements RequestCallback
|
|||
}
|
||||
else
|
||||
{
|
||||
replicaPlan.keyspace().metric.idealCLWriteLatency.addNano(nanoTime() - queryStartNanoTime);
|
||||
replicaPlan.keyspace().metric.idealCLWriteLatency.addNano(nanoTime() - requestTime.startedAtNanos());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -354,7 +352,8 @@ public abstract class AbstractWriteResponseHandler<T> implements RequestCallback
|
|||
|
||||
writePerformer.apply(mutation, replicaPlan.withContacts(uncontacted),
|
||||
(AbstractWriteResponseHandler<IMutation>) this,
|
||||
localDC);
|
||||
localDC,
|
||||
requestTime);
|
||||
}
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import org.apache.cassandra.exceptions.WriteFailureException;
|
|||
import org.apache.cassandra.exceptions.WriteTimeoutException;
|
||||
import org.apache.cassandra.locator.InetAddressAndPort;
|
||||
import org.apache.cassandra.net.Message;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
|
||||
public class BatchlogResponseHandler<T> extends AbstractWriteResponseHandler<T>
|
||||
{
|
||||
|
|
@ -34,9 +35,9 @@ public class BatchlogResponseHandler<T> extends AbstractWriteResponseHandler<T>
|
|||
private static final AtomicIntegerFieldUpdater<BatchlogResponseHandler> requiredBeforeFinishUpdater
|
||||
= AtomicIntegerFieldUpdater.newUpdater(BatchlogResponseHandler.class, "requiredBeforeFinish");
|
||||
|
||||
public BatchlogResponseHandler(AbstractWriteResponseHandler<T> wrapped, int requiredBeforeFinish, BatchlogCleanup cleanup, long queryStartNanoTime)
|
||||
public BatchlogResponseHandler(AbstractWriteResponseHandler<T> wrapped, int requiredBeforeFinish, BatchlogCleanup cleanup, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
super(wrapped.replicaPlan, wrapped.callback, wrapped.writeType, null, queryStartNanoTime);
|
||||
super(wrapped.replicaPlan, wrapped.callback, wrapped.writeType, null, requestTime);
|
||||
this.wrapped = wrapped;
|
||||
this.requiredBeforeFinish = requiredBeforeFinish;
|
||||
this.cleanup = cleanup;
|
||||
|
|
|
|||
|
|
@ -111,6 +111,12 @@ public class CassandraDaemon
|
|||
return instance;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public NativeTransportService nativeTransportService()
|
||||
{
|
||||
return nativeTransportService;
|
||||
}
|
||||
|
||||
static {
|
||||
// Need to register metrics before instrumented appender is created(first access to LoggerFactory).
|
||||
SharedMetricRegistries.getOrCreate("logback-metrics").addListener(new MetricRegistryListener.Base()
|
||||
|
|
@ -818,12 +824,16 @@ public class CassandraDaemon
|
|||
StorageService.instance.setRpcReady(true);
|
||||
}
|
||||
|
||||
@Deprecated(since = "5.0.0")
|
||||
public void stopNativeTransport()
|
||||
{
|
||||
stopNativeTransport(false);
|
||||
}
|
||||
|
||||
public void stopNativeTransport(boolean force)
|
||||
{
|
||||
if (nativeTransportService != null)
|
||||
{
|
||||
nativeTransportService.stop();
|
||||
}
|
||||
nativeTransportService.stop(force);
|
||||
}
|
||||
|
||||
public boolean isNativeTransportRunning()
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import org.apache.cassandra.locator.ReplicaPlan;
|
|||
import org.apache.cassandra.net.Message;
|
||||
import org.apache.cassandra.db.ConsistencyLevel;
|
||||
import org.apache.cassandra.db.WriteType;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
|
||||
/**
|
||||
* This class blocks for a quorum of responses _in all datacenters_ (CL.EACH_QUORUM).
|
||||
|
|
@ -46,10 +47,10 @@ public class DatacenterSyncWriteResponseHandler<T> extends AbstractWriteResponse
|
|||
Runnable callback,
|
||||
WriteType writeType,
|
||||
Supplier<Mutation> hintOnFailure,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
// Response is been managed by the map so make it 1 for the superclass.
|
||||
super(replicaPlan, callback, writeType, hintOnFailure, queryStartNanoTime);
|
||||
super(replicaPlan, callback, writeType, hintOnFailure, requestTime);
|
||||
assert replicaPlan.consistencyLevel() == ConsistencyLevel.EACH_QUORUM;
|
||||
|
||||
if (replicaPlan.replicationStrategy() instanceof NetworkTopologyStrategy)
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import org.apache.cassandra.locator.InOurDc;
|
|||
import org.apache.cassandra.locator.InetAddressAndPort;
|
||||
import org.apache.cassandra.locator.ReplicaPlan;
|
||||
import org.apache.cassandra.net.Message;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
|
|
@ -38,9 +39,9 @@ public class DatacenterWriteResponseHandler<T> extends WriteResponseHandler<T>
|
|||
Runnable callback,
|
||||
WriteType writeType,
|
||||
Supplier<Mutation> hintOnFailure,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
super(replicaPlan, callback, writeType, hintOnFailure, queryStartNanoTime);
|
||||
super(replicaPlan, callback, writeType, hintOnFailure, requestTime);
|
||||
assert replicaPlan.consistencyLevel().isDatacenterLocal();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -139,7 +139,12 @@ public class NativeTransportService
|
|||
*/
|
||||
public void stop()
|
||||
{
|
||||
servers.forEach(Server::stop);
|
||||
stop(false);
|
||||
}
|
||||
|
||||
public void stop(boolean force)
|
||||
{
|
||||
servers.forEach((s) -> s.stop(force));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import java.nio.ByteBuffer;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
|
@ -136,6 +137,7 @@ import org.apache.cassandra.service.reads.ReadCallback;
|
|||
import org.apache.cassandra.service.reads.range.RangeCommands;
|
||||
import org.apache.cassandra.service.reads.repair.ReadRepair;
|
||||
import org.apache.cassandra.tracing.Tracing;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.triggers.TriggerExecutor;
|
||||
import org.apache.cassandra.utils.Clock;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
|
|
@ -220,10 +222,10 @@ public class StorageProxy implements StorageProxyMBean
|
|||
MBeanWrapper.instance.registerMBean(instance, MBEAN_NAME);
|
||||
HintsService.instance.registerMBean();
|
||||
|
||||
standardWritePerformer = (mutation, targets, responseHandler, localDataCenter) ->
|
||||
standardWritePerformer = (mutation, targets, responseHandler, localDataCenter, requestTime) ->
|
||||
{
|
||||
assert mutation instanceof Mutation;
|
||||
sendToHintedReplicas((Mutation) mutation, targets, responseHandler, localDataCenter, Stage.MUTATION);
|
||||
sendToHintedReplicas((Mutation) mutation, targets, responseHandler, localDataCenter, Stage.MUTATION, requestTime);
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -232,19 +234,19 @@ public class StorageProxy implements StorageProxyMBean
|
|||
* but on the latter case, the verb handler already run on the COUNTER_MUTATION stage, so we must not execute the
|
||||
* underlying on the stage otherwise we risk a deadlock. Hence two different performer.
|
||||
*/
|
||||
counterWritePerformer = (mutation, targets, responseHandler, localDataCenter) ->
|
||||
counterWritePerformer = (mutation, targets, responseHandler, localDataCenter, requestTime) ->
|
||||
{
|
||||
EndpointsForToken selected = targets.contacts().withoutSelf();
|
||||
Replicas.temporaryAssertFull(selected); // TODO CASSANDRA-14548
|
||||
counterWriteTask(mutation, targets.withContacts(selected), responseHandler, localDataCenter).run();
|
||||
counterWriteTask(mutation, targets.withContacts(selected), responseHandler, localDataCenter, requestTime).run();
|
||||
};
|
||||
|
||||
counterWriteOnCoordinatorPerformer = (mutation, targets, responseHandler, localDataCenter) ->
|
||||
counterWriteOnCoordinatorPerformer = (mutation, targets, responseHandler, localDataCenter, requestTime) ->
|
||||
{
|
||||
EndpointsForToken selected = targets.contacts().withoutSelf();
|
||||
Replicas.temporaryAssertFull(selected); // TODO CASSANDRA-14548
|
||||
Stage.COUNTER_MUTATION.executor()
|
||||
.execute(counterWriteTask(mutation, targets.withContacts(selected), responseHandler, localDataCenter));
|
||||
.execute(counterWriteTask(mutation, targets.withContacts(selected), responseHandler, localDataCenter, requestTime));
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -310,7 +312,7 @@ public class StorageProxy implements StorageProxyMBean
|
|||
ConsistencyLevel consistencyForCommit,
|
||||
ClientState clientState,
|
||||
long nowInSeconds,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
throws UnavailableException, IsBootstrappingException, RequestFailureException, RequestTimeoutException, InvalidRequestException, CasWriteUnknownResultException
|
||||
{
|
||||
if (DatabaseDescriptor.getPartitionDenylistEnabled() && DatabaseDescriptor.getDenylistWritesEnabled() && !partitionDenylist.isKeyPermitted(keyspaceName, cfName, key.getKey()))
|
||||
|
|
@ -322,7 +324,7 @@ public class StorageProxy implements StorageProxyMBean
|
|||
|
||||
return Paxos.useV2()
|
||||
? Paxos.cas(key, request, consistencyForPaxos, consistencyForCommit, clientState)
|
||||
: legacyCas(keyspaceName, cfName, key, request, consistencyForPaxos, consistencyForCommit, clientState, nowInSeconds, queryStartNanoTime);
|
||||
: legacyCas(keyspaceName, cfName, key, request, consistencyForPaxos, consistencyForCommit, clientState, nowInSeconds, requestTime);
|
||||
}
|
||||
|
||||
public static RowIterator legacyCas(String keyspaceName,
|
||||
|
|
@ -333,10 +335,9 @@ public class StorageProxy implements StorageProxyMBean
|
|||
ConsistencyLevel consistencyForCommit,
|
||||
ClientState clientState,
|
||||
long nowInSeconds,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
throws UnavailableException, IsBootstrappingException, RequestFailureException, RequestTimeoutException, InvalidRequestException
|
||||
{
|
||||
final long startTimeForMetrics = nanoTime();
|
||||
try
|
||||
{
|
||||
TableMetadata metadata = Schema.instance.validateTable(keyspaceName, cfName);
|
||||
|
|
@ -345,11 +346,11 @@ public class StorageProxy implements StorageProxyMBean
|
|||
{
|
||||
// read the current values and check they validate the conditions
|
||||
Tracing.trace("Reading existing values for CAS precondition");
|
||||
SinglePartitionReadCommand readCommand = (SinglePartitionReadCommand) request.readCommand(nowInSeconds);
|
||||
SinglePartitionReadCommand readCommand = request.readCommand(nowInSeconds);
|
||||
ConsistencyLevel readConsistency = consistencyForPaxos == ConsistencyLevel.LOCAL_SERIAL ? ConsistencyLevel.LOCAL_QUORUM : ConsistencyLevel.QUORUM;
|
||||
|
||||
FilteredPartition current;
|
||||
try (RowIterator rowIter = readOne(readCommand, readConsistency, queryStartNanoTime))
|
||||
try (RowIterator rowIter = readOne(readCommand, readConsistency, requestTime))
|
||||
{
|
||||
current = FilteredPartition.create(rowIter);
|
||||
}
|
||||
|
|
@ -388,7 +389,7 @@ public class StorageProxy implements StorageProxyMBean
|
|||
consistencyForPaxos,
|
||||
consistencyForCommit,
|
||||
consistencyForCommit,
|
||||
queryStartNanoTime,
|
||||
requestTime,
|
||||
casWriteMetrics,
|
||||
updateProposer);
|
||||
|
||||
|
|
@ -430,7 +431,9 @@ public class StorageProxy implements StorageProxyMBean
|
|||
}
|
||||
finally
|
||||
{
|
||||
final long latency = nanoTime() - startTimeForMetrics;
|
||||
// We track latency based on request processing time, since the amount of time that request spends in the queue
|
||||
// is not a representative metric of replica performance.
|
||||
long latency = nanoTime() - requestTime.startedAtNanos();
|
||||
casWriteMetrics.addNano(latency);
|
||||
writeMetricsForLevel(consistencyForPaxos).addNano(latency);
|
||||
}
|
||||
|
|
@ -466,7 +469,7 @@ public class StorageProxy implements StorageProxyMBean
|
|||
* {@link ConsistencyLevel#LOCAL_SERIAL}).
|
||||
* @param consistencyForReplayCommits the consistency for the commit phase of "replayed" in-progress operations.
|
||||
* @param consistencyForCommit the consistency for the commit phase of _this_ operation update.
|
||||
* @param queryStartNanoTime the nano time for the start of the query this is part of. This is the base time for
|
||||
* @param requestTime the nano time for the start of the query this is part of. This is the base time for
|
||||
* timeouts.
|
||||
* @param casMetrics the metrics to update for this operation.
|
||||
* @param createUpdateProposal method called after a successful 'prepare' phase to obtain 1) the actual update of
|
||||
|
|
@ -481,7 +484,7 @@ public class StorageProxy implements StorageProxyMBean
|
|||
ConsistencyLevel consistencyForPaxos,
|
||||
ConsistencyLevel consistencyForReplayCommits,
|
||||
ConsistencyLevel consistencyForCommit,
|
||||
long queryStartNanoTime,
|
||||
Dispatcher.RequestTime requestTime,
|
||||
CASClientRequestMetrics casMetrics,
|
||||
Function<Ballot, Pair<PartitionUpdate, RowIterator>> createUpdateProposal)
|
||||
throws UnavailableException, IsBootstrappingException, RequestFailureException, RequestTimeoutException, InvalidRequestException
|
||||
|
|
@ -496,12 +499,13 @@ public class StorageProxy implements StorageProxyMBean
|
|||
consistencyForCommit.validateForCasCommit(latestRs);
|
||||
|
||||
long timeoutNanos = DatabaseDescriptor.getCasContentionTimeout(NANOSECONDS);
|
||||
while (nanoTime() - queryStartNanoTime < timeoutNanos)
|
||||
long deadline = requestTime.computeDeadline(timeoutNanos);
|
||||
while (nanoTime() < deadline)
|
||||
{
|
||||
// for simplicity, we'll do a single liveness check at the start of each attempt
|
||||
ReplicaPlan.ForPaxosWrite replicaPlan = ReplicaPlans.forPaxos(keyspace, key, consistencyForPaxos);
|
||||
latestRs = replicaPlan.replicationStrategy();
|
||||
PaxosBallotAndContention pair = beginAndRepairPaxos(queryStartNanoTime,
|
||||
PaxosBallotAndContention pair = beginAndRepairPaxos(requestTime,
|
||||
key,
|
||||
metadata,
|
||||
replicaPlan,
|
||||
|
|
@ -519,14 +523,14 @@ public class StorageProxy implements StorageProxyMBean
|
|||
|
||||
Commit proposal = Commit.newProposal(ballot, proposalPair.left);
|
||||
Tracing.trace("CAS precondition is met; proposing client-requested updates for {}", ballot);
|
||||
if (proposePaxos(proposal, replicaPlan, true, queryStartNanoTime))
|
||||
if (proposePaxos(proposal, replicaPlan, true, requestTime))
|
||||
{
|
||||
// We skip committing accepted updates when they are empty. This is an optimization which works
|
||||
// because we also skip replaying those same empty update in beginAndRepairPaxos (see the longer
|
||||
// comment there). As empty update are somewhat common (serial reads and non-applying CAS propose
|
||||
// them), this is worth bothering.
|
||||
if (!proposal.update.isEmpty())
|
||||
commitPaxos(proposal, consistencyForCommit, true, queryStartNanoTime);
|
||||
commitPaxos(proposal, consistencyForCommit, true, requestTime);
|
||||
RowIterator result = proposalPair.right;
|
||||
if (result != null)
|
||||
Tracing.trace("CAS did not apply");
|
||||
|
|
@ -569,7 +573,7 @@ public class StorageProxy implements StorageProxyMBean
|
|||
* @return the Paxos ballot promised by the replicas if no in-progress requests were seen and a quorum of
|
||||
* nodes have seen the mostRecentCommit. Otherwise, return null.
|
||||
*/
|
||||
private static PaxosBallotAndContention beginAndRepairPaxos(long queryStartNanoTime,
|
||||
private static PaxosBallotAndContention beginAndRepairPaxos(Dispatcher.RequestTime requestTime,
|
||||
DecoratedKey key,
|
||||
TableMetadata metadata,
|
||||
ReplicaPlan.ForPaxosWrite paxosPlan,
|
||||
|
|
@ -582,7 +586,8 @@ public class StorageProxy implements StorageProxyMBean
|
|||
|
||||
PrepareCallback summary = null;
|
||||
int contentions = 0;
|
||||
while (nanoTime() - queryStartNanoTime < timeoutNanos)
|
||||
long deadline = requestTime.computeDeadline(timeoutNanos);
|
||||
while (nanoTime() < deadline)
|
||||
{
|
||||
// We want a timestamp that is guaranteed to be unique for that node (so that the ballot is globally unique), but if we've got a prepare rejected
|
||||
// already we also want to make sure we pick a timestamp that has a chance to be promised, i.e. one that is greater that the most recently known
|
||||
|
|
@ -598,7 +603,7 @@ public class StorageProxy implements StorageProxyMBean
|
|||
{
|
||||
Tracing.trace("Preparing {}", ballot);
|
||||
Commit toPrepare = Commit.newPrepare(key, metadata, ballot);
|
||||
summary = preparePaxos(toPrepare, paxosPlan, queryStartNanoTime);
|
||||
summary = preparePaxos(toPrepare, paxosPlan, requestTime);
|
||||
if (!summary.promised)
|
||||
{
|
||||
Tracing.trace("Some replicas have already promised a higher ballot than ours; aborting");
|
||||
|
|
@ -634,9 +639,9 @@ public class StorageProxy implements StorageProxyMBean
|
|||
Tracing.trace("Finishing incomplete paxos round {}", inProgress);
|
||||
casMetrics.unfinishedCommit.inc();
|
||||
Commit refreshedInProgress = Commit.newProposal(ballot, inProgress.update);
|
||||
if (proposePaxos(refreshedInProgress, paxosPlan, false, queryStartNanoTime))
|
||||
if (proposePaxos(refreshedInProgress, paxosPlan, false, requestTime))
|
||||
{
|
||||
commitPaxos(refreshedInProgress, consistencyForCommit, false, queryStartNanoTime);
|
||||
commitPaxos(refreshedInProgress, consistencyForCommit, false, requestTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -686,10 +691,10 @@ public class StorageProxy implements StorageProxyMBean
|
|||
MessagingService.instance().send(message, target);
|
||||
}
|
||||
|
||||
private static PrepareCallback preparePaxos(Commit toPrepare, ReplicaPlan.ForPaxosWrite replicaPlan, long queryStartNanoTime)
|
||||
private static PrepareCallback preparePaxos(Commit toPrepare, ReplicaPlan.ForPaxosWrite replicaPlan, Dispatcher.RequestTime requestTime)
|
||||
throws WriteTimeoutException
|
||||
{
|
||||
PrepareCallback callback = new PrepareCallback(toPrepare.update.partitionKey(), toPrepare.update.metadata(), replicaPlan.requiredParticipants(), replicaPlan.consistencyLevel(), queryStartNanoTime);
|
||||
PrepareCallback callback = new PrepareCallback(toPrepare.update.partitionKey(), toPrepare.update.metadata(), replicaPlan.requiredParticipants(), replicaPlan.consistencyLevel(), requestTime);
|
||||
Message<Commit> message = Message.out(PAXOS_PREPARE_REQ, toPrepare);
|
||||
|
||||
boolean hasLocalRequest = false;
|
||||
|
|
@ -730,10 +735,10 @@ public class StorageProxy implements StorageProxyMBean
|
|||
* When {@param backoffIfPartial} is true, the proposer backs off when seeing the proposal being accepted by some but not a quorum.
|
||||
* The result of the cooresponding CAS in uncertain as the accepted proposal may or may not be spread to other nodes in later rounds.
|
||||
*/
|
||||
private static boolean proposePaxos(Commit proposal, ReplicaPlan.ForPaxosWrite replicaPlan, boolean backoffIfPartial, long queryStartNanoTime)
|
||||
private static boolean proposePaxos(Commit proposal, ReplicaPlan.ForPaxosWrite replicaPlan, boolean backoffIfPartial, Dispatcher.RequestTime requestTime)
|
||||
throws WriteTimeoutException, CasWriteUnknownResultException
|
||||
{
|
||||
ProposeCallback callback = new ProposeCallback(replicaPlan.contacts().size(), replicaPlan.requiredParticipants(), !backoffIfPartial, replicaPlan.consistencyLevel(), queryStartNanoTime);
|
||||
ProposeCallback callback = new ProposeCallback(replicaPlan.contacts().size(), replicaPlan.requiredParticipants(), !backoffIfPartial, replicaPlan.consistencyLevel(), requestTime);
|
||||
Message<Commit> message = Message.out(PAXOS_PROPOSE_REQ, proposal);
|
||||
for (Replica replica : replicaPlan.contacts())
|
||||
{
|
||||
|
|
@ -767,7 +772,7 @@ public class StorageProxy implements StorageProxyMBean
|
|||
return false;
|
||||
}
|
||||
|
||||
private static void commitPaxos(Commit proposal, ConsistencyLevel consistencyLevel, boolean allowHints, long queryStartNanoTime) throws WriteTimeoutException
|
||||
private static void commitPaxos(Commit proposal, ConsistencyLevel consistencyLevel, boolean allowHints, Dispatcher.RequestTime requestTime) throws WriteTimeoutException
|
||||
{
|
||||
boolean shouldBlock = consistencyLevel != ConsistencyLevel.ANY;
|
||||
Keyspace keyspace = Keyspace.open(proposal.update.metadata().keyspace);
|
||||
|
|
@ -780,7 +785,7 @@ public class StorageProxy implements StorageProxyMBean
|
|||
if (shouldBlock)
|
||||
{
|
||||
AbstractReplicationStrategy rs = replicaPlan.replicationStrategy();
|
||||
responseHandler = rs.getWriteResponseHandler(replicaPlan, null, WriteType.SIMPLE, proposal::makeMutation, queryStartNanoTime);
|
||||
responseHandler = rs.getWriteResponseHandler(replicaPlan, null, WriteType.SIMPLE, proposal::makeMutation, requestTime);
|
||||
}
|
||||
|
||||
Message<Commit> message = Message.outWithFlag(PAXOS_COMMIT_REQ, proposal, MessageFlag.CALL_BACK_ON_FAILURE);
|
||||
|
|
@ -794,7 +799,7 @@ public class StorageProxy implements StorageProxyMBean
|
|||
if (shouldBlock)
|
||||
{
|
||||
if (replica.isSelf())
|
||||
commitPaxosLocal(replica, message, responseHandler);
|
||||
commitPaxosLocal(replica, message, responseHandler, requestTime);
|
||||
else
|
||||
MessagingService.instance().sendWriteWithCallback(message, replica, responseHandler);
|
||||
}
|
||||
|
|
@ -825,9 +830,9 @@ public class StorageProxy implements StorageProxyMBean
|
|||
* submit a fake one that executes immediately on the mutation stage, but generates the necessary backpressure
|
||||
* signal for hints
|
||||
*/
|
||||
private static void commitPaxosLocal(Replica localReplica, final Message<Commit> message, final AbstractWriteResponseHandler<?> responseHandler)
|
||||
private static void commitPaxosLocal(Replica localReplica, final Message<Commit> message, final AbstractWriteResponseHandler<?> responseHandler, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
PAXOS_COMMIT_REQ.stage.maybeExecuteImmediately(new LocalMutationRunnable(localReplica)
|
||||
PAXOS_COMMIT_REQ.stage.maybeExecuteImmediately(new LocalMutationRunnable(localReplica, requestTime)
|
||||
{
|
||||
public void runMayThrow()
|
||||
{
|
||||
|
|
@ -867,16 +872,14 @@ public class StorageProxy implements StorageProxyMBean
|
|||
*
|
||||
* @param mutations the mutations to be applied across the replicas
|
||||
* @param consistencyLevel the consistency level for the operation
|
||||
* @param queryStartNanoTime the value of nanoTime() when the query started to be processed
|
||||
* @param requestTime object holding times when request got enqueued and started execution
|
||||
*/
|
||||
public static void mutate(List<? extends IMutation> mutations, ConsistencyLevel consistencyLevel, long queryStartNanoTime)
|
||||
public static void mutate(List<? extends IMutation> mutations, ConsistencyLevel consistencyLevel, Dispatcher.RequestTime requestTime)
|
||||
throws UnavailableException, OverloadedException, WriteTimeoutException, WriteFailureException
|
||||
{
|
||||
Tracing.trace("Determining replicas for mutation");
|
||||
final String localDataCenter = DatabaseDescriptor.getEndpointSnitch().getLocalDatacenter();
|
||||
|
||||
long startTime = nanoTime();
|
||||
|
||||
List<AbstractWriteResponseHandler<IMutation>> responseHandlers = new ArrayList<>(mutations.size());
|
||||
WriteType plainWriteType = mutations.size() <= 1 ? WriteType.SIMPLE : WriteType.UNLOGGED_BATCH;
|
||||
|
||||
|
|
@ -885,9 +888,9 @@ public class StorageProxy implements StorageProxyMBean
|
|||
for (IMutation mutation : mutations)
|
||||
{
|
||||
if (mutation instanceof CounterMutation)
|
||||
responseHandlers.add(mutateCounter((CounterMutation)mutation, localDataCenter, queryStartNanoTime));
|
||||
responseHandlers.add(mutateCounter((CounterMutation)mutation, localDataCenter, requestTime));
|
||||
else
|
||||
responseHandlers.add(performWrite(mutation, consistencyLevel, localDataCenter, standardWritePerformer, null, plainWriteType, queryStartNanoTime));
|
||||
responseHandlers.add(performWrite(mutation, consistencyLevel, localDataCenter, standardWritePerformer, null, plainWriteType, requestTime));
|
||||
}
|
||||
|
||||
// upgrade to full quorum any failed cheap quorums
|
||||
|
|
@ -943,7 +946,9 @@ public class StorageProxy implements StorageProxyMBean
|
|||
}
|
||||
finally
|
||||
{
|
||||
long latency = nanoTime() - startTime;
|
||||
// We track latency based on request processing time, since the amount of time that request spends in the queue
|
||||
// is not a representative metric of replica performance.
|
||||
long latency = nanoTime() - requestTime.startedAtNanos();
|
||||
writeMetrics.addNano(latency);
|
||||
writeMetricsForLevel(consistencyLevel).addNano(latency);
|
||||
updateCoordinatorWriteLatencyTableMetric(mutations, latency);
|
||||
|
|
@ -999,9 +1004,9 @@ public class StorageProxy implements StorageProxyMBean
|
|||
* @param mutations the mutations to be applied across the replicas
|
||||
* @param writeCommitLog if commitlog should be written
|
||||
* @param baseComplete time from epoch in ms that the local base mutation was(or will be) completed
|
||||
* @param queryStartNanoTime the value of nanoTime() when the query started to be processed
|
||||
* @param requestTime object holding times when request got enqueued and started execution
|
||||
*/
|
||||
public static void mutateMV(ByteBuffer dataKey, Collection<Mutation> mutations, boolean writeCommitLog, AtomicLong baseComplete, long queryStartNanoTime)
|
||||
public static void mutateMV(ByteBuffer dataKey, Collection<Mutation> mutations, boolean writeCommitLog, AtomicLong baseComplete, Dispatcher.RequestTime requestTime)
|
||||
throws UnavailableException, OverloadedException, WriteTimeoutException
|
||||
{
|
||||
Tracing.trace("Determining replicas for mutation");
|
||||
|
|
@ -1032,7 +1037,7 @@ public class StorageProxy implements StorageProxyMBean
|
|||
//Since the base -> view replication is 1:1 we only need to store the BL locally
|
||||
ReplicaPlan.ForWrite replicaPlan = ReplicaPlans.forLocalBatchlogWrite();
|
||||
BatchlogCleanup cleanup = new BatchlogCleanup(mutations.size(),
|
||||
() -> asyncRemoveFromBatchlog(replicaPlan, batchUUID));
|
||||
() -> asyncRemoveFromBatchlog(replicaPlan, batchUUID, requestTime));
|
||||
|
||||
// add a handler for each mutation - includes checking availability, but doesn't initiate any writes, yet
|
||||
for (Mutation mutation : mutations)
|
||||
|
|
@ -1087,7 +1092,7 @@ public class StorageProxy implements StorageProxyMBean
|
|||
baseComplete,
|
||||
WriteType.BATCH,
|
||||
cleanup,
|
||||
queryStartNanoTime));
|
||||
requestTime));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1097,7 +1102,7 @@ public class StorageProxy implements StorageProxyMBean
|
|||
|
||||
// Perform remote writes
|
||||
if (!wrappers.isEmpty())
|
||||
asyncWriteBatchedMutations(wrappers, localDataCenter, Stage.VIEW_MUTATION);
|
||||
asyncWriteBatchedMutations(wrappers, localDataCenter, Stage.VIEW_MUTATION, requestTime);
|
||||
}
|
||||
}
|
||||
finally
|
||||
|
|
@ -1110,7 +1115,7 @@ public class StorageProxy implements StorageProxyMBean
|
|||
public static void mutateWithTriggers(List<? extends IMutation> mutations,
|
||||
ConsistencyLevel consistencyLevel,
|
||||
boolean mutateAtomically,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
throws WriteTimeoutException, WriteFailureException, UnavailableException, OverloadedException, InvalidRequestException
|
||||
{
|
||||
if (DatabaseDescriptor.getPartitionDenylistEnabled() && DatabaseDescriptor.getDenylistWritesEnabled())
|
||||
|
|
@ -1143,13 +1148,13 @@ public class StorageProxy implements StorageProxyMBean
|
|||
writeMetricsForLevel(consistencyLevel).mutationSize.update(size);
|
||||
|
||||
if (augmented != null)
|
||||
mutateAtomically(augmented, consistencyLevel, updatesView, queryStartNanoTime);
|
||||
mutateAtomically(augmented, consistencyLevel, updatesView, requestTime);
|
||||
else
|
||||
{
|
||||
if (mutateAtomically || updatesView)
|
||||
mutateAtomically((Collection<Mutation>) mutations, consistencyLevel, updatesView, queryStartNanoTime);
|
||||
mutateAtomically((Collection<Mutation>) mutations, consistencyLevel, updatesView, requestTime);
|
||||
else
|
||||
mutate(mutations, consistencyLevel, queryStartNanoTime);
|
||||
mutate(mutations, consistencyLevel, requestTime);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1162,12 +1167,12 @@ public class StorageProxy implements StorageProxyMBean
|
|||
* @param mutations the Mutations to be applied across the replicas
|
||||
* @param consistency_level the consistency level for the operation
|
||||
* @param requireQuorumForRemove at least a quorum of nodes will see update before deleting batchlog
|
||||
* @param queryStartNanoTime the value of nanoTime() when the query started to be processed
|
||||
* @param requestTime object holding times when request got enqueued and started execution
|
||||
*/
|
||||
public static void mutateAtomically(Collection<Mutation> mutations,
|
||||
ConsistencyLevel consistency_level,
|
||||
boolean requireQuorumForRemove,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
throws UnavailableException, OverloadedException, WriteTimeoutException
|
||||
{
|
||||
Tracing.trace("Determining replicas for atomic batch");
|
||||
|
|
@ -1198,7 +1203,7 @@ public class StorageProxy implements StorageProxyMBean
|
|||
|
||||
final TimeUUID batchUUID = nextTimeUUID();
|
||||
BatchlogCleanup cleanup = new BatchlogCleanup(mutations.size(),
|
||||
() -> asyncRemoveFromBatchlog(replicaPlan, batchUUID));
|
||||
() -> asyncRemoveFromBatchlog(replicaPlan, batchUUID, requestTime));
|
||||
|
||||
// add a handler for each mutation - includes checking availability, but doesn't initiate any writes, yet
|
||||
for (Mutation mutation : mutations)
|
||||
|
|
@ -1208,16 +1213,16 @@ public class StorageProxy implements StorageProxyMBean
|
|||
batchConsistencyLevel,
|
||||
WriteType.BATCH,
|
||||
cleanup,
|
||||
queryStartNanoTime);
|
||||
requestTime);
|
||||
// exit early if we can't fulfill the CL at this time.
|
||||
wrappers.add(wrapper);
|
||||
}
|
||||
|
||||
// write to the batchlog
|
||||
syncWriteToBatchlog(mutations, replicaPlan, batchUUID, queryStartNanoTime);
|
||||
syncWriteToBatchlog(mutations, replicaPlan, batchUUID, requestTime);
|
||||
|
||||
// now actually perform the writes and wait for them to complete
|
||||
syncWriteBatchedMutations(wrappers, Stage.MUTATION);
|
||||
syncWriteBatchedMutations(wrappers, Stage.MUTATION, requestTime);
|
||||
}
|
||||
catch (UnavailableException e)
|
||||
{
|
||||
|
|
@ -1271,13 +1276,13 @@ public class StorageProxy implements StorageProxyMBean
|
|||
}
|
||||
}
|
||||
|
||||
private static void syncWriteToBatchlog(Collection<Mutation> mutations, ReplicaPlan.ForWrite replicaPlan, TimeUUID uuid, long queryStartNanoTime)
|
||||
private static void syncWriteToBatchlog(Collection<Mutation> mutations, ReplicaPlan.ForWrite replicaPlan, TimeUUID uuid, Dispatcher.RequestTime requestTime)
|
||||
throws WriteTimeoutException, WriteFailureException
|
||||
{
|
||||
WriteResponseHandler<?> handler = new WriteResponseHandler(replicaPlan,
|
||||
WriteType.BATCH_LOG,
|
||||
null,
|
||||
queryStartNanoTime);
|
||||
WriteResponseHandler<?> handler = new WriteResponseHandler<>(replicaPlan,
|
||||
WriteType.BATCH_LOG,
|
||||
null,
|
||||
requestTime);
|
||||
|
||||
Batch batch = Batch.createLocal(uuid, FBUtilities.timestampMicros(), mutations);
|
||||
Message<Batch> message = Message.out(BATCH_STORE_REQ, batch);
|
||||
|
|
@ -1286,14 +1291,14 @@ public class StorageProxy implements StorageProxyMBean
|
|||
logger.trace("Sending batchlog store request {} to {} for {} mutations", batch.id, replica, batch.size());
|
||||
|
||||
if (replica.isSelf())
|
||||
performLocally(Stage.MUTATION, replica, () -> BatchlogManager.store(batch), handler, "Batchlog store");
|
||||
performLocally(Stage.MUTATION, replica, () -> BatchlogManager.store(batch), handler, "Batchlog store", requestTime);
|
||||
else
|
||||
MessagingService.instance().sendWithCallback(message, replica.endpoint(), handler);
|
||||
}
|
||||
handler.get();
|
||||
}
|
||||
|
||||
private static void asyncRemoveFromBatchlog(ReplicaPlan.ForWrite replicaPlan, TimeUUID uuid)
|
||||
private static void asyncRemoveFromBatchlog(ReplicaPlan.ForWrite replicaPlan, TimeUUID uuid, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
Message<TimeUUID> message = Message.out(Verb.BATCH_REMOVE_REQ, uuid);
|
||||
for (Replica target : replicaPlan.contacts())
|
||||
|
|
@ -1302,13 +1307,13 @@ public class StorageProxy implements StorageProxyMBean
|
|||
logger.trace("Sending batchlog remove request {} to {}", uuid, target);
|
||||
|
||||
if (target.isSelf())
|
||||
performLocally(Stage.MUTATION, target, () -> BatchlogManager.remove(uuid), "Batchlog remove");
|
||||
performLocally(Stage.MUTATION, target, () -> BatchlogManager.remove(uuid), "Batchlog remove", requestTime);
|
||||
else
|
||||
MessagingService.instance().send(message, target.endpoint());
|
||||
}
|
||||
}
|
||||
|
||||
private static void asyncWriteBatchedMutations(List<WriteResponseHandlerWrapper> wrappers, String localDataCenter, Stage stage)
|
||||
private static void asyncWriteBatchedMutations(List<WriteResponseHandlerWrapper> wrappers, String localDataCenter, Stage stage, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
for (WriteResponseHandlerWrapper wrapper : wrappers)
|
||||
{
|
||||
|
|
@ -1317,7 +1322,7 @@ public class StorageProxy implements StorageProxyMBean
|
|||
|
||||
try
|
||||
{
|
||||
sendToHintedReplicas(wrapper.mutation, replicas, wrapper.handler, localDataCenter, stage);
|
||||
sendToHintedReplicas(wrapper.mutation, replicas, wrapper.handler, localDataCenter, stage, requestTime);
|
||||
}
|
||||
catch (OverloadedException | WriteTimeoutException e)
|
||||
{
|
||||
|
|
@ -1326,7 +1331,7 @@ public class StorageProxy implements StorageProxyMBean
|
|||
}
|
||||
}
|
||||
|
||||
private static void syncWriteBatchedMutations(List<WriteResponseHandlerWrapper> wrappers, Stage stage)
|
||||
private static void syncWriteBatchedMutations(List<WriteResponseHandlerWrapper> wrappers, Stage stage, Dispatcher.RequestTime requestTime)
|
||||
throws WriteTimeoutException, OverloadedException
|
||||
{
|
||||
String localDataCenter = DatabaseDescriptor.getEndpointSnitch().getLocalDatacenter();
|
||||
|
|
@ -1335,7 +1340,7 @@ public class StorageProxy implements StorageProxyMBean
|
|||
{
|
||||
EndpointsForToken sendTo = wrapper.handler.replicaPlan.liveAndDown();
|
||||
Replicas.temporaryAssertFull(sendTo); // TODO: CASSANDRA-14549
|
||||
sendToHintedReplicas(wrapper.mutation, wrapper.handler.replicaPlan.withContacts(sendTo), wrapper.handler, localDataCenter, stage);
|
||||
sendToHintedReplicas(wrapper.mutation, wrapper.handler.replicaPlan.withContacts(sendTo), wrapper.handler, localDataCenter, stage, requestTime);
|
||||
}
|
||||
|
||||
for (WriteResponseHandlerWrapper wrapper : wrappers)
|
||||
|
|
@ -1354,7 +1359,7 @@ public class StorageProxy implements StorageProxyMBean
|
|||
* given the list of write endpoints (either standardWritePerformer for
|
||||
* standard writes or counterWritePerformer for counter writes).
|
||||
* @param callback an optional callback to be run if and when the write is
|
||||
* @param queryStartNanoTime the value of nanoTime() when the query started to be processed
|
||||
* @param requestTime object holding times when request got enqueued and started execution
|
||||
*/
|
||||
public static AbstractWriteResponseHandler<IMutation> performWrite(IMutation mutation,
|
||||
ConsistencyLevel consistencyLevel,
|
||||
|
|
@ -1362,7 +1367,7 @@ public class StorageProxy implements StorageProxyMBean
|
|||
WritePerformer performer,
|
||||
Runnable callback,
|
||||
WriteType writeType,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
String keyspaceName = mutation.getKeyspaceName();
|
||||
Keyspace keyspace = Keyspace.open(keyspaceName);
|
||||
|
|
@ -1376,9 +1381,9 @@ public class StorageProxy implements StorageProxyMBean
|
|||
writeMetrics.remoteRequests.mark();
|
||||
|
||||
AbstractReplicationStrategy rs = replicaPlan.replicationStrategy();
|
||||
AbstractWriteResponseHandler<IMutation> responseHandler = rs.getWriteResponseHandler(replicaPlan, callback, writeType, mutation.hintOnFailure(), queryStartNanoTime);
|
||||
AbstractWriteResponseHandler<IMutation> responseHandler = rs.getWriteResponseHandler(replicaPlan, callback, writeType, mutation.hintOnFailure(), requestTime);
|
||||
|
||||
performer.apply(mutation, replicaPlan, responseHandler, localDataCenter);
|
||||
performer.apply(mutation, replicaPlan, responseHandler, localDataCenter, requestTime);
|
||||
return responseHandler;
|
||||
}
|
||||
|
||||
|
|
@ -1388,7 +1393,7 @@ public class StorageProxy implements StorageProxyMBean
|
|||
ConsistencyLevel batchConsistencyLevel,
|
||||
WriteType writeType,
|
||||
BatchlogResponseHandler.BatchlogCleanup cleanup,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
Keyspace keyspace = Keyspace.open(mutation.getKeyspaceName());
|
||||
Token tk = mutation.key().getToken();
|
||||
|
|
@ -1401,8 +1406,8 @@ public class StorageProxy implements StorageProxyMBean
|
|||
writeMetrics.remoteRequests.mark();
|
||||
|
||||
AbstractReplicationStrategy rs = replicaPlan.replicationStrategy();
|
||||
AbstractWriteResponseHandler<IMutation> writeHandler = rs.getWriteResponseHandler(replicaPlan, null, writeType, mutation, queryStartNanoTime);
|
||||
BatchlogResponseHandler<IMutation> batchHandler = new BatchlogResponseHandler<>(writeHandler, batchConsistencyLevel.blockFor(rs), cleanup, queryStartNanoTime);
|
||||
AbstractWriteResponseHandler<IMutation> writeHandler = rs.getWriteResponseHandler(replicaPlan, null, writeType, mutation, requestTime);
|
||||
BatchlogResponseHandler<IMutation> batchHandler = new BatchlogResponseHandler<>(writeHandler, batchConsistencyLevel.blockFor(rs), cleanup, requestTime);
|
||||
return new WriteResponseHandlerWrapper(batchHandler, mutation);
|
||||
}
|
||||
|
||||
|
|
@ -1417,7 +1422,7 @@ public class StorageProxy implements StorageProxyMBean
|
|||
AtomicLong baseComplete,
|
||||
WriteType writeType,
|
||||
BatchlogResponseHandler.BatchlogCleanup cleanup,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
Keyspace keyspace = Keyspace.open(mutation.getKeyspaceName());
|
||||
ReplicaPlan.ForWrite replicaPlan = ReplicaPlans.forWrite(keyspace, consistencyLevel, liveAndDown, ReplicaPlans.writeAll);
|
||||
|
|
@ -1425,8 +1430,8 @@ public class StorageProxy implements StorageProxyMBean
|
|||
AbstractWriteResponseHandler<IMutation> writeHandler = replicationStrategy.getWriteResponseHandler(replicaPlan, () -> {
|
||||
long delay = Math.max(0, currentTimeMillis() - baseComplete.get());
|
||||
viewWriteMetrics.viewWriteLatency.update(delay, MILLISECONDS);
|
||||
}, writeType, mutation, queryStartNanoTime);
|
||||
BatchlogResponseHandler<IMutation> batchHandler = new ViewWriteMetricsWrapped(writeHandler, batchConsistencyLevel.blockFor(replicationStrategy), cleanup, queryStartNanoTime);
|
||||
}, writeType, mutation, requestTime);
|
||||
BatchlogResponseHandler<IMutation> batchHandler = new ViewWriteMetricsWrapped(writeHandler, batchConsistencyLevel.blockFor(replicationStrategy), cleanup, requestTime);
|
||||
return new WriteResponseHandlerWrapper(batchHandler, mutation);
|
||||
}
|
||||
|
||||
|
|
@ -1464,7 +1469,8 @@ public class StorageProxy implements StorageProxyMBean
|
|||
ReplicaPlan.ForWrite plan,
|
||||
AbstractWriteResponseHandler<IMutation> responseHandler,
|
||||
String localDataCenter,
|
||||
Stage stage)
|
||||
Stage stage,
|
||||
Dispatcher.RequestTime requestTime)
|
||||
throws OverloadedException
|
||||
{
|
||||
// this dc replicas:
|
||||
|
|
@ -1502,7 +1508,12 @@ public class StorageProxy implements StorageProxyMBean
|
|||
{
|
||||
// belongs on a different server
|
||||
if (message == null)
|
||||
message = Message.outWithFlag(MUTATION_REQ, mutation, MessageFlag.CALL_BACK_ON_FAILURE);
|
||||
{
|
||||
message = Message.outWithFlags(MUTATION_REQ,
|
||||
mutation,
|
||||
requestTime,
|
||||
Collections.singletonList(MessageFlag.CALL_BACK_ON_FAILURE));
|
||||
}
|
||||
|
||||
String dc = DatabaseDescriptor.getEndpointSnitch().getDatacenter(destination);
|
||||
|
||||
|
|
@ -1542,13 +1553,13 @@ public class StorageProxy implements StorageProxyMBean
|
|||
}
|
||||
}
|
||||
|
||||
if (endpointsToHint != null)
|
||||
if (endpointsToHint != null && requestTime.shouldSendHints())
|
||||
submitHint(mutation, EndpointsForToken.copyOf(mutation.key().getToken(), endpointsToHint), responseHandler);
|
||||
|
||||
if (insertLocal)
|
||||
{
|
||||
Preconditions.checkNotNull(localReplica);
|
||||
performLocally(stage, localReplica, mutation::apply, responseHandler, mutation);
|
||||
performLocally(stage, localReplica, mutation::apply, responseHandler, mutation, requestTime);
|
||||
}
|
||||
|
||||
if (localDc != null)
|
||||
|
|
@ -1623,9 +1634,9 @@ public class StorageProxy implements StorageProxyMBean
|
|||
return select.get(ThreadLocalRandom.current().nextInt(0, select.size()));
|
||||
}
|
||||
|
||||
private static void performLocally(Stage stage, Replica localReplica, final Runnable runnable, String description)
|
||||
private static void performLocally(Stage stage, Replica localReplica, final Runnable runnable, String description, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
stage.maybeExecuteImmediately(new LocalMutationRunnable(localReplica)
|
||||
stage.maybeExecuteImmediately(new LocalMutationRunnable(localReplica, requestTime)
|
||||
{
|
||||
public void runMayThrow()
|
||||
{
|
||||
|
|
@ -1653,9 +1664,9 @@ public class StorageProxy implements StorageProxyMBean
|
|||
});
|
||||
}
|
||||
|
||||
private static void performLocally(Stage stage, Replica localReplica, final Runnable runnable, final RequestCallback<?> handler, Object description)
|
||||
private static void performLocally(Stage stage, Replica localReplica, final Runnable runnable, final RequestCallback<?> handler, Object description, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
stage.maybeExecuteImmediately(new LocalMutationRunnable(localReplica)
|
||||
stage.maybeExecuteImmediately(new LocalMutationRunnable(localReplica, requestTime)
|
||||
{
|
||||
public void runMayThrow()
|
||||
{
|
||||
|
|
@ -1702,13 +1713,13 @@ public class StorageProxy implements StorageProxyMBean
|
|||
* quicker response and because the WriteResponseHandlers don't make it easy to send back an error. We also always gather
|
||||
* the write latencies at the coordinator node to make gathering point similar to the case of standard writes.
|
||||
*/
|
||||
public static AbstractWriteResponseHandler<IMutation> mutateCounter(CounterMutation cm, String localDataCenter, long queryStartNanoTime) throws UnavailableException, OverloadedException
|
||||
public static AbstractWriteResponseHandler<IMutation> mutateCounter(CounterMutation cm, String localDataCenter, Dispatcher.RequestTime requestTime) throws UnavailableException, OverloadedException
|
||||
{
|
||||
Replica replica = findSuitableReplica(cm.getKeyspaceName(), cm.key(), localDataCenter, cm.consistency());
|
||||
|
||||
if (replica.isSelf())
|
||||
{
|
||||
return applyCounterMutationOnCoordinator(cm, localDataCenter, queryStartNanoTime);
|
||||
return applyCounterMutationOnCoordinator(cm, localDataCenter, requestTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1727,7 +1738,7 @@ public class StorageProxy implements StorageProxyMBean
|
|||
|
||||
// Forward the actual update to the chosen leader replica
|
||||
AbstractWriteResponseHandler<IMutation> responseHandler = new WriteResponseHandler<>(ReplicaPlans.forForwardingCounterWrite(keyspace, tk, replica),
|
||||
WriteType.COUNTER, null, queryStartNanoTime);
|
||||
WriteType.COUNTER, null, requestTime);
|
||||
|
||||
Tracing.trace("Enqueuing counter update to {}", replica);
|
||||
Message message = Message.outWithFlag(Verb.COUNTER_MUTATION_REQ, cm, MessageFlag.CALL_BACK_ON_FAILURE);
|
||||
|
|
@ -1785,26 +1796,27 @@ public class StorageProxy implements StorageProxyMBean
|
|||
|
||||
// Must be called on a replica of the mutation. This replica becomes the
|
||||
// leader of this mutation.
|
||||
public static AbstractWriteResponseHandler<IMutation> applyCounterMutationOnLeader(CounterMutation cm, String localDataCenter, Runnable callback, long queryStartNanoTime)
|
||||
public static AbstractWriteResponseHandler<IMutation> applyCounterMutationOnLeader(CounterMutation cm, String localDataCenter, Runnable callback, Dispatcher.RequestTime requestTime)
|
||||
throws UnavailableException, OverloadedException
|
||||
{
|
||||
return performWrite(cm, cm.consistency(), localDataCenter, counterWritePerformer, callback, WriteType.COUNTER, queryStartNanoTime);
|
||||
return performWrite(cm, cm.consistency(), localDataCenter, counterWritePerformer, callback, WriteType.COUNTER, requestTime);
|
||||
}
|
||||
|
||||
// Same as applyCounterMutationOnLeader but must with the difference that it use the MUTATION stage to execute the write (while
|
||||
// applyCounterMutationOnLeader assumes it is on the MUTATION stage already)
|
||||
public static AbstractWriteResponseHandler<IMutation> applyCounterMutationOnCoordinator(CounterMutation cm, String localDataCenter, long queryStartNanoTime)
|
||||
public static AbstractWriteResponseHandler<IMutation> applyCounterMutationOnCoordinator(CounterMutation cm, String localDataCenter, Dispatcher.RequestTime requestTime)
|
||||
throws UnavailableException, OverloadedException
|
||||
{
|
||||
return performWrite(cm, cm.consistency(), localDataCenter, counterWriteOnCoordinatorPerformer, null, WriteType.COUNTER, queryStartNanoTime);
|
||||
return performWrite(cm, cm.consistency(), localDataCenter, counterWriteOnCoordinatorPerformer, null, WriteType.COUNTER, requestTime);
|
||||
}
|
||||
|
||||
private static Runnable counterWriteTask(final IMutation mutation,
|
||||
final ReplicaPlan.ForWrite replicaPlan,
|
||||
final AbstractWriteResponseHandler<IMutation> responseHandler,
|
||||
final String localDataCenter)
|
||||
final String localDataCenter,
|
||||
final Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
return new DroppableRunnable(Verb.COUNTER_MUTATION_REQ)
|
||||
return new DroppableRunnable(Verb.COUNTER_MUTATION_REQ, requestTime)
|
||||
{
|
||||
@Override
|
||||
public void runMayThrow() throws OverloadedException, WriteTimeoutException
|
||||
|
|
@ -1813,7 +1825,7 @@ public class StorageProxy implements StorageProxyMBean
|
|||
|
||||
Mutation result = ((CounterMutation) mutation).applyCounterMutation();
|
||||
responseHandler.onResponse(null);
|
||||
sendToHintedReplicas(result, replicaPlan, responseHandler, localDataCenter, Stage.COUNTER_MUTATION);
|
||||
sendToHintedReplicas(result, replicaPlan, responseHandler, localDataCenter, Stage.COUNTER_MUTATION, requestTime);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -1826,17 +1838,17 @@ public class StorageProxy implements StorageProxyMBean
|
|||
return true;
|
||||
}
|
||||
|
||||
public static RowIterator readOne(SinglePartitionReadCommand command, ConsistencyLevel consistencyLevel, long queryStartNanoTime)
|
||||
public static RowIterator readOne(SinglePartitionReadCommand command, ConsistencyLevel consistencyLevel, Dispatcher.RequestTime requestTime)
|
||||
throws UnavailableException, IsBootstrappingException, ReadFailureException, ReadTimeoutException, InvalidRequestException
|
||||
{
|
||||
return PartitionIterators.getOnlyElement(read(SinglePartitionReadCommand.Group.one(command), consistencyLevel, queryStartNanoTime), command);
|
||||
return PartitionIterators.getOnlyElement(read(SinglePartitionReadCommand.Group.one(command), consistencyLevel, requestTime), command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the actual reading of a row out of the StorageService, fetching
|
||||
* a specific set of column names from a given column family.
|
||||
*/
|
||||
public static PartitionIterator read(SinglePartitionReadCommand.Group group, ConsistencyLevel consistencyLevel, long queryStartNanoTime)
|
||||
public static PartitionIterator read(SinglePartitionReadCommand.Group group, ConsistencyLevel consistencyLevel, Dispatcher.RequestTime requestTime)
|
||||
throws UnavailableException, IsBootstrappingException, ReadFailureException, ReadTimeoutException, InvalidRequestException
|
||||
{
|
||||
if (!isSafeToPerformRead(group.queries))
|
||||
|
|
@ -1862,8 +1874,8 @@ public class StorageProxy implements StorageProxyMBean
|
|||
}
|
||||
|
||||
return consistencyLevel.isSerialConsistency()
|
||||
? readWithPaxos(group, consistencyLevel, queryStartNanoTime)
|
||||
: readRegular(group, consistencyLevel, queryStartNanoTime);
|
||||
? readWithPaxos(group, consistencyLevel, requestTime)
|
||||
: readRegular(group, consistencyLevel, requestTime);
|
||||
}
|
||||
|
||||
public static boolean isSafeToPerformRead(List<SinglePartitionReadCommand> queries)
|
||||
|
|
@ -1876,21 +1888,20 @@ public class StorageProxy implements StorageProxyMBean
|
|||
return !StorageService.instance.isBootstrapMode();
|
||||
}
|
||||
|
||||
private static PartitionIterator readWithPaxos(SinglePartitionReadCommand.Group group, ConsistencyLevel consistencyLevel, long queryStartNanoTime)
|
||||
private static PartitionIterator readWithPaxos(SinglePartitionReadCommand.Group group, ConsistencyLevel consistencyLevel, Dispatcher.RequestTime requestTime)
|
||||
throws InvalidRequestException, UnavailableException, ReadFailureException, ReadTimeoutException
|
||||
{
|
||||
return Paxos.useV2()
|
||||
? Paxos.read(group, consistencyLevel)
|
||||
: legacyReadWithPaxos(group, consistencyLevel, queryStartNanoTime);
|
||||
? Paxos.read(group, consistencyLevel, requestTime)
|
||||
: legacyReadWithPaxos(group, consistencyLevel, requestTime);
|
||||
}
|
||||
|
||||
private static PartitionIterator legacyReadWithPaxos(SinglePartitionReadCommand.Group group, ConsistencyLevel consistencyLevel, long queryStartNanoTime)
|
||||
private static PartitionIterator legacyReadWithPaxos(SinglePartitionReadCommand.Group group, ConsistencyLevel consistencyLevel, Dispatcher.RequestTime requestTime)
|
||||
throws InvalidRequestException, UnavailableException, ReadFailureException, ReadTimeoutException
|
||||
{
|
||||
if (group.queries.size() > 1)
|
||||
throw new InvalidRequestException("SERIAL/LOCAL_SERIAL consistency may only be requested for one partition at a time");
|
||||
|
||||
long start = nanoTime();
|
||||
SinglePartitionReadCommand command = group.queries.get(0);
|
||||
TableMetadata metadata = command.metadata();
|
||||
DecoratedKey key = command.partitionKey();
|
||||
|
|
@ -1921,7 +1932,7 @@ public class StorageProxy implements StorageProxyMBean
|
|||
consistencyLevel,
|
||||
consistencyForReplayCommitsOrFetch,
|
||||
ConsistencyLevel.ANY,
|
||||
start,
|
||||
requestTime,
|
||||
casReadMetrics,
|
||||
updateProposer);
|
||||
}
|
||||
|
|
@ -1934,7 +1945,7 @@ public class StorageProxy implements StorageProxyMBean
|
|||
throw new ReadFailureException(consistencyLevel, e.received, e.blockFor, false, e.failureReasonByEndpoint);
|
||||
}
|
||||
|
||||
result = fetchRows(group.queries, consistencyForReplayCommitsOrFetch, queryStartNanoTime);
|
||||
result = fetchRows(group.queries, consistencyForReplayCommitsOrFetch, requestTime);
|
||||
}
|
||||
catch (UnavailableException e)
|
||||
{
|
||||
|
|
@ -1968,7 +1979,9 @@ public class StorageProxy implements StorageProxyMBean
|
|||
}
|
||||
finally
|
||||
{
|
||||
long latency = nanoTime() - start;
|
||||
// We track latency based on request processing time, since the amount of time that request spends in the queue
|
||||
// is not a representative metric of replica performance.
|
||||
long latency = nanoTime() - requestTime.startedAtNanos();
|
||||
readMetrics.addNano(latency);
|
||||
casReadMetrics.addNano(latency);
|
||||
readMetricsForLevel(consistencyLevel).addNano(latency);
|
||||
|
|
@ -1978,13 +1991,13 @@ public class StorageProxy implements StorageProxyMBean
|
|||
return result;
|
||||
}
|
||||
|
||||
private static PartitionIterator readRegular(SinglePartitionReadCommand.Group group, ConsistencyLevel consistencyLevel, long queryStartNanoTime)
|
||||
@SuppressWarnings("resource")
|
||||
private static PartitionIterator readRegular(SinglePartitionReadCommand.Group group, ConsistencyLevel consistencyLevel, Dispatcher.RequestTime requestTime)
|
||||
throws UnavailableException, ReadFailureException, ReadTimeoutException
|
||||
{
|
||||
long start = nanoTime();
|
||||
try
|
||||
{
|
||||
PartitionIterator result = fetchRows(group.queries, consistencyLevel, queryStartNanoTime);
|
||||
PartitionIterator result = fetchRows(group.queries, consistencyLevel, requestTime);
|
||||
// Note that the only difference between the command in a group must be the partition key on which
|
||||
// they applied.
|
||||
boolean enforceStrictLiveness = group.queries.get(0).metadata().enforceStrictLiveness();
|
||||
|
|
@ -2021,7 +2034,9 @@ public class StorageProxy implements StorageProxyMBean
|
|||
}
|
||||
finally
|
||||
{
|
||||
long latency = nanoTime() - start;
|
||||
// We track latency based on request processing time, since the amount of time that request spends in the queue
|
||||
// is not a representative metric of replica performance.
|
||||
long latency = nanoTime() - requestTime.startedAtNanos();
|
||||
readMetrics.addNano(latency);
|
||||
readMetricsForLevel(consistencyLevel).addNano(latency);
|
||||
// TODO avoid giving every command the same latency number. Can fix this in CASSADRA-5329
|
||||
|
|
@ -2075,7 +2090,9 @@ public class StorageProxy implements StorageProxyMBean
|
|||
* 4. If the digests (if any) match the data return the data
|
||||
* 5. else carry out read repair by getting data from all the nodes.
|
||||
*/
|
||||
private static PartitionIterator fetchRows(List<SinglePartitionReadCommand> commands, ConsistencyLevel consistencyLevel, long queryStartNanoTime)
|
||||
private static PartitionIterator fetchRows(List<SinglePartitionReadCommand> commands,
|
||||
ConsistencyLevel consistencyLevel,
|
||||
Dispatcher.RequestTime requestTime)
|
||||
throws UnavailableException, ReadFailureException, ReadTimeoutException
|
||||
{
|
||||
int cmdCount = commands.size();
|
||||
|
|
@ -2086,7 +2103,9 @@ public class StorageProxy implements StorageProxyMBean
|
|||
// for type of speculation we'll use in this read
|
||||
for (int i=0; i<cmdCount; i++)
|
||||
{
|
||||
reads[i] = AbstractReadExecutor.getReadExecutor(commands.get(i), consistencyLevel, queryStartNanoTime);
|
||||
reads[i] = AbstractReadExecutor.getReadExecutor(commands.get(i),
|
||||
consistencyLevel,
|
||||
requestTime);
|
||||
|
||||
if (reads[i].hasLocalRead())
|
||||
readMetrics.localRequests.mark();
|
||||
|
|
@ -2149,14 +2168,14 @@ public class StorageProxy implements StorageProxyMBean
|
|||
private final ReadCallback handler;
|
||||
private final boolean trackRepairedStatus;
|
||||
|
||||
public LocalReadRunnable(ReadCommand command, ReadCallback handler)
|
||||
public LocalReadRunnable(ReadCommand command, ReadCallback handler, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
this(command, handler, false);
|
||||
this(command, handler, requestTime, false);
|
||||
}
|
||||
|
||||
public LocalReadRunnable(ReadCommand command, ReadCallback handler, boolean trackRepairedStatus)
|
||||
public LocalReadRunnable(ReadCommand command, ReadCallback handler, Dispatcher.RequestTime requestTime, boolean trackRepairedStatus)
|
||||
{
|
||||
super(Verb.READ_REQ);
|
||||
super(Verb.READ_REQ, requestTime);
|
||||
this.command = command;
|
||||
this.handler = handler;
|
||||
this.trackRepairedStatus = trackRepairedStatus;
|
||||
|
|
@ -2169,7 +2188,8 @@ public class StorageProxy implements StorageProxyMBean
|
|||
MessageParams.reset();
|
||||
|
||||
boolean readRejected = false;
|
||||
command.setMonitoringTime(approxCreationTimeNanos, false, verb.expiresAfterNanos(), DatabaseDescriptor.getSlowQueryTimeout(NANOSECONDS));
|
||||
long deadline = requestTime.computeDeadline(verb.expiresAfterNanos());
|
||||
command.setMonitoringTime(requestTime.startedAtNanos(), false, deadline - requestTime.startedAtNanos(), DatabaseDescriptor.getSlowQueryTimeout(NANOSECONDS));
|
||||
|
||||
ReadResponse response;
|
||||
try (ReadExecutionController controller = command.executionController(trackRepairedStatus);
|
||||
|
|
@ -2198,12 +2218,14 @@ public class StorageProxy implements StorageProxyMBean
|
|||
}
|
||||
else
|
||||
{
|
||||
MessagingService.instance().metrics.recordSelfDroppedMessage(verb, MonotonicClock.Global.approxTime.now() - approxCreationTimeNanos, NANOSECONDS);
|
||||
// We track latency based on request processing time
|
||||
MessagingService.instance().metrics.recordSelfDroppedMessage(verb, MonotonicClock.Global.preciseTime.now() - requestTime.startedAtNanos(), NANOSECONDS);
|
||||
handler.onFailure(FBUtilities.getBroadcastAddressAndPort(), RequestFailureReason.UNKNOWN);
|
||||
}
|
||||
|
||||
if (!readRejected)
|
||||
MessagingService.instance().latencySubscribers.add(FBUtilities.getBroadcastAddressAndPort(), MonotonicClock.Global.approxTime.now() - approxCreationTimeNanos, NANOSECONDS);
|
||||
// We track latency based on request processing time
|
||||
MessagingService.instance().latencySubscribers.add(FBUtilities.getBroadcastAddressAndPort(), MonotonicClock.Global.preciseTime.now() - requestTime.startedAtNanos(), NANOSECONDS);
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
|
|
@ -2223,13 +2245,13 @@ public class StorageProxy implements StorageProxyMBean
|
|||
@Override
|
||||
public long creationTimeNanos()
|
||||
{
|
||||
return approxCreationTimeNanos;
|
||||
return requestTime.enqueuedAtNanos();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long startTimeNanos()
|
||||
{
|
||||
return approxStartTimeNanos;
|
||||
return requestTime.startedAtNanos();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -2241,7 +2263,7 @@ public class StorageProxy implements StorageProxyMBean
|
|||
|
||||
public static PartitionIterator getRangeSlice(PartitionRangeReadCommand command,
|
||||
ConsistencyLevel consistencyLevel,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
if (DatabaseDescriptor.getPartitionDenylistEnabled() && DatabaseDescriptor.getDenylistRangeReadsEnabled())
|
||||
{
|
||||
|
|
@ -2255,7 +2277,7 @@ public class StorageProxy implements StorageProxyMBean
|
|||
tokens));
|
||||
}
|
||||
}
|
||||
return RangeCommands.partitions(command, consistencyLevel, queryStartNanoTime);
|
||||
return RangeCommands.partitions(command, consistencyLevel, requestTime);
|
||||
}
|
||||
|
||||
public Map<String, List<String>> getSchemaVersions()
|
||||
|
|
@ -2523,7 +2545,8 @@ public class StorageProxy implements StorageProxyMBean
|
|||
public void apply(IMutation mutation,
|
||||
ReplicaPlan.ForWrite targets,
|
||||
AbstractWriteResponseHandler<IMutation> responseHandler,
|
||||
String localDataCenter) throws OverloadedException;
|
||||
String localDataCenter,
|
||||
Dispatcher.RequestTime requestTime) throws OverloadedException;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2531,9 +2554,9 @@ public class StorageProxy implements StorageProxyMBean
|
|||
*/
|
||||
private static class ViewWriteMetricsWrapped extends BatchlogResponseHandler<IMutation>
|
||||
{
|
||||
public ViewWriteMetricsWrapped(AbstractWriteResponseHandler<IMutation> writeHandler, int i, BatchlogCleanup cleanup, long queryStartNanoTime)
|
||||
public ViewWriteMetricsWrapped(AbstractWriteResponseHandler<IMutation> writeHandler, int i, BatchlogCleanup cleanup, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
super(writeHandler, i, cleanup, queryStartNanoTime);
|
||||
super(writeHandler, i, cleanup, requestTime);
|
||||
viewWriteMetrics.viewReplicasAttempted.inc(candidateReplicaCount());
|
||||
}
|
||||
|
||||
|
|
@ -2549,25 +2572,22 @@ public class StorageProxy implements StorageProxyMBean
|
|||
*/
|
||||
private static abstract class DroppableRunnable implements Runnable
|
||||
{
|
||||
protected final long approxCreationTimeNanos;
|
||||
protected volatile long approxStartTimeNanos;
|
||||
|
||||
final Verb verb;
|
||||
|
||||
public DroppableRunnable(Verb verb)
|
||||
final Dispatcher.RequestTime requestTime;
|
||||
public DroppableRunnable(Verb verb, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
this.approxCreationTimeNanos = MonotonicClock.Global.approxTime.now();
|
||||
this.verb = verb;
|
||||
this.requestTime = requestTime;
|
||||
}
|
||||
|
||||
public final void run()
|
||||
{
|
||||
approxStartTimeNanos = MonotonicClock.Global.approxTime.now();
|
||||
long expirationTimeNanos = verb.expiresAtNanos(approxCreationTimeNanos);
|
||||
if (approxStartTimeNanos > expirationTimeNanos)
|
||||
long nowNanos = MonotonicClock.Global.preciseTime.now();
|
||||
long deadline = requestTime.computeDeadline(verb.expiresAfterNanos());
|
||||
if (nowNanos > deadline)
|
||||
{
|
||||
long timeTakenNanos = approxStartTimeNanos - approxCreationTimeNanos;
|
||||
MessagingService.instance().metrics.recordSelfDroppedMessage(verb, timeTakenNanos, NANOSECONDS);
|
||||
long elapsed = nowNanos - requestTime.startedAtNanos();
|
||||
MessagingService.instance().metrics.recordSelfDroppedMessage(verb, elapsed, NANOSECONDS);
|
||||
return;
|
||||
}
|
||||
try
|
||||
|
|
@ -2589,35 +2609,37 @@ public class StorageProxy implements StorageProxyMBean
|
|||
*/
|
||||
private static abstract class LocalMutationRunnable implements RunnableDebuggableTask
|
||||
{
|
||||
private final long approxCreationTimeNanos = MonotonicClock.Global.approxTime.now();
|
||||
private volatile long approxStartTimeNanos;
|
||||
|
||||
private final Replica localReplica;
|
||||
private final Dispatcher.RequestTime requestTime;
|
||||
|
||||
LocalMutationRunnable(Replica localReplica)
|
||||
LocalMutationRunnable(Replica localReplica, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
this.localReplica = localReplica;
|
||||
this.requestTime = requestTime;
|
||||
}
|
||||
|
||||
public final void run()
|
||||
{
|
||||
final Verb verb = verb();
|
||||
approxStartTimeNanos = MonotonicClock.Global.approxTime.now();
|
||||
long expirationTimeNanos = verb.expiresAtNanos(approxCreationTimeNanos);
|
||||
|
||||
if (approxStartTimeNanos > expirationTimeNanos)
|
||||
long now = MonotonicClock.Global.approxTime.now();
|
||||
long deadline = requestTime.computeDeadline(verb.expiresAfterNanos());
|
||||
|
||||
if (now > deadline)
|
||||
{
|
||||
long timeTakenNanos = approxStartTimeNanos - approxCreationTimeNanos;
|
||||
long timeTakenNanos = now - startTimeNanos();
|
||||
MessagingService.instance().metrics.recordSelfDroppedMessage(Verb.MUTATION_REQ, timeTakenNanos, NANOSECONDS);
|
||||
|
||||
HintRunnable runnable = new HintRunnable(EndpointsForToken.of(localReplica.range().right, localReplica))
|
||||
if (requestTime.shouldSendHints())
|
||||
{
|
||||
protected void runMayThrow() throws Exception
|
||||
HintRunnable runnable = new HintRunnable(EndpointsForToken.of(localReplica.range().right, localReplica))
|
||||
{
|
||||
LocalMutationRunnable.this.runMayThrow();
|
||||
}
|
||||
};
|
||||
submitHint(runnable);
|
||||
protected void runMayThrow() throws Exception
|
||||
{
|
||||
LocalMutationRunnable.this.runMayThrow();
|
||||
}
|
||||
};
|
||||
submitHint(runnable);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -2634,13 +2656,13 @@ public class StorageProxy implements StorageProxyMBean
|
|||
@Override
|
||||
public long creationTimeNanos()
|
||||
{
|
||||
return approxCreationTimeNanos;
|
||||
return requestTime.enqueuedAtNanos();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long startTimeNanos()
|
||||
{
|
||||
return approxStartTimeNanos;
|
||||
return requestTime.startedAtNanos();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -2738,14 +2760,14 @@ public class StorageProxy implements StorageProxyMBean
|
|||
}
|
||||
}
|
||||
|
||||
public static Future<Void> submitHint(Mutation mutation, Replica target, AbstractWriteResponseHandler<IMutation> responseHandler)
|
||||
public static void submitHint(Mutation mutation, Replica target, AbstractWriteResponseHandler<IMutation> responseHandler)
|
||||
{
|
||||
return submitHint(mutation, EndpointsForToken.of(target.range().right, target), responseHandler);
|
||||
submitHint(mutation, EndpointsForToken.of(target.range().right, target), responseHandler);
|
||||
}
|
||||
|
||||
public static Future<Void> submitHint(Mutation mutation,
|
||||
EndpointsForToken targets,
|
||||
AbstractWriteResponseHandler<IMutation> responseHandler)
|
||||
private static void submitHint(Mutation mutation,
|
||||
EndpointsForToken targets,
|
||||
AbstractWriteResponseHandler<IMutation> responseHandler)
|
||||
{
|
||||
Replicas.assertFull(targets); // hints should not be written for transient replicas
|
||||
HintRunnable runnable = new HintRunnable(targets)
|
||||
|
|
@ -2774,7 +2796,7 @@ public class StorageProxy implements StorageProxyMBean
|
|||
}
|
||||
};
|
||||
|
||||
return submitHint(runnable);
|
||||
submitHint(runnable);
|
||||
}
|
||||
|
||||
private static Future<Void> submitHint(HintRunnable runnable)
|
||||
|
|
|
|||
|
|
@ -595,13 +595,13 @@ public class StorageService extends NotificationBroadcasterSupport implements IE
|
|||
}
|
||||
}
|
||||
|
||||
public void stopNativeTransport()
|
||||
public void stopNativeTransport(boolean force)
|
||||
{
|
||||
if (daemon == null)
|
||||
{
|
||||
throw new IllegalStateException("No configured daemon");
|
||||
}
|
||||
daemon.stopNativeTransport();
|
||||
daemon.stopNativeTransport(force);
|
||||
}
|
||||
|
||||
public boolean isNativeTransportRunning()
|
||||
|
|
@ -7452,4 +7452,71 @@ public class StorageService extends NotificationBroadcasterSupport implements IE
|
|||
if (!skipNotificationListeners)
|
||||
super.addNotificationListener(listener, filter, handback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getNativeTransportQueueMaxItemAgeThreshold()
|
||||
{
|
||||
return DatabaseDescriptor.getNativeTransportQueueMaxItemAgeThreshold();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNativeTransportQueueMaxItemAgeThreshold(double threshold)
|
||||
{
|
||||
DatabaseDescriptor.setNativeTransportMaxQueueItemAgeThreshold(threshold);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getNativeTransportMinBackoffOnQueueOverloadInMillis()
|
||||
{
|
||||
return DatabaseDescriptor.getNativeTransportMinBackoffOnQueueOverload(MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getNativeTransportMaxBackoffOnQueueOverloadInMillis()
|
||||
{
|
||||
return DatabaseDescriptor.getNativeTransportMaxBackoffOnQueueOverload(MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNativeTransportBackoffOnQueueOverloadInMillis(long min, long max)
|
||||
{
|
||||
DatabaseDescriptor.setNativeTransportBackoffOnQueueOverload(min, max, MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getNativeTransportThrowOnOverload()
|
||||
{
|
||||
return DatabaseDescriptor.getNativeTransportThrowOnOverload();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNativeTransportThrowOnOverload(boolean throwOnOverload)
|
||||
{
|
||||
DatabaseDescriptor.setNativeTransportThrowOnOverload(throwOnOverload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getNativeTransportTimeoutMillis()
|
||||
{
|
||||
return DatabaseDescriptor.getNativeTransportTimeout(MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNativeTransportTimeoutMillis(long deadlineMillis)
|
||||
{
|
||||
DatabaseDescriptor.setNativeTransportTimeout(deadlineMillis, MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getEnforceNativeDeadlineForHints()
|
||||
{
|
||||
return DatabaseDescriptor.getEnforceNativeDeadlineForHints();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnforceNativeDeadlineForHints(boolean value)
|
||||
{
|
||||
DatabaseDescriptor.setEnforceNativeDeadlineForHints(value);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -665,7 +665,8 @@ public interface StorageServiceMBean extends NotificationEmitter
|
|||
// to determine if initialization has completed
|
||||
public boolean isInitialized();
|
||||
|
||||
public void stopNativeTransport();
|
||||
@Deprecated(since = "5.0") public default void stopNativeTransport() { stopNativeTransport(false); }
|
||||
public void stopNativeTransport(boolean force);
|
||||
public void startNativeTransport();
|
||||
public boolean isNativeTransportRunning();
|
||||
public void enableNativeTransportOldProtocolVersions();
|
||||
|
|
@ -1262,4 +1263,20 @@ public interface StorageServiceMBean extends NotificationEmitter
|
|||
|
||||
public void setSkipStreamDiskSpaceCheck(boolean value);
|
||||
public boolean getSkipStreamDiskSpaceCheck();
|
||||
}
|
||||
|
||||
double getNativeTransportQueueMaxItemAgeThreshold();
|
||||
void setNativeTransportQueueMaxItemAgeThreshold(double threshold);
|
||||
|
||||
long getNativeTransportMinBackoffOnQueueOverloadInMillis();
|
||||
long getNativeTransportMaxBackoffOnQueueOverloadInMillis();
|
||||
void setNativeTransportBackoffOnQueueOverloadInMillis(long min, long max);
|
||||
|
||||
boolean getNativeTransportThrowOnOverload();
|
||||
void setNativeTransportThrowOnOverload(boolean throwOnOverload);
|
||||
|
||||
long getNativeTransportTimeoutMillis();
|
||||
void setNativeTransportTimeoutMillis(long deadlineMillis);
|
||||
|
||||
boolean getEnforceNativeDeadlineForHints();
|
||||
void setEnforceNativeDeadlineForHints(boolean value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
import org.apache.cassandra.net.Message;
|
||||
import org.apache.cassandra.db.WriteType;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
|
||||
/**
|
||||
* Handles blocking writes for ONE, ANY, TWO, THREE, QUORUM, and ALL consistency levels.
|
||||
|
|
@ -43,15 +44,15 @@ public class WriteResponseHandler<T> extends AbstractWriteResponseHandler<T>
|
|||
Runnable callback,
|
||||
WriteType writeType,
|
||||
Supplier<Mutation> hintOnFailure,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
super(replicaPlan, callback, writeType, hintOnFailure, queryStartNanoTime);
|
||||
super(replicaPlan, callback, writeType, hintOnFailure, requestTime);
|
||||
responses = blockFor();
|
||||
}
|
||||
|
||||
public WriteResponseHandler(ReplicaPlan.ForWrite replicaPlan, WriteType writeType, Supplier<Mutation> hintOnFailure, long queryStartNanoTime)
|
||||
public WriteResponseHandler(ReplicaPlan.ForWrite replicaPlan, WriteType writeType, Supplier<Mutation> hintOnFailure, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
this(replicaPlan, null, writeType, hintOnFailure, queryStartNanoTime);
|
||||
this(replicaPlan, null, writeType, hintOnFailure, requestTime);
|
||||
}
|
||||
|
||||
public void onResponse(Message<T> m)
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import org.apache.cassandra.db.filter.DataLimits;
|
|||
import org.apache.cassandra.db.transform.Transformation;
|
||||
import org.apache.cassandra.schema.TableMetadata;
|
||||
import org.apache.cassandra.service.ClientState;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
|
||||
abstract class AbstractQueryPager<T extends ReadQuery> implements QueryPager
|
||||
|
|
@ -59,7 +60,7 @@ abstract class AbstractQueryPager<T extends ReadQuery> implements QueryPager
|
|||
return query.executionController();
|
||||
}
|
||||
|
||||
public PartitionIterator fetchPage(int pageSize, ConsistencyLevel consistency, ClientState clientState, long queryStartNanoTime)
|
||||
public PartitionIterator fetchPage(int pageSize, ConsistencyLevel consistency, ClientState clientState, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
if (isExhausted())
|
||||
return EmptyIterators.partition();
|
||||
|
|
@ -72,7 +73,7 @@ abstract class AbstractQueryPager<T extends ReadQuery> implements QueryPager
|
|||
exhausted = true;
|
||||
return EmptyIterators.partition();
|
||||
}
|
||||
return Transformation.apply(readQuery.execute(consistency, clientState, queryStartNanoTime), pager);
|
||||
return Transformation.apply(readQuery.execute(consistency, clientState, requestTime), pager);
|
||||
}
|
||||
|
||||
public PartitionIterator fetchPageInternal(int pageSize, ReadExecutionController executionController)
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@ import org.apache.cassandra.db.partitions.PartitionIterator;
|
|||
import org.apache.cassandra.db.rows.Row;
|
||||
import org.apache.cassandra.db.rows.RowIterator;
|
||||
import org.apache.cassandra.service.ClientState;
|
||||
|
||||
import static org.apache.cassandra.utils.Clock.Global.nanoTime;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
|
||||
/**
|
||||
* {@code QueryPager} that takes care of fetching the pages for aggregation queries.
|
||||
|
|
@ -55,12 +54,12 @@ public final class AggregationQueryPager implements QueryPager
|
|||
public PartitionIterator fetchPage(int pageSize,
|
||||
ConsistencyLevel consistency,
|
||||
ClientState clientState,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
if (limits.isGroupByLimit())
|
||||
return new GroupByPartitionIterator(pageSize, consistency, clientState, queryStartNanoTime);
|
||||
return new GroupByPartitionIterator(pageSize, consistency, clientState, requestTime);
|
||||
|
||||
return new AggregationPartitionIterator(pageSize, consistency, clientState, queryStartNanoTime);
|
||||
return new AggregationPartitionIterator(pageSize, consistency, clientState, requestTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -73,9 +72,9 @@ public final class AggregationQueryPager implements QueryPager
|
|||
public PartitionIterator fetchPageInternal(int pageSize, ReadExecutionController executionController)
|
||||
{
|
||||
if (limits.isGroupByLimit())
|
||||
return new GroupByPartitionIterator(pageSize, executionController, nanoTime());
|
||||
return new GroupByPartitionIterator(pageSize, executionController, Dispatcher.RequestTime.forImmediateExecution());
|
||||
|
||||
return new AggregationPartitionIterator(pageSize, executionController, nanoTime());
|
||||
return new AggregationPartitionIterator(pageSize, executionController, Dispatcher.RequestTime.forImmediateExecution());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -161,34 +160,34 @@ public final class AggregationQueryPager implements QueryPager
|
|||
*/
|
||||
private int initialMaxRemaining;
|
||||
|
||||
private long queryStartNanoTime;
|
||||
private Dispatcher.RequestTime requestTime;
|
||||
|
||||
public GroupByPartitionIterator(int pageSize,
|
||||
ConsistencyLevel consistency,
|
||||
ClientState clientState,
|
||||
long queryStartNanoTime)
|
||||
ConsistencyLevel consistency,
|
||||
ClientState clientState,
|
||||
Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
this(pageSize, consistency, clientState, null, queryStartNanoTime);
|
||||
this(pageSize, consistency, clientState, null, requestTime);
|
||||
}
|
||||
|
||||
public GroupByPartitionIterator(int pageSize,
|
||||
ReadExecutionController executionController,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
this(pageSize, null, null, executionController, queryStartNanoTime);
|
||||
this(pageSize, null, null, executionController, requestTime);
|
||||
}
|
||||
|
||||
private GroupByPartitionIterator(int pageSize,
|
||||
ConsistencyLevel consistency,
|
||||
ClientState clientState,
|
||||
ReadExecutionController executionController,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
this.pageSize = handlePagingOff(pageSize);
|
||||
this.consistency = consistency;
|
||||
this.clientState = clientState;
|
||||
this.executionController = executionController;
|
||||
this.queryStartNanoTime = queryStartNanoTime;
|
||||
this.requestTime = requestTime;
|
||||
}
|
||||
|
||||
private int handlePagingOff(int pageSize)
|
||||
|
|
@ -295,7 +294,7 @@ public final class AggregationQueryPager implements QueryPager
|
|||
*/
|
||||
private final PartitionIterator fetchSubPage(int subPageSize)
|
||||
{
|
||||
return consistency != null ? subPager.fetchPage(subPageSize, consistency, clientState, queryStartNanoTime)
|
||||
return consistency != null ? subPager.fetchPage(subPageSize, consistency, clientState, requestTime)
|
||||
: subPager.fetchPageInternal(subPageSize, executionController);
|
||||
}
|
||||
|
||||
|
|
@ -409,16 +408,16 @@ public final class AggregationQueryPager implements QueryPager
|
|||
public AggregationPartitionIterator(int pageSize,
|
||||
ConsistencyLevel consistency,
|
||||
ClientState clientState,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
super(pageSize, consistency, clientState, queryStartNanoTime);
|
||||
super(pageSize, consistency, clientState, requestTime);
|
||||
}
|
||||
|
||||
public AggregationPartitionIterator(int pageSize,
|
||||
ReadExecutionController executionController,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
super(pageSize, executionController, queryStartNanoTime);
|
||||
super(pageSize, executionController, requestTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
*/
|
||||
package org.apache.cassandra.service.pager;
|
||||
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
import org.apache.cassandra.utils.AbstractIterator;
|
||||
|
||||
|
|
@ -30,8 +31,6 @@ import org.apache.cassandra.exceptions.RequestValidationException;
|
|||
import org.apache.cassandra.exceptions.RequestExecutionException;
|
||||
import org.apache.cassandra.service.ClientState;
|
||||
|
||||
import static org.apache.cassandra.utils.Clock.Global.nanoTime;
|
||||
|
||||
/**
|
||||
* Pager over a list of SinglePartitionReadQuery.
|
||||
*
|
||||
|
|
@ -149,16 +148,18 @@ public class MultiPartitionPager<T extends SinglePartitionReadQuery> implements
|
|||
throw new AssertionError("Shouldn't be called on an exhausted pager");
|
||||
}
|
||||
|
||||
public PartitionIterator fetchPage(int pageSize, ConsistencyLevel consistency, ClientState clientState, long queryStartNanoTime) throws RequestValidationException, RequestExecutionException
|
||||
@SuppressWarnings("resource") // iter closed via countingIter
|
||||
@Override
|
||||
public PartitionIterator fetchPage(int pageSize, ConsistencyLevel consistency, ClientState clientState, Dispatcher.RequestTime requestTime) throws RequestValidationException, RequestExecutionException
|
||||
{
|
||||
int toQuery = Math.min(remaining, pageSize);
|
||||
return new PagersIterator(toQuery, consistency, clientState, null, queryStartNanoTime);
|
||||
return new PagersIterator(toQuery, consistency, clientState, null, requestTime);
|
||||
}
|
||||
|
||||
public PartitionIterator fetchPageInternal(int pageSize, ReadExecutionController executionController) throws RequestValidationException, RequestExecutionException
|
||||
{
|
||||
int toQuery = Math.min(remaining, pageSize);
|
||||
return new PagersIterator(toQuery, null, null, executionController, nanoTime());
|
||||
return new PagersIterator(toQuery, null, null, executionController, Dispatcher.RequestTime.forImmediateExecution());
|
||||
}
|
||||
|
||||
private class PagersIterator extends AbstractIterator<RowIterator> implements PartitionIterator
|
||||
|
|
@ -166,7 +167,7 @@ public class MultiPartitionPager<T extends SinglePartitionReadQuery> implements
|
|||
private final int pageSize;
|
||||
private PartitionIterator result;
|
||||
private boolean closed;
|
||||
private final long queryStartNanoTime;
|
||||
private final Dispatcher.RequestTime requestTime;
|
||||
|
||||
// For "normal" queries
|
||||
private final ConsistencyLevel consistency;
|
||||
|
|
@ -178,13 +179,13 @@ public class MultiPartitionPager<T extends SinglePartitionReadQuery> implements
|
|||
private int pagerMaxRemaining;
|
||||
private int counted;
|
||||
|
||||
public PagersIterator(int pageSize, ConsistencyLevel consistency, ClientState clientState, ReadExecutionController executionController, long queryStartNanoTime)
|
||||
public PagersIterator(int pageSize, ConsistencyLevel consistency, ClientState clientState, ReadExecutionController executionController, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
this.pageSize = pageSize;
|
||||
this.consistency = consistency;
|
||||
this.clientState = clientState;
|
||||
this.executionController = executionController;
|
||||
this.queryStartNanoTime = queryStartNanoTime;
|
||||
this.requestTime = requestTime;
|
||||
}
|
||||
|
||||
protected RowIterator computeNext()
|
||||
|
|
@ -213,7 +214,7 @@ public class MultiPartitionPager<T extends SinglePartitionReadQuery> implements
|
|||
int toQuery = pageSize - counted;
|
||||
result = consistency == null
|
||||
? pagers[current].fetchPageInternal(toQuery, executionController)
|
||||
: pagers[current].fetchPage(toQuery, consistency, clientState, queryStartNanoTime);
|
||||
: pagers[current].fetchPage(toQuery, consistency, clientState, requestTime);
|
||||
}
|
||||
return result.next();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import org.apache.cassandra.db.partitions.PartitionIterator;
|
|||
import org.apache.cassandra.exceptions.RequestExecutionException;
|
||||
import org.apache.cassandra.exceptions.RequestValidationException;
|
||||
import org.apache.cassandra.service.ClientState;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
|
||||
/**
|
||||
* Perform a query, paging it by page of a given size.
|
||||
|
|
@ -54,7 +55,7 @@ public interface QueryPager
|
|||
return ReadExecutionController.empty();
|
||||
}
|
||||
|
||||
public PartitionIterator fetchPage(int pageSize, ConsistencyLevel consistency, ClientState clientState, long queryStartNanoTime) throws RequestValidationException, RequestExecutionException
|
||||
public PartitionIterator fetchPage(int pageSize, ConsistencyLevel consistency, ClientState clientState, Dispatcher.RequestTime requestTime) throws RequestValidationException, RequestExecutionException
|
||||
{
|
||||
return EmptyIterators.partition();
|
||||
}
|
||||
|
|
@ -94,7 +95,7 @@ public interface QueryPager
|
|||
* {@code consistency} is a serial consistency.
|
||||
* @return the page of result.
|
||||
*/
|
||||
public PartitionIterator fetchPage(int pageSize, ConsistencyLevel consistency, ClientState clientState, long queryStartNanoTime) throws RequestValidationException, RequestExecutionException;
|
||||
public PartitionIterator fetchPage(int pageSize, ConsistencyLevel consistency, ClientState clientState, Dispatcher.RequestTime requestTime) throws RequestValidationException, RequestExecutionException;
|
||||
|
||||
/**
|
||||
* Starts a new read operation.
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ import org.apache.cassandra.service.paxos.cleanup.PaxosRepairState;
|
|||
import org.apache.cassandra.service.reads.DataResolver;
|
||||
import org.apache.cassandra.service.reads.repair.NoopReadRepair;
|
||||
import org.apache.cassandra.tracing.Tracing;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.triggers.TriggerExecutor;
|
||||
import org.apache.cassandra.utils.CassandraVersion;
|
||||
import org.apache.cassandra.utils.CollectionSerializer;
|
||||
|
|
@ -820,21 +821,20 @@ public class Paxos
|
|||
return read.rowIterator();
|
||||
}
|
||||
|
||||
public static PartitionIterator read(SinglePartitionReadCommand.Group group, ConsistencyLevel consistencyForConsensus)
|
||||
public static PartitionIterator read(SinglePartitionReadCommand.Group group, ConsistencyLevel consistencyForConsensus, Dispatcher.RequestTime requestTime)
|
||||
throws InvalidRequestException, UnavailableException, ReadFailureException, ReadTimeoutException
|
||||
{
|
||||
long start = nanoTime();
|
||||
long deadline = start + DatabaseDescriptor.getReadRpcTimeout(NANOSECONDS);
|
||||
return read(group, consistencyForConsensus, start, deadline);
|
||||
long deadline = requestTime.computeDeadline(DatabaseDescriptor.getReadRpcTimeout(NANOSECONDS));
|
||||
return read(group, consistencyForConsensus, requestTime, deadline);
|
||||
}
|
||||
|
||||
public static PartitionIterator read(SinglePartitionReadCommand.Group group, ConsistencyLevel consistencyForConsensus, long deadline)
|
||||
throws InvalidRequestException, UnavailableException, ReadFailureException, ReadTimeoutException
|
||||
{
|
||||
return read(group, consistencyForConsensus, nanoTime(), deadline);
|
||||
return read(group, consistencyForConsensus, Dispatcher.RequestTime.forImmediateExecution(), deadline);
|
||||
}
|
||||
|
||||
private static PartitionIterator read(SinglePartitionReadCommand.Group group, ConsistencyLevel consistencyForConsensus, long start, long deadline)
|
||||
private static PartitionIterator read(SinglePartitionReadCommand.Group group, ConsistencyLevel consistencyForConsensus, Dispatcher.RequestTime requestTime, long deadline)
|
||||
throws InvalidRequestException, UnavailableException, ReadFailureException, ReadTimeoutException
|
||||
{
|
||||
if (group.queries.size() > 1)
|
||||
|
|
@ -901,7 +901,9 @@ public class Paxos
|
|||
}
|
||||
finally
|
||||
{
|
||||
long latency = nanoTime() - start;
|
||||
// We track latency based on request processing time, since the amount of time that request spends in the queue
|
||||
// is not a representative metric of replica performance.
|
||||
long latency = nanoTime() - requestTime.startedAtNanos();
|
||||
readMetrics.addNano(latency);
|
||||
casReadMetrics.addNano(latency);
|
||||
readMetricsMap.get(consistencyForConsensus).addNano(latency);
|
||||
|
|
@ -1039,7 +1041,7 @@ public class Paxos
|
|||
// round's proposal (if any).
|
||||
PaxosPrepare.Success success = prepare.success();
|
||||
|
||||
DataResolver<?, ?> resolver = new DataResolver(query, success.participants, NoopReadRepair.instance, query.creationTimeNanos());
|
||||
DataResolver<?, ?> resolver = new DataResolver(query, success.participants, NoopReadRepair.instance, new Dispatcher.RequestTime(query.creationTimeNanos()));
|
||||
for (int i = 0 ; i < success.responses.size() ; ++i)
|
||||
resolver.preprocess(success.responses.get(i));
|
||||
|
||||
|
|
|
|||
|
|
@ -17,17 +17,17 @@
|
|||
*/
|
||||
package org.apache.cassandra.service.paxos.v1;
|
||||
|
||||
import org.apache.cassandra.utils.concurrent.CountDownLatch;
|
||||
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.db.ConsistencyLevel;
|
||||
import org.apache.cassandra.db.WriteType;
|
||||
import org.apache.cassandra.exceptions.WriteTimeoutException;
|
||||
import org.apache.cassandra.net.RequestCallback;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.utils.concurrent.UncheckedInterruptedException;
|
||||
import org.apache.cassandra.utils.Clock;
|
||||
import org.apache.cassandra.utils.concurrent.CountDownLatch;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.NANOSECONDS;
|
||||
import static org.apache.cassandra.utils.Clock.Global.nanoTime;
|
||||
import static org.apache.cassandra.utils.concurrent.CountDownLatch.newCountDownLatch;
|
||||
|
||||
public abstract class AbstractPaxosCallback<T> implements RequestCallback<T>
|
||||
|
|
@ -35,14 +35,14 @@ public abstract class AbstractPaxosCallback<T> implements RequestCallback<T>
|
|||
protected final CountDownLatch latch;
|
||||
protected final int targets;
|
||||
private final ConsistencyLevel consistency;
|
||||
private final long queryStartNanoTime;
|
||||
private final Dispatcher.RequestTime requestTime;
|
||||
|
||||
public AbstractPaxosCallback(int targets, ConsistencyLevel consistency, long queryStartNanoTime)
|
||||
public AbstractPaxosCallback(int targets, ConsistencyLevel consistency, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
this.targets = targets;
|
||||
this.consistency = consistency;
|
||||
latch = newCountDownLatch(targets);
|
||||
this.queryStartNanoTime = queryStartNanoTime;
|
||||
this.requestTime = requestTime;
|
||||
}
|
||||
|
||||
public int getResponseCount()
|
||||
|
|
@ -54,7 +54,9 @@ public abstract class AbstractPaxosCallback<T> implements RequestCallback<T>
|
|||
{
|
||||
try
|
||||
{
|
||||
long timeout = DatabaseDescriptor.getWriteRpcTimeout(NANOSECONDS) - (nanoTime() - queryStartNanoTime);
|
||||
long now = Clock.Global.nanoTime();
|
||||
long timeout = requestTime.computeTimeout(now, DatabaseDescriptor.getWriteRpcTimeout(NANOSECONDS));
|
||||
|
||||
if (!latch.await(timeout, NANOSECONDS))
|
||||
throw new WriteTimeoutException(WriteType.CAS, consistency, getResponseCount(), targets);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ import org.slf4j.LoggerFactory;
|
|||
import org.apache.cassandra.net.Message;
|
||||
import org.apache.cassandra.service.paxos.Commit;
|
||||
import org.apache.cassandra.service.paxos.PrepareResponse;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
|
||||
public class PrepareCallback extends AbstractPaxosCallback<PrepareResponse>
|
||||
{
|
||||
|
|
@ -45,9 +46,9 @@ public class PrepareCallback extends AbstractPaxosCallback<PrepareResponse>
|
|||
|
||||
private final Map<InetAddressAndPort, Commit> commitsByReplica = new ConcurrentHashMap<>();
|
||||
|
||||
public PrepareCallback(DecoratedKey key, TableMetadata metadata, int targets, ConsistencyLevel consistency, long queryStartNanoTime)
|
||||
public PrepareCallback(DecoratedKey key, TableMetadata metadata, int targets, ConsistencyLevel consistency, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
super(targets, consistency, queryStartNanoTime);
|
||||
super(targets, consistency, requestTime);
|
||||
// need to inject the right key in the empty commit so comparing with empty commits in the response works as expected
|
||||
mostRecentCommit = Commit.emptyCommit(key, metadata);
|
||||
mostRecentInProgressCommit = Commit.emptyCommit(key, metadata);
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.apache.cassandra.net.Message;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.utils.Nemesis;
|
||||
|
||||
/**
|
||||
|
|
@ -49,9 +50,9 @@ public class ProposeCallback extends AbstractPaxosCallback<Boolean>
|
|||
private final int requiredAccepts;
|
||||
private final boolean failFast;
|
||||
|
||||
public ProposeCallback(int totalTargets, int requiredTargets, boolean failFast, ConsistencyLevel consistency, long queryStartNanoTime)
|
||||
public ProposeCallback(int totalTargets, int requiredTargets, boolean failFast, ConsistencyLevel consistency, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
super(totalTargets, consistency, queryStartNanoTime);
|
||||
super(totalTargets, consistency, requestTime);
|
||||
this.requiredAccepts = requiredTargets;
|
||||
this.failFast = failFast;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,10 +45,13 @@ import org.apache.cassandra.service.StorageProxy.LocalReadRunnable;
|
|||
import org.apache.cassandra.service.reads.repair.ReadRepair;
|
||||
import org.apache.cassandra.tracing.TraceState;
|
||||
import org.apache.cassandra.tracing.Tracing;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
|
||||
import static com.google.common.collect.Iterables.all;
|
||||
import static java.util.concurrent.TimeUnit.MICROSECONDS;
|
||||
import static java.util.concurrent.TimeUnit.NANOSECONDS;
|
||||
import static org.apache.cassandra.utils.MonotonicClock.Global.preciseTime;
|
||||
|
||||
/**
|
||||
* Sends a read request to the replicas needed to satisfy a given ConsistencyLevel.
|
||||
|
|
@ -69,22 +72,23 @@ public abstract class AbstractReadExecutor
|
|||
protected final ReadCallback<EndpointsForToken, ReplicaPlan.ForTokenRead> handler;
|
||||
protected final TraceState traceState;
|
||||
protected final ColumnFamilyStore cfs;
|
||||
protected final long queryStartNanoTime;
|
||||
protected final Dispatcher.RequestTime requestTime;
|
||||
|
||||
private final int initialDataRequestCount;
|
||||
protected volatile PartitionIterator result = null;
|
||||
|
||||
AbstractReadExecutor(ColumnFamilyStore cfs, ReadCommand command, ReplicaPlan.ForTokenRead replicaPlan, int initialDataRequestCount, long queryStartNanoTime)
|
||||
AbstractReadExecutor(ColumnFamilyStore cfs, ReadCommand command, ReplicaPlan.ForTokenRead replicaPlan, int initialDataRequestCount, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
this.command = command;
|
||||
this.replicaPlan = ReplicaPlan.shared(replicaPlan);
|
||||
this.initialDataRequestCount = initialDataRequestCount;
|
||||
// the ReadRepair and DigestResolver both need to see our updated
|
||||
this.readRepair = ReadRepair.create(command, this.replicaPlan, queryStartNanoTime);
|
||||
this.digestResolver = new DigestResolver<>(command, this.replicaPlan, queryStartNanoTime);
|
||||
this.handler = new ReadCallback<>(digestResolver, command, this.replicaPlan, queryStartNanoTime);
|
||||
this.readRepair = ReadRepair.create(command, this.replicaPlan, requestTime);
|
||||
this.digestResolver = new DigestResolver<>(command, this.replicaPlan, requestTime);
|
||||
this.handler = new ReadCallback<>(digestResolver, command, this.replicaPlan, requestTime);
|
||||
this.cfs = cfs;
|
||||
this.traceState = Tracing.instance.get();
|
||||
this.queryStartNanoTime = queryStartNanoTime;
|
||||
this.requestTime = requestTime;
|
||||
|
||||
|
||||
// Set the digest version (if we request some digests). This is the smallest version amongst all our target replicas since new nodes
|
||||
|
|
@ -147,7 +151,9 @@ public abstract class AbstractReadExecutor
|
|||
traceState.trace("reading {} from {}", readCommand.isDigestQuery() ? "digest" : "data", endpoint);
|
||||
|
||||
if (null == message)
|
||||
message = readCommand.createMessage(false);
|
||||
{
|
||||
message = readCommand.createMessage(false, requestTime);
|
||||
}
|
||||
|
||||
MessagingService.instance().sendWithCallback(message, endpoint, handler);
|
||||
}
|
||||
|
|
@ -156,7 +162,7 @@ public abstract class AbstractReadExecutor
|
|||
if (hasLocalEndpoint)
|
||||
{
|
||||
logger.trace("reading {} locally", readCommand.isDigestQuery() ? "digest" : "data");
|
||||
Stage.READ.maybeExecuteImmediately(new LocalReadRunnable(readCommand, handler));
|
||||
Stage.READ.maybeExecuteImmediately(new LocalReadRunnable(readCommand, handler, requestTime));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -181,9 +187,7 @@ public abstract class AbstractReadExecutor
|
|||
/**
|
||||
* @return an executor appropriate for the configured speculative read policy
|
||||
*/
|
||||
public static AbstractReadExecutor getReadExecutor(SinglePartitionReadCommand command,
|
||||
ConsistencyLevel consistencyLevel,
|
||||
long queryStartNanoTime) throws UnavailableException
|
||||
public static AbstractReadExecutor getReadExecutor(SinglePartitionReadCommand command, ConsistencyLevel consistencyLevel, Dispatcher.RequestTime requestTime) throws UnavailableException
|
||||
{
|
||||
Keyspace keyspace = Keyspace.open(command.metadata().keyspace);
|
||||
ColumnFamilyStore cfs = keyspace.getColumnFamilyStore(command.metadata().id);
|
||||
|
|
@ -198,20 +202,20 @@ public abstract class AbstractReadExecutor
|
|||
// Speculative retry is disabled *OR*
|
||||
// 11980: Disable speculative retry if using EACH_QUORUM in order to prevent miscounting DC responses
|
||||
if (retry.equals(NeverSpeculativeRetryPolicy.INSTANCE) || consistencyLevel == ConsistencyLevel.EACH_QUORUM)
|
||||
return new NeverSpeculatingReadExecutor(cfs, command, replicaPlan, queryStartNanoTime, false);
|
||||
return new NeverSpeculatingReadExecutor(cfs, command, replicaPlan, requestTime, false);
|
||||
|
||||
// There are simply no extra replicas to speculate.
|
||||
// Handle this separately so it can record failed attempts to speculate due to lack of replicas
|
||||
if (replicaPlan.contacts().size() == replicaPlan.readCandidates().size())
|
||||
{
|
||||
boolean recordFailedSpeculation = consistencyLevel != ConsistencyLevel.ALL;
|
||||
return new NeverSpeculatingReadExecutor(cfs, command, replicaPlan, queryStartNanoTime, recordFailedSpeculation);
|
||||
return new NeverSpeculatingReadExecutor(cfs, command, replicaPlan, requestTime, recordFailedSpeculation);
|
||||
}
|
||||
|
||||
if (retry.equals(AlwaysSpeculativeRetryPolicy.INSTANCE))
|
||||
return new AlwaysSpeculatingReadExecutor(cfs, command, replicaPlan, queryStartNanoTime);
|
||||
return new AlwaysSpeculatingReadExecutor(cfs, command, replicaPlan, requestTime);
|
||||
else // PERCENTILE or CUSTOM.
|
||||
return new SpeculatingReadExecutor(cfs, command, replicaPlan, queryStartNanoTime);
|
||||
return new SpeculatingReadExecutor(cfs, command, replicaPlan, requestTime);
|
||||
}
|
||||
|
||||
public boolean hasLocalRead()
|
||||
|
|
@ -225,17 +229,27 @@ public abstract class AbstractReadExecutor
|
|||
*/
|
||||
boolean shouldSpeculateAndMaybeWait()
|
||||
{
|
||||
long now = preciseTime.now();
|
||||
long sampleLatencyNanos = MICROSECONDS.toNanos(cfs.sampleReadLatencyMicros);
|
||||
// no latency information, or we're overloaded
|
||||
if (cfs.sampleReadLatencyMicros > command.getTimeout(MICROSECONDS))
|
||||
if (sampleLatencyNanos > command.getTimeout(NANOSECONDS))
|
||||
{
|
||||
if (logger.isTraceEnabled())
|
||||
logger.trace("Decided not to speculate as {} > {}", cfs.sampleReadLatencyMicros, command.getTimeout(MICROSECONDS));
|
||||
logger.trace("Decided not to speculate as {}ns > {}ns", sampleLatencyNanos, command.getTimeout(NANOSECONDS));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (now + sampleLatencyNanos > requestTime.clientDeadline())
|
||||
{
|
||||
logger.trace("Decided not to speculate as native transport timeout will be reached before speculating");
|
||||
return false;
|
||||
}
|
||||
|
||||
// We track latency based on request processing time, since the amount of time that request spends in the queue
|
||||
// is not a representative metric of replica performance.
|
||||
if (logger.isTraceEnabled())
|
||||
logger.trace("Awaiting {} microseconds before speculating", cfs.sampleReadLatencyMicros);
|
||||
return !handler.await(cfs.sampleReadLatencyMicros, MICROSECONDS);
|
||||
logger.trace("Awaiting {}ns before speculating", sampleLatencyNanos);
|
||||
|
||||
return !handler.awaitUntil(requestTime.startedAtNanos() + sampleLatencyNanos);
|
||||
}
|
||||
|
||||
ReplicaPlan.ForTokenRead replicaPlan()
|
||||
|
|
@ -254,9 +268,13 @@ public abstract class AbstractReadExecutor
|
|||
*/
|
||||
private final boolean logFailedSpeculation;
|
||||
|
||||
public NeverSpeculatingReadExecutor(ColumnFamilyStore cfs, ReadCommand command, ReplicaPlan.ForTokenRead replicaPlan, long queryStartNanoTime, boolean logFailedSpeculation)
|
||||
public NeverSpeculatingReadExecutor(ColumnFamilyStore cfs,
|
||||
ReadCommand command,
|
||||
ReplicaPlan.ForTokenRead replicaPlan,
|
||||
Dispatcher.RequestTime requestTime,
|
||||
boolean logFailedSpeculation)
|
||||
{
|
||||
super(cfs, command, replicaPlan, 1, queryStartNanoTime);
|
||||
super(cfs, command, replicaPlan, 1, requestTime);
|
||||
this.logFailedSpeculation = logFailedSpeculation;
|
||||
}
|
||||
|
||||
|
|
@ -276,12 +294,12 @@ public abstract class AbstractReadExecutor
|
|||
public SpeculatingReadExecutor(ColumnFamilyStore cfs,
|
||||
ReadCommand command,
|
||||
ReplicaPlan.ForTokenRead replicaPlan,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
// We're hitting additional targets for read repair (??). Since our "extra" replica is the least-
|
||||
// preferred by the snitch, we do an extra data read to start with against a replica more
|
||||
// likely to respond; better to let RR fail than the entire query.
|
||||
super(cfs, command, replicaPlan, replicaPlan.readQuorum() < replicaPlan.contacts().size() ? 2 : 1, queryStartNanoTime);
|
||||
super(cfs, command, replicaPlan, replicaPlan.readQuorum() < replicaPlan.contacts().size() ? 2 : 1, requestTime);
|
||||
}
|
||||
|
||||
public void maybeTryAdditionalReplicas()
|
||||
|
|
@ -327,7 +345,8 @@ public abstract class AbstractReadExecutor
|
|||
if (traceState != null)
|
||||
traceState.trace("speculating read retry on {}", extraReplica);
|
||||
logger.trace("speculating read retry on {}", extraReplica);
|
||||
MessagingService.instance().sendWithCallback(retryCommand.createMessage(false), extraReplica.endpoint(), handler);
|
||||
|
||||
MessagingService.instance().sendWithCallback(retryCommand.createMessage(false, requestTime), extraReplica.endpoint(), handler);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -346,11 +365,11 @@ public abstract class AbstractReadExecutor
|
|||
public AlwaysSpeculatingReadExecutor(ColumnFamilyStore cfs,
|
||||
ReadCommand command,
|
||||
ReplicaPlan.ForTokenRead replicaPlan,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
// presumably, we speculate an extra data request here in case it is our data request that fails to respond,
|
||||
// and there are no more nodes to consult
|
||||
super(cfs, command, replicaPlan, replicaPlan.contacts().size() > 1 ? 2 : 1, queryStartNanoTime);
|
||||
super(cfs, command, replicaPlan, replicaPlan.contacts().size() > 1 ? 2 : 1, requestTime);
|
||||
}
|
||||
|
||||
public void maybeTryAdditionalReplicas()
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ import org.apache.cassandra.service.reads.repair.NoopReadRepair;
|
|||
import org.apache.cassandra.service.reads.repair.ReadRepair;
|
||||
import org.apache.cassandra.service.reads.repair.RepairedDataTracker;
|
||||
import org.apache.cassandra.service.reads.repair.RepairedDataVerifier;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
|
||||
import static com.google.common.collect.Iterables.*;
|
||||
|
||||
|
|
@ -64,14 +65,14 @@ public class DataResolver<E extends Endpoints<E>, P extends ReplicaPlan.ForRead<
|
|||
private final ReadRepair<E, P> readRepair;
|
||||
private final boolean trackRepairedStatus;
|
||||
|
||||
public DataResolver(ReadCommand command, Supplier<? extends P> replicaPlan, ReadRepair<E, P> readRepair, long queryStartNanoTime)
|
||||
public DataResolver(ReadCommand command, Supplier<? extends P> replicaPlan, ReadRepair<E, P> readRepair, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
this(command, replicaPlan, readRepair, queryStartNanoTime, false);
|
||||
this(command, replicaPlan, readRepair, requestTime, false);
|
||||
}
|
||||
|
||||
public DataResolver(ReadCommand command, Supplier<? extends P> replicaPlan, ReadRepair<E, P> readRepair, long queryStartNanoTime, boolean trackRepairedStatus)
|
||||
public DataResolver(ReadCommand command, Supplier<? extends P> replicaPlan, ReadRepair<E, P> readRepair, Dispatcher.RequestTime requestTime, boolean trackRepairedStatus)
|
||||
{
|
||||
super(command, replicaPlan, queryStartNanoTime);
|
||||
super(command, replicaPlan, requestTime);
|
||||
this.enforceStrictLiveness = command.metadata().enforceStrictLiveness();
|
||||
this.readRepair = readRepair;
|
||||
this.trackRepairedStatus = trackRepairedStatus;
|
||||
|
|
@ -208,7 +209,7 @@ public class DataResolver<E extends Endpoints<E>, P extends ReplicaPlan.ForRead<
|
|||
originalResponse,
|
||||
command,
|
||||
context.mergedResultCounter,
|
||||
queryStartNanoTime,
|
||||
requestTime,
|
||||
enforceStrictLiveness)
|
||||
: originalResponse;
|
||||
}
|
||||
|
|
@ -251,7 +252,7 @@ public class DataResolver<E extends Endpoints<E>, P extends ReplicaPlan.ForRead<
|
|||
ReplicaFilteringProtection<E> rfp = new ReplicaFilteringProtection<>(replicaPlan().keyspace(),
|
||||
command,
|
||||
replicaPlan().consistencyLevel(),
|
||||
queryStartNanoTime,
|
||||
requestTime,
|
||||
replicas,
|
||||
DatabaseDescriptor.getCachedReplicaRowsWarnThreshold(),
|
||||
DatabaseDescriptor.getCachedReplicaRowsFailThreshold());
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import org.apache.cassandra.locator.InetAddressAndPort;
|
|||
import org.apache.cassandra.locator.ReplicaPlan;
|
||||
import org.apache.cassandra.net.Message;
|
||||
import org.apache.cassandra.service.reads.repair.NoopReadRepair;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
|
||||
import static com.google.common.collect.Iterables.any;
|
||||
|
|
@ -44,9 +45,9 @@ public class DigestResolver<E extends Endpoints<E>, P extends ReplicaPlan.ForRea
|
|||
{
|
||||
private volatile Message<ReadResponse> dataResponse;
|
||||
|
||||
public DigestResolver(ReadCommand command, ReplicaPlan.Shared<E, P> replicaPlan, long queryStartNanoTime)
|
||||
public DigestResolver(ReadCommand command, ReplicaPlan.Shared<E, P> replicaPlan, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
super(command, replicaPlan, queryStartNanoTime);
|
||||
super(command, replicaPlan, requestTime);
|
||||
Preconditions.checkArgument(command instanceof SinglePartitionReadCommand,
|
||||
"DigestResolver can only be used with SinglePartitionReadCommand commands");
|
||||
}
|
||||
|
|
@ -86,7 +87,7 @@ public class DigestResolver<E extends Endpoints<E>, P extends ReplicaPlan.ForRea
|
|||
// This path can be triggered only if we've got responses from full replicas and they match, but
|
||||
// transient replica response still contains data, which needs to be reconciled.
|
||||
DataResolver<E, P> dataResolver
|
||||
= new DataResolver<>(command, replicaPlan, NoopReadRepair.instance, queryStartNanoTime);
|
||||
= new DataResolver<>(command, replicaPlan, NoopReadRepair.instance, requestTime);
|
||||
|
||||
dataResolver.preprocess(dataResponse);
|
||||
// Reconcile with transient replicas
|
||||
|
|
|
|||
|
|
@ -24,13 +24,11 @@ import java.util.concurrent.TimeUnit;
|
|||
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
|
||||
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
|
||||
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.db.MessageParams;
|
||||
import org.apache.cassandra.locator.ReplicaPlan;
|
||||
import org.apache.cassandra.utils.concurrent.Condition;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.db.MessageParams;
|
||||
import org.apache.cassandra.db.PartitionRangeReadCommand;
|
||||
import org.apache.cassandra.db.ReadCommand;
|
||||
import org.apache.cassandra.db.ReadResponse;
|
||||
|
|
@ -39,6 +37,7 @@ import org.apache.cassandra.exceptions.ReadTimeoutException;
|
|||
import org.apache.cassandra.exceptions.RequestFailureReason;
|
||||
import org.apache.cassandra.locator.Endpoints;
|
||||
import org.apache.cassandra.locator.InetAddressAndPort;
|
||||
import org.apache.cassandra.locator.ReplicaPlan;
|
||||
import org.apache.cassandra.net.Message;
|
||||
import org.apache.cassandra.net.ParamType;
|
||||
import org.apache.cassandra.net.RequestCallback;
|
||||
|
|
@ -47,13 +46,13 @@ import org.apache.cassandra.service.reads.thresholds.CoordinatorWarnings;
|
|||
import org.apache.cassandra.service.reads.thresholds.WarningContext;
|
||||
import org.apache.cassandra.service.reads.thresholds.WarningsSnapshot;
|
||||
import org.apache.cassandra.tracing.Tracing;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.utils.concurrent.Condition;
|
||||
import org.apache.cassandra.utils.concurrent.UncheckedInterruptedException;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static java.util.concurrent.TimeUnit.NANOSECONDS;
|
||||
import static java.util.concurrent.atomic.AtomicIntegerFieldUpdater.newUpdater;
|
||||
import static org.apache.cassandra.tracing.Tracing.isTracing;
|
||||
import static org.apache.cassandra.utils.Clock.Global.nanoTime;
|
||||
import static org.apache.cassandra.utils.concurrent.Condition.newOneTimeCondition;
|
||||
|
||||
public class ReadCallback<E extends Endpoints<E>, P extends ReplicaPlan.ForRead<E, P>> implements RequestCallback<ReadResponse>
|
||||
|
|
@ -62,7 +61,7 @@ public class ReadCallback<E extends Endpoints<E>, P extends ReplicaPlan.ForRead<
|
|||
|
||||
public final ResponseResolver<E, P> resolver;
|
||||
final Condition condition = newOneTimeCondition();
|
||||
private final long queryStartNanoTime;
|
||||
private final Dispatcher.RequestTime requestTime;
|
||||
final int blockFor; // TODO: move to replica plan as well?
|
||||
// this uses a plain reference, but is initialised before handoff to any other threads; the later updates
|
||||
// may not be visible to the threads immediately, but ReplicaPlan only contains final fields, so they will never see an uninitialised object
|
||||
|
|
@ -76,11 +75,11 @@ public class ReadCallback<E extends Endpoints<E>, P extends ReplicaPlan.ForRead<
|
|||
private static final AtomicReferenceFieldUpdater<ReadCallback, WarningContext> warningsUpdater
|
||||
= AtomicReferenceFieldUpdater.newUpdater(ReadCallback.class, WarningContext.class, "warningContext");
|
||||
|
||||
public ReadCallback(ResponseResolver<E, P> resolver, ReadCommand command, ReplicaPlan.Shared<E, P> replicaPlan, long queryStartNanoTime)
|
||||
public ReadCallback(ResponseResolver<E, P> resolver, ReadCommand command, ReplicaPlan.Shared<E, P> replicaPlan, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
this.command = command;
|
||||
this.resolver = resolver;
|
||||
this.queryStartNanoTime = queryStartNanoTime;
|
||||
this.requestTime = requestTime;
|
||||
this.replicaPlan = replicaPlan;
|
||||
this.blockFor = replicaPlan.get().readQuorum();
|
||||
this.failureReasonByEndpoint = new ConcurrentHashMap<>();
|
||||
|
|
@ -96,12 +95,29 @@ public class ReadCallback<E extends Endpoints<E>, P extends ReplicaPlan.ForRead<
|
|||
return replicaPlan.get();
|
||||
}
|
||||
|
||||
public boolean await(long timePastStart, TimeUnit unit)
|
||||
public boolean await(long commandTimeout, TimeUnit unit)
|
||||
{
|
||||
return awaitUntil(requestTime.computeDeadline(unit.toNanos(commandTimeout)));
|
||||
}
|
||||
|
||||
/**
|
||||
* In case of speculation, we want to time out the request immediately if we have _also_ hit a deadline.
|
||||
*
|
||||
* For example, we have a read timeout of 10s, 99% latency of 5 seconds, native_transport_timeout of 12s,
|
||||
* and time base is QUEUE:
|
||||
* * Request has spent 3 seconds in the queue. Here, we will wait for 2 seconds and try to speculate
|
||||
* * Request has spent 10 seconds in the queue. Here, we will wait for 0 seconds and try to speculate
|
||||
*
|
||||
* If the time base is REQUEST:
|
||||
* * Request has spent 10 seconds in the queue. Here, we will only wait 2 seconds and then try to speculate
|
||||
*
|
||||
* We should _not_ speculate in all these cases, since by that time we are already past request deadline.
|
||||
*/
|
||||
public boolean awaitUntil(long deadline)
|
||||
{
|
||||
long time = unit.toNanos(timePastStart) - (nanoTime() - queryStartNanoTime);
|
||||
try
|
||||
{
|
||||
return condition.await(time, NANOSECONDS);
|
||||
return condition.awaitUntil(deadline);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ import org.apache.cassandra.service.ClientWarn;
|
|||
import org.apache.cassandra.service.StorageProxy;
|
||||
import org.apache.cassandra.service.reads.repair.NoopReadRepair;
|
||||
import org.apache.cassandra.tracing.Tracing;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.utils.NoSpamLogger;
|
||||
import org.apache.cassandra.utils.btree.BTreeSet;
|
||||
|
||||
|
|
@ -100,7 +101,7 @@ public class ReplicaFilteringProtection<E extends Endpoints<E>>
|
|||
private final Keyspace keyspace;
|
||||
private final ReadCommand command;
|
||||
private final ConsistencyLevel consistency;
|
||||
private final long queryStartNanoTime;
|
||||
private final Dispatcher.RequestTime requestTime;
|
||||
private final E sources;
|
||||
private final TableMetrics tableMetrics;
|
||||
|
||||
|
|
@ -121,7 +122,7 @@ public class ReplicaFilteringProtection<E extends Endpoints<E>>
|
|||
ReplicaFilteringProtection(Keyspace keyspace,
|
||||
ReadCommand command,
|
||||
ConsistencyLevel consistency,
|
||||
long queryStartNanoTime,
|
||||
Dispatcher.RequestTime requestTime,
|
||||
E sources,
|
||||
int cachedRowsWarnThreshold,
|
||||
int cachedRowsFailThreshold)
|
||||
|
|
@ -129,7 +130,7 @@ public class ReplicaFilteringProtection<E extends Endpoints<E>>
|
|||
this.keyspace = keyspace;
|
||||
this.command = command;
|
||||
this.consistency = consistency;
|
||||
this.queryStartNanoTime = queryStartNanoTime;
|
||||
this.requestTime = requestTime;
|
||||
this.sources = sources;
|
||||
this.originalPartitions = new ArrayList<>(sources.size());
|
||||
|
||||
|
|
@ -148,19 +149,19 @@ public class ReplicaFilteringProtection<E extends Endpoints<E>>
|
|||
{
|
||||
@SuppressWarnings("unchecked")
|
||||
DataResolver<EndpointsForToken, ReplicaPlan.ForTokenRead> resolver =
|
||||
new DataResolver<>(cmd, replicaPlan, (NoopReadRepair<EndpointsForToken, ReplicaPlan.ForTokenRead>) NoopReadRepair.instance, queryStartNanoTime);
|
||||
new DataResolver<>(cmd, replicaPlan, (NoopReadRepair<EndpointsForToken, ReplicaPlan.ForTokenRead>) NoopReadRepair.instance, requestTime);
|
||||
|
||||
ReadCallback<EndpointsForToken, ReplicaPlan.ForTokenRead> handler = new ReadCallback<>(resolver, cmd, replicaPlan, queryStartNanoTime);
|
||||
ReadCallback<EndpointsForToken, ReplicaPlan.ForTokenRead> handler = new ReadCallback<>(resolver, cmd, replicaPlan, requestTime);
|
||||
|
||||
if (source.isSelf())
|
||||
{
|
||||
Stage.READ.maybeExecuteImmediately(new StorageProxy.LocalReadRunnable(cmd, handler));
|
||||
Stage.READ.maybeExecuteImmediately(new StorageProxy.LocalReadRunnable(cmd, handler, requestTime));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (source.isTransient())
|
||||
cmd = cmd.copyAsTransientQuery(source);
|
||||
MessagingService.instance().sendWithCallback(cmd.createMessage(false), source.endpoint(), handler);
|
||||
MessagingService.instance().sendWithCallback(cmd.createMessage(false, requestTime), source.endpoint(), handler);
|
||||
}
|
||||
|
||||
// We don't call handler.get() because we want to preserve tombstones since we're still in the middle of merging node results.
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import org.apache.cassandra.db.ReadResponse;
|
|||
import org.apache.cassandra.locator.Endpoints;
|
||||
import org.apache.cassandra.locator.ReplicaPlan;
|
||||
import org.apache.cassandra.net.Message;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.utils.concurrent.Accumulator;
|
||||
|
||||
public abstract class ResponseResolver<E extends Endpoints<E>, P extends ReplicaPlan.ForRead<E, P>>
|
||||
|
|
@ -39,14 +40,14 @@ public abstract class ResponseResolver<E extends Endpoints<E>, P extends Replica
|
|||
|
||||
// Accumulator gives us non-blocking thread-safety with optimal algorithmic constraints
|
||||
protected final Accumulator<Message<ReadResponse>> responses;
|
||||
protected final long queryStartNanoTime;
|
||||
protected final Dispatcher.RequestTime requestTime;
|
||||
|
||||
public ResponseResolver(ReadCommand command, Supplier<? extends P> replicaPlan, long queryStartNanoTime)
|
||||
public ResponseResolver(ReadCommand command, Supplier<? extends P> replicaPlan, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
this.command = command;
|
||||
this.replicaPlan = replicaPlan;
|
||||
this.responses = new Accumulator<>(replicaPlan.get().readCandidates().size());
|
||||
this.queryStartNanoTime = queryStartNanoTime;
|
||||
this.requestTime = requestTime;
|
||||
}
|
||||
|
||||
protected P replicaPlan()
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ import org.apache.cassandra.net.MessagingService;
|
|||
import org.apache.cassandra.service.reads.repair.NoopReadRepair;
|
||||
import org.apache.cassandra.service.StorageProxy;
|
||||
import org.apache.cassandra.tracing.Tracing;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
|
||||
public class ShortReadPartitionsProtection extends Transformation<UnfilteredRowIterator> implements MorePartitions<UnfilteredPartitionIterator>
|
||||
{
|
||||
|
|
@ -62,21 +63,21 @@ public class ShortReadPartitionsProtection extends Transformation<UnfilteredRowI
|
|||
|
||||
private boolean partitionsFetched; // whether we've seen any new partitions since iteration start or last moreContents() call
|
||||
|
||||
private final long queryStartNanoTime;
|
||||
private final Dispatcher.RequestTime requestTime;
|
||||
|
||||
public ShortReadPartitionsProtection(ReadCommand command,
|
||||
Replica source,
|
||||
Runnable preFetchCallback,
|
||||
DataLimits.Counter singleResultCounter,
|
||||
DataLimits.Counter mergedResultCounter,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
this.command = command;
|
||||
this.source = source;
|
||||
this.preFetchCallback = preFetchCallback;
|
||||
this.singleResultCounter = singleResultCounter;
|
||||
this.mergedResultCounter = mergedResultCounter;
|
||||
this.queryStartNanoTime = queryStartNanoTime;
|
||||
this.requestTime = requestTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -177,18 +178,18 @@ public class ShortReadPartitionsProtection extends Transformation<UnfilteredRowI
|
|||
private <E extends Endpoints<E>, P extends ReplicaPlan.ForRead<E, P>>
|
||||
UnfilteredPartitionIterator executeReadCommand(ReadCommand cmd, ReplicaPlan.Shared<E, P> replicaPlan)
|
||||
{
|
||||
DataResolver<E, P> resolver = new DataResolver<>(cmd, replicaPlan, (NoopReadRepair<E, P>)NoopReadRepair.instance, queryStartNanoTime);
|
||||
ReadCallback<E, P> handler = new ReadCallback<>(resolver, cmd, replicaPlan, queryStartNanoTime);
|
||||
DataResolver<E, P> resolver = new DataResolver<>(cmd, replicaPlan, (NoopReadRepair<E, P>)NoopReadRepair.instance, requestTime);
|
||||
ReadCallback<E, P> handler = new ReadCallback<>(resolver, cmd, replicaPlan, requestTime);
|
||||
|
||||
if (source.isSelf())
|
||||
{
|
||||
Stage.READ.maybeExecuteImmediately(new StorageProxy.LocalReadRunnable(cmd, handler));
|
||||
Stage.READ.maybeExecuteImmediately(new StorageProxy.LocalReadRunnable(cmd, handler, requestTime));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (source.isTransient())
|
||||
cmd = cmd.copyAsTransientQuery(source);
|
||||
MessagingService.instance().sendWithCallback(cmd.createMessage(false), source.endpoint(), handler);
|
||||
MessagingService.instance().sendWithCallback(cmd.createMessage(false, requestTime), source.endpoint(), handler);
|
||||
}
|
||||
|
||||
// We don't call handler.get() because we want to preserve tombstones since we're still in the middle of merging node results.
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import org.apache.cassandra.db.partitions.UnfilteredPartitionIterator;
|
|||
import org.apache.cassandra.db.transform.MorePartitions;
|
||||
import org.apache.cassandra.db.transform.Transformation;
|
||||
import org.apache.cassandra.locator.Replica;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
|
||||
/**
|
||||
* We have a potential short read if the result from a given node contains the requested number of rows
|
||||
|
|
@ -43,7 +44,7 @@ public class ShortReadProtection
|
|||
UnfilteredPartitionIterator partitions,
|
||||
ReadCommand command,
|
||||
DataLimits.Counter mergedResultCounter,
|
||||
long queryStartNanoTime,
|
||||
Dispatcher.RequestTime requestTime,
|
||||
boolean enforceStrictLiveness)
|
||||
{
|
||||
DataLimits.Counter singleResultCounter = command.limits().newCounter(command.nowInSec(),
|
||||
|
|
@ -56,7 +57,7 @@ public class ShortReadProtection
|
|||
preFetchCallback,
|
||||
singleResultCounter,
|
||||
mergedResultCounter,
|
||||
queryStartNanoTime);
|
||||
requestTime);
|
||||
|
||||
/*
|
||||
* The order of extention and transformations is important here. Extending with more partitions has to happen
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ import org.apache.cassandra.service.reads.DataResolver;
|
|||
import org.apache.cassandra.service.reads.ReadCallback;
|
||||
import org.apache.cassandra.service.reads.repair.ReadRepair;
|
||||
import org.apache.cassandra.tracing.Tracing;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.utils.AbstractIterator;
|
||||
import org.apache.cassandra.utils.CloseableIterator;
|
||||
|
||||
|
|
@ -66,11 +67,12 @@ public class RangeCommandIterator extends AbstractIterator<RowIterator> implemen
|
|||
final int totalRangeCount;
|
||||
final PartitionRangeReadCommand command;
|
||||
final boolean enforceStrictLiveness;
|
||||
final long queryStartNanoTime;
|
||||
final Dispatcher.RequestTime requestTime;
|
||||
|
||||
int rangesQueried;
|
||||
int batchesRequested = 0;
|
||||
|
||||
private final long startTime;
|
||||
|
||||
private DataLimits.Counter counter;
|
||||
private PartitionIterator sentQueryIterator;
|
||||
|
||||
|
|
@ -85,16 +87,14 @@ public class RangeCommandIterator extends AbstractIterator<RowIterator> implemen
|
|||
int concurrencyFactor,
|
||||
int maxConcurrencyFactor,
|
||||
int totalRangeCount,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
this.replicaPlans = replicaPlans;
|
||||
this.command = command;
|
||||
this.concurrencyFactor = concurrencyFactor;
|
||||
this.maxConcurrencyFactor = maxConcurrencyFactor;
|
||||
this.totalRangeCount = totalRangeCount;
|
||||
this.queryStartNanoTime = queryStartNanoTime;
|
||||
|
||||
startTime = nanoTime();
|
||||
this.requestTime = requestTime;
|
||||
enforceStrictLiveness = command.metadata().enforceStrictLiveness();
|
||||
}
|
||||
|
||||
|
|
@ -196,15 +196,15 @@ public class RangeCommandIterator extends AbstractIterator<RowIterator> implemen
|
|||
|
||||
ReplicaPlan.SharedForRangeRead sharedReplicaPlan = ReplicaPlan.shared(replicaPlan);
|
||||
ReadRepair<EndpointsForRange, ReplicaPlan.ForRangeRead> readRepair =
|
||||
ReadRepair.create(command, sharedReplicaPlan, queryStartNanoTime);
|
||||
ReadRepair.create(command, sharedReplicaPlan, requestTime);
|
||||
DataResolver<EndpointsForRange, ReplicaPlan.ForRangeRead> resolver =
|
||||
new DataResolver<>(rangeCommand, sharedReplicaPlan, readRepair, queryStartNanoTime, trackRepairedStatus);
|
||||
new DataResolver<>(rangeCommand, sharedReplicaPlan, readRepair, requestTime, trackRepairedStatus);
|
||||
ReadCallback<EndpointsForRange, ReplicaPlan.ForRangeRead> handler =
|
||||
new ReadCallback<>(resolver, rangeCommand, sharedReplicaPlan, queryStartNanoTime);
|
||||
new ReadCallback<>(resolver, rangeCommand, sharedReplicaPlan, requestTime);
|
||||
|
||||
if (replicaPlan.contacts().size() == 1 && replicaPlan.contacts().get(0).isSelf())
|
||||
{
|
||||
Stage.READ.execute(new StorageProxy.LocalReadRunnable(rangeCommand, handler, trackRepairedStatus));
|
||||
Stage.READ.execute(new StorageProxy.LocalReadRunnable(rangeCommand, handler, requestTime, trackRepairedStatus));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -212,7 +212,7 @@ public class RangeCommandIterator extends AbstractIterator<RowIterator> implemen
|
|||
{
|
||||
Tracing.trace("Enqueuing request to {}", replica);
|
||||
ReadCommand command = replica.isFull() ? rangeCommand : rangeCommand.copyAsTransientQuery(replica);
|
||||
Message<ReadCommand> message = command.createMessage(trackRepairedStatus && replica.isFull());
|
||||
Message<ReadCommand> message = command.createMessage(trackRepairedStatus && replica.isFull(), requestTime);
|
||||
MessagingService.instance().sendWithCallback(message, replica.endpoint(), handler);
|
||||
}
|
||||
}
|
||||
|
|
@ -267,7 +267,9 @@ public class RangeCommandIterator extends AbstractIterator<RowIterator> implemen
|
|||
}
|
||||
finally
|
||||
{
|
||||
long latency = nanoTime() - startTime;
|
||||
// We track latency based on request processing time, since the amount of time that request spends in the queue
|
||||
// is not a representative metric of replica performance.
|
||||
long latency = nanoTime() - requestTime.startedAtNanos();
|
||||
rangeMetrics.addNano(latency);
|
||||
rangeMetrics.roundTrips.update(batchesRequested);
|
||||
Keyspace.openAndGetStore(command.metadata()).metric.coordinatorScanLatency.update(latency, TimeUnit.NANOSECONDS);
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import org.apache.cassandra.index.Index;
|
|||
import org.apache.cassandra.locator.ReplicaPlans;
|
||||
import org.apache.cassandra.schema.TableMetadata;
|
||||
import org.apache.cassandra.tracing.Tracing;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
|
||||
public class RangeCommands
|
||||
|
|
@ -54,10 +55,10 @@ public class RangeCommands
|
|||
|
||||
public static PartitionIterator partitions(PartitionRangeReadCommand command,
|
||||
ConsistencyLevel consistencyLevel,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
// Note that in general, a RangeCommandIterator will honor the command limit for each range, but will not enforce it globally.
|
||||
RangeCommandIterator rangeCommands = rangeCommandIterator(command, consistencyLevel, queryStartNanoTime);
|
||||
RangeCommandIterator rangeCommands = rangeCommandIterator(command, consistencyLevel, requestTime);
|
||||
return command.limits().filter(command.postReconciliationProcessing(rangeCommands),
|
||||
command.nowInSec(),
|
||||
command.selectsFullPartition(),
|
||||
|
|
@ -67,7 +68,7 @@ public class RangeCommands
|
|||
@VisibleForTesting
|
||||
static RangeCommandIterator rangeCommandIterator(PartitionRangeReadCommand command,
|
||||
ConsistencyLevel consistencyLevel,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
Tracing.trace("Computing ranges to query");
|
||||
|
||||
|
|
@ -78,7 +79,7 @@ public class RangeCommands
|
|||
consistencyLevel);
|
||||
|
||||
if (command.isTopK())
|
||||
return new ScanAllRangesCommandIterator(keyspace, replicaPlans, command, replicaPlans.size(), queryStartNanoTime);
|
||||
return new ScanAllRangesCommandIterator(keyspace, replicaPlans, command, replicaPlans.size(), requestTime);
|
||||
|
||||
int maxConcurrencyFactor = Math.min(replicaPlans.size(), MAX_CONCURRENT_RANGE_REQUESTS);
|
||||
int concurrencyFactor = maxConcurrencyFactor;
|
||||
|
|
@ -111,7 +112,7 @@ public class RangeCommands
|
|||
concurrencyFactor,
|
||||
maxConcurrencyFactor,
|
||||
replicaPlans.size(),
|
||||
queryStartNanoTime);
|
||||
requestTime);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ import org.apache.cassandra.service.reads.DataResolver;
|
|||
import org.apache.cassandra.service.reads.ReadCallback;
|
||||
import org.apache.cassandra.service.reads.repair.NoopReadRepair;
|
||||
import org.apache.cassandra.tracing.Tracing;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.utils.CloseableIterator;
|
||||
|
||||
/**
|
||||
|
|
@ -62,9 +63,9 @@ public class ScanAllRangesCommandIterator extends RangeCommandIterator
|
|||
ScanAllRangesCommandIterator(Keyspace keyspace, CloseableIterator<ReplicaPlan.ForRangeRead> replicaPlans,
|
||||
PartitionRangeReadCommand command,
|
||||
int totalRangeCount,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
super(replicaPlans, command, totalRangeCount, totalRangeCount, totalRangeCount, queryStartNanoTime);
|
||||
super(replicaPlans, command, totalRangeCount, totalRangeCount, totalRangeCount, requestTime);
|
||||
Preconditions.checkState(command.isTopK());
|
||||
|
||||
this.keyspace = keyspace;
|
||||
|
|
@ -91,14 +92,14 @@ public class ScanAllRangesCommandIterator extends RangeCommandIterator
|
|||
|
||||
ReplicaPlan.ForRangeRead plan = ReplicaPlans.forFullRangeRead(keyspace, consistencyLevel, command.dataRange().keyRange(), replicasToQuery, totalRangeCount);
|
||||
ReplicaPlan.SharedForRangeRead sharedReplicaPlan = ReplicaPlan.shared(plan);
|
||||
DataResolver<EndpointsForRange, ReplicaPlan.ForRangeRead> resolver = new DataResolver<>(command, sharedReplicaPlan, NoopReadRepair.instance, queryStartNanoTime, false);
|
||||
ReadCallback<EndpointsForRange, ReplicaPlan.ForRangeRead> handler = new ReadCallback<>(resolver, command, sharedReplicaPlan, queryStartNanoTime);
|
||||
DataResolver<EndpointsForRange, ReplicaPlan.ForRangeRead> resolver = new DataResolver<>(command, sharedReplicaPlan, NoopReadRepair.instance, requestTime, false);
|
||||
ReadCallback<EndpointsForRange, ReplicaPlan.ForRangeRead> handler = new ReadCallback<>(resolver, command, sharedReplicaPlan, requestTime);
|
||||
|
||||
int nodes = 0;
|
||||
for (InetAddressAndPort endpoint : replicasToQuery)
|
||||
{
|
||||
Tracing.trace("Enqueuing request to {}", endpoint);
|
||||
Message<ReadCommand> message = command.createMessage(false);
|
||||
Message<ReadCommand> message = command.createMessage(false, requestTime);
|
||||
MessagingService.instance().sendWithCallback(message, endpoint, handler);
|
||||
nodes++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,12 +20,11 @@ package org.apache.cassandra.service.reads.repair;
|
|||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.codahale.metrics.Meter;
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.codahale.metrics.Meter;
|
||||
import org.apache.cassandra.concurrent.Stage;
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.db.ColumnFamilyStore;
|
||||
|
|
@ -46,6 +45,7 @@ import org.apache.cassandra.service.reads.DataResolver;
|
|||
import org.apache.cassandra.service.reads.DigestResolver;
|
||||
import org.apache.cassandra.service.reads.ReadCallback;
|
||||
import org.apache.cassandra.tracing.Tracing;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MICROSECONDS;
|
||||
|
||||
|
|
@ -55,7 +55,7 @@ public abstract class AbstractReadRepair<E extends Endpoints<E>, P extends Repli
|
|||
protected static final Logger logger = LoggerFactory.getLogger(AbstractReadRepair.class);
|
||||
|
||||
protected final ReadCommand command;
|
||||
protected final long queryStartNanoTime;
|
||||
protected final Dispatcher.RequestTime requestTime;
|
||||
protected final ReplicaPlan.Shared<E, P> replicaPlan;
|
||||
protected final ColumnFamilyStore cfs;
|
||||
|
||||
|
|
@ -77,10 +77,10 @@ public abstract class AbstractReadRepair<E extends Endpoints<E>, P extends Repli
|
|||
|
||||
public AbstractReadRepair(ReadCommand command,
|
||||
ReplicaPlan.Shared<E, P> replicaPlan,
|
||||
long queryStartNanoTime)
|
||||
Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
this.command = command;
|
||||
this.queryStartNanoTime = queryStartNanoTime;
|
||||
this.requestTime = requestTime;
|
||||
this.replicaPlan = replicaPlan;
|
||||
this.cfs = Keyspace.openAndGetStore(command.metadata());
|
||||
}
|
||||
|
|
@ -96,7 +96,7 @@ public abstract class AbstractReadRepair<E extends Endpoints<E>, P extends Repli
|
|||
|
||||
if (to.isSelf())
|
||||
{
|
||||
Stage.READ.maybeExecuteImmediately(new StorageProxy.LocalReadRunnable(command, readCallback, trackRepairedStatus));
|
||||
Stage.READ.maybeExecuteImmediately(new StorageProxy.LocalReadRunnable(command, readCallback, requestTime, trackRepairedStatus));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -116,7 +116,7 @@ public abstract class AbstractReadRepair<E extends Endpoints<E>, P extends Repli
|
|||
Tracing.trace("Enqueuing {} data read to {}", type, to);
|
||||
}
|
||||
|
||||
Message<ReadCommand> message = command.createMessage(trackRepairedStatus && to.isFull());
|
||||
Message<ReadCommand> message = command.createMessage(trackRepairedStatus && to.isFull(), requestTime);
|
||||
MessagingService.instance().sendWithCallback(message, to.endpoint(), readCallback);
|
||||
}
|
||||
|
||||
|
|
@ -139,8 +139,8 @@ public abstract class AbstractReadRepair<E extends Endpoints<E>, P extends Repli
|
|||
boolean trackRepairedStatus = DatabaseDescriptor.getRepairedDataTrackingForPartitionReadsEnabled();
|
||||
|
||||
// Do a full data read to resolve the correct response (and repair node that need be)
|
||||
DataResolver<E, P> resolver = new DataResolver<>(command, replicaPlan, this, queryStartNanoTime, trackRepairedStatus);
|
||||
ReadCallback<E, P> readCallback = new ReadCallback<>(resolver, command, replicaPlan, queryStartNanoTime);
|
||||
DataResolver<E, P> resolver = new DataResolver<>(command, replicaPlan, this, requestTime, trackRepairedStatus);
|
||||
ReadCallback<E, P> readCallback = new ReadCallback<>(resolver, command, replicaPlan, requestTime);
|
||||
|
||||
digestRepair = new DigestRepair<>(resolver, readCallback, resultConsumer);
|
||||
|
||||
|
|
@ -190,7 +190,7 @@ public abstract class AbstractReadRepair<E extends Endpoints<E>, P extends Repli
|
|||
if (repair == null)
|
||||
return;
|
||||
|
||||
if (shouldSpeculate() && !repair.readCallback.await(cfs.sampleReadLatencyMicros, MICROSECONDS))
|
||||
if (shouldSpeculate() && !repair.readCallback.awaitUntil(requestTime.startedAtNanos() + MICROSECONDS.toNanos(cfs.sampleReadLatencyMicros)))
|
||||
{
|
||||
Replica uncontacted = replicaPlan().firstUncontactedCandidate(replica -> true);
|
||||
if (uncontacted == null)
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ import org.apache.cassandra.locator.Replica;
|
|||
import org.apache.cassandra.locator.ReplicaPlan;
|
||||
import org.apache.cassandra.metrics.ReadRepairMetrics;
|
||||
import org.apache.cassandra.tracing.Tracing;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MICROSECONDS;
|
||||
import static java.util.concurrent.TimeUnit.NANOSECONDS;
|
||||
|
|
@ -53,9 +54,9 @@ public class BlockingReadRepair<E extends Endpoints<E>, P extends ReplicaPlan.Fo
|
|||
|
||||
protected final Queue<BlockingPartitionRepair> repairs = new ConcurrentLinkedQueue<>();
|
||||
|
||||
BlockingReadRepair(ReadCommand command, ReplicaPlan.Shared<E, P> replicaPlan, long queryStartNanoTime)
|
||||
BlockingReadRepair(ReadCommand command, ReplicaPlan.Shared<E, P> replicaPlan, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
super(command, replicaPlan, queryStartNanoTime);
|
||||
super(command, replicaPlan, requestTime);
|
||||
}
|
||||
|
||||
public UnfilteredPartitionIterators.MergeListener getMergeListener(P replicaPlan)
|
||||
|
|
@ -84,7 +85,9 @@ public class BlockingReadRepair<E extends Endpoints<E>, P extends ReplicaPlan.Fo
|
|||
BlockingPartitionRepair timedOut = null;
|
||||
for (BlockingPartitionRepair repair : repairs)
|
||||
{
|
||||
if (!repair.awaitRepairsUntil(DatabaseDescriptor.getReadRpcTimeout(NANOSECONDS) + queryStartNanoTime, NANOSECONDS))
|
||||
long deadline = requestTime.computeDeadline(DatabaseDescriptor.getReadRpcTimeout(NANOSECONDS));
|
||||
|
||||
if (!repair.awaitRepairsUntil(deadline, NANOSECONDS))
|
||||
{
|
||||
timedOut = repair;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import org.apache.cassandra.locator.Endpoints;
|
|||
import org.apache.cassandra.locator.Replica;
|
||||
import org.apache.cassandra.locator.ReplicaPlan;
|
||||
import org.apache.cassandra.metrics.ReadRepairMetrics;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
|
||||
/**
|
||||
* Only performs the collection of data responses and reconciliation of them, doesn't send repair mutations
|
||||
|
|
@ -37,9 +38,9 @@ import org.apache.cassandra.metrics.ReadRepairMetrics;
|
|||
public class ReadOnlyReadRepair<E extends Endpoints<E>, P extends ReplicaPlan.ForRead<E, P>>
|
||||
extends AbstractReadRepair<E, P>
|
||||
{
|
||||
ReadOnlyReadRepair(ReadCommand command, ReplicaPlan.Shared<E, P> replicaPlan, long queryStartNanoTime)
|
||||
ReadOnlyReadRepair(ReadCommand command, ReplicaPlan.Shared<E, P> replicaPlan, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
super(command, replicaPlan, queryStartNanoTime);
|
||||
super(command, replicaPlan, requestTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -31,19 +31,20 @@ import org.apache.cassandra.exceptions.ReadTimeoutException;
|
|||
import org.apache.cassandra.locator.Replica;
|
||||
import org.apache.cassandra.locator.ReplicaPlan;
|
||||
import org.apache.cassandra.service.reads.DigestResolver;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
|
||||
public interface ReadRepair<E extends Endpoints<E>, P extends ReplicaPlan.ForRead<E, P>>
|
||||
{
|
||||
public interface Factory
|
||||
{
|
||||
<E extends Endpoints<E>, P extends ReplicaPlan.ForRead<E, P>>
|
||||
ReadRepair<E, P> create(ReadCommand command, ReplicaPlan.Shared<E, P> replicaPlan, long queryStartNanoTime);
|
||||
ReadRepair<E, P> create(ReadCommand command, ReplicaPlan.Shared<E, P> replicaPlan, Dispatcher.RequestTime requestTime);
|
||||
}
|
||||
|
||||
static <E extends Endpoints<E>, P extends ReplicaPlan.ForRead<E, P>>
|
||||
ReadRepair<E, P> create(ReadCommand command, ReplicaPlan.Shared<E, P> replicaPlan, long queryStartNanoTime)
|
||||
ReadRepair<E, P> create(ReadCommand command, ReplicaPlan.Shared<E, P> replicaPlan, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
return command.metadata().params.readRepair.create(command, replicaPlan, queryStartNanoTime);
|
||||
return command.metadata().params.readRepair.create(command, replicaPlan, requestTime);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -21,24 +21,25 @@ package org.apache.cassandra.service.reads.repair;
|
|||
import org.apache.cassandra.db.ReadCommand;
|
||||
import org.apache.cassandra.locator.Endpoints;
|
||||
import org.apache.cassandra.locator.ReplicaPlan;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
|
||||
public enum ReadRepairStrategy implements ReadRepair.Factory
|
||||
{
|
||||
NONE
|
||||
{
|
||||
public <E extends Endpoints<E>, P extends ReplicaPlan.ForRead<E, P>>
|
||||
ReadRepair<E, P> create(ReadCommand command, ReplicaPlan.Shared<E, P> replicaPlan, long queryStartNanoTime)
|
||||
ReadRepair<E, P> create(ReadCommand command, ReplicaPlan.Shared<E, P> replicaPlan, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
return new ReadOnlyReadRepair<>(command, replicaPlan, queryStartNanoTime);
|
||||
return new ReadOnlyReadRepair<>(command, replicaPlan, requestTime);
|
||||
}
|
||||
},
|
||||
|
||||
BLOCKING
|
||||
{
|
||||
public <E extends Endpoints<E>, P extends ReplicaPlan.ForRead<E, P>>
|
||||
ReadRepair<E, P> create(ReadCommand command, ReplicaPlan.Shared<E, P> replicaPlan, long queryStartNanoTime)
|
||||
ReadRepair<E, P> create(ReadCommand command, ReplicaPlan.Shared<E, P> replicaPlan, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
return new BlockingReadRepair<>(command, replicaPlan, queryStartNanoTime);
|
||||
return new BlockingReadRepair<>(command, replicaPlan, requestTime);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1337,9 +1337,9 @@ public class NodeProbe implements AutoCloseable
|
|||
}
|
||||
}
|
||||
|
||||
public void stopNativeTransport()
|
||||
public void stopNativeTransport(boolean force)
|
||||
{
|
||||
ssProxy.stopNativeTransport();
|
||||
ssProxy.stopNativeTransport(force);
|
||||
}
|
||||
|
||||
public void startNativeTransport()
|
||||
|
|
|
|||
|
|
@ -18,16 +18,19 @@
|
|||
package org.apache.cassandra.tools.nodetool;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
|
||||
import io.airlift.airline.Option;
|
||||
import org.apache.cassandra.tools.NodeProbe;
|
||||
import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
|
||||
|
||||
@Command(name = "disablebinary", description = "Disable native transport (binary protocol)")
|
||||
public class DisableBinary extends NodeToolCmd
|
||||
{
|
||||
@Option(title = "force", name = { "-f", "--force"}, description = "Use -f to interrupt client requests that have already started")
|
||||
private boolean force = false;
|
||||
|
||||
@Override
|
||||
public void execute(NodeProbe probe)
|
||||
{
|
||||
probe.stopNativeTransport();
|
||||
probe.stopNativeTransport(force);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import org.apache.cassandra.db.Mutation;
|
|||
import org.apache.cassandra.exceptions.OverloadedException;
|
||||
import org.apache.cassandra.locator.InetAddressAndPort;
|
||||
import org.apache.cassandra.service.StorageProxy;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.utils.JVMStabilityInspector;
|
||||
import org.apache.cassandra.utils.TimeUUID;
|
||||
import org.apache.cassandra.utils.concurrent.Future;
|
||||
|
|
@ -40,7 +41,6 @@ import org.apache.cassandra.utils.concurrent.FutureCombiner;
|
|||
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.apache.cassandra.db.ConsistencyLevel.ANY;
|
||||
import static org.apache.cassandra.utils.Clock.Global.nanoTime;
|
||||
|
||||
/**
|
||||
* ThreadLocal state for a tracing session. The presence of an instance of this class as a ThreadLocal denotes that an
|
||||
|
|
@ -113,7 +113,7 @@ public class TraceStateImpl extends TraceState
|
|||
{
|
||||
try
|
||||
{
|
||||
StorageProxy.mutate(singletonList(mutation), ANY, nanoTime());
|
||||
StorageProxy.mutate(singletonList(mutation), ANY, Dispatcher.RequestTime.forImmediateExecution());
|
||||
}
|
||||
catch (OverloadedException e)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -21,10 +21,9 @@ package org.apache.cassandra.transport;
|
|||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.google.common.primitives.Ints;
|
||||
import org.apache.cassandra.transport.ClientResourceLimits.Overload;
|
||||
import org.apache.cassandra.utils.concurrent.NonBlockingRateLimiter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
|
@ -33,8 +32,8 @@ import io.netty.buffer.Unpooled;
|
|||
import io.netty.channel.Channel;
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.exceptions.OverloadedException;
|
||||
import org.apache.cassandra.metrics.ClientMetrics;
|
||||
import org.apache.cassandra.metrics.ClientMessageSizeMetrics;
|
||||
import org.apache.cassandra.metrics.ClientMetrics;
|
||||
import org.apache.cassandra.net.AbstractMessageHandler;
|
||||
import org.apache.cassandra.net.FrameDecoder;
|
||||
import org.apache.cassandra.net.FrameDecoder.IntactFrame;
|
||||
|
|
@ -42,9 +41,11 @@ import org.apache.cassandra.net.FrameEncoder;
|
|||
import org.apache.cassandra.net.ResourceLimits;
|
||||
import org.apache.cassandra.net.ResourceLimits.Limit;
|
||||
import org.apache.cassandra.net.ShareableBytes;
|
||||
import org.apache.cassandra.transport.ClientResourceLimits.Overload;
|
||||
import org.apache.cassandra.transport.Flusher.FlushItem.Framed;
|
||||
import org.apache.cassandra.transport.messages.ErrorMessage;
|
||||
import org.apache.cassandra.utils.NoSpamLogger;
|
||||
import org.apache.cassandra.utils.concurrent.NonBlockingRateLimiter;
|
||||
|
||||
import static org.apache.cassandra.utils.MonotonicClock.Global.approxTime;
|
||||
|
||||
|
|
@ -81,6 +82,7 @@ public class CQLMessageHandler<M extends Message> extends AbstractMessageHandler
|
|||
public static final int LARGE_MESSAGE_THRESHOLD = FrameEncoder.Payload.MAX_SIZE - 1;
|
||||
public static final TimeUnit RATE_LIMITER_DELAY_UNIT = TimeUnit.NANOSECONDS;
|
||||
|
||||
private final QueueBackpressure queueBackpressure;
|
||||
private final Envelope.Decoder envelopeDecoder;
|
||||
private final Message.Decoder<M> messageDecoder;
|
||||
private final FrameEncoder.PayloadAllocator payloadAllocator;
|
||||
|
|
@ -95,7 +97,8 @@ public class CQLMessageHandler<M extends Message> extends AbstractMessageHandler
|
|||
|
||||
interface MessageConsumer<M extends Message>
|
||||
{
|
||||
void accept(Channel channel, M message, Dispatcher.FlushItemConverter toFlushItem, Overload backpressure);
|
||||
void dispatch(Channel channel, M message, Dispatcher.FlushItemConverter toFlushItem, Overload backpressure);
|
||||
boolean hasQueueCapacity();
|
||||
}
|
||||
|
||||
interface ErrorHandler
|
||||
|
|
@ -111,6 +114,7 @@ public class CQLMessageHandler<M extends Message> extends AbstractMessageHandler
|
|||
MessageConsumer<M> dispatcher,
|
||||
FrameEncoder.PayloadAllocator payloadAllocator,
|
||||
int queueCapacity,
|
||||
QueueBackpressure queueBackpressure,
|
||||
ClientResourceLimits.ResourceProvider resources,
|
||||
OnHandlerClosed onClosed,
|
||||
ErrorHandler errorHandler,
|
||||
|
|
@ -129,6 +133,7 @@ public class CQLMessageHandler<M extends Message> extends AbstractMessageHandler
|
|||
this.messageDecoder = messageDecoder;
|
||||
this.payloadAllocator = payloadAllocator;
|
||||
this.dispatcher = dispatcher;
|
||||
this.queueBackpressure = queueBackpressure;
|
||||
this.errorHandler = errorHandler;
|
||||
this.throwOnOverload = throwOnOverload;
|
||||
this.version = version;
|
||||
|
|
@ -160,6 +165,7 @@ public class CQLMessageHandler<M extends Message> extends AbstractMessageHandler
|
|||
* @throws ErrorMessage.WrappedException with an {@link OverloadedException} if overload occurs and the
|
||||
* connection is configured to throw on overload
|
||||
*/
|
||||
@Override
|
||||
protected boolean processOneContainedMessage(ShareableBytes bytes, Limit endpointReserve, Limit globalReserve)
|
||||
{
|
||||
ByteBuffer buf = bytes.get();
|
||||
|
|
@ -178,7 +184,8 @@ public class CQLMessageHandler<M extends Message> extends AbstractMessageHandler
|
|||
|
||||
// max CQL message size defaults to 256mb, so should be safe to downcast
|
||||
int messageSize = Ints.checkedCast(header.bodySizeInBytes);
|
||||
|
||||
|
||||
Overload backpressure = Overload.NONE;
|
||||
if (throwOnOverload)
|
||||
{
|
||||
if (!acquireCapacity(header, endpointReserve, globalReserve))
|
||||
|
|
@ -188,51 +195,61 @@ public class CQLMessageHandler<M extends Message> extends AbstractMessageHandler
|
|||
}
|
||||
|
||||
if (DatabaseDescriptor.getNativeTransportRateLimitingEnabled() && !requestRateLimiter.tryReserve())
|
||||
backpressure = Overload.REQUESTS;
|
||||
else if (!dispatcher.hasQueueCapacity())
|
||||
backpressure = Overload.QUEUE_TIME;
|
||||
|
||||
if (backpressure != Overload.NONE)
|
||||
{
|
||||
// We've already allocated against the bytes-in-flight limits, so release those resources.
|
||||
release(header);
|
||||
discardAndThrow(endpointReserve, globalReserve, buf, header, messageSize, Overload.REQUESTS);
|
||||
discardAndThrow(endpointReserve, globalReserve, buf, header, messageSize, backpressure);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Overload backpressure = Overload.NONE;
|
||||
long delay = -1;
|
||||
|
||||
if (!acquireCapacityAndQueueOnFailure(header, endpointReserve, globalReserve))
|
||||
{
|
||||
if (processRequestAndUpdateMetrics(bytes, header, messageSize, Overload.BYTES_IN_FLIGHT))
|
||||
{
|
||||
if (decoder.isActive())
|
||||
ClientMetrics.instance.pauseConnection();
|
||||
}
|
||||
|
||||
backpressure = Overload.BYTES_IN_FLIGHT;
|
||||
}
|
||||
|
||||
|
||||
// Apply rate limiting, if enabled
|
||||
if (DatabaseDescriptor.getNativeTransportRateLimitingEnabled())
|
||||
{
|
||||
// Reserve a permit even if we've already triggered backpressure on bytes in flight.
|
||||
long delay = requestRateLimiter.reserveAndGetDelay(RATE_LIMITER_DELAY_UNIT);
|
||||
|
||||
if (backpressure == Overload.NONE && delay > 0)
|
||||
{
|
||||
if (processRequestAndUpdateMetrics(bytes, header, messageSize, Overload.REQUESTS))
|
||||
{
|
||||
if (decoder.isActive())
|
||||
ClientMetrics.instance.pauseConnection();
|
||||
delay = requestRateLimiter.reserveAndGetDelay(RATE_LIMITER_DELAY_UNIT);
|
||||
|
||||
// Schedule a wakup here if we process successfully. The connection should be closing otherwise.
|
||||
if (backpressure == Overload.NONE && delay > 0)
|
||||
backpressure = Overload.REQUESTS;
|
||||
}
|
||||
|
||||
// Check queue time, if enabled
|
||||
if (backpressure == Overload.NONE && !dispatcher.hasQueueCapacity())
|
||||
{
|
||||
delay = queueBackpressure.markAndGetDelay(RATE_LIMITER_DELAY_UNIT);
|
||||
|
||||
if (delay > 0)
|
||||
backpressure = Overload.QUEUE_TIME;
|
||||
}
|
||||
|
||||
if (backpressure != Overload.NONE)
|
||||
{
|
||||
if (processRequestAndUpdateMetrics(bytes, header, messageSize, backpressure))
|
||||
{
|
||||
if (decoder.isActive())
|
||||
ClientMetrics.instance.pauseConnection();
|
||||
|
||||
if (delay > 0)
|
||||
{
|
||||
// Schedule a wakeup here if we process successfully. The connection should be closing otherwise.
|
||||
scheduleConnectionWakeupTask(delay, RATE_LIMITER_DELAY_UNIT);
|
||||
}
|
||||
|
||||
backpressure = Overload.REQUESTS;
|
||||
}
|
||||
}
|
||||
|
||||
// If we triggered backpressure, make sure the caller stops processing frames after the request completes.
|
||||
if (backpressure != Overload.NONE)
|
||||
|
||||
// If we triggered backpressure, make sure the caller stops processing frames after the request completes.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return processRequestAndUpdateMetrics(bytes, header, messageSize, Overload.NONE);
|
||||
|
|
@ -252,7 +269,7 @@ public class CQLMessageHandler<M extends Message> extends AbstractMessageHandler
|
|||
ClientMetrics.instance.markRequestDiscarded();
|
||||
logOverload(endpointReserve, globalReserve, header, messageSize);
|
||||
|
||||
OverloadedException exception = buildOverloadedException(endpointReserve, globalReserve, overload);
|
||||
OverloadedException exception = buildOverloadedException(endpointReserve, globalReserve, requestRateLimiter, overload);
|
||||
handleError(exception, header);
|
||||
|
||||
// Don't stop processing incoming messages, as we rely on the client to apply
|
||||
|
|
@ -262,14 +279,33 @@ public class CQLMessageHandler<M extends Message> extends AbstractMessageHandler
|
|||
buf.position(buf.position() + Envelope.Header.LENGTH + messageSize);
|
||||
}
|
||||
|
||||
private OverloadedException buildOverloadedException(Limit endpointReserve, Limit globalReserve, Overload overload) {
|
||||
return overload == Overload.REQUESTS
|
||||
? new OverloadedException(String.format("Request breached global limit of %d requests/second. Server is " +
|
||||
"currently in an overloaded state and cannot accept more requests.",
|
||||
requestRateLimiter.getRate()))
|
||||
: new OverloadedException(String.format("Request breached limit on bytes in flight. (Endpoint: %d/%d bytes, Global: %d/%d bytes.) " +
|
||||
"Server is currently in an overloaded state and cannot accept more requests.",
|
||||
endpointReserve.using(), endpointReserve.limit(), globalReserve.using(), globalReserve.limit()));
|
||||
public static OverloadedException buildOverloadedException(Limit endpointReserve, Limit globalReserve, NonBlockingRateLimiter requestRateLimiter, Overload overload)
|
||||
{
|
||||
return buildOverloadedException(() -> String.format("Endpoint: %d/%d bytes, Global: %d/%d bytes.", endpointReserve.using(), endpointReserve.limit(),
|
||||
globalReserve.using(), globalReserve.limit()),
|
||||
requestRateLimiter,
|
||||
overload);
|
||||
}
|
||||
public static OverloadedException buildOverloadedException(Supplier<String> endpointLimits, NonBlockingRateLimiter requestRateLimiter, Overload overload)
|
||||
{
|
||||
switch (overload)
|
||||
{
|
||||
case REQUESTS:
|
||||
return new OverloadedException(String.format("Request breached global limit of %d requests/second. Server is " +
|
||||
"currently in an overloaded state and cannot accept more requests.",
|
||||
requestRateLimiter.getRate()));
|
||||
case BYTES_IN_FLIGHT:
|
||||
return new OverloadedException(String.format("Request breached limit on bytes in flight. (%s)" +
|
||||
"Server is currently in an overloaded state and cannot accept more requests.",
|
||||
endpointLimits.get()));
|
||||
case QUEUE_TIME:
|
||||
return new OverloadedException(String.format("Request has spent over %s time of the maximum timeout %dms in the queue",
|
||||
DatabaseDescriptor.getNativeTransportQueueMaxItemAgeThreshold(),
|
||||
DatabaseDescriptor.getNativeTransportTimeout(TimeUnit.MILLISECONDS)));
|
||||
default:
|
||||
throw new IllegalArgumentException("Overload exception should not have been thrown with " + overload);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void logOverload(Limit endpointReserve, Limit globalReserve, Envelope.Header header, int messageSize)
|
||||
|
|
@ -348,7 +384,7 @@ public class CQLMessageHandler<M extends Message> extends AbstractMessageHandler
|
|||
try
|
||||
{
|
||||
message = messageDecoder.decode(channel, request);
|
||||
dispatcher.accept(channel, message, this::toFlushItem, backpressure);
|
||||
dispatcher.dispatch(channel, message, this::toFlushItem, backpressure);
|
||||
|
||||
// sucessfully delivered a CQL message to the execution
|
||||
// stage, so reset the counter of consecutive errors
|
||||
|
|
@ -494,55 +530,79 @@ public class CQLMessageHandler<M extends Message> extends AbstractMessageHandler
|
|||
|
||||
LargeMessage largeMessage = new LargeMessage(header);
|
||||
|
||||
if (!acquireCapacity(header, endpointReserve, globalReserve))
|
||||
if (throwOnOverload)
|
||||
{
|
||||
// In the case of large messages, never stop processing incoming frames
|
||||
// as this will halt the client meaning no further frames will be sent,
|
||||
// leading to starvation.
|
||||
// If the throwOnOverload option is set, don't process the message once
|
||||
// read, return an error response to notify the client that resource
|
||||
// limits have been exceeded. If the option isn't set, the only thing we
|
||||
// can do is to consume the subsequent frames and process the message.
|
||||
// Large and small messages are never interleaved for a single client, so
|
||||
// we know that this client will finish sending the large message before
|
||||
// anything else. Other clients sending small messages concurrently will
|
||||
// be backpressured by the global resource limits. The server is still
|
||||
// vulnerable to overload by multiple clients sending large messages
|
||||
// concurrently.
|
||||
if (throwOnOverload)
|
||||
if (!acquireCapacity(header, endpointReserve, globalReserve))
|
||||
{
|
||||
// In the case of large messages, never stop processing incoming frames
|
||||
// as this will halt the client meaning no further frames will be sent,
|
||||
// leading to starvation.
|
||||
// If the throwOnOverload option is set, don't process the message once
|
||||
// read, return an error response to notify the client that resource
|
||||
// limits have been exceeded. If the option isn't set, the only thing we
|
||||
// can do is to consume the subsequent frames and process the message.
|
||||
// Large and small messages are never interleaved for a single client, so
|
||||
// we know that this client will finish sending the large message before
|
||||
// anything else. Other clients sending small messages concurrently will
|
||||
// be backpressured by the global resource limits. The server is still
|
||||
// vulnerable to overload by multiple clients sending large messages
|
||||
// concurrently.
|
||||
|
||||
// Mark as overloaded so that discard the message after consuming any subsequent frames.
|
||||
ClientMetrics.instance.markRequestDiscarded();
|
||||
logOverload(endpointReserve, globalReserve, header, messageSize);
|
||||
largeMessage.markOverloaded(Overload.BYTES_IN_FLIGHT);
|
||||
}
|
||||
}
|
||||
else if (DatabaseDescriptor.getNativeTransportRateLimitingEnabled())
|
||||
{
|
||||
if (throwOnOverload)
|
||||
else
|
||||
{
|
||||
if (!requestRateLimiter.tryReserve())
|
||||
Overload backpressure = Overload.NONE;
|
||||
if (DatabaseDescriptor.getNativeTransportRateLimitingEnabled() && !requestRateLimiter.tryReserve())
|
||||
backpressure = Overload.REQUESTS;
|
||||
else if (!dispatcher.hasQueueCapacity())
|
||||
backpressure = Overload.QUEUE_TIME;
|
||||
|
||||
if (backpressure != Overload.NONE)
|
||||
{
|
||||
ClientMetrics.instance.markRequestDiscarded();
|
||||
logOverload(endpointReserve, globalReserve, header, messageSize);
|
||||
|
||||
|
||||
// Mark as overloaded so that we discard the message after consuming any subsequent frames.
|
||||
// (i.e. Request resources we may already have acquired above will be released.)
|
||||
largeMessage.markOverloaded(Overload.REQUESTS);
|
||||
|
||||
largeMessage.markOverloaded(backpressure);
|
||||
|
||||
this.largeMessage = largeMessage;
|
||||
largeMessage.supply(frame);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
{
|
||||
if (acquireCapacity(header, endpointReserve, globalReserve))
|
||||
{
|
||||
long delay = requestRateLimiter.reserveAndGetDelay(RATE_LIMITER_DELAY_UNIT);
|
||||
long delay = -1;
|
||||
Overload backpressure = Overload.NONE;
|
||||
|
||||
if (DatabaseDescriptor.getNativeTransportRateLimitingEnabled())
|
||||
{
|
||||
delay = requestRateLimiter.reserveAndGetDelay(RATE_LIMITER_DELAY_UNIT);
|
||||
|
||||
if (delay > 0)
|
||||
backpressure = Overload.REQUESTS;
|
||||
}
|
||||
|
||||
if (backpressure == Overload.NONE && !dispatcher.hasQueueCapacity())
|
||||
{
|
||||
delay = queueBackpressure.markAndGetDelay(RATE_LIMITER_DELAY_UNIT);
|
||||
|
||||
if (delay > 0)
|
||||
backpressure = Overload.QUEUE_TIME;
|
||||
}
|
||||
|
||||
if (delay > 0)
|
||||
{
|
||||
this.largeMessage = largeMessage;
|
||||
largeMessage.markBackpressure(Overload.REQUESTS);
|
||||
largeMessage.markBackpressure(backpressure);
|
||||
largeMessage.supply(frame);
|
||||
|
||||
if (decoder.isActive())
|
||||
|
|
@ -553,7 +613,7 @@ public class CQLMessageHandler<M extends Message> extends AbstractMessageHandler
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.largeMessage = largeMessage;
|
||||
largeMessage.supply(frame);
|
||||
return true;
|
||||
|
|
@ -695,7 +755,7 @@ public class CQLMessageHandler<M extends Message> extends AbstractMessageHandler
|
|||
protected void onComplete()
|
||||
{
|
||||
if (overload != Overload.NONE)
|
||||
handleErrorAndRelease(buildOverloadedException(endpointReserveCapacity, globalReserveCapacity, overload), header);
|
||||
handleErrorAndRelease(buildOverloadedException(endpointReserveCapacity, globalReserveCapacity, requestRateLimiter, overload), header);
|
||||
else if (!isCorrupt)
|
||||
processRequest(assembleFrame(), backpressure);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ public class ClientResourceLimits
|
|||
|
||||
public static final NonBlockingRateLimiter GLOBAL_REQUEST_LIMITER = new NonBlockingRateLimiter(getNativeTransportMaxRequestsPerSecond());
|
||||
|
||||
public enum Overload { NONE, REQUESTS, BYTES_IN_FLIGHT }
|
||||
public enum Overload { NONE, REQUESTS, BYTES_IN_FLIGHT, QUEUE_TIME }
|
||||
|
||||
public static Allocator getAllocatorForEndpoint(InetAddress endpoint)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -83,5 +83,6 @@ public class Connection
|
|||
public interface Tracker
|
||||
{
|
||||
void addConnection(Channel ch, Connection connection);
|
||||
boolean isRunning();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,9 +31,10 @@ import org.slf4j.LoggerFactory;
|
|||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.EventLoop;
|
||||
import io.netty.util.AttributeKey;
|
||||
import org.apache.cassandra.concurrent.DebuggableTask.RunnableDebuggableTask;
|
||||
import org.apache.cassandra.concurrent.DebuggableTask;
|
||||
import org.apache.cassandra.concurrent.LocalAwareExecutorPlus;
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.exceptions.OverloadedException;
|
||||
import org.apache.cassandra.metrics.ClientMetrics;
|
||||
import org.apache.cassandra.net.FrameEncoder;
|
||||
import org.apache.cassandra.service.ClientWarn;
|
||||
|
|
@ -44,12 +45,12 @@ import org.apache.cassandra.transport.Flusher.FlushItem;
|
|||
import org.apache.cassandra.transport.messages.ErrorMessage;
|
||||
import org.apache.cassandra.transport.messages.EventMessage;
|
||||
import org.apache.cassandra.utils.JVMStabilityInspector;
|
||||
import org.apache.cassandra.utils.MonotonicClock;
|
||||
import org.apache.cassandra.utils.NoSpamLogger;
|
||||
|
||||
import static org.apache.cassandra.concurrent.SharedExecutorPool.SHARED;
|
||||
import static org.apache.cassandra.utils.Clock.Global.nanoTime;
|
||||
|
||||
public class Dispatcher
|
||||
public class Dispatcher implements CQLMessageHandler.MessageConsumer<Message.Request>
|
||||
{
|
||||
private static final Logger logger = LoggerFactory.getLogger(Dispatcher.class);
|
||||
|
||||
|
|
@ -99,8 +100,23 @@ public class Dispatcher
|
|||
this.useLegacyFlusher = useLegacyFlusher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatch(Channel channel, Message.Request request, FlushItemConverter forFlusher, Overload backpressure)
|
||||
{
|
||||
if (!request.connection().getTracker().isRunning())
|
||||
{
|
||||
// We can not respond with a custom, transport, or server exceptions since, given current implementation of clients,
|
||||
// they will defunct the connection. Without a protocol version bump that introduces an "I am going away message",
|
||||
// we have to stick to an existing error code.
|
||||
Message.Response response = ErrorMessage.fromException(new OverloadedException("Server is shutting down"));
|
||||
response.setStreamId(request.getStreamId());
|
||||
response.setWarnings(ClientWarn.instance.getWarnings());
|
||||
response.attach(request.connection);
|
||||
FlushItem<?> toFlush = forFlusher.toFlushItem(channel, request, response);
|
||||
flush(toFlush);
|
||||
return;
|
||||
}
|
||||
|
||||
// if native_transport_max_auth_threads is < 1, don't delegate to new pool on auth messages
|
||||
boolean isAuthQuery = DatabaseDescriptor.getNativeTransportMaxAuthThreads() > 0 &&
|
||||
(request.type == Message.Type.AUTH_RESPONSE || request.type == Message.Type.CREDENTIALS);
|
||||
|
|
@ -112,16 +128,170 @@ public class Dispatcher
|
|||
ClientMetrics.instance.markRequestDispatched();
|
||||
}
|
||||
|
||||
public class RequestProcessor implements RunnableDebuggableTask
|
||||
public static class RequestTime
|
||||
{
|
||||
private final long enqueuedAtNanos;
|
||||
private final long startedAtNanos;
|
||||
|
||||
public RequestTime(long createdAtNanos)
|
||||
{
|
||||
this(createdAtNanos, createdAtNanos);
|
||||
}
|
||||
|
||||
public RequestTime(long enqueuedAtNanos, long startedAtNanos)
|
||||
{
|
||||
this.enqueuedAtNanos = enqueuedAtNanos;
|
||||
this.startedAtNanos = startedAtNanos;
|
||||
}
|
||||
|
||||
public static RequestTime forImmediateExecution()
|
||||
{
|
||||
return new RequestTime(MonotonicClock.Global.preciseTime.now());
|
||||
}
|
||||
|
||||
public long startedAtNanos()
|
||||
{
|
||||
return startedAtNanos;
|
||||
}
|
||||
|
||||
public long enqueuedAtNanos()
|
||||
{
|
||||
return enqueuedAtNanos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base time is used by timeouts, and can be set to either when the request was added to the queue,
|
||||
* or when the processing has started, which is controlled by {@link DatabaseDescriptor#getCQLStartTime()}
|
||||
*
|
||||
* Since client read/write timeouts are usually aligned with server-side timeouts, it is desireable to use
|
||||
* enqueue time as a base. However, since client removes the handler `readTimeoutMillis` (which is 12 seconds
|
||||
* by default), the upper bound for any execution on the coordinator is 12 seconds (thanks to CASSANDRA-7392,
|
||||
* any replica-side query is capped by the verb timeout), if REQUEST option is used. But even simply allowing
|
||||
* such long timeouts also implicitly allows queues to grow large, since our queues are currently unbounded.
|
||||
*
|
||||
* Latency, however, is _always_ based on request processing time, since the amount of time that request spends
|
||||
* in the queue is not a representative metric of replica performance.
|
||||
*/
|
||||
public long baseTimeNanos()
|
||||
{
|
||||
switch (DatabaseDescriptor.getCQLStartTime())
|
||||
{
|
||||
case REQUEST:
|
||||
return startedAtNanos();
|
||||
case QUEUE:
|
||||
return enqueuedAtNanos();
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown start time: " + DatabaseDescriptor.getCQLStartTime());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the current time and a base timeout for the verb return a request's expiration deadline,
|
||||
* the time at which it becomes eligible for load shedding.
|
||||
* The two factors to consider are the per-verb and client timeouts. Both are calculated by subtracting the
|
||||
* time already elapsed during the lifetime of the request from some base value.
|
||||
*
|
||||
* When deriving verb timeout, two alternative semantics are available. This timeout may represent either:
|
||||
* * the total time available for a coordinator to process a client request and return its response
|
||||
* * a time bound for a coordinator to send internode requests and gather responses from replicas
|
||||
*
|
||||
* The point from which elapsed time is measured here is configurable to accommodate these two different
|
||||
* options. For the former, the clock starts when a client request is received and enqueued by the coordinator.
|
||||
* For the latter, it starts when the request is dequeued by the coordinator and processing is started.
|
||||
* See {@link #baseTimeNanos()} for details.
|
||||
*
|
||||
* The client timeout represents how long the sender of a request is prepared to wait for a response. By
|
||||
* implication, after this window has passed any further work done on the server side is wasted effort. Ideally,
|
||||
* the base for this timeout would be set on a per-request basis but as this not currently supported in the
|
||||
* protocol, it is configured uniformly for all requests. See {@link DatabaseDescriptor#getNativeTransportTimeout}.
|
||||
* For this calculation, elapsed time is always measured from the point when a request is received and enqueued.
|
||||
*
|
||||
* Where verb timeout is based on queue admission, deadline computation is straightforward. The expiration
|
||||
* deadline is simply the current time plus the smaller of the verb and client timeouts.
|
||||
*
|
||||
* However, if verb timeout is based on when the request is dequeued, the implications are more nuanced.
|
||||
* In this scenario, while there may still be "headroom" available within the verb timeout, using it could
|
||||
* exceed the client timeout (which is always based on admission time).
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* * Client timeout base is 10 (cb), verb timeout base is 5 (vb)
|
||||
* * Request is enqueued at t1 (e)
|
||||
* * Request is dequeued at t8 (d)
|
||||
* * computeDeadline is called at t9 (n)
|
||||
*
|
||||
* If verb timeout is based on dequeuing, there would still some time remaining before a verb-based deadline.
|
||||
* elapsed = (n - d) ; 1
|
||||
* timeout = (vb - elapsed) ; 4
|
||||
* deadline = (n + timeout) ; t13
|
||||
* ostensibly, the coordinator has until t13 to complete processing
|
||||
*
|
||||
* But as client timeout is measured from admission time, the request may exceeded the maximum wait period for
|
||||
* the client sooner.
|
||||
* elapsed = (n - e) ; 8
|
||||
* timeout = (cb - elapsed) ; 2
|
||||
* deadline = (n + timeout) ; t11
|
||||
* So the coordinator actually only has until t11 to complete processing, beyond then the client will not accept
|
||||
* any response.
|
||||
*
|
||||
* @param verbExpiresAfterNanos the base timeout value for the verb being executed
|
||||
* @return the point in time after which no further processing should occur
|
||||
*/
|
||||
public long computeDeadline(long verbExpiresAfterNanos)
|
||||
{
|
||||
long clientDeadline = clientDeadline();
|
||||
|
||||
long verbDeadline = baseTimeNanos() + verbExpiresAfterNanos;
|
||||
// Whichever one is closer
|
||||
return Math.min(verbDeadline, clientDeadline);
|
||||
}
|
||||
|
||||
public long computeTimeout(long now, long verbExpiresAfterNanos)
|
||||
{
|
||||
return computeDeadline(verbExpiresAfterNanos) - now;
|
||||
}
|
||||
|
||||
/**
|
||||
* No request should survive native request deadline, but in order to err on the side of caution, we have this
|
||||
* swtich that allows hints to be submitted to mutation stage when cluster is potentially overloaded. Allowing
|
||||
* hints to be not bound by deadline can exacerbate overload, but since there are also correctness implications,
|
||||
* this seemed like a reasonable configuration option.
|
||||
*/
|
||||
public boolean shouldSendHints()
|
||||
{
|
||||
if (!DatabaseDescriptor.getEnforceNativeDeadlineForHints())
|
||||
return true;
|
||||
|
||||
long now = MonotonicClock.Global.preciseTime.now();
|
||||
long clientDeadline = clientDeadline();
|
||||
return now < clientDeadline;
|
||||
}
|
||||
|
||||
public long clientDeadline()
|
||||
{
|
||||
return enqueuedAtNanos() + DatabaseDescriptor.getNativeTransportTimeout(TimeUnit.NANOSECONDS);
|
||||
}
|
||||
|
||||
public long timeSpentInQueueNanos()
|
||||
{
|
||||
return startedAtNanos - enqueuedAtNanos;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* It is important to keep this class an instance of {@link DebuggableTask}, either runnable or callable since this
|
||||
* is the only way we can keep it not wrapped into a callable on SEPExecutor submission path. And we need this
|
||||
* functionality for tracking time purposes.
|
||||
*/
|
||||
public class RequestProcessor implements DebuggableTask.RunnableDebuggableTask
|
||||
{
|
||||
private final Channel channel;
|
||||
private final Message.Request request;
|
||||
private final FlushItemConverter forFlusher;
|
||||
private final Overload backpressure;
|
||||
|
||||
private final long creationTimeNanos = nanoTime();
|
||||
|
||||
private volatile long startTimeNanos;
|
||||
|
||||
|
||||
public RequestProcessor(Channel channel, Message.Request request, FlushItemConverter forFlusher, Overload backpressure)
|
||||
{
|
||||
this.channel = channel;
|
||||
|
|
@ -133,14 +303,14 @@ public class Dispatcher
|
|||
@Override
|
||||
public void run()
|
||||
{
|
||||
startTimeNanos = nanoTime();
|
||||
processRequest(channel, request, forFlusher, backpressure, startTimeNanos);
|
||||
startTimeNanos = MonotonicClock.Global.preciseTime.now();
|
||||
processRequest(channel, request, forFlusher, backpressure, new RequestTime(request.createdAtNanos, startTimeNanos));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long creationTimeNanos()
|
||||
{
|
||||
return creationTimeNanos;
|
||||
return request.createdAtNanos;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -154,14 +324,49 @@ public class Dispatcher
|
|||
{
|
||||
return request.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "RequestProcessor{" +
|
||||
"request=" + request +
|
||||
", approxStartTimeNanos=" + startTimeNanos +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the item in the head of the queue has spent more than allowed time in the queue.
|
||||
*/
|
||||
@Override
|
||||
public boolean hasQueueCapacity()
|
||||
{
|
||||
double threshold = DatabaseDescriptor.getNativeTransportQueueMaxItemAgeThreshold();
|
||||
if (threshold <= 0)
|
||||
return true;
|
||||
|
||||
return requestExecutor.oldestTaskQueueTime() < (DatabaseDescriptor.getNativeTransportTimeout(TimeUnit.NANOSECONDS) * threshold);
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: this method may be executed on the netty event loop, during initial protocol negotiation; the caller is
|
||||
* responsible for cleaning up any global or thread-local state. (ex. tracing, client warnings, etc.).
|
||||
*/
|
||||
private static Message.Response processRequest(ServerConnection connection, Message.Request request, Overload backpressure, long startTimeNanos)
|
||||
private static Message.Response processRequest(ServerConnection connection, Message.Request request, Overload backpressure, RequestTime requestTime)
|
||||
{
|
||||
long queueTime = requestTime.timeSpentInQueueNanos();
|
||||
|
||||
// If we have already crossed the max timeout for all possible RPCs, we time out the query immediately.
|
||||
// We do not differentiate between query types here, since if we got into a situation when, say, we have a PREPARE
|
||||
// query that is stuck behind the EXECUTE query, we would rather time it out and catch up with a backlog, expecting
|
||||
// that the bursts are going to be short-lived.
|
||||
ClientMetrics.instance.queueTime(queueTime, TimeUnit.NANOSECONDS);
|
||||
if (queueTime > DatabaseDescriptor.getNativeTransportTimeout(TimeUnit.NANOSECONDS))
|
||||
{
|
||||
ClientMetrics.instance.markTimedOutBeforeProcessing();
|
||||
return ErrorMessage.fromException(new OverloadedException("Query timed out before it could start"));
|
||||
}
|
||||
|
||||
if (connection.getVersion().isGreaterOrEqualTo(ProtocolVersion.V4))
|
||||
ClientWarn.instance.captureWarnings();
|
||||
|
||||
|
|
@ -170,28 +375,45 @@ public class Dispatcher
|
|||
if (request.isTrackable())
|
||||
CoordinatorWarnings.init();
|
||||
|
||||
if (backpressure == Overload.REQUESTS)
|
||||
switch (backpressure)
|
||||
{
|
||||
String message = String.format("Request breached global limit of %d requests/second and triggered backpressure.",
|
||||
ClientResourceLimits.getNativeTransportMaxRequestsPerSecond());
|
||||
case NONE:
|
||||
break;
|
||||
case REQUESTS:
|
||||
{
|
||||
String message = String.format("Request breached global limit of %d requests/second and triggered backpressure.",
|
||||
ClientResourceLimits.getNativeTransportMaxRequestsPerSecond());
|
||||
|
||||
NoSpamLogger.log(logger, NoSpamLogger.Level.INFO, 1, TimeUnit.MINUTES, message);
|
||||
ClientWarn.instance.warn(message);
|
||||
}
|
||||
else if (backpressure == Overload.BYTES_IN_FLIGHT)
|
||||
{
|
||||
String message = String.format("Request breached limit(s) on bytes in flight (Endpoint: %d, Global: %d) and triggered backpressure.",
|
||||
ClientResourceLimits.getEndpointLimit(), ClientResourceLimits.getGlobalLimit());
|
||||
NoSpamLogger.log(logger, NoSpamLogger.Level.INFO, 1, TimeUnit.MINUTES, message);
|
||||
ClientWarn.instance.warn(message);
|
||||
break;
|
||||
}
|
||||
case BYTES_IN_FLIGHT:
|
||||
{
|
||||
String message = String.format("Request breached limit(s) on bytes in flight (Endpoint: %d, Global: %d) and triggered backpressure.",
|
||||
ClientResourceLimits.getEndpointLimit(), ClientResourceLimits.getGlobalLimit());
|
||||
|
||||
NoSpamLogger.log(logger, NoSpamLogger.Level.INFO, 1, TimeUnit.MINUTES, message);
|
||||
ClientWarn.instance.warn(message);
|
||||
NoSpamLogger.log(logger, NoSpamLogger.Level.INFO, 1, TimeUnit.MINUTES, message);
|
||||
ClientWarn.instance.warn(message);
|
||||
break;
|
||||
}
|
||||
case QUEUE_TIME:
|
||||
{
|
||||
String message = String.format("Request has spent over %s time of the maximum timeout %dms in the queue",
|
||||
DatabaseDescriptor.getNativeTransportQueueMaxItemAgeThreshold(),
|
||||
DatabaseDescriptor.getNativeTransportTimeout(TimeUnit.MILLISECONDS));
|
||||
|
||||
NoSpamLogger.log(logger, NoSpamLogger.Level.INFO, 1, TimeUnit.MINUTES, message);
|
||||
ClientWarn.instance.warn(message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QueryState qstate = connection.validateNewMessage(request.type, connection.getVersion());
|
||||
|
||||
Message.logger.trace("Received: {}, v={}", request, connection.getVersion());
|
||||
connection.requests.inc();
|
||||
Message.Response response = request.execute(qstate, startTimeNanos);
|
||||
Message.Response response = request.execute(qstate, requestTime);
|
||||
|
||||
if (request.isTrackable())
|
||||
CoordinatorWarnings.done();
|
||||
|
|
@ -206,11 +428,11 @@ public class Dispatcher
|
|||
/**
|
||||
* Note: this method may be executed on the netty event loop.
|
||||
*/
|
||||
static Message.Response processRequest(Channel channel, Message.Request request, Overload backpressure, long startTimeNanos)
|
||||
static Message.Response processRequest(Channel channel, Message.Request request, Overload backpressure, RequestTime requestTime)
|
||||
{
|
||||
try
|
||||
{
|
||||
return processRequest((ServerConnection) request.connection(), request, backpressure, startTimeNanos);
|
||||
return processRequest((ServerConnection) request.connection(), request, backpressure, requestTime);
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
|
|
@ -235,9 +457,9 @@ public class Dispatcher
|
|||
/**
|
||||
* Note: this method is not expected to execute on the netty event loop.
|
||||
*/
|
||||
void processRequest(Channel channel, Message.Request request, FlushItemConverter forFlusher, Overload backpressure, long startTimeNanos)
|
||||
void processRequest(Channel channel, Message.Request request, FlushItemConverter forFlusher, Overload backpressure, RequestTime requestTime)
|
||||
{
|
||||
Message.Response response = processRequest(channel, request, backpressure, startTimeNanos);
|
||||
Message.Response response = processRequest(channel, request, backpressure, requestTime);
|
||||
FlushItem<?> toFlush = forFlusher.toFlushItem(channel, request, response);
|
||||
Message.logger.trace("Responding: {}, v={}", response, request.connection().getVersion());
|
||||
flush(toFlush);
|
||||
|
|
@ -259,6 +481,11 @@ public class Dispatcher
|
|||
flusher.start();
|
||||
}
|
||||
|
||||
public boolean isDone()
|
||||
{
|
||||
return requestExecutor.getPendingTaskCount() == 0 && requestExecutor.getActiveTaskCount() == 0;
|
||||
}
|
||||
|
||||
public static void shutdown()
|
||||
{
|
||||
requestExecutor.shutdown();
|
||||
|
|
@ -270,7 +497,7 @@ public class Dispatcher
|
|||
* for delivering events to registered clients is dependent on protocol version and the configuration
|
||||
* of the pipeline. For v5 and newer connections, the event message is encoded into an Envelope,
|
||||
* wrapped in a FlushItem and then delivered via the pipeline's flusher, in a similar way to
|
||||
* a Response returned from {@link #processRequest(Channel, Message.Request, FlushItemConverter, Overload, long)}.
|
||||
* a Response returned from {@link #processRequest(Channel, Message.Request, FlushItemConverter, Overload, RequestTime)}.
|
||||
* It's worth noting that events are not generally fired as a direct response to a client request,
|
||||
* so this flush item has a null request attribute. The dispatcher itself is created when the
|
||||
* pipeline is first configured during protocol negotiation and is attached to the channel for
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
import org.apache.cassandra.transport.ClientResourceLimits.Overload;
|
||||
import org.apache.cassandra.utils.MonotonicClock;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
|
@ -149,8 +148,7 @@ public class InitialConnectionHandler extends ByteToMessageDecoder
|
|||
promise = new VoidChannelPromise(ctx.channel(), false);
|
||||
}
|
||||
|
||||
long approxStartTimeNanos = MonotonicClock.Global.approxTime.now();
|
||||
final Message.Response response = Dispatcher.processRequest(ctx.channel(), startup, Overload.NONE, approxStartTimeNanos);
|
||||
final Message.Response response = Dispatcher.processRequest(ctx.channel(), startup, Overload.NONE, Dispatcher.RequestTime.forImmediateExecution());
|
||||
|
||||
outbound = response.encode(inbound.header.version);
|
||||
ctx.writeAndFlush(outbound, promise);
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ import org.apache.cassandra.service.StorageService;
|
|||
import org.apache.cassandra.tracing.Tracing;
|
||||
import org.apache.cassandra.transport.messages.*;
|
||||
import org.apache.cassandra.service.QueryState;
|
||||
import org.apache.cassandra.utils.MonotonicClock;
|
||||
import org.apache.cassandra.utils.ReflectionUtils;
|
||||
import org.apache.cassandra.utils.TimeUUID;
|
||||
|
||||
|
|
@ -203,11 +204,13 @@ public abstract class Message
|
|||
public static abstract class Request extends Message
|
||||
{
|
||||
private boolean tracingRequested;
|
||||
|
||||
public final long createdAtNanos;
|
||||
protected Request(Type type)
|
||||
{
|
||||
super(type);
|
||||
|
||||
createdAtNanos = MonotonicClock.Global.preciseTime.now();
|
||||
|
||||
if (type.direction != Direction.REQUEST)
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
|
@ -228,9 +231,9 @@ public abstract class Message
|
|||
return false;
|
||||
}
|
||||
|
||||
protected abstract Response execute(QueryState queryState, long queryStartNanoTime, boolean traceRequest);
|
||||
protected abstract Response execute(QueryState queryState, Dispatcher.RequestTime requestTime, boolean traceRequest);
|
||||
|
||||
public final Response execute(QueryState queryState, long queryStartNanoTime)
|
||||
public final Response execute(QueryState queryState, Dispatcher.RequestTime requestTime)
|
||||
{
|
||||
boolean shouldTrace = false;
|
||||
TimeUUID tracingSessionId = null;
|
||||
|
|
@ -253,7 +256,7 @@ public abstract class Message
|
|||
Response response;
|
||||
try
|
||||
{
|
||||
response = execute(queryState, queryStartNanoTime, shouldTrace);
|
||||
response = execute(queryState, requestTime, shouldTrace);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
@ -276,6 +279,15 @@ public abstract class Message
|
|||
{
|
||||
return tracingRequested;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "Request{" +
|
||||
"tracingRequested=" + tracingRequested +
|
||||
", createdAtNanos=" + createdAtNanos +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
public static abstract class Response extends Message
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
|
@ -97,16 +98,32 @@ public class PipelineConfigurator
|
|||
private final boolean keepAlive;
|
||||
private final EncryptionOptions.TlsEncryptionPolicy tlsEncryptionPolicy;
|
||||
private final Dispatcher dispatcher;
|
||||
// Shared between pre-v5 and CQLMessage handlers
|
||||
private final QueueBackpressure queueBackpressure;
|
||||
|
||||
public PipelineConfigurator(boolean epoll,
|
||||
boolean keepAlive,
|
||||
boolean legacyFlusher,
|
||||
EncryptionOptions.TlsEncryptionPolicy encryptionPolicy,
|
||||
Dispatcher dispatcher)
|
||||
{
|
||||
this.epoll = epoll;
|
||||
this.keepAlive = keepAlive;
|
||||
this.tlsEncryptionPolicy = encryptionPolicy;
|
||||
this.dispatcher = dispatcher;
|
||||
this.queueBackpressure = QueueBackpressure.DEFAULT;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public PipelineConfigurator(boolean epoll,
|
||||
boolean keepAlive,
|
||||
boolean useLegacyFlusher,
|
||||
EncryptionOptions.TlsEncryptionPolicy encryptionPolicy)
|
||||
{
|
||||
this.epoll = epoll;
|
||||
this.keepAlive = keepAlive;
|
||||
this.tlsEncryptionPolicy = encryptionPolicy;
|
||||
this.dispatcher = dispatcher(legacyFlusher);
|
||||
this.dispatcher = new Dispatcher(useLegacyFlusher);
|
||||
this.queueBackpressure = QueueBackpressure.DEFAULT;
|
||||
}
|
||||
|
||||
public ChannelFuture initializeChannel(final EventLoopGroup workerGroup,
|
||||
|
|
@ -288,7 +305,12 @@ public class PipelineConfigurator
|
|||
int queueCapacity = DatabaseDescriptor.getNativeTransportReceiveQueueCapacityInBytes();
|
||||
ClientResourceLimits.ResourceProvider resourceProvider = resourceProvider(resourceAllocator);
|
||||
AbstractMessageHandler.OnHandlerClosed onClosed = handler -> resourceProvider.release();
|
||||
boolean throwOnOverload = "1".equals(options.get(StartupMessage.THROW_ON_OVERLOAD));
|
||||
String fromOptions = options.get(StartupMessage.THROW_ON_OVERLOAD);
|
||||
boolean throwOnOverload;
|
||||
if (fromOptions == null)
|
||||
throwOnOverload = DatabaseDescriptor.getNativeTransportThrowOnOverload();
|
||||
else
|
||||
throwOnOverload = "1".equals(fromOptions);
|
||||
|
||||
CQLMessageHandler.MessageConsumer<Message.Request> messageConsumer = messageConsumer();
|
||||
CQLMessageHandler<Message.Request> processor =
|
||||
|
|
@ -300,6 +322,7 @@ public class PipelineConfigurator
|
|||
messageConsumer,
|
||||
payloadAllocator,
|
||||
queueCapacity,
|
||||
queueBackpressure,
|
||||
resourceProvider,
|
||||
onClosed,
|
||||
errorHandler,
|
||||
|
|
@ -334,7 +357,7 @@ public class PipelineConfigurator
|
|||
|
||||
protected CQLMessageHandler.MessageConsumer<Message.Request> messageConsumer()
|
||||
{
|
||||
return dispatcher::dispatch;
|
||||
return dispatcher;
|
||||
}
|
||||
|
||||
protected Message.Decoder<Message.Request> messageDecoder()
|
||||
|
|
@ -368,7 +391,7 @@ public class PipelineConfigurator
|
|||
pipeline.addBefore(INITIAL_HANDLER, MESSAGE_COMPRESSOR, Envelope.Compressor.instance);
|
||||
pipeline.addBefore(INITIAL_HANDLER, MESSAGE_DECODER, PreV5Handlers.ProtocolDecoder.instance);
|
||||
pipeline.addBefore(INITIAL_HANDLER, MESSAGE_ENCODER, PreV5Handlers.ProtocolEncoder.instance);
|
||||
pipeline.addBefore(INITIAL_HANDLER, LEGACY_MESSAGE_PROCESSOR, new PreV5Handlers.LegacyDispatchHandler(dispatcher, limits));
|
||||
pipeline.addBefore(INITIAL_HANDLER, LEGACY_MESSAGE_PROCESSOR, new PreV5Handlers.LegacyDispatchHandler(dispatcher, queueBackpressure, limits));
|
||||
pipeline.remove(INITIAL_HANDLER);
|
||||
onNegotiationComplete(pipeline);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,9 +21,6 @@ package org.apache.cassandra.transport;
|
|||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.transport.ClientResourceLimits.Overload;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
|
@ -37,9 +34,11 @@ import io.netty.channel.ChannelInboundHandlerAdapter;
|
|||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||
import io.netty.handler.codec.MessageToMessageEncoder;
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.exceptions.OverloadedException;
|
||||
import org.apache.cassandra.metrics.ClientMetrics;
|
||||
import org.apache.cassandra.net.ResourceLimits;
|
||||
import org.apache.cassandra.transport.ClientResourceLimits.Overload;
|
||||
import org.apache.cassandra.transport.messages.ErrorMessage;
|
||||
import org.apache.cassandra.utils.JVMStabilityInspector;
|
||||
|
||||
|
|
@ -59,6 +58,8 @@ public class PreV5Handlers
|
|||
private final Dispatcher dispatcher;
|
||||
private final ClientResourceLimits.Allocator endpointPayloadTracker;
|
||||
|
||||
private final QueueBackpressure queueBackpressure;
|
||||
|
||||
/**
|
||||
* Current count of *request* bytes that are live on the channel.
|
||||
* <p>
|
||||
|
|
@ -69,9 +70,10 @@ public class PreV5Handlers
|
|||
/** The cause of the current connection pause, or {@link Overload#NONE} if it is unpaused. */
|
||||
private Overload backpressure = Overload.NONE;
|
||||
|
||||
LegacyDispatchHandler(Dispatcher dispatcher, ClientResourceLimits.Allocator endpointPayloadTracker)
|
||||
LegacyDispatchHandler(Dispatcher dispatcher, QueueBackpressure queueBackpressure, ClientResourceLimits.Allocator endpointPayloadTracker)
|
||||
{
|
||||
this.dispatcher = dispatcher;
|
||||
this.queueBackpressure = queueBackpressure;
|
||||
this.endpointPayloadTracker = endpointPayloadTracker;
|
||||
}
|
||||
|
||||
|
|
@ -152,12 +154,19 @@ public class PreV5Handlers
|
|||
discardAndThrow(request, requestSize, Overload.BYTES_IN_FLIGHT);
|
||||
}
|
||||
|
||||
Overload backpressure = Overload.NONE;
|
||||
if (DatabaseDescriptor.getNativeTransportRateLimitingEnabled() && !GLOBAL_REQUEST_LIMITER.tryReserve())
|
||||
backpressure = Overload.REQUESTS;
|
||||
else if (!dispatcher.hasQueueCapacity())
|
||||
backpressure = Overload.QUEUE_TIME;
|
||||
|
||||
if (backpressure != Overload.NONE)
|
||||
{
|
||||
// We've already allocated against the payload tracker here, so release those resources.
|
||||
endpointPayloadTracker.release(requestSize);
|
||||
discardAndThrow(request, requestSize, Overload.REQUESTS);
|
||||
discardAndThrow(request, requestSize, backpressure);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -172,20 +181,33 @@ public class PreV5Handlers
|
|||
backpressure = Overload.BYTES_IN_FLIGHT;
|
||||
}
|
||||
|
||||
long delay = -1;
|
||||
|
||||
if (DatabaseDescriptor.getNativeTransportRateLimitingEnabled())
|
||||
{
|
||||
// Reserve a permit even if we've already triggered backpressure on bytes in flight.
|
||||
long delay = GLOBAL_REQUEST_LIMITER.reserveAndGetDelay(RATE_LIMITER_DELAY_UNIT);
|
||||
delay = GLOBAL_REQUEST_LIMITER.reserveAndGetDelay(RATE_LIMITER_DELAY_UNIT);
|
||||
|
||||
// If we've already triggered backpressure on bytes in flight, no further action is necessary.
|
||||
if (backpressure == Overload.NONE && delay > 0)
|
||||
{
|
||||
pauseConnection(ctx);
|
||||
|
||||
// A permit isn't immediately available, so schedule an unpause for when it is.
|
||||
ctx.channel().eventLoop().schedule(() -> unpauseConnection(ctx.channel().config()), delay, RATE_LIMITER_DELAY_UNIT);
|
||||
backpressure = Overload.REQUESTS;
|
||||
}
|
||||
}
|
||||
|
||||
if (backpressure == Overload.NONE && !dispatcher.hasQueueCapacity())
|
||||
{
|
||||
delay = queueBackpressure.markAndGetDelay(RATE_LIMITER_DELAY_UNIT);
|
||||
|
||||
if (delay > 0)
|
||||
backpressure = Overload.QUEUE_TIME;
|
||||
}
|
||||
|
||||
if (delay > 0)
|
||||
{
|
||||
assert backpressure == Overload.REQUESTS || backpressure == Overload.QUEUE_TIME : backpressure;
|
||||
pauseConnection(ctx);
|
||||
|
||||
// A permit isn't immediately available, so schedule an unpause for when it is.
|
||||
ctx.channel().eventLoop().schedule(() -> unpauseConnection(ctx.channel().config()), delay, RATE_LIMITER_DELAY_UNIT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -219,15 +241,9 @@ public class PreV5Handlers
|
|||
requestSize, channelPayloadBytesInFlight, endpointPayloadTracker,
|
||||
GLOBAL_REQUEST_LIMITER, request);
|
||||
|
||||
OverloadedException exception = overload == Overload.REQUESTS
|
||||
? new OverloadedException(String.format("Request breached global limit of %d requests/second. Server is " +
|
||||
"currently in an overloaded state and cannot accept more requests.",
|
||||
GLOBAL_REQUEST_LIMITER.getRate()))
|
||||
: new OverloadedException(String.format("Request breached limit on bytes in flight. (%s)) " +
|
||||
"Server is currently in an overloaded state and cannot accept more requests.",
|
||||
|
||||
endpointPayloadTracker));
|
||||
|
||||
OverloadedException exception = CQLMessageHandler.buildOverloadedException(endpointPayloadTracker::toString,
|
||||
GLOBAL_REQUEST_LIMITER,
|
||||
overload);
|
||||
throw ErrorMessage.wrap(exception, request.getSource().header.streamId);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.cassandra.transport;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.LongSupplier;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
|
||||
import static org.apache.cassandra.utils.MonotonicClock.Global.preciseTime;
|
||||
|
||||
/**
|
||||
* Native Queue Backpressure mechanism. If the queue fills up above {@link DatabaseDescriptor#getNativeTransportQueueMaxItemAgeThreshold()}.
|
||||
* In other words, request has been sitting more than a % of {@link DatabaseDescriptor#getNativeTransportQueueMaxItemAgeThreshold()} in the queue,
|
||||
* we start an incident.
|
||||
* <p>
|
||||
* Incident starts by marking the incident time and raising severity level to 1. Each time we observe an old item in the head of
|
||||
* the queue, we first bump then number of times we have applied the backpressure. After bumping it 10 times, we increase severity level by 1.
|
||||
* <p>
|
||||
* Backpressure delay applied to the client socket is computed by multiplying the severity level by the minimum delay.
|
||||
* <p>
|
||||
* If we have not seen old requests in the head of the queue for 1 second, we close the incident.
|
||||
* <p>
|
||||
* If the queue remains saturated for a prolonged period (meaning {@link Dispatcher#hasQueueCapacity} returns false), the amount of delay
|
||||
* will increase in proportion to the request rate as appliedTimes & severityLevel are incremented. If no new requests are considered
|
||||
* overloaded in this way for a second, the incident will be reset and so the delay will drop back down to {@link Incident#minDelayNanos()}.
|
||||
*/
|
||||
public interface QueueBackpressure
|
||||
{
|
||||
QueueBackpressure NO_OP = timeUnit -> 0;
|
||||
|
||||
QueueBackpressure DEFAULT = new QueueBackpressure()
|
||||
{
|
||||
private final AtomicReference<Incident> state = new AtomicReference<>(noBackpressure(() -> DatabaseDescriptor.getNativeTransportMinBackoffOnQueueOverload(TimeUnit.NANOSECONDS),
|
||||
() -> DatabaseDescriptor.getNativeTransportMaxBackoffOnQueueOverload(TimeUnit.NANOSECONDS)));
|
||||
|
||||
public long markAndGetDelay(TimeUnit timeUnit)
|
||||
{
|
||||
return state.updateAndGet(Incident::mark).delay(timeUnit);
|
||||
}
|
||||
};
|
||||
|
||||
long markAndGetDelay(TimeUnit timeUnit);
|
||||
|
||||
static Incident noBackpressure(LongSupplier minDelayNanos, LongSupplier maxDelayNanos)
|
||||
{
|
||||
return new Incident(minDelayNanos, maxDelayNanos,
|
||||
-1, 0, 0);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
class Incident
|
||||
{
|
||||
private final long appliedAt;
|
||||
|
||||
private final int severityLevel;
|
||||
private final int appliedTimes;
|
||||
|
||||
private final LongSupplier minDelayNanos;
|
||||
private final LongSupplier maxDelayNanos;
|
||||
|
||||
@VisibleForTesting
|
||||
public Incident(LongSupplier minDelayNanos, LongSupplier maxDelayNanos, long appliedAt, int severityLevel, int appliedTimes)
|
||||
{
|
||||
this.minDelayNanos = minDelayNanos;
|
||||
this.maxDelayNanos = maxDelayNanos;
|
||||
this.appliedAt = appliedAt;
|
||||
this.severityLevel = severityLevel;
|
||||
this.appliedTimes = appliedTimes;
|
||||
}
|
||||
|
||||
public Incident mark()
|
||||
{
|
||||
return mark(preciseTime.now());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public Incident mark(long now)
|
||||
{
|
||||
// Last time we have applied backpressure was over a second ago, consider this a new incident
|
||||
if (appliedAt > 0 && now - appliedAt >= TimeUnit.SECONDS.toNanos(1))
|
||||
{
|
||||
return new Incident(minDelayNanos, maxDelayNanos, now, 1, 1);
|
||||
}
|
||||
// Continuing incident: apply backpressure but do not bump severity level yet
|
||||
else if (appliedTimes < 10)
|
||||
{
|
||||
return new Incident(minDelayNanos, maxDelayNanos, now, severityLevel == 0 ? 1 : severityLevel, appliedTimes + 1);
|
||||
}
|
||||
//
|
||||
else
|
||||
{
|
||||
return new Incident(minDelayNanos, maxDelayNanos, now, severityLevel + 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
public long appliedAt()
|
||||
{
|
||||
return appliedAt;
|
||||
}
|
||||
|
||||
public long delay(TimeUnit timeUnit)
|
||||
{
|
||||
return timeUnit.convert(Math.min(maxDelayNanos(), severityLevel * minDelayNanos()), TimeUnit.NANOSECONDS);
|
||||
}
|
||||
|
||||
public long minDelayNanos()
|
||||
{
|
||||
return minDelayNanos.getAsLong();
|
||||
}
|
||||
|
||||
public long maxDelayNanos()
|
||||
{
|
||||
return maxDelayNanos.getAsLong();
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return "QueueBackpressure{" +
|
||||
"appliedAgo=" + (appliedAt == -1 ? "never" : TimeUnit.NANOSECONDS.toMillis(preciseTime.now() - appliedAt)) +
|
||||
", severityLevel=" + severityLevel +
|
||||
", appliedTimes=" + appliedTimes +
|
||||
", currentDelay=" + delay(TimeUnit.MILLISECONDS) + "ms" +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -22,7 +22,10 @@ import java.net.InetSocketAddress;
|
|||
import java.net.UnknownHostException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
|
@ -64,7 +67,7 @@ public class Server implements CassandraDaemon.Server
|
|||
private static final Logger logger = LoggerFactory.getLogger(Server.class);
|
||||
private static final boolean useEpoll = NativeTransportService.useEpoll();
|
||||
|
||||
private final ConnectionTracker connectionTracker = new ConnectionTracker();
|
||||
private final ConnectionTracker connectionTracker;
|
||||
|
||||
private final Connection.Factory connectionFactory = new Connection.Factory()
|
||||
{
|
||||
|
|
@ -79,7 +82,7 @@ public class Server implements CassandraDaemon.Server
|
|||
private final AtomicBoolean isRunning = new AtomicBoolean(false);
|
||||
private final PipelineConfigurator pipelineConfigurator;
|
||||
private final EventLoopGroup workerGroup;
|
||||
|
||||
private final Dispatcher dispatcher;
|
||||
private Server (Builder builder)
|
||||
{
|
||||
this.socket = builder.getSocket();
|
||||
|
|
@ -96,14 +99,16 @@ public class Server implements CassandraDaemon.Server
|
|||
workerGroup = new NioEventLoopGroup();
|
||||
}
|
||||
|
||||
dispatcher = new Dispatcher(DatabaseDescriptor.useNativeTransportLegacyFlusher());
|
||||
pipelineConfigurator = builder.pipelineConfigurator != null
|
||||
? builder.pipelineConfigurator
|
||||
: new PipelineConfigurator(useEpoll,
|
||||
DatabaseDescriptor.getRpcKeepAlive(),
|
||||
DatabaseDescriptor.useNativeTransportLegacyFlusher(),
|
||||
builder.tlsEncryptionPolicy);
|
||||
builder.tlsEncryptionPolicy,
|
||||
dispatcher);
|
||||
|
||||
EventNotifier notifier = builder.eventNotifier != null ? builder.eventNotifier : new EventNotifier();
|
||||
connectionTracker = new ConnectionTracker(isRunning::get);
|
||||
notifier.registerConnectionTracker(connectionTracker);
|
||||
StorageService.instance.register(notifier);
|
||||
Schema.instance.registerListener(notifier);
|
||||
|
|
@ -111,8 +116,13 @@ public class Server implements CassandraDaemon.Server
|
|||
|
||||
public void stop()
|
||||
{
|
||||
if (isRunning.compareAndSet(true, false))
|
||||
close();
|
||||
stop(false);
|
||||
}
|
||||
|
||||
public void stop(boolean force)
|
||||
{
|
||||
if (isRunning.compareAndSet(true, false))
|
||||
close(force);
|
||||
}
|
||||
|
||||
public boolean isRunning()
|
||||
|
|
@ -168,8 +178,15 @@ public class Server implements CassandraDaemon.Server
|
|||
connectionTracker.protocolVersionTracker.clear();
|
||||
}
|
||||
|
||||
private void close()
|
||||
|
||||
private void close(boolean force)
|
||||
{
|
||||
if (!force)
|
||||
{
|
||||
while (!dispatcher.isDone())
|
||||
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(100));
|
||||
}
|
||||
|
||||
// Close opened connections
|
||||
connectionTracker.closeAll();
|
||||
|
||||
|
|
@ -257,11 +274,13 @@ public class Server implements CassandraDaemon.Server
|
|||
public final ChannelGroup allChannels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
|
||||
private final EnumMap<Event.Type, ChannelGroup> groups = new EnumMap<>(Event.Type.class);
|
||||
private final ProtocolVersionTracker protocolVersionTracker = new ProtocolVersionTracker();
|
||||
private final BooleanSupplier isRunning;
|
||||
|
||||
public ConnectionTracker()
|
||||
private ConnectionTracker(BooleanSupplier isRunning)
|
||||
{
|
||||
for (Event.Type type : Event.Type.values())
|
||||
groups.put(type, new DefaultChannelGroup(type.toString(), GlobalEventExecutor.INSTANCE));
|
||||
this.isRunning = isRunning;
|
||||
}
|
||||
|
||||
public void addConnection(Channel ch, Connection connection)
|
||||
|
|
@ -272,6 +291,11 @@ public class Server implements CassandraDaemon.Server
|
|||
protocolVersionTracker.addConnection(((InetSocketAddress) ch.remoteAddress()).getAddress(), connection.getVersion());
|
||||
}
|
||||
|
||||
public boolean isRunning()
|
||||
{
|
||||
return isRunning.getAsBoolean();
|
||||
}
|
||||
|
||||
public void register(Event.Type type, Channel ch)
|
||||
{
|
||||
groups.get(type).add(ch);
|
||||
|
|
@ -293,7 +317,7 @@ public class Server implements CassandraDaemon.Server
|
|||
|
||||
void closeAll()
|
||||
{
|
||||
allChannels.close().awaitUninterruptibly();
|
||||
allChannels.flush().close().awaitUninterruptibly();
|
||||
}
|
||||
|
||||
int countConnectedClients()
|
||||
|
|
|
|||
|
|
@ -367,6 +367,12 @@ public class SimpleClient implements Closeable
|
|||
private static class ConnectionTracker implements Connection.Tracker
|
||||
{
|
||||
public void addConnection(Channel ch, Connection connection) {}
|
||||
|
||||
@Override
|
||||
public boolean isRunning()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static class HandlerNames
|
||||
|
|
@ -447,8 +453,17 @@ public class SimpleClient implements Closeable
|
|||
FrameEncoder frameEncoder = frameEncoder(ctx);
|
||||
FrameEncoder.PayloadAllocator payloadAllocator = frameEncoder.allocator();
|
||||
|
||||
CQLMessageHandler.MessageConsumer<Message.Response> responseConsumer = (c, message, converter, backpressured) -> {
|
||||
responseHandler.handleResponse(c, message);
|
||||
CQLMessageHandler.MessageConsumer<Message.Response> responseConsumer = new CQLMessageHandler.MessageConsumer<Message.Response>()
|
||||
{
|
||||
public void dispatch(Channel channel, Message.Response message, Dispatcher.FlushItemConverter toFlushItem, Overload backpressure)
|
||||
{
|
||||
responseHandler.handleResponse(channel, message);
|
||||
}
|
||||
|
||||
public boolean hasQueueCapacity()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
CQLMessageHandler.ErrorHandler errorHandler = (error) -> {
|
||||
|
|
@ -503,6 +518,7 @@ public class SimpleClient implements Closeable
|
|||
responseConsumer,
|
||||
payloadAllocator,
|
||||
queueCapacity,
|
||||
QueueBackpressure.NO_OP,
|
||||
resources,
|
||||
handler -> {},
|
||||
errorHandler,
|
||||
|
|
@ -541,7 +557,7 @@ public class SimpleClient implements Closeable
|
|||
pipeline.remove(this);
|
||||
|
||||
Message.Response message = messageDecoder.decode(ctx.channel(), response);
|
||||
responseConsumer.accept(channel, message, (ch, req, resp) -> null, Overload.NONE);
|
||||
responseConsumer.dispatch(channel, message, (ch, req, resp) -> null, Overload.NONE);
|
||||
}
|
||||
|
||||
private FrameDecoder frameDecoder(ChannelHandlerContext ctx, BufferPoolAllocator allocator)
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ public class AuthResponse extends Message.Request
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Response execute(QueryState queryState, long queryStartNanoTime, boolean traceRequest)
|
||||
protected Response execute(QueryState queryState, Dispatcher.RequestTime requestTime, boolean traceRequest)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ import org.apache.cassandra.service.ClientState;
|
|||
import org.apache.cassandra.service.QueryState;
|
||||
import org.apache.cassandra.tracing.Tracing;
|
||||
import org.apache.cassandra.transport.CBUtil;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.transport.Message;
|
||||
import org.apache.cassandra.transport.ProtocolException;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
|
|
@ -169,7 +170,7 @@ public class BatchMessage extends Message.Request
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Message.Response execute(QueryState state, long queryStartNanoTime, boolean traceRequest)
|
||||
protected Message.Response execute(QueryState state, Dispatcher.RequestTime requestTime, boolean traceRequest)
|
||||
{
|
||||
List<QueryHandler.Prepared> prepared = null;
|
||||
try
|
||||
|
|
@ -226,7 +227,7 @@ public class BatchMessage extends Message.Request
|
|||
BatchStatement batch = new BatchStatement(batchType, VariableSpecifications.empty(), statements, Attributes.none());
|
||||
|
||||
long queryTime = currentTimeMillis();
|
||||
Message.Response response = handler.processBatch(batch, state, batchOptions, getCustomPayload(), queryStartNanoTime);
|
||||
Message.Response response = handler.processBatch(batch, state, batchOptions, getCustomPayload(), requestTime);
|
||||
if (queries != null)
|
||||
QueryEvents.instance.notifyBatchSuccess(batchType, statements, queries, values, options, state, queryTime, response);
|
||||
return response;
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import org.apache.cassandra.service.ClientState;
|
|||
import org.apache.cassandra.service.QueryState;
|
||||
import org.apache.cassandra.tracing.Tracing;
|
||||
import org.apache.cassandra.transport.CBUtil;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.transport.Message;
|
||||
import org.apache.cassandra.transport.ProtocolException;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
|
|
@ -125,7 +126,7 @@ public class ExecuteMessage extends Message.Request
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Message.Response execute(QueryState state, long queryStartNanoTime, boolean traceRequest)
|
||||
protected Message.Response execute(QueryState state, Dispatcher.RequestTime requestTime, boolean traceRequest)
|
||||
{
|
||||
QueryHandler.Prepared prepared = null;
|
||||
try
|
||||
|
|
@ -148,7 +149,6 @@ public class ExecuteMessage extends Message.Request
|
|||
nospam.error(msg);
|
||||
}
|
||||
|
||||
|
||||
CQLStatement statement = prepared.statement;
|
||||
options.prepare(statement.getBindVariables());
|
||||
|
||||
|
|
@ -164,7 +164,7 @@ public class ExecuteMessage extends Message.Request
|
|||
|
||||
long requestStartTime = currentTimeMillis();
|
||||
|
||||
Message.Response response = handler.processPrepared(statement, state, queryOptions, getCustomPayload(), queryStartNanoTime);
|
||||
Message.Response response = handler.processPrepared(statement, state, queryOptions, getCustomPayload(), requestTime);
|
||||
|
||||
QueryEvents.instance.notifyExecuteSuccess(prepared.statement, prepared.rawCQLStatement, options, state, requestStartTime, response);
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import io.netty.buffer.ByteBuf;
|
|||
import org.apache.cassandra.cql3.QueryProcessor;
|
||||
import org.apache.cassandra.service.QueryState;
|
||||
import org.apache.cassandra.transport.Compressor;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.transport.Message;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
|
||||
|
|
@ -58,7 +59,7 @@ public class OptionsMessage extends Message.Request
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Message.Response execute(QueryState state, long queryStartNanoTime, boolean traceRequest)
|
||||
protected Message.Response execute(QueryState state, Dispatcher.RequestTime requestTime, boolean traceRequest)
|
||||
{
|
||||
List<String> cqlVersions = new ArrayList<String>();
|
||||
cqlVersions.add(QueryProcessor.CQL_VERSION.toString());
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import org.apache.cassandra.service.ClientState;
|
|||
import org.apache.cassandra.service.QueryState;
|
||||
import org.apache.cassandra.tracing.Tracing;
|
||||
import org.apache.cassandra.transport.CBUtil;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.transport.Message;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
import org.apache.cassandra.utils.JVMStabilityInspector;
|
||||
|
|
@ -114,7 +115,7 @@ public class PrepareMessage extends Message.Request
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Message.Response execute(QueryState state, long queryStartNanoTime, boolean traceRequest)
|
||||
protected Message.Response execute(QueryState state, Dispatcher.RequestTime requestTime, boolean traceRequest)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import org.apache.cassandra.service.ClientState;
|
|||
import org.apache.cassandra.service.QueryState;
|
||||
import org.apache.cassandra.tracing.Tracing;
|
||||
import org.apache.cassandra.transport.CBUtil;
|
||||
import org.apache.cassandra.transport.Dispatcher;
|
||||
import org.apache.cassandra.transport.Message;
|
||||
import org.apache.cassandra.transport.ProtocolException;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
|
|
@ -98,7 +99,7 @@ public class QueryMessage extends Message.Request
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Message.Response execute(QueryState state, long queryStartNanoTime, boolean traceRequest)
|
||||
protected Message.Response execute(QueryState state, Dispatcher.RequestTime requestTime, boolean traceRequest)
|
||||
{
|
||||
CQLStatement statement = null;
|
||||
try
|
||||
|
|
@ -113,7 +114,7 @@ public class QueryMessage extends Message.Request
|
|||
|
||||
QueryHandler queryHandler = ClientState.getCQLQueryHandler();
|
||||
statement = queryHandler.parse(query, state, options);
|
||||
Message.Response response = queryHandler.process(statement, state, options, getCustomPayload(), queryStartNanoTime);
|
||||
Message.Response response = queryHandler.process(statement, state, options, getCustomPayload(), requestTime);
|
||||
QueryEvents.instance.notifyQuerySuccess(statement, query, options, state, queryStartTime, response);
|
||||
|
||||
if (options.skipMetadata() && response instanceof ResultMessage.Rows)
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ public class RegisterMessage extends Message.Request
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Response execute(QueryState state, long queryStartNanoTime, boolean traceRequest)
|
||||
protected Response execute(QueryState state, Dispatcher.RequestTime requestTime, boolean traceRequest)
|
||||
{
|
||||
assert connection instanceof ServerConnection;
|
||||
Connection.Tracker tracker = connection.getTracker();
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ public class StartupMessage extends Message.Request
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Message.Response execute(QueryState state, long queryStartNanoTime, boolean traceRequest)
|
||||
protected Message.Response execute(QueryState state, Dispatcher.RequestTime requestTime, boolean traceRequest)
|
||||
{
|
||||
String cqlVersion = options.get(CQL_VERSION);
|
||||
if (cqlVersion == null)
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ public class DriverBurnTest extends CQLTester
|
|||
{
|
||||
QueryMessage queryMessage = QueryMessage.codec.decode(body, version);
|
||||
return new QueryMessage(queryMessage.query, queryMessage.options) {
|
||||
protected Message.Response execute(QueryState state, long queryStartNanoTime, boolean traceRequest)
|
||||
protected Message.Response execute(QueryState state, Dispatcher.RequestTime requestTime, boolean traceRequest)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
@ -89,7 +89,7 @@ public class DriverBurnTest extends CQLTester
|
|||
catch (NumberFormatException e)
|
||||
{
|
||||
// for the requests driver issues under the hood
|
||||
return super.execute(state, queryStartNanoTime, traceRequest);
|
||||
return super.execute(state, requestTime, traceRequest);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -338,7 +338,7 @@ public class DriverBurnTest extends CQLTester
|
|||
{
|
||||
QueryMessage queryMessage = QueryMessage.codec.decode(body, version);
|
||||
return new QueryMessage(queryMessage.query, queryMessage.options) {
|
||||
protected Message.Response execute(QueryState state, long queryStartNanoTime, boolean traceRequest)
|
||||
protected Message.Response execute(QueryState state, Dispatcher.RequestTime requestTime, boolean traceRequest)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
@ -348,7 +348,7 @@ public class DriverBurnTest extends CQLTester
|
|||
catch (NumberFormatException e)
|
||||
{
|
||||
// for the requests driver issues under the hood
|
||||
return super.execute(state, queryStartNanoTime, traceRequest);
|
||||
return super.execute(state, requestTime, traceRequest);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue