mirror of https://github.com/apache/cassandra
Accord Query Tracing
Also improve: - Metric listeners patch by Benedict; reviewed by David Capwell for CASSANDRA-20773
This commit is contained in:
parent
88805177d2
commit
fbe12e6291
|
|
@ -1 +1 @@
|
||||||
Subproject commit e66a30cd944e902ad2749b5182e1f0d56903303f
|
Subproject commit f40826db9571af286a689deada1613ffc872e5f8
|
||||||
|
|
@ -92,8 +92,9 @@ public class ExecutorLocals implements WithResources, Closeable
|
||||||
/**
|
/**
|
||||||
* Overwrite current locals, and return the previous ones
|
* Overwrite current locals, and return the previous ones
|
||||||
*/
|
*/
|
||||||
public Closeable get()
|
public ExecutorLocals get()
|
||||||
{
|
{
|
||||||
|
// TODO (desired): add compareAndSet to save one thread local round trip
|
||||||
ExecutorLocals old = current();
|
ExecutorLocals old = current();
|
||||||
if (old != this)
|
if (old != this)
|
||||||
locals.set(this);
|
locals.set(this);
|
||||||
|
|
|
||||||
|
|
@ -20,18 +20,31 @@ package org.apache.cassandra.metrics;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
import accord.api.EventListener;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import accord.api.CoordinatorEventListener;
|
||||||
|
import accord.api.LocalEventListener;
|
||||||
|
import accord.api.Result;
|
||||||
|
import accord.coordinate.ExecutePath;
|
||||||
|
import accord.impl.progresslog.DefaultProgressLog;
|
||||||
import accord.local.Command;
|
import accord.local.Command;
|
||||||
|
import accord.local.Node;
|
||||||
|
import accord.local.SafeCommandStore;
|
||||||
|
import accord.primitives.Ballot;
|
||||||
import accord.primitives.Deps;
|
import accord.primitives.Deps;
|
||||||
import accord.primitives.PartialDeps;
|
import accord.primitives.PartialDeps;
|
||||||
import accord.primitives.Timestamp;
|
import accord.primitives.Timestamp;
|
||||||
import accord.primitives.TxnId;
|
import accord.primitives.TxnId;
|
||||||
import com.codahale.metrics.Counting;
|
import com.codahale.metrics.Counting;
|
||||||
|
import com.codahale.metrics.Gauge;
|
||||||
import com.codahale.metrics.Histogram;
|
import com.codahale.metrics.Histogram;
|
||||||
import com.codahale.metrics.Meter;
|
import com.codahale.metrics.Meter;
|
||||||
import com.codahale.metrics.Timer;
|
import com.codahale.metrics.Timer;
|
||||||
|
import org.apache.cassandra.service.accord.AccordService;
|
||||||
import org.apache.cassandra.service.accord.api.AccordTimeService;
|
import org.apache.cassandra.service.accord.api.AccordTimeService;
|
||||||
|
import org.apache.cassandra.tracing.Tracing;
|
||||||
|
|
||||||
import static java.util.concurrent.TimeUnit.MICROSECONDS;
|
import static java.util.concurrent.TimeUnit.MICROSECONDS;
|
||||||
import static org.apache.cassandra.metrics.CassandraMetricsRegistry.Metrics;
|
import static org.apache.cassandra.metrics.CassandraMetricsRegistry.Metrics;
|
||||||
|
|
@ -41,16 +54,21 @@ public class AccordMetrics
|
||||||
public final static AccordMetrics readMetrics = new AccordMetrics("ro");
|
public final static AccordMetrics readMetrics = new AccordMetrics("ro");
|
||||||
public final static AccordMetrics writeMetrics = new AccordMetrics("rw");
|
public final static AccordMetrics writeMetrics = new AccordMetrics("rw");
|
||||||
|
|
||||||
public static final String STABLE_LATENCY = "StableLatency";
|
public static final String ACCORD_REPLICA = "AccordReplica";
|
||||||
public static final String PREAPPLY_LATENCY = "PreApplyLatency";
|
public static final String REPLICA_STABLE_LATENCY = "StableLatency";
|
||||||
public static final String APPLY_LATENCY = "ApplyLatency";
|
public static final String REPLICA_PREAPPLY_LATENCY = "PreApplyLatency";
|
||||||
public static final String APPLY_DURATION = "ApplyDuration";
|
public static final String REPLICA_APPLY_LATENCY = "ApplyLatency";
|
||||||
public static final String PARTIAL_DEPENDENCIES = "PartialDependencies";
|
public static final String REPLICA_APPLY_DURATION = "ApplyDuration";
|
||||||
|
public static final String REPLICA_DEPENDENCIES = "Dependencies";
|
||||||
public static final String PROGRESS_LOG_SIZE = "ProgressLogSize";
|
public static final String PROGRESS_LOG_SIZE = "ProgressLogSize";
|
||||||
|
|
||||||
public static final String DEPENDENCIES = "Dependencies";
|
public static final String ACCORD_COORDINATOR = "AccordCoordinator";
|
||||||
public static final String EPHEMERAL = "Ephemeral";
|
public static final String COORDINATOR_DEPENDENCIES = "Dependencies";
|
||||||
|
public static final String COORDINATOR_PREACCEPT_LATENCY = "PreAcceptLatency";
|
||||||
|
public static final String COORDINATOR_EXECUTE_LATENCY = "ExecuteLatency";
|
||||||
|
public static final String COORDINATOR_APPLY_LATENCY = "ApplyLatency";
|
||||||
public static final String FAST_PATHS = "FastPaths";
|
public static final String FAST_PATHS = "FastPaths";
|
||||||
|
public static final String MEDIUM_PATHS = "MediumPaths";
|
||||||
public static final String SLOW_PATHS = "SlowPaths";
|
public static final String SLOW_PATHS = "SlowPaths";
|
||||||
public static final String PREEMPTS = "Preempts";
|
public static final String PREEMPTS = "Preempts";
|
||||||
public static final String TIMEOUTS = "Timeouts";
|
public static final String TIMEOUTS = "Timeouts";
|
||||||
|
|
@ -58,51 +76,66 @@ public class AccordMetrics
|
||||||
public static final String RECOVERY_DELAY = "RecoveryDelay";
|
public static final String RECOVERY_DELAY = "RecoveryDelay";
|
||||||
public static final String RECOVERY_TIME = "RecoveryTime";
|
public static final String RECOVERY_TIME = "RecoveryTime";
|
||||||
public static final String FAST_PATH_TO_TOTAL = "FastPathToTotal";
|
public static final String FAST_PATH_TO_TOTAL = "FastPathToTotal";
|
||||||
public static final String ACCORD_REPLICA = "AccordReplica";
|
|
||||||
public static final String ACCORD_COORDINATOR = "AccordCoordinator";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The time between start on the coordinator and commit on this replica.
|
* The time between start on the coordinator and commit on this replica.
|
||||||
*/
|
*/
|
||||||
public final Timer stableLatency;
|
public final Timer replicaStableLatency;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The time between start on the coordinator and arrival of the result on this replica.
|
* The time between start on the coordinator and arrival of the result on this replica.
|
||||||
*/
|
*/
|
||||||
public final Timer preapplyLatency;
|
public final Timer replicaPreapplyLatency;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The time between start on the coordinator and application on this replica.
|
* The time between start on the coordinator and application on this replica.
|
||||||
*/
|
*/
|
||||||
public final Timer applyLatency;
|
public final Timer replicaApplyLatency;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO (expected): probably more interesting is latency from preapplied to apply;
|
* TODO (expected): probably more interesting is latency from preapplied to apply;
|
||||||
* we already track local write latencies, whch this effectively duplicates (but including queueing latencies)
|
* we already track local write latencies, whch this effectively duplicates (but including queueing latencies)
|
||||||
* Duration of applying changes.
|
* Duration of applying changes.
|
||||||
*/
|
*/
|
||||||
public final Timer applyDuration;
|
public final Timer replicaApplyDuration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A histogram of the number of dependencies per transaction at this replica.
|
* A histogram of the number of dependencies per transaction at this replica.
|
||||||
*/
|
*/
|
||||||
public final Histogram localDependencies;
|
public final Histogram replicaDependencies;
|
||||||
|
|
||||||
/**
|
public final Gauge<Long> progressLogSize;
|
||||||
* TODO (expected): this should be a Gauge
|
|
||||||
*/
|
|
||||||
public final Meter progressLogSize;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A histogram of the number of dependencies per transaction at this coordinator.
|
* A histogram of the number of dependencies per transaction at this coordinator.
|
||||||
*/
|
*/
|
||||||
public final Histogram coordinatorDependencies;
|
public final Histogram coordinatorDependencies;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A histogram of the time to preaccept on this coordinator
|
||||||
|
*/
|
||||||
|
public final Histogram coordinatorPreacceptLatency;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A histogram of the time to begin execution on this coordinator
|
||||||
|
*/
|
||||||
|
public final Histogram coordinatorExecuteLatency;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A histogram of the time to complete execution on this coordinator
|
||||||
|
*/
|
||||||
|
public final Histogram coordinatorApplyLatency;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The number of fast path transactions executed on this coordinator.
|
* The number of fast path transactions executed on this coordinator.
|
||||||
*/
|
*/
|
||||||
public final Meter fastPaths;
|
public final Meter fastPaths;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of medium path transactions executed on this coordinator.
|
||||||
|
*/
|
||||||
|
public final Meter mediumPaths;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The number of slow path transactions executed on this coordinator.
|
* The number of slow path transactions executed on this coordinator.
|
||||||
*/
|
*/
|
||||||
|
|
@ -141,23 +174,33 @@ public class AccordMetrics
|
||||||
private AccordMetrics(String scope)
|
private AccordMetrics(String scope)
|
||||||
{
|
{
|
||||||
DefaultNameFactory replica = new DefaultNameFactory(ACCORD_REPLICA, scope);
|
DefaultNameFactory replica = new DefaultNameFactory(ACCORD_REPLICA, scope);
|
||||||
stableLatency = Metrics.timer(replica.createMetricName(STABLE_LATENCY));
|
replicaStableLatency = Metrics.timer(replica.createMetricName(REPLICA_STABLE_LATENCY));
|
||||||
preapplyLatency = Metrics.timer(replica.createMetricName(PREAPPLY_LATENCY));
|
replicaPreapplyLatency = Metrics.timer(replica.createMetricName(REPLICA_PREAPPLY_LATENCY));
|
||||||
applyLatency = Metrics.timer(replica.createMetricName(APPLY_LATENCY));
|
replicaApplyLatency = Metrics.timer(replica.createMetricName(REPLICA_APPLY_LATENCY));
|
||||||
applyDuration = Metrics.timer(replica.createMetricName(APPLY_DURATION));
|
replicaApplyDuration = Metrics.timer(replica.createMetricName(REPLICA_APPLY_DURATION));
|
||||||
localDependencies = Metrics.histogram(replica.createMetricName(PARTIAL_DEPENDENCIES), true);
|
replicaDependencies = Metrics.histogram(replica.createMetricName(REPLICA_DEPENDENCIES), true);
|
||||||
progressLogSize = Metrics.meter(replica.createMetricName(PROGRESS_LOG_SIZE));
|
progressLogSize = Metrics.gauge(replica.createMetricName(PROGRESS_LOG_SIZE), () -> {
|
||||||
|
AtomicLong i = new AtomicLong();
|
||||||
|
AccordService.instance().node().commandStores().forEachCommandStore(store -> {
|
||||||
|
i.addAndGet(((DefaultProgressLog)store.unsafeProgressLog()).size());
|
||||||
|
});
|
||||||
|
return i.get();
|
||||||
|
});
|
||||||
|
|
||||||
DefaultNameFactory coordinator = new DefaultNameFactory(ACCORD_COORDINATOR, scope);
|
DefaultNameFactory coordinator = new DefaultNameFactory(ACCORD_COORDINATOR, scope);
|
||||||
coordinatorDependencies = Metrics.histogram(coordinator.createMetricName(DEPENDENCIES), true);
|
coordinatorDependencies = Metrics.histogram(coordinator.createMetricName(COORDINATOR_DEPENDENCIES), true);
|
||||||
|
coordinatorPreacceptLatency = Metrics.histogram(coordinator.createMetricName(COORDINATOR_PREACCEPT_LATENCY), true);
|
||||||
|
coordinatorExecuteLatency = Metrics.histogram(coordinator.createMetricName(COORDINATOR_EXECUTE_LATENCY), true);
|
||||||
|
coordinatorApplyLatency = Metrics.histogram(coordinator.createMetricName(COORDINATOR_APPLY_LATENCY), true);
|
||||||
fastPaths = Metrics.meter(coordinator.createMetricName(FAST_PATHS));
|
fastPaths = Metrics.meter(coordinator.createMetricName(FAST_PATHS));
|
||||||
|
mediumPaths = Metrics.meter(coordinator.createMetricName(MEDIUM_PATHS));
|
||||||
slowPaths = Metrics.meter(coordinator.createMetricName(SLOW_PATHS));
|
slowPaths = Metrics.meter(coordinator.createMetricName(SLOW_PATHS));
|
||||||
preempts = Metrics.meter(coordinator.createMetricName(PREEMPTS));
|
preempts = Metrics.meter(coordinator.createMetricName(PREEMPTS));
|
||||||
timeouts = Metrics.meter(coordinator.createMetricName(TIMEOUTS));
|
timeouts = Metrics.meter(coordinator.createMetricName(TIMEOUTS));
|
||||||
invalidations = Metrics.meter(coordinator.createMetricName(INVALIDATIONS));
|
invalidations = Metrics.meter(coordinator.createMetricName(INVALIDATIONS));
|
||||||
recoveryDelay = Metrics.timer(coordinator.createMetricName(RECOVERY_DELAY));
|
recoveryDelay = Metrics.timer(coordinator.createMetricName(RECOVERY_DELAY));
|
||||||
recoveryDuration = Metrics.timer(coordinator.createMetricName(RECOVERY_TIME));
|
recoveryDuration = Metrics.timer(coordinator.createMetricName(RECOVERY_TIME));
|
||||||
fastPathToTotal = new RatioGaugeSet(fastPaths, RatioGaugeSet.sum(fastPaths, slowPaths), coordinator, FAST_PATH_TO_TOTAL + ".%s");
|
fastPathToTotal = new RatioGaugeSet(fastPaths, RatioGaugeSet.sum(fastPaths, mediumPaths, slowPaths), coordinator, FAST_PATH_TO_TOTAL + ".%s");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -186,7 +229,7 @@ public class AccordMetrics
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Listener implements EventListener
|
public static class Listener implements CoordinatorEventListener, LocalEventListener
|
||||||
{
|
{
|
||||||
public final static Listener instance = new Listener(AccordMetrics.readMetrics, AccordMetrics.writeMetrics);
|
public final static Listener instance = new Listener(AccordMetrics.readMetrics, AccordMetrics.writeMetrics);
|
||||||
|
|
||||||
|
|
@ -212,112 +255,112 @@ public class AccordMetrics
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStable(Command cmd)
|
public void onStable(SafeCommandStore safeStore, Command cmd)
|
||||||
{
|
{
|
||||||
|
Tracing.trace("Stable {} on {}", cmd.txnId(), safeStore.commandStore());
|
||||||
long now = AccordTimeService.nowMicros();
|
long now = AccordTimeService.nowMicros();
|
||||||
AccordMetrics metrics = forTransaction(cmd.txnId());
|
AccordMetrics metrics = forTransaction(cmd.txnId());
|
||||||
if (metrics != null)
|
if (metrics != null)
|
||||||
{
|
{
|
||||||
long trxTimestamp = cmd.txnId().hlc();
|
long trxTimestamp = cmd.txnId().hlc();
|
||||||
metrics.stableLatency.update(now - trxTimestamp, TimeUnit.MICROSECONDS);
|
metrics.replicaStableLatency.update(now - trxTimestamp, TimeUnit.MICROSECONDS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPreApplied(Command cmd)
|
public void onPreApplied(SafeCommandStore safeStore, Command cmd)
|
||||||
{
|
{
|
||||||
|
Tracing.trace("Preapplied {} on {}", cmd.txnId(), safeStore.commandStore());
|
||||||
long now = AccordTimeService.nowMicros();
|
long now = AccordTimeService.nowMicros();
|
||||||
AccordMetrics metrics = forTransaction(cmd.txnId());
|
AccordMetrics metrics = forTransaction(cmd.txnId());
|
||||||
if (metrics != null)
|
if (metrics != null)
|
||||||
{
|
{
|
||||||
Timestamp trxTimestamp = cmd.txnId();
|
Timestamp trxTimestamp = cmd.txnId();
|
||||||
metrics.preapplyLatency.update(now - trxTimestamp.hlc(), TimeUnit.MICROSECONDS);
|
metrics.replicaPreapplyLatency.update(now - trxTimestamp.hlc(), TimeUnit.MICROSECONDS);
|
||||||
PartialDeps deps = cmd.partialDeps();
|
PartialDeps deps = cmd.partialDeps();
|
||||||
metrics.localDependencies.update(deps != null ? deps.txnIdCount() : 0);
|
metrics.replicaDependencies.update(deps != null ? deps.txnIdCount() : 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onApplied(Command cmd, long applyStartTimestamp)
|
public void onApplied(SafeCommandStore safeStore, Command cmd, long applyStartedAt)
|
||||||
{
|
{
|
||||||
|
Tracing.trace("Applied {} on {}", cmd.txnId(), safeStore.commandStore());
|
||||||
long now = AccordTimeService.nowMicros();
|
long now = AccordTimeService.nowMicros();
|
||||||
AccordMetrics metrics = forTransaction(cmd.txnId());
|
AccordMetrics metrics = forTransaction(cmd.txnId());
|
||||||
if (metrics != null)
|
if (metrics != null)
|
||||||
{
|
{
|
||||||
Timestamp trxTimestamp = cmd.txnId();
|
Timestamp trxTimestamp = cmd.txnId();
|
||||||
metrics.applyLatency.update(now - trxTimestamp.hlc(), TimeUnit.MICROSECONDS);
|
metrics.replicaApplyLatency.update(now - trxTimestamp.hlc(), TimeUnit.MICROSECONDS);
|
||||||
if (applyStartTimestamp > 0)
|
if (applyStartedAt > 0)
|
||||||
metrics.applyDuration.update(now - applyStartTimestamp, TimeUnit.MICROSECONDS);
|
metrics.replicaApplyDuration.update(now - applyStartedAt, TimeUnit.MICROSECONDS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFastPathTaken(TxnId txnId, Deps deps)
|
public void onPreAccepted(TxnId txnId)
|
||||||
{
|
{
|
||||||
AccordMetrics metrics = forTransaction(txnId);
|
AccordMetrics metrics = forTransaction(txnId);
|
||||||
if (metrics != null)
|
if (metrics != null)
|
||||||
{
|
{
|
||||||
metrics.fastPaths.mark();
|
long now = AccordTimeService.nowMicros();
|
||||||
metrics.coordinatorDependencies.update(deps.txnIdCount());
|
metrics.coordinatorPreacceptLatency.update(Math.max(0, now - txnId.hlc()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSlowPathTaken(TxnId txnId, Deps deps)
|
public void onExecuting(TxnId txnId, @Nullable Ballot ballot, Deps deps, @Nullable ExecutePath path)
|
||||||
|
{
|
||||||
|
Tracing.trace("{} agreed {}", path, txnId);
|
||||||
|
AccordMetrics metrics = forTransaction(txnId);
|
||||||
|
if (metrics != null)
|
||||||
|
{
|
||||||
|
metrics.coordinatorDependencies.update(deps.txnIdCount());
|
||||||
|
long now = AccordTimeService.nowMicros();
|
||||||
|
metrics.coordinatorExecuteLatency.update(Math.max(0, now - txnId.hlc()));
|
||||||
|
if (path != null)
|
||||||
|
{
|
||||||
|
switch (path)
|
||||||
|
{
|
||||||
|
case FAST: metrics.fastPaths.mark(); break;
|
||||||
|
case MEDIUM: metrics.mediumPaths.mark(); break;
|
||||||
|
case SLOW: metrics.slowPaths.mark(); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onExecuted(TxnId txnId, Ballot ballot)
|
||||||
{
|
{
|
||||||
AccordMetrics metrics = forTransaction(txnId);
|
AccordMetrics metrics = forTransaction(txnId);
|
||||||
if (metrics != null)
|
if (metrics != null)
|
||||||
{
|
{
|
||||||
metrics.slowPaths.mark();
|
long now = AccordTimeService.nowMicros();
|
||||||
metrics.coordinatorDependencies.update(deps.txnIdCount());
|
metrics.coordinatorApplyLatency.update(Math.max(0, now - txnId.hlc()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRecover(TxnId txnId, Timestamp recoveryTimestamp)
|
public void onRecoveryStopped(Node node, TxnId txnId, Ballot ballot, Result result, Throwable failure)
|
||||||
{
|
{
|
||||||
AccordMetrics metrics = forTransaction(txnId);
|
AccordMetrics metrics = forTransaction(txnId);
|
||||||
if (metrics != null)
|
if (metrics != null)
|
||||||
{
|
{
|
||||||
long now = AccordTimeService.nowMicros();
|
long now = AccordTimeService.nowMicros();
|
||||||
|
|
||||||
metrics.recoveryDuration.update(now - recoveryTimestamp.hlc(), MICROSECONDS);
|
metrics.recoveryDuration.update(Math.max(0, now - ballot.hlc()), MICROSECONDS);
|
||||||
metrics.recoveryDelay.update(recoveryTimestamp.hlc() - txnId.hlc(), MICROSECONDS);
|
metrics.recoveryDelay.update(Math.max(0, ballot.hlc() - txnId.hlc()), MICROSECONDS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPreempted(TxnId txnId)
|
|
||||||
{
|
|
||||||
AccordMetrics metrics = forTransaction(txnId);
|
|
||||||
if (metrics != null)
|
|
||||||
metrics.preempts.mark();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTimeout(TxnId txnId)
|
|
||||||
{
|
|
||||||
// TODO (required): we appear to be marking this twice, once in AccordResult and once here.
|
|
||||||
// why does AccordMetricsTest only see this one? remove duplication.
|
|
||||||
AccordMetrics metrics = forTransaction(txnId);
|
|
||||||
if (metrics != null)
|
|
||||||
metrics.timeouts.mark();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onInvalidated(TxnId txnId)
|
public void onInvalidated(TxnId txnId)
|
||||||
{
|
{
|
||||||
|
Tracing.trace("Invalidated {}", txnId);
|
||||||
AccordMetrics metrics = forTransaction(txnId);
|
AccordMetrics metrics = forTransaction(txnId);
|
||||||
if (metrics != null)
|
if (metrics != null)
|
||||||
metrics.invalidations.mark();
|
metrics.invalidations.mark();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onProgressLogSizeChange(TxnId txnId, int delta)
|
|
||||||
{
|
|
||||||
AccordMetrics metrics = forTransaction(txnId);
|
|
||||||
if (metrics != null)
|
|
||||||
metrics.progressLogSize.mark(delta);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,10 @@ import accord.utils.async.AsyncChains;
|
||||||
import accord.utils.async.AsyncResults.CountingResult;
|
import accord.utils.async.AsyncResults.CountingResult;
|
||||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||||
import org.apache.cassandra.db.ColumnFamilyStore;
|
import org.apache.cassandra.db.ColumnFamilyStore;
|
||||||
|
import org.apache.cassandra.schema.Schema;
|
||||||
import org.apache.cassandra.schema.TableId;
|
import org.apache.cassandra.schema.TableId;
|
||||||
|
import org.apache.cassandra.schema.TableMetadata;
|
||||||
|
import org.apache.cassandra.schema.TableMetadataRef;
|
||||||
import org.apache.cassandra.service.accord.AccordKeyspace.CommandsForKeyAccessor;
|
import org.apache.cassandra.service.accord.AccordKeyspace.CommandsForKeyAccessor;
|
||||||
import org.apache.cassandra.service.accord.IAccordService.AccordCompactionInfo;
|
import org.apache.cassandra.service.accord.IAccordService.AccordCompactionInfo;
|
||||||
import org.apache.cassandra.service.accord.api.TokenKey;
|
import org.apache.cassandra.service.accord.api.TokenKey;
|
||||||
|
|
@ -159,6 +162,7 @@ public class AccordCommandStore extends CommandStore
|
||||||
private long lastSystemTimestampMicros = Long.MIN_VALUE;
|
private long lastSystemTimestampMicros = Long.MIN_VALUE;
|
||||||
private final CommandsForRanges.Manager commandsForRanges;
|
private final CommandsForRanges.Manager commandsForRanges;
|
||||||
private final TableId tableId;
|
private final TableId tableId;
|
||||||
|
private TableMetadataRef metadata;
|
||||||
volatile SafeRedundantBefore safeRedundantBefore;
|
volatile SafeRedundantBefore safeRedundantBefore;
|
||||||
|
|
||||||
private AccordSafeCommandStore current;
|
private AccordSafeCommandStore current;
|
||||||
|
|
@ -502,7 +506,7 @@ public class AccordCommandStore extends CommandStore
|
||||||
protected void ensureDurable(Ranges ranges, RedundantBefore onCommandStoreDurable)
|
protected void ensureDurable(Ranges ranges, RedundantBefore onCommandStoreDurable)
|
||||||
{
|
{
|
||||||
long reportId = nextDurabilityLoggingId.incrementAndGet();
|
long reportId = nextDurabilityLoggingId.incrementAndGet();
|
||||||
logger.info("{} awaiting local metadata durability for {} ({})", this, ranges, reportId);
|
logger.debug("{} awaiting local metadata durability for {} ({})", this, ranges, reportId);
|
||||||
executor().afterSubmittedAndConsequences(() -> {
|
executor().afterSubmittedAndConsequences(() -> {
|
||||||
logger.debug("{}: saving intersecting keys ({})", this, reportId);
|
logger.debug("{}: saving intersecting keys ({})", this, reportId);
|
||||||
class Ready extends CountingResult implements Runnable
|
class Ready extends CountingResult implements Runnable
|
||||||
|
|
@ -640,4 +644,29 @@ public class AccordCommandStore extends CommandStore
|
||||||
return a.ticket >= b.ticket ? a : b;
|
return a.ticket >= b.ticket ? a : b;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private @Nullable TableMetadata tableMetadata()
|
||||||
|
{
|
||||||
|
TableMetadataRef metadataRef = this.metadata;
|
||||||
|
if (metadataRef != null)
|
||||||
|
return metadataRef.get();
|
||||||
|
|
||||||
|
TableMetadata metadata = Schema.instance.getTableMetadata(tableId);
|
||||||
|
if (metadata == null)
|
||||||
|
return null;
|
||||||
|
this.metadata = metadata.ref;
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
TableMetadata metadata = tableMetadata();
|
||||||
|
StringBuilder sb = new StringBuilder("[");
|
||||||
|
if (metadata != null)
|
||||||
|
sb.append(metadata).append('|');
|
||||||
|
sb.append(tableId.lsb());
|
||||||
|
sb.append(',').append(id).append(',').append(node.id().id).append(']');
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,10 @@ import org.apache.cassandra.metrics.AccordCacheMetrics;
|
||||||
import org.apache.cassandra.service.accord.AccordCacheEntry.LoadExecutor;
|
import org.apache.cassandra.service.accord.AccordCacheEntry.LoadExecutor;
|
||||||
import org.apache.cassandra.service.accord.AccordCacheEntry.SaveExecutor;
|
import org.apache.cassandra.service.accord.AccordCacheEntry.SaveExecutor;
|
||||||
import org.apache.cassandra.service.accord.AccordCacheEntry.UniqueSave;
|
import org.apache.cassandra.service.accord.AccordCacheEntry.UniqueSave;
|
||||||
|
import org.apache.cassandra.concurrent.ExecutorLocals;
|
||||||
|
import org.apache.cassandra.utils.Closeable;
|
||||||
import org.apache.cassandra.utils.MonotonicClock;
|
import org.apache.cassandra.utils.MonotonicClock;
|
||||||
|
import org.apache.cassandra.utils.WithResources;
|
||||||
import org.apache.cassandra.utils.concurrent.AsyncPromise;
|
import org.apache.cassandra.utils.concurrent.AsyncPromise;
|
||||||
import org.apache.cassandra.utils.concurrent.Condition;
|
import org.apache.cassandra.utils.concurrent.Condition;
|
||||||
import org.apache.cassandra.utils.concurrent.Future;
|
import org.apache.cassandra.utils.concurrent.Future;
|
||||||
|
|
@ -900,6 +903,7 @@ public abstract class AccordExecutor implements CacheSize, LoadExecutor<AccordTa
|
||||||
|
|
||||||
static abstract class SubmittableTask extends Task
|
static abstract class SubmittableTask extends Task
|
||||||
{
|
{
|
||||||
|
final WithResources locals = ExecutorLocals.propagate();
|
||||||
abstract void submitExclusive(AccordExecutor owner);
|
abstract void submitExclusive(AccordExecutor owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1261,7 +1265,10 @@ public abstract class AccordExecutor implements CacheSize, LoadExecutor<AccordTa
|
||||||
@Override
|
@Override
|
||||||
protected void runInternal()
|
protected void runInternal()
|
||||||
{
|
{
|
||||||
run.run();
|
try (Closeable close = locals.get())
|
||||||
|
{
|
||||||
|
run.run();
|
||||||
|
}
|
||||||
if (result != null)
|
if (result != null)
|
||||||
result.trySuccess(null);
|
result.trySuccess(null);
|
||||||
}
|
}
|
||||||
|
|
@ -1358,7 +1365,10 @@ public abstract class AccordExecutor implements CacheSize, LoadExecutor<AccordTa
|
||||||
@Override
|
@Override
|
||||||
public void runInternal()
|
public void runInternal()
|
||||||
{
|
{
|
||||||
result = entry.owner.parent().adapter().load(entry.owner.commandStore, entry.key());
|
try (Closeable close = locals.get())
|
||||||
|
{
|
||||||
|
result = entry.owner.parent().adapter().load(entry.owner.commandStore, entry.key());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -1400,7 +1410,10 @@ public abstract class AccordExecutor implements CacheSize, LoadExecutor<AccordTa
|
||||||
@Override
|
@Override
|
||||||
protected void runInternal()
|
protected void runInternal()
|
||||||
{
|
{
|
||||||
wrapped.runInternal();
|
try (Closeable close = locals.get())
|
||||||
|
{
|
||||||
|
wrapped.runInternal();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -1446,7 +1459,10 @@ public abstract class AccordExecutor implements CacheSize, LoadExecutor<AccordTa
|
||||||
@Override
|
@Override
|
||||||
public void runInternal()
|
public void runInternal()
|
||||||
{
|
{
|
||||||
run.run();
|
try (Closeable close = locals.get())
|
||||||
|
{
|
||||||
|
run.run();
|
||||||
|
}
|
||||||
failure = null;
|
failure = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1486,7 +1502,7 @@ public abstract class AccordExecutor implements CacheSize, LoadExecutor<AccordTa
|
||||||
protected void runInternal()
|
protected void runInternal()
|
||||||
{
|
{
|
||||||
T success;
|
T success;
|
||||||
try
|
try (Closeable close = locals.get())
|
||||||
{
|
{
|
||||||
success = call.call();
|
success = call.call();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,9 @@ import org.apache.cassandra.service.accord.AccordExecutor.SubmittableTask;
|
||||||
import org.apache.cassandra.service.accord.AccordExecutor.TaskQueue;
|
import org.apache.cassandra.service.accord.AccordExecutor.TaskQueue;
|
||||||
import org.apache.cassandra.service.accord.AccordKeyspace.CommandsForKeyAccessor;
|
import org.apache.cassandra.service.accord.AccordKeyspace.CommandsForKeyAccessor;
|
||||||
import org.apache.cassandra.service.accord.api.TokenKey;
|
import org.apache.cassandra.service.accord.api.TokenKey;
|
||||||
|
import org.apache.cassandra.tracing.Tracing;
|
||||||
import org.apache.cassandra.utils.Clock;
|
import org.apache.cassandra.utils.Clock;
|
||||||
|
import org.apache.cassandra.utils.Closeable;
|
||||||
import org.apache.cassandra.utils.NoSpamLogger;
|
import org.apache.cassandra.utils.NoSpamLogger;
|
||||||
import org.apache.cassandra.utils.concurrent.Condition;
|
import org.apache.cassandra.utils.concurrent.Condition;
|
||||||
|
|
||||||
|
|
@ -652,8 +654,11 @@ public abstract class AccordTask<R> extends SubmittableTask implements Function<
|
||||||
{
|
{
|
||||||
logger.trace("Running {} with state {}", this, state);
|
logger.trace("Running {} with state {}", this, state);
|
||||||
AccordSafeCommandStore safeStore = null;
|
AccordSafeCommandStore safeStore = null;
|
||||||
try
|
try (Closeable close = locals.get())
|
||||||
{
|
{
|
||||||
|
if (Tracing.isTracing())
|
||||||
|
Tracing.trace(preLoadContext.describe());
|
||||||
|
|
||||||
if (state != RUNNING)
|
if (state != RUNNING)
|
||||||
throw illegalState("Unexpected state " + toDescription());
|
throw illegalState("Unexpected state " + toDescription());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,9 +29,9 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import accord.api.Agent;
|
import accord.api.Agent;
|
||||||
import accord.api.EventListener;
|
import accord.api.CoordinatorEventListener;
|
||||||
|
import accord.api.LocalEventListener;
|
||||||
import accord.api.ProgressLog.BlockedUntil;
|
import accord.api.ProgressLog.BlockedUntil;
|
||||||
import accord.api.Result;
|
|
||||||
import accord.api.RoutingKey;
|
import accord.api.RoutingKey;
|
||||||
import accord.api.Tracing;
|
import accord.api.Tracing;
|
||||||
import accord.api.TraceEventType;
|
import accord.api.TraceEventType;
|
||||||
|
|
@ -127,11 +127,6 @@ public class AccordAgent implements Agent
|
||||||
self = id;
|
self = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRecover(Node node, Result success, Throwable fail)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onInconsistentTimestamp(Command command, Timestamp prev, Timestamp next)
|
public void onInconsistentTimestamp(Command command, Timestamp prev, Timestamp next)
|
||||||
{
|
{
|
||||||
|
|
@ -227,7 +222,13 @@ public class AccordAgent implements Agent
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EventListener eventListener()
|
public CoordinatorEventListener coordinatorEvents()
|
||||||
|
{
|
||||||
|
return AccordMetrics.Listener.instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LocalEventListener localEvents()
|
||||||
{
|
{
|
||||||
return AccordMetrics.Listener.instance;
|
return AccordMetrics.Listener.instance;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -143,7 +143,7 @@ public class TxnWrite extends AbstractKeySorted<TxnWrite.Update> implements Writ
|
||||||
if (!preserveTimestamps)
|
if (!preserveTimestamps)
|
||||||
update = new PartitionUpdate.Builder(update, 0).updateAllTimestamp(timestamp).build();
|
update = new PartitionUpdate.Builder(update, 0).updateAllTimestamp(timestamp).build();
|
||||||
Mutation mutation = new Mutation(update, PotentialTxnConflicts.ALLOW);
|
Mutation mutation = new Mutation(update, PotentialTxnConflicts.ALLOW);
|
||||||
return AsyncChains.ofRunnable(executor, mutation::applyUnsafe);
|
return AsyncChains.ofRunnable(executor, () -> mutation.apply(false, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -266,7 +266,7 @@ public class AccordMetricsTest extends AccordTestBase
|
||||||
assertThat(metric.apply(AccordMetrics.TIMEOUTS)).isEqualTo(timeouts);
|
assertThat(metric.apply(AccordMetrics.TIMEOUTS)).isEqualTo(timeouts);
|
||||||
assertThat(metric.apply(AccordMetrics.RECOVERY_DELAY)).isEqualTo(recoveries);
|
assertThat(metric.apply(AccordMetrics.RECOVERY_DELAY)).isEqualTo(recoveries);
|
||||||
assertThat(metric.apply(AccordMetrics.RECOVERY_TIME)).isEqualTo(recoveries);
|
assertThat(metric.apply(AccordMetrics.RECOVERY_TIME)).isEqualTo(recoveries);
|
||||||
assertThat(metric.apply(AccordMetrics.DEPENDENCIES)).isEqualTo(fastPaths + slowPaths);
|
assertThat(metric.apply(AccordMetrics.COORDINATOR_DEPENDENCIES)).isEqualTo(fastPaths + slowPaths);
|
||||||
|
|
||||||
// Verify that coordinator metrics are published to the appropriate virtual table:
|
// Verify that coordinator metrics are published to the appropriate virtual table:
|
||||||
SimpleQueryResult res = SHARED_CLUSTER.get(node + 1)
|
SimpleQueryResult res = SHARED_CLUSTER.get(node + 1)
|
||||||
|
|
@ -290,11 +290,11 @@ public class AccordMetricsTest extends AccordTestBase
|
||||||
DefaultNameFactory nameFactory = new DefaultNameFactory(AccordMetrics.ACCORD_REPLICA, scope);
|
DefaultNameFactory nameFactory = new DefaultNameFactory(AccordMetrics.ACCORD_REPLICA, scope);
|
||||||
Map<String, Long> metrics = diff(countingMetrics0).get(node);
|
Map<String, Long> metrics = diff(countingMetrics0).get(node);
|
||||||
Function<String, Long> metric = n -> metrics.get(nameFactory.createMetricName(n).getMetricName());
|
Function<String, Long> metric = n -> metrics.get(nameFactory.createMetricName(n).getMetricName());
|
||||||
assertThat(metric.apply(AccordMetrics.STABLE_LATENCY)).isLessThanOrEqualTo(stable);
|
assertThat(metric.apply(AccordMetrics.REPLICA_STABLE_LATENCY)).isLessThanOrEqualTo(stable);
|
||||||
assertThat(metric.apply(AccordMetrics.PREAPPLY_LATENCY)).isEqualTo(executions);
|
assertThat(metric.apply(AccordMetrics.REPLICA_PREAPPLY_LATENCY)).isEqualTo(executions);
|
||||||
assertThat(metric.apply(AccordMetrics.APPLY_LATENCY)).isEqualTo(applications);
|
assertThat(metric.apply(AccordMetrics.REPLICA_APPLY_LATENCY)).isEqualTo(applications);
|
||||||
assertThat(metric.apply(AccordMetrics.APPLY_DURATION)).isEqualTo(scope.equals("rw") ? applications : 0);
|
assertThat(metric.apply(AccordMetrics.REPLICA_APPLY_DURATION)).isEqualTo(scope.equals("rw") ? applications : 0);
|
||||||
assertThat(metric.apply(AccordMetrics.PARTIAL_DEPENDENCIES)).isEqualTo(executions);
|
assertThat(metric.apply(AccordMetrics.REPLICA_DEPENDENCIES)).isEqualTo(executions);
|
||||||
|
|
||||||
// Verify that replica metrics are published to the appropriate virtual table:
|
// Verify that replica metrics are published to the appropriate virtual table:
|
||||||
SimpleQueryResult vtableResults = SHARED_CLUSTER.get(node + 1)
|
SimpleQueryResult vtableResults = SHARED_CLUSTER.get(node + 1)
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,6 @@ import accord.api.DataStore;
|
||||||
import accord.api.Journal;
|
import accord.api.Journal;
|
||||||
import accord.api.Key;
|
import accord.api.Key;
|
||||||
import accord.api.ProgressLog;
|
import accord.api.ProgressLog;
|
||||||
import accord.api.Result;
|
|
||||||
import accord.api.RoutingKey;
|
import accord.api.RoutingKey;
|
||||||
import accord.api.Timeouts;
|
import accord.api.Timeouts;
|
||||||
import accord.impl.AbstractSafeCommandStore;
|
import accord.impl.AbstractSafeCommandStore;
|
||||||
|
|
@ -659,7 +658,6 @@ public class CommandsForKeySerializerTest
|
||||||
@Override public void shutdown() { }
|
@Override public void shutdown() { }
|
||||||
@Override protected void registerTransitive(SafeCommandStore safeStore, RangeDeps deps){ }
|
@Override protected void registerTransitive(SafeCommandStore safeStore, RangeDeps deps){ }
|
||||||
@Override public <T> AsyncChain<T> build(Callable<T> task) { throw new UnsupportedOperationException(); }
|
@Override public <T> AsyncChain<T> build(Callable<T> task) { throw new UnsupportedOperationException(); }
|
||||||
@Override public void onRecover(Node node, Result success, Throwable fail) { throw new UnsupportedOperationException(); }
|
|
||||||
@Override public void onInconsistentTimestamp(Command command, Timestamp prev, Timestamp next) { throw new UnsupportedOperationException(); }
|
@Override public void onInconsistentTimestamp(Command command, Timestamp prev, Timestamp next) { throw new UnsupportedOperationException(); }
|
||||||
@Override public void onFailedBootstrap(int attempts, String phase, Ranges ranges, Runnable retry, Throwable failure) { throw new UnsupportedOperationException(); }
|
@Override public void onFailedBootstrap(int attempts, String phase, Ranges ranges, Runnable retry, Throwable failure) { throw new UnsupportedOperationException(); }
|
||||||
@Override public void onStale(Timestamp staleSince, Ranges ranges) { throw new UnsupportedOperationException(); }
|
@Override public void onStale(Timestamp staleSince, Ranges ranges) { throw new UnsupportedOperationException(); }
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue