diff --git a/conf/cassandra.yaml b/conf/cassandra.yaml index a507dcd943..4341422dbd 100644 --- a/conf/cassandra.yaml +++ b/conf/cassandra.yaml @@ -2661,3 +2661,6 @@ storage_compatibility_mode: NONE # # # Progress log scheduling delay # progress_log_schedule_delay: 1s +# +# # how quickly the fast path is reconfigured when nodes go up/down +# fast_path_update_delay: 5s diff --git a/modules/accord b/modules/accord index 9f21a24660..5523cfefef 160000 --- a/modules/accord +++ b/modules/accord @@ -1 +1 @@ -Subproject commit 9f21a24660fe49881e0131813f9eff850e25b3dc +Subproject commit 5523cfefef163efee53c8cc57595f5b50ea4f363 diff --git a/src/java/org/apache/cassandra/config/AccordSpec.java b/src/java/org/apache/cassandra/config/AccordSpec.java index 2143342bd4..d821c31e87 100644 --- a/src/java/org/apache/cassandra/config/AccordSpec.java +++ b/src/java/org/apache/cassandra/config/AccordSpec.java @@ -42,4 +42,6 @@ public class AccordSpec public DurationSpec.IntMillisecondsBound barrier_max_backoff = new DurationSpec.IntMillisecondsBound("10m"); public DurationSpec.IntMillisecondsBound range_barrier_timeout = new DurationSpec.IntMillisecondsBound("2m"); + + public volatile DurationSpec fast_path_update_delay = new DurationSpec.IntSecondsBound(5); } diff --git a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java index 12da2dae42..f4eccb000a 100644 --- a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java +++ b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java @@ -5313,6 +5313,16 @@ public class DatabaseDescriptor return conf.accord.shard_count.or(DatabaseDescriptor::getAvailableProcessors); } + public static long getAccordFastPathUpdateDelayMillis() + { + return conf.accord.fast_path_update_delay.to(TimeUnit.MILLISECONDS); + } + + public static void setAccordFastPathUpdateDelayMillis(long millis) + { + conf.accord.fast_path_update_delay = new DurationSpec.IntMillisecondsBound(millis); + } + public static boolean getForceNewPreparedStatementBehaviour() { return conf.force_new_prepared_statement_behaviour; diff --git a/src/java/org/apache/cassandra/cql3/statements/TransactionStatement.java b/src/java/org/apache/cassandra/cql3/statements/TransactionStatement.java index cff94f9526..bb9180130b 100644 --- a/src/java/org/apache/cassandra/cql3/statements/TransactionStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/TransactionStatement.java @@ -371,7 +371,7 @@ public class TransactionStatement implements CQLStatement.CompositeCQLStatement, Txn txn = createTxn(state.getClientState(), options); - AccordService.instance().maybeConvertKeyspacesToAccord(txn); + AccordService.instance().maybeConvertTablesToAccord(txn); TxnResult txnResult = AccordService.instance().coordinate(txn, options.getConsistency(), requestTime); if (txnResult.kind() == retry_new_protocol) diff --git a/src/java/org/apache/cassandra/cql3/statements/schema/KeyspaceAttributes.java b/src/java/org/apache/cassandra/cql3/statements/schema/KeyspaceAttributes.java index d4d5b984b3..0be8b882dd 100644 --- a/src/java/org/apache/cassandra/cql3/statements/schema/KeyspaceAttributes.java +++ b/src/java/org/apache/cassandra/cql3/statements/schema/KeyspaceAttributes.java @@ -23,9 +23,11 @@ import com.google.common.collect.ImmutableSet; import org.apache.cassandra.cql3.statements.PropertyDefinitions; import org.apache.cassandra.exceptions.ConfigurationException; +import org.apache.cassandra.exceptions.SyntaxException; import org.apache.cassandra.schema.KeyspaceParams; import org.apache.cassandra.schema.KeyspaceParams.Option; import org.apache.cassandra.schema.ReplicationParams; +import org.apache.cassandra.service.accord.fastpath.FastPathStrategy; public final class KeyspaceAttributes extends PropertyDefinitions { @@ -48,6 +50,10 @@ public final class KeyspaceAttributes extends PropertyDefinitions Map replicationOptions = getAllReplicationOptions(); if (!replicationOptions.isEmpty() && !replicationOptions.containsKey(ReplicationParams.CLASS)) throw new ConfigurationException("Missing replication strategy class"); + + FastPathStrategy strategy = getFastPathStrategy(); + if (strategy != null && strategy.kind() == FastPathStrategy.Kind.INHERIT_KEYSPACE) + throw new ConfigurationException("Cannot use keyspace inheriting fast path strategy with keyspaces"); } public String getReplicationStrategyClass() @@ -63,10 +69,26 @@ public final class KeyspaceAttributes extends PropertyDefinitions : replication; } + private FastPathStrategy getFastPathStrategy() + { + if (!hasOption(Option.FAST_PATH)) + return null; + + try + { + return FastPathStrategy.fromMap(getMap(Option.FAST_PATH.toString())); + } + catch (SyntaxException e) + { + return FastPathStrategy.keyspaceStrategyFromString(getString(Option.FAST_PATH.toString())); + } + } + KeyspaceParams asNewKeyspaceParams() { boolean durableWrites = getBoolean(Option.DURABLE_WRITES.toString(), KeyspaceParams.DEFAULT_DURABLE_WRITES); - return KeyspaceParams.create(durableWrites, getAllReplicationOptions()); + FastPathStrategy fastPath = getFastPathStrategy(); + return KeyspaceParams.create(durableWrites, getAllReplicationOptions(), fastPath != null ? fastPath : FastPathStrategy.simple()); } KeyspaceParams asAlteredKeyspaceParams(KeyspaceParams previous) @@ -76,7 +98,8 @@ public final class KeyspaceAttributes extends PropertyDefinitions ReplicationParams replication = getReplicationStrategyClass() == null ? previous.replication : ReplicationParams.fromMapWithDefaults(getAllReplicationOptions(), previousOptions); - return new KeyspaceParams(durableWrites, replication); + FastPathStrategy fastPath = getFastPathStrategy(); + return new KeyspaceParams(durableWrites, replication, fastPath != null ? fastPath : previous.fastPath); } public boolean hasOption(Option option) diff --git a/src/java/org/apache/cassandra/cql3/statements/schema/TableAttributes.java b/src/java/org/apache/cassandra/cql3/statements/schema/TableAttributes.java index 87af6b840b..eb18918628 100644 --- a/src/java/org/apache/cassandra/cql3/statements/schema/TableAttributes.java +++ b/src/java/org/apache/cassandra/cql3/statements/schema/TableAttributes.java @@ -25,6 +25,7 @@ import com.google.common.collect.Sets; import org.apache.cassandra.cql3.statements.PropertyDefinitions; import org.apache.cassandra.exceptions.ConfigurationException; +import org.apache.cassandra.exceptions.SyntaxException; import org.apache.cassandra.schema.CachingParams; import org.apache.cassandra.schema.CompactionParams; import org.apache.cassandra.schema.CompressionParams; @@ -32,6 +33,7 @@ import org.apache.cassandra.schema.MemtableParams; import org.apache.cassandra.schema.TableId; import org.apache.cassandra.schema.TableParams; import org.apache.cassandra.schema.TableParams.Option; +import org.apache.cassandra.service.accord.fastpath.FastPathStrategy; import org.apache.cassandra.service.reads.SpeculativeRetryPolicy; import org.apache.cassandra.service.reads.repair.ReadRepairStrategy; @@ -151,6 +153,18 @@ public final class TableAttributes extends PropertyDefinitions if (hasOption(READ_REPAIR)) builder.readRepair(ReadRepairStrategy.fromString(getString(READ_REPAIR))); + if (hasOption(Option.FAST_PATH)) + { + try + { + builder.fastPath(FastPathStrategy.fromMap(getMap(Option.FAST_PATH))); + } + catch (SyntaxException e) + { + builder.fastPath(FastPathStrategy.tableStrategyFromString(getString(Option.FAST_PATH))); + } + } + return builder.build(); } diff --git a/src/java/org/apache/cassandra/db/streaming/CassandraStreamReceiver.java b/src/java/org/apache/cassandra/db/streaming/CassandraStreamReceiver.java index 62af761277..99ef8e96b3 100644 --- a/src/java/org/apache/cassandra/db/streaming/CassandraStreamReceiver.java +++ b/src/java/org/apache/cassandra/db/streaming/CassandraStreamReceiver.java @@ -246,7 +246,7 @@ public class CassandraStreamReceiver implements StreamReceiver checkNotNull(minVersion, "Unable to determine minimum cluster version"); IAccordService accordService = AccordService.instance(); if (session.streamOperation().requiresBarrierTransaction() - && accordService.isAccordManagedKeyspace(cfs.keyspace.getName()) + && accordService.isAccordManagedTable(cfs.getTableId()) && CassandraVersion.CASSANDRA_5_0.compareTo(minVersion) >= 0) accordService.postStreamReceivingBarrier(cfs, ranges); diff --git a/src/java/org/apache/cassandra/dht/AccordSplitter.java b/src/java/org/apache/cassandra/dht/AccordSplitter.java index b0868b47e8..467ac2a105 100644 --- a/src/java/org/apache/cassandra/dht/AccordSplitter.java +++ b/src/java/org/apache/cassandra/dht/AccordSplitter.java @@ -21,6 +21,7 @@ package org.apache.cassandra.dht; import java.math.BigInteger; import accord.local.ShardDistributor; +import org.apache.cassandra.schema.TableId; import org.apache.cassandra.service.accord.TokenRange; import org.apache.cassandra.service.accord.api.AccordRoutingKey; import org.apache.cassandra.service.accord.api.AccordRoutingKey.SentinelKey; @@ -54,9 +55,9 @@ public abstract class AccordSplitter implements ShardDistributor.EvenSplit.Split BigInteger end = endBound instanceof SentinelKey ? maximumValue() : valueForToken(endBound.token()); BigInteger sizeOfRange = end.subtract(start); - String keyspace = startBound.keyspace(); - return new TokenRange(startOffset.equals(ZERO) ? startBound : new TokenKey(keyspace, tokenForValue(start.add(startOffset))), - endOffset.compareTo(sizeOfRange) >= 0 ? endBound : new TokenKey(keyspace, tokenForValue(start.add(endOffset)))); + TableId tableId = startBound.table(); + return new TokenRange(startOffset.equals(ZERO) ? startBound : new TokenKey(tableId, tokenForValue(start.add(startOffset))), + endOffset.compareTo(sizeOfRange) >= 0 ? endBound : new TokenKey(tableId, tokenForValue(start.add(endOffset)))); } @Override diff --git a/src/java/org/apache/cassandra/dht/BootStrapper.java b/src/java/org/apache/cassandra/dht/BootStrapper.java index 4ec9e4834f..609b4b89e7 100644 --- a/src/java/org/apache/cassandra/dht/BootStrapper.java +++ b/src/java/org/apache/cassandra/dht/BootStrapper.java @@ -40,7 +40,6 @@ import org.apache.cassandra.locator.InetAddressAndPort; import org.apache.cassandra.metrics.StorageMetrics; import org.apache.cassandra.schema.KeyspaceMetadata; import org.apache.cassandra.schema.Schema; -import org.apache.cassandra.service.accord.AccordService; import org.apache.cassandra.streaming.StreamEvent; import org.apache.cassandra.streaming.StreamEventHandler; import org.apache.cassandra.streaming.StreamOperation; @@ -127,7 +126,8 @@ public class BootStrapper extends ProgressEventNotifierSupport true, DatabaseDescriptor.getStreamingConnectionsPerHost(), movements, - strictMovements); + strictMovements, + true); if (beingReplaced != null) streamer.addSourceFilter(new RangeStreamer.ExcludedSourcesFilter(Collections.singleton(beingReplaced))); @@ -137,8 +137,6 @@ public class BootStrapper extends ProgressEventNotifierSupport logger.debug("Schema does not contain any non-local keyspaces to stream on bootstrap"); for (String keyspaceName : nonLocalStrategyKeyspaces) { - if (AccordService.instance().isAccordManagedKeyspace(keyspaceName)) - continue; KeyspaceMetadata ksm = metadata.schema.getKeyspaces().get(keyspaceName).get(); if (ksm.params.replication.isMeta()) continue; diff --git a/src/java/org/apache/cassandra/dht/RangeStreamer.java b/src/java/org/apache/cassandra/dht/RangeStreamer.java index de66fab4f9..f21dd3186d 100644 --- a/src/java/org/apache/cassandra/dht/RangeStreamer.java +++ b/src/java/org/apache/cassandra/dht/RangeStreamer.java @@ -59,7 +59,9 @@ import org.apache.cassandra.locator.ReplicaCollection; import org.apache.cassandra.locator.ReplicaCollection.Builder.Conflict; import org.apache.cassandra.locator.Replicas; import org.apache.cassandra.locator.NodeProximity; +import org.apache.cassandra.schema.KeyspaceMetadata; import org.apache.cassandra.schema.ReplicationParams; +import org.apache.cassandra.schema.Schema; import org.apache.cassandra.streaming.PreviewKind; import org.apache.cassandra.streaming.StreamOperation; import org.apache.cassandra.streaming.StreamPlan; @@ -99,6 +101,7 @@ public class RangeStreamer private final StreamStateStore stateStore; private final MovementMap movements; private final MovementMap strictMovements; + private final boolean excludeAccordTables; public static class FetchReplica { @@ -299,10 +302,11 @@ public class RangeStreamer boolean connectSequentially, int connectionsPerHost, MovementMap movements, - MovementMap strictMovements) + MovementMap strictMovements, + boolean excludeAccordTables) { this(metadata, streamOperation, useStrictConsistency, proximity, stateStore, - FailureDetector.instance, connectSequentially, connectionsPerHost, movements, strictMovements); + FailureDetector.instance, connectSequentially, connectionsPerHost, movements, strictMovements, excludeAccordTables); } RangeStreamer(ClusterMetadata metadata, @@ -314,8 +318,10 @@ public class RangeStreamer boolean connectSequentially, int connectionsPerHost, MovementMap movements, - MovementMap strictMovements) + MovementMap strictMovements, + boolean excludeAccordTables) { + this.excludeAccordTables = excludeAccordTables; Preconditions.checkArgument(streamOperation == StreamOperation.BOOTSTRAP || streamOperation == StreamOperation.REBUILD, streamOperation); this.metadata = metadata; this.description = streamOperation.getDescription(); @@ -760,8 +766,17 @@ public class RangeStreamer logger.debug("Source and our replicas {}", fetchReplicas); logger.debug("Source {} Keyspace {} streaming full {} transient {}", source, keyspace, full, transientReplicas); - /* Send messages to respective folks to stream data over to me */ - streamPlan.requestRanges(source, keyspace, full, transientReplicas); + KeyspaceMetadata ksm = Schema.instance.getKeyspaceMetadata(keyspace); + if (excludeAccordTables && StreamPlan.hasAccordTables(ksm)) + { + String[] cfNames = StreamPlan.nonAccordTablesForKeyspace(ksm); + if (cfNames != null) + streamPlan.requestRanges(source, keyspace, full, transientReplicas, cfNames); + } + else + { + streamPlan.requestRanges(source, keyspace, full, transientReplicas); + } }); }); diff --git a/src/java/org/apache/cassandra/locator/ReplicaLayout.java b/src/java/org/apache/cassandra/locator/ReplicaLayout.java index 6b464237d0..2e111dc9aa 100644 --- a/src/java/org/apache/cassandra/locator/ReplicaLayout.java +++ b/src/java/org/apache/cassandra/locator/ReplicaLayout.java @@ -26,6 +26,7 @@ import org.apache.cassandra.db.PartitionPosition; import org.apache.cassandra.dht.AbstractBounds; import org.apache.cassandra.dht.Token; import org.apache.cassandra.schema.KeyspaceMetadata; +import org.apache.cassandra.schema.TableId; import org.apache.cassandra.service.reads.ReadCoordinator; import org.apache.cassandra.tcm.ClusterMetadata; import org.apache.cassandra.utils.FBUtilities; @@ -357,11 +358,11 @@ public abstract class ReplicaLayout> * @return the read layout for a token - this includes natural replicas, i.e. those that are not pending. * They are reverse sorted by the badness score of the configured snitch */ - static ReplicaLayout.ForTokenRead forTokenReadSorted(ClusterMetadata metadata, Keyspace keyspace, AbstractReplicationStrategy replicationStrategy, Token token, ReadCoordinator coordinator) + static ReplicaLayout.ForTokenRead forTokenReadSorted(ClusterMetadata metadata, Keyspace keyspace, AbstractReplicationStrategy replicationStrategy, TableId tableId, Token token, ReadCoordinator coordinator) { EndpointsForToken replicas = keyspace.getMetadata().params.replication.isLocal() ? forLocalStrategyToken(metadata, replicationStrategy, token) - : coordinator.forNonLocalStrategyTokenRead(metadata, keyspace.getMetadata(), token); + : coordinator.forNonLocalStrategyTokenRead(metadata, keyspace.getMetadata(), tableId, token); replicas = DatabaseDescriptor.getNodeProximity().sortedByProximity(FBUtilities.getBroadcastAddressAndPort(), replicas); diff --git a/src/java/org/apache/cassandra/locator/ReplicaPlans.java b/src/java/org/apache/cassandra/locator/ReplicaPlans.java index 5aef13a6d3..d009ed33db 100644 --- a/src/java/org/apache/cassandra/locator/ReplicaPlans.java +++ b/src/java/org/apache/cassandra/locator/ReplicaPlans.java @@ -62,6 +62,7 @@ import org.apache.cassandra.gms.FailureDetector; import org.apache.cassandra.index.Index; import org.apache.cassandra.index.IndexStatusManager; import org.apache.cassandra.schema.SchemaConstants; +import org.apache.cassandra.schema.TableId; import org.apache.cassandra.service.StorageService; import org.apache.cassandra.service.reads.ReadCoordinator; import org.apache.cassandra.tcm.ClusterMetadata; @@ -534,7 +535,7 @@ public class ReplicaPlans } - public static ReplicaPlan.ForWrite forReadRepair(ReplicaPlan forRead, ClusterMetadata metadata, Keyspace keyspace, ConsistencyLevel consistencyLevel, Token token, Predicate isAlive, ReadCoordinator coordinator) throws UnavailableException + public static ReplicaPlan.ForWrite forReadRepair(ReplicaPlan forRead, ClusterMetadata metadata, Keyspace keyspace, TableId tableId, ConsistencyLevel consistencyLevel, Token token, Predicate isAlive, ReadCoordinator coordinator) throws UnavailableException { AbstractReplicationStrategy replicationStrategy = keyspace.getReplicationStrategy(); Selector selector = writeReadRepair(forRead); @@ -551,7 +552,7 @@ public class ReplicaPlans liveAndDown.all(), live.all(), contacts, - (newClusterMetadata) -> forReadRepair(forRead, newClusterMetadata, keyspace, consistencyLevel, token, isAlive, coordinator), + (newClusterMetadata) -> forReadRepair(forRead, newClusterMetadata, keyspace, tableId, consistencyLevel, token, isAlive, coordinator), metadata.epoch); } @@ -880,28 +881,31 @@ public class ReplicaPlans * it would break EACH_QUORUM to do so without further filtering */ public static ReplicaPlan.ForTokenRead forRead(Keyspace keyspace, + TableId tableId, Token token, @Nullable Index.QueryPlan indexQueryPlan, ConsistencyLevel consistencyLevel, SpeculativeRetryPolicy retry, ReadCoordinator coordinator) { - return forRead(ClusterMetadata.current(), keyspace, token, indexQueryPlan, consistencyLevel, retry, coordinator, false); + return forRead(ClusterMetadata.current(), keyspace, tableId, token, indexQueryPlan, consistencyLevel, retry, coordinator, false); } public static ReplicaPlan.ForTokenRead forRead(ClusterMetadata metadata, Keyspace keyspace, + TableId tableId, Token token, @Nullable Index.QueryPlan indexQueryPlan, ConsistencyLevel consistencyLevel, SpeculativeRetryPolicy retry, ReadCoordinator coordinator) { - return forRead(metadata, keyspace, token, indexQueryPlan, consistencyLevel, retry, coordinator, true); + return forRead(metadata, keyspace, tableId, token, indexQueryPlan, consistencyLevel, retry, coordinator, true); } private static ReplicaPlan.ForTokenRead forRead(ClusterMetadata metadata, Keyspace keyspace, + TableId tableId, Token token, @Nullable Index.QueryPlan indexQueryPlan, ConsistencyLevel consistencyLevel, @@ -910,7 +914,7 @@ public class ReplicaPlans boolean throwOnInsufficientLiveReplicas) { AbstractReplicationStrategy replicationStrategy = keyspace.getReplicationStrategy(); - ReplicaLayout.ForTokenRead forTokenReadLiveAndDown = ReplicaLayout.forTokenReadSorted(metadata, keyspace, replicationStrategy, token, coordinator); + ReplicaLayout.ForTokenRead forTokenReadLiveAndDown = ReplicaLayout.forTokenReadSorted(metadata, keyspace, replicationStrategy, tableId, token, coordinator); ReplicaLayout.ForTokenRead forTokenReadLive = forTokenReadLiveAndDown.filter(FailureDetector.isReplicaAlive); EndpointsForToken candidates = candidatesForRead(keyspace, indexQueryPlan, consistencyLevel, forTokenReadLive.all()); EndpointsForToken contacts = contactForRead(metadata.locator, replicationStrategy, consistencyLevel, retry.equals(AlwaysSpeculativeRetryPolicy.INSTANCE), candidates); @@ -919,8 +923,8 @@ public class ReplicaPlans assureSufficientLiveReplicasForRead(metadata.locator, replicationStrategy, consistencyLevel, contacts); return new ReplicaPlan.ForTokenRead(keyspace, replicationStrategy, consistencyLevel, candidates, contacts, forTokenReadLiveAndDown.all(), - (newClusterMetadata) -> forRead(newClusterMetadata, keyspace, token, indexQueryPlan, consistencyLevel, retry, coordinator, false), - (self) -> forReadRepair(self, metadata, keyspace, consistencyLevel, token, FailureDetector.isReplicaAlive, coordinator), + (newClusterMetadata) -> forRead(newClusterMetadata, keyspace, tableId, token, indexQueryPlan, consistencyLevel, retry, coordinator, false), + (self) -> forReadRepair(self, metadata, keyspace, tableId, consistencyLevel, token, FailureDetector.isReplicaAlive, coordinator), metadata.epoch); } @@ -932,16 +936,18 @@ public class ReplicaPlans * There is no speculation for range read queries at present, so we never 'always speculate' here, and a failed response fails the query. */ public static ReplicaPlan.ForRangeRead forRangeRead(Keyspace keyspace, + TableId tableId, @Nullable Index.QueryPlan indexQueryPlan, ConsistencyLevel consistencyLevel, AbstractBounds range, int vnodeCount) { - return forRangeRead(ClusterMetadata.current(), keyspace, indexQueryPlan, consistencyLevel, range, vnodeCount, true); + return forRangeRead(ClusterMetadata.current(), keyspace, tableId, indexQueryPlan, consistencyLevel, range, vnodeCount, true); } public static ReplicaPlan.ForRangeRead forRangeRead(ClusterMetadata metadata, Keyspace keyspace, + TableId tableId, @Nullable Index.QueryPlan indexQueryPlan, ConsistencyLevel consistencyLevel, AbstractBounds range, @@ -965,8 +971,8 @@ public class ReplicaPlans contacts, forRangeReadLiveAndDown.all(), vnodeCount, - (newClusterMetadata) -> forRangeRead(newClusterMetadata, keyspace, indexQueryPlan, consistencyLevel, range, vnodeCount, false), - (self, token) -> forReadRepair(self, metadata, keyspace, consistencyLevel, token, FailureDetector.isReplicaAlive, ReadCoordinator.DEFAULT), + (newClusterMetadata) -> forRangeRead(newClusterMetadata, keyspace, tableId, indexQueryPlan, consistencyLevel, range, vnodeCount, false), + (self, token) -> forReadRepair(self, metadata, keyspace, tableId, consistencyLevel, token, FailureDetector.isReplicaAlive, ReadCoordinator.DEFAULT), metadata.epoch); } @@ -1000,6 +1006,7 @@ public class ReplicaPlans */ public static ReplicaPlan.ForRangeRead maybeMerge(ClusterMetadata metadata, Keyspace keyspace, + TableId tableId, ConsistencyLevel consistencyLevel, ReplicaPlan.ForRangeRead left, ReplicaPlan.ForRangeRead right) @@ -1037,6 +1044,7 @@ public class ReplicaPlans newVnodeCount, (newClusterMetadata) -> forRangeRead(newClusterMetadata, keyspace, + tableId, null, // TODO (TCM) - we only use the recomputed ForRangeRead to check stillAppliesTo - make sure passing null here is ok consistencyLevel, newRange, @@ -1045,7 +1053,7 @@ public class ReplicaPlans (self, token) -> { // It might happen that the ring has moved forward since the operation has started, but because we'll be recomputing a quorum // after the operation is complete, we will catch inconsistencies either way. - return forReadRepair(self, ClusterMetadata.current(), keyspace, consistencyLevel, token, FailureDetector.isReplicaAlive, ReadCoordinator.DEFAULT); + return forReadRepair(self, ClusterMetadata.current(), keyspace, tableId, consistencyLevel, token, FailureDetector.isReplicaAlive, ReadCoordinator.DEFAULT); }, left.epoch); } diff --git a/src/java/org/apache/cassandra/repair/AccordRepairJob.java b/src/java/org/apache/cassandra/repair/AccordRepairJob.java index c2e9eb792e..8db43b46b3 100644 --- a/src/java/org/apache/cassandra/repair/AccordRepairJob.java +++ b/src/java/org/apache/cassandra/repair/AccordRepairJob.java @@ -21,6 +21,7 @@ package org.apache.cassandra.repair; import java.math.BigInteger; import javax.annotation.Nullable; +import org.apache.cassandra.service.accord.AccordTopology; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,7 +32,6 @@ import accord.primitives.Seekables; import org.apache.cassandra.dht.AccordSplitter; import org.apache.cassandra.dht.IPartitioner; import org.apache.cassandra.service.accord.AccordService; -import org.apache.cassandra.service.accord.AccordTopologyUtils; import org.apache.cassandra.service.accord.TokenRange; import org.apache.cassandra.service.consensus.migration.ConsensusTableMigrationState.ConsensusMigrationRepairResult; import org.apache.cassandra.tcm.ClusterMetadata; @@ -65,7 +65,7 @@ public class AccordRepairJob extends AbstractRepairJob { super(repairSession, cfname); IPartitioner partitioner = desc.ranges.iterator().next().left.getPartitioner(); - this.ranges = AccordTopologyUtils.toAccordRanges(desc.keyspace, desc.ranges); + this.ranges = AccordTopology.toAccordRanges(desc.keyspace, desc.ranges); this.splitter = partitioner.accordSplitter().apply(ranges); } diff --git a/src/java/org/apache/cassandra/schema/DistributedMetadataLogKeyspace.java b/src/java/org/apache/cassandra/schema/DistributedMetadataLogKeyspace.java index 37af87f3e4..1e4a41c9ff 100644 --- a/src/java/org/apache/cassandra/schema/DistributedMetadataLogKeyspace.java +++ b/src/java/org/apache/cassandra/schema/DistributedMetadataLogKeyspace.java @@ -26,8 +26,6 @@ import java.util.function.Supplier; import com.google.common.collect.ImmutableMap; -import org.apache.cassandra.locator.MetaStrategy; -import org.apache.cassandra.utils.JVMStabilityInspector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,6 +34,8 @@ import org.apache.cassandra.cql3.UntypedResultSet; import org.apache.cassandra.cql3.statements.schema.CreateTableStatement; import org.apache.cassandra.db.ConsistencyLevel; import org.apache.cassandra.exceptions.CasWriteTimeoutException; +import org.apache.cassandra.locator.MetaStrategy; +import org.apache.cassandra.service.accord.fastpath.FastPathStrategy; import org.apache.cassandra.tcm.ClusterMetadataService; import org.apache.cassandra.tcm.Epoch; import org.apache.cassandra.tcm.MetadataSnapshots; @@ -44,6 +44,7 @@ import org.apache.cassandra.tcm.log.Entry; import org.apache.cassandra.tcm.log.LogReader; import org.apache.cassandra.tcm.log.LogState; import org.apache.cassandra.tcm.transformations.cms.PreInitialize; +import org.apache.cassandra.utils.JVMStabilityInspector; import static org.apache.cassandra.tcm.Epoch.FIRST; @@ -223,7 +224,7 @@ public final class DistributedMetadataLogKeyspace public static KeyspaceMetadata initialMetadata(Set knownDatacenters) { - return KeyspaceMetadata.create(SchemaConstants.METADATA_KEYSPACE_NAME, new KeyspaceParams(true, ReplicationParams.simpleMeta(1, knownDatacenters)), Tables.of(Log)); + return KeyspaceMetadata.create(SchemaConstants.METADATA_KEYSPACE_NAME, new KeyspaceParams(true, ReplicationParams.simpleMeta(1, knownDatacenters), FastPathStrategy.simple()), Tables.of(Log)); } public static KeyspaceMetadata initialMetadata(String datacenter) diff --git a/src/java/org/apache/cassandra/schema/KeyspaceMetadata.java b/src/java/org/apache/cassandra/schema/KeyspaceMetadata.java index 8065c59290..0700b33212 100644 --- a/src/java/org/apache/cassandra/schema/KeyspaceMetadata.java +++ b/src/java/org/apache/cassandra/schema/KeyspaceMetadata.java @@ -49,6 +49,7 @@ import org.apache.cassandra.tcm.serialization.Version; import org.apache.cassandra.schema.Tables.TablesDiff; import org.apache.cassandra.schema.Types.TypesDiff; import org.apache.cassandra.schema.Views.ViewsDiff; +import org.apache.cassandra.utils.LocalizeString; import static com.google.common.collect.Iterables.any; import static java.lang.String.format; @@ -364,9 +365,16 @@ public final class KeyspaceMetadata implements SchemaElement params.replication.appendCqlTo(builder); builder.append(" AND durable_writes = ") - .append(params.durableWrites) - .append(';') - .toString(); + .append(params.durableWrites); + + if (params.fastPath != null) + { + builder.append(" AND fast_path = '") + .append(LocalizeString.toLowerCaseLocalized(params.fastPath.toString())) + .append("'"); + } + + builder.append(';'); } return builder.toString(); } diff --git a/src/java/org/apache/cassandra/schema/KeyspaceParams.java b/src/java/org/apache/cassandra/schema/KeyspaceParams.java index 76516334b8..fe05b10b5d 100644 --- a/src/java/org/apache/cassandra/schema/KeyspaceParams.java +++ b/src/java/org/apache/cassandra/schema/KeyspaceParams.java @@ -28,10 +28,12 @@ import org.apache.cassandra.service.ClientState; import org.apache.cassandra.db.TypeSizes; import org.apache.cassandra.io.util.DataInputPlus; import org.apache.cassandra.io.util.DataOutputPlus; +import org.apache.cassandra.service.accord.fastpath.FastPathStrategy; import org.apache.cassandra.tcm.ClusterMetadata; import org.apache.cassandra.tcm.serialization.MetadataSerializer; import org.apache.cassandra.tcm.serialization.Version; +import static org.apache.cassandra.tcm.serialization.Version.V2; import static org.apache.cassandra.utils.LocalizeString.toLowerCaseLocalized; /** @@ -54,7 +56,8 @@ public final class KeyspaceParams public enum Option { DURABLE_WRITES, - REPLICATION; + REPLICATION, + FAST_PATH; @Override public String toString() @@ -65,41 +68,53 @@ public final class KeyspaceParams public final boolean durableWrites; public final ReplicationParams replication; + public final FastPathStrategy fastPath; - public KeyspaceParams(boolean durableWrites, ReplicationParams replication) + public KeyspaceParams(boolean durableWrites, ReplicationParams replication, FastPathStrategy fastPath) { this.durableWrites = durableWrites; this.replication = replication; + this.fastPath = fastPath; + } + + public static KeyspaceParams create(boolean durableWrites, Map replication, FastPathStrategy fastPath) + { + return new KeyspaceParams(durableWrites, ReplicationParams.fromMap(replication), fastPath); + } + + public static KeyspaceParams create(boolean durableWrites, Map replication, Map fastPath) + { + return create(durableWrites, replication, FastPathStrategy.fromMap(fastPath)); } public static KeyspaceParams create(boolean durableWrites, Map replication) { - return new KeyspaceParams(durableWrites, ReplicationParams.fromMap(replication)); + return create(durableWrites, replication, FastPathStrategy.simple()); } public static KeyspaceParams local() { - return new KeyspaceParams(DEFAULT_LOCAL_DURABLE_WRITES, ReplicationParams.local()); + return new KeyspaceParams(DEFAULT_LOCAL_DURABLE_WRITES, ReplicationParams.local(), FastPathStrategy.simple()); } public static KeyspaceParams simple(int replicationFactor) { - return new KeyspaceParams(true, ReplicationParams.simple(replicationFactor)); + return new KeyspaceParams(true, ReplicationParams.simple(replicationFactor), FastPathStrategy.simple()); } public static KeyspaceParams simple(String replicationFactor) { - return new KeyspaceParams(true, ReplicationParams.simple(replicationFactor)); + return new KeyspaceParams(true, ReplicationParams.simple(replicationFactor), FastPathStrategy.simple()); } public static KeyspaceParams simpleTransient(int replicationFactor) { - return new KeyspaceParams(false, ReplicationParams.simple(replicationFactor)); + return new KeyspaceParams(false, ReplicationParams.simple(replicationFactor), FastPathStrategy.simple()); } public static KeyspaceParams nts(Object... args) { - return new KeyspaceParams(true, ReplicationParams.nts(args)); + return new KeyspaceParams(true, ReplicationParams.nts(args), FastPathStrategy.simple()); } public void validate(String name, ClientState state, ClusterMetadata metadata) @@ -118,13 +133,13 @@ public final class KeyspaceParams KeyspaceParams p = (KeyspaceParams) o; - return durableWrites == p.durableWrites && replication.equals(p.replication); + return durableWrites == p.durableWrites && replication.equals(p.replication) && fastPath.equals(p.fastPath); } @Override public int hashCode() { - return Objects.hashCode(durableWrites, replication); + return Objects.hashCode(durableWrites, replication, fastPath); } @Override @@ -133,6 +148,7 @@ public final class KeyspaceParams return MoreObjects.toStringHelper(this) .add(Option.DURABLE_WRITES.toString(), durableWrites) .add(Option.REPLICATION.toString(), replication) + .add(Option.FAST_PATH.toString(), fastPath.toString()) .toString(); } @@ -142,19 +158,25 @@ public final class KeyspaceParams { ReplicationParams.serializer.serialize(t.replication, out, version); out.writeBoolean(t.durableWrites); + if (version.isAtLeast(V2)) + FastPathStrategy.serializer.serialize(t.fastPath, out, version); } public KeyspaceParams deserialize(DataInputPlus in, Version version) throws IOException { ReplicationParams params = ReplicationParams.serializer.deserialize(in, version); boolean durableWrites = in.readBoolean(); - return new KeyspaceParams(durableWrites, params); + FastPathStrategy fastPath = version.isAtLeast(V2) + ? FastPathStrategy.serializer.deserialize(in, version) + : FastPathStrategy.simple(); + return new KeyspaceParams(durableWrites, params, fastPath); } public long serializedSize(KeyspaceParams t, Version version) { return ReplicationParams.serializer.serializedSize(t.replication, version) + - TypeSizes.sizeof(t.durableWrites); + TypeSizes.sizeof(t.durableWrites) + + (version.isAtLeast(V2) ? FastPathStrategy.serializer.serializedSize(t.fastPath, version) : 0); } } } diff --git a/src/java/org/apache/cassandra/schema/SchemaKeyspace.java b/src/java/org/apache/cassandra/schema/SchemaKeyspace.java index ce8fa750b3..cd37fa4dac 100644 --- a/src/java/org/apache/cassandra/schema/SchemaKeyspace.java +++ b/src/java/org/apache/cassandra/schema/SchemaKeyspace.java @@ -44,6 +44,7 @@ import org.apache.cassandra.db.marshal.*; import org.apache.cassandra.db.partitions.*; import org.apache.cassandra.db.rows.*; import org.apache.cassandra.exceptions.InvalidRequestException; +import org.apache.cassandra.service.accord.fastpath.FastPathStrategy; import org.apache.cassandra.service.reads.SpeculativeRetryPolicy; import org.apache.cassandra.schema.ColumnMetadata.ClusteringOrder; import org.apache.cassandra.schema.Keyspaces.KeyspacesDiff; @@ -97,6 +98,7 @@ public final class SchemaKeyspace + "keyspace_name text," + "durable_writes boolean," + "replication frozen>," + + "fast_path frozen>," + "PRIMARY KEY ((keyspace_name)))"); private static final TableMetadata Tables = @@ -128,6 +130,7 @@ public final class SchemaKeyspace + "additional_write_policy text," + "cdc boolean," + "read_repair text," + + "fast_path frozen>," + "PRIMARY KEY ((keyspace_name), table_name))"); private static final TableMetadata Columns = @@ -491,7 +494,8 @@ public final class SchemaKeyspace .row() .add(KeyspaceParams.Option.DURABLE_WRITES.toString(), params.durableWrites) .add(KeyspaceParams.Option.REPLICATION.toString(), - (params.replication.isMeta() ? params.replication.asNonMeta() : params.replication).asMap()); + (params.replication.isMeta() ? params.replication.asNonMeta() : params.replication).asMap()) + .add(KeyspaceParams.Option.FAST_PATH.toString(), params.fastPath.asMap()); return builder; } @@ -551,7 +555,7 @@ public final class SchemaKeyspace .add("id", table.id.asUUID()) .add("flags", TableMetadata.Flag.toStringSet(table.flags)); - addTableParamsToRowBuilder(table.params, rowBuilder); + addTableParamsToRowBuilder(table.params, rowBuilder, false); if (withColumnsAndTriggers) { @@ -569,7 +573,7 @@ public final class SchemaKeyspace } } - private static void addTableParamsToRowBuilder(TableParams params, Row.SimpleBuilder builder) + private static void addTableParamsToRowBuilder(TableParams params, Row.SimpleBuilder builder, boolean forView) { builder.add("bloom_filter_fp_chance", params.bloomFilterFpChance) .add("comment", params.comment) @@ -608,6 +612,9 @@ public final class SchemaKeyspace // incremental_backups is enabled, to avoid RTE in pre-4.2 versioned node during upgrades if (!params.incrementalBackups) builder.add("incremental_backups", false); + + if (DatabaseDescriptor.getAccordTransactionsEnabled() && !forView) + builder.add("fast_path", params.fastPath.asMap()); } private static void addAlterTableToSchemaMutation(TableMetadata oldTable, TableMetadata newTable, Mutation.SimpleBuilder builder) @@ -820,7 +827,7 @@ public final class SchemaKeyspace .add("where_clause", view.whereClause.toCQLString()) .add("id", table.id.asUUID()); - addTableParamsToRowBuilder(table.params, rowBuilder); + addTableParamsToRowBuilder(table.params, rowBuilder, true); if (includeColumns) { @@ -966,9 +973,11 @@ public final class SchemaKeyspace UntypedResultSet.Row row = query(query, keyspaceName).one(); boolean durableWrites = row.getBoolean(KeyspaceParams.Option.DURABLE_WRITES.toString()); Map replication = row.getFrozenTextMap(KeyspaceParams.Option.REPLICATION.toString()); - KeyspaceParams params = KeyspaceParams.create(durableWrites, replication); + Map fastPath = row.getFrozenTextMap(KeyspaceParams.Option.FAST_PATH.toString()); + KeyspaceParams params = KeyspaceParams.create(durableWrites, replication, fastPath); + if (keyspaceName.equals(SchemaConstants.METADATA_KEYSPACE_NAME)) - params = new KeyspaceParams(params.durableWrites, params.replication.asMeta()); + params = new KeyspaceParams(params.durableWrites, params.replication.asMeta(), FastPathStrategy.simple()); return params; } @@ -1070,7 +1079,8 @@ public final class SchemaKeyspace SpeculativeRetryPolicy.fromString(row.getString("additional_write_policy")) : SpeculativeRetryPolicy.fromString("99PERCENTILE")) .cdc(row.has("cdc") && row.getBoolean("cdc")) - .readRepair(getReadRepairStrategy(row)); + .readRepair(getReadRepairStrategy(row)) + .fastPath(getFastPathStrategy(row)); // allow_auto_snapshot column was introduced in 4.2 if (row.has("allow_auto_snapshot")) @@ -1448,4 +1458,11 @@ public final class SchemaKeyspace ? ReadRepairStrategy.fromString(row.getString("read_repair")) : ReadRepairStrategy.BLOCKING; } + + private static FastPathStrategy getFastPathStrategy(UntypedResultSet.Row row) + { + return row.has("fast_path") + ? FastPathStrategy.fromMap(row.getFrozenTextMap("fast_path")) + : FastPathStrategy.inheritKeyspace(); + } } diff --git a/src/java/org/apache/cassandra/schema/TableMetadata.java b/src/java/org/apache/cassandra/schema/TableMetadata.java index 90c56e47bb..88a3f80d0b 100644 --- a/src/java/org/apache/cassandra/schema/TableMetadata.java +++ b/src/java/org/apache/cassandra/schema/TableMetadata.java @@ -70,6 +70,7 @@ import org.apache.cassandra.exceptions.ConfigurationException; import org.apache.cassandra.exceptions.InvalidRequestException; import org.apache.cassandra.io.util.DataInputPlus; import org.apache.cassandra.io.util.DataOutputPlus; +import org.apache.cassandra.service.accord.fastpath.FastPathStrategy; import org.apache.cassandra.service.reads.SpeculativeRetryPolicy; import org.apache.cassandra.tcm.Epoch; import org.apache.cassandra.tcm.serialization.UDTAndFunctionsAwareMetadataSerializer; @@ -973,6 +974,12 @@ public class TableMetadata implements SchemaElement return this; } + public Builder fastPath(FastPathStrategy val) + { + params.fastPath(val); + return this; + } + public Builder defaultTimeToLive(int val) { params.defaultTimeToLive(val); diff --git a/src/java/org/apache/cassandra/schema/TableParams.java b/src/java/org/apache/cassandra/schema/TableParams.java index 6903179525..40614f65ea 100644 --- a/src/java/org/apache/cassandra/schema/TableParams.java +++ b/src/java/org/apache/cassandra/schema/TableParams.java @@ -32,6 +32,7 @@ import org.apache.cassandra.cql3.CqlBuilder; import org.apache.cassandra.exceptions.ConfigurationException; import org.apache.cassandra.io.util.DataInputPlus; import org.apache.cassandra.io.util.DataOutputPlus; +import org.apache.cassandra.service.accord.fastpath.FastPathStrategy; import org.apache.cassandra.tcm.serialization.MetadataSerializer; import org.apache.cassandra.tcm.serialization.Version; import org.apache.cassandra.service.reads.PercentileSpeculativeRetryPolicy; @@ -69,7 +70,8 @@ public final class TableParams ADDITIONAL_WRITE_POLICY, CRC_CHECK_CHANCE, CDC, - READ_REPAIR; + READ_REPAIR, + FAST_PATH; @Override public String toString() @@ -97,6 +99,7 @@ public final class TableParams public final ImmutableMap extensions; public final boolean cdc; public final ReadRepairStrategy readRepair; + public final FastPathStrategy fastPath; private TableParams(Builder builder) { @@ -121,6 +124,7 @@ public final class TableParams extensions = builder.extensions; cdc = builder.cdc; readRepair = builder.readRepair; + fastPath = builder.fastPath; } public static Builder builder() @@ -148,7 +152,8 @@ public final class TableParams .additionalWritePolicy(params.additionalWritePolicy) .extensions(params.extensions) .cdc(params.cdc) - .readRepair(params.readRepair); + .readRepair(params.readRepair) + .fastPath(params.fastPath); } public Builder unbuild() @@ -239,7 +244,8 @@ public final class TableParams && memtable.equals(p.memtable) && extensions.equals(p.extensions) && cdc == p.cdc - && readRepair == p.readRepair; + && readRepair == p.readRepair + && fastPath.equals(fastPath); } @Override @@ -263,7 +269,8 @@ public final class TableParams memtable, extensions, cdc, - readRepair); + readRepair, + fastPath); } @Override @@ -275,6 +282,7 @@ public final class TableParams .add(ALLOW_AUTO_SNAPSHOT.toString(), allowAutoSnapshot) .add(BLOOM_FILTER_FP_CHANCE.toString(), bloomFilterFpChance) .add(CRC_CHECK_CHANCE.toString(), crcCheckChance) + .add(FAST_PATH.toString(), fastPath) .add(GC_GRACE_SECONDS.toString(), gcGraceSeconds) .add(DEFAULT_TIME_TO_LIVE.toString(), defaultTimeToLive) .add(INCREMENTAL_BACKUPS.toString(), incrementalBackups) @@ -289,6 +297,7 @@ public final class TableParams .add(EXTENSIONS.toString(), extensions) .add(CDC.toString(), cdc) .add(READ_REPAIR.toString(), readRepair) + .add(Option.FAST_PATH.toString(), fastPath) .toString(); } @@ -318,8 +327,8 @@ public final class TableParams if (!isView) { - builder.append("AND default_time_to_live = ").append(defaultTimeToLive) - .newLine(); + builder.append("AND fast_path = ").append(fastPath.asCQL()).newLine(); + builder.append("AND default_time_to_live = ").append(defaultTimeToLive).newLine(); } builder.append("AND extensions = ").append(extensions.entrySet() @@ -364,6 +373,7 @@ public final class TableParams private ImmutableMap extensions = ImmutableMap.of(); private boolean cdc; private ReadRepairStrategy readRepair = ReadRepairStrategy.BLOCKING; + private FastPathStrategy fastPath = FastPathStrategy.inheritKeyspace(); public Builder() { @@ -482,6 +492,12 @@ public final class TableParams return this; } + public Builder fastPath(FastPathStrategy val) + { + fastPath = val; + return this; + } + public Builder extensions(Map val) { extensions = ImmutableMap.copyOf(val); @@ -504,7 +520,10 @@ public final class TableParams out.writeUTF(t.speculativeRetry.toString()); out.writeUTF(t.additionalWritePolicy.toString()); if (version.isAtLeast(Version.V2)) + { out.writeUTF(t.memtable.configurationKey()); + FastPathStrategy.serializer.serialize(t.fastPath, out, version); + } serializeMap(t.caching.asMap(), out); serializeMap(t.compaction.asMap(), out); serializeMap(t.compression.asMap(), out); @@ -532,6 +551,7 @@ public final class TableParams .speculativeRetry(SpeculativeRetryPolicy.fromString(in.readUTF())) .additionalWritePolicy(SpeculativeRetryPolicy.fromString(in.readUTF())) .memtable(version.isAtLeast(Version.V2) ? MemtableParams.get(in.readUTF()) : MemtableParams.DEFAULT) + .fastPath(version.isAtLeast(Version.V2) ? FastPathStrategy.serializer.deserialize(in, version) : FastPathStrategy.simple()) .caching(CachingParams.fromMap(deserializeMap(in))) .compaction(CompactionParams.fromMap(deserializeMap(in))) .compression(CompressionParams.fromMap(deserializeMap(in))) @@ -556,6 +576,7 @@ public final class TableParams sizeof(t.speculativeRetry.toString()) + sizeof(t.additionalWritePolicy.toString()) + (version.isAtLeast(Version.V2) ? sizeof(t.memtable.configurationKey()) : 0) + + (version.isAtLeast(Version.V2) ? FastPathStrategy.serializer.serializedSize(t.fastPath, version) : 0) + serializedSizeMap(t.caching.asMap()) + serializedSizeMap(t.compaction.asMap()) + serializedSizeMap(t.compression.asMap()) + diff --git a/src/java/org/apache/cassandra/service/Rebuild.java b/src/java/org/apache/cassandra/service/Rebuild.java index 673a6ca486..b6e4d61d1b 100644 --- a/src/java/org/apache/cassandra/service/Rebuild.java +++ b/src/java/org/apache/cassandra/service/Rebuild.java @@ -113,7 +113,8 @@ public class Rebuild false, DatabaseDescriptor.getStreamingConnectionsPerHost(), rebuildMovements, - null); + null, + true); if (sourceDc != null) streamer.addSourceFilter(new RangeStreamer.SingleDatacenterFilter(metadata.locator, sourceDc)); @@ -123,16 +124,11 @@ public class Rebuild if (keyspace == null) { for (String keyspaceName : Schema.instance.getNonLocalStrategyKeyspaces().names()) - { - if (AccordService.instance().isAccordManagedKeyspace(keyspaceName)) - continue; streamer.addKeyspaceToFetch(keyspaceName); - } } else if (tokens == null) { - if (!AccordService.instance().isAccordManagedKeyspace(keyspace)) - streamer.addKeyspaceToFetch(keyspace); + streamer.addKeyspaceToFetch(keyspace); } else { @@ -159,8 +155,7 @@ public class Rebuild streamer.addSourceFilter(new RangeStreamer.AllowedSourcesFilter(sources)); } - if (!AccordService.instance().isAccordManagedKeyspace(keyspace)) - streamer.addKeyspaceToFetch(keyspace); + streamer.addKeyspaceToFetch(keyspace); } StreamResultFuture resultFuture = streamer.fetchAsync(); diff --git a/src/java/org/apache/cassandra/service/StorageProxy.java b/src/java/org/apache/cassandra/service/StorageProxy.java index a40426c001..52cc03ef5a 100644 --- a/src/java/org/apache/cassandra/service/StorageProxy.java +++ b/src/java/org/apache/cassandra/service/StorageProxy.java @@ -378,7 +378,7 @@ public class StorageProxy implements StorageProxyMBean clientState, nowInSeconds); IAccordService accordService = AccordService.instance(); - accordService.maybeConvertKeyspacesToAccord(txn); + accordService.maybeConvertTablesToAccord(txn); TxnResult txnResult = accordService.coordinate(txn, consistencyForPaxos, requestTime); @@ -1251,7 +1251,7 @@ public class StorageProxy implements StorageProxyMBean AccordUpdate update = new TxnUpdate(fragments, TxnCondition.none(), clForCommit); Txn.InMemory txn = new Txn.InMemory(Keys.of(partitionKeys), TxnRead.EMPTY, TxnQuery.EMPTY, update); IAccordService accordService = AccordService.instance(); - accordService.maybeConvertKeyspacesToAccord(txn); + accordService.maybeConvertTablesToAccord(txn); accordService.coordinate(txn, consistencyLevel, requestTime); } @@ -2001,7 +2001,7 @@ public class StorageProxy implements StorageProxyMBean TxnRead read = TxnRead.createSerialRead(readCommand, consistencyLevel); Txn txn = new Txn.InMemory(read.keys(), read, TxnQuery.ALL); IAccordService accordService = AccordService.instance(); - accordService.maybeConvertKeyspacesToAccord(txn); + accordService.maybeConvertTablesToAccord(txn); TxnResult txnResult = accordService.coordinate(txn, consistencyLevel, requestTime); if (txnResult.kind() == retry_new_protocol) return RETRY_NEW_PROTOCOL; diff --git a/src/java/org/apache/cassandra/service/StorageService.java b/src/java/org/apache/cassandra/service/StorageService.java index e9dc473577..d473ae5f09 100644 --- a/src/java/org/apache/cassandra/service/StorageService.java +++ b/src/java/org/apache/cassandra/service/StorageService.java @@ -4232,11 +4232,24 @@ public class StorageService extends NotificationBroadcasterSupport implements IE @Override public List getAccordManagedKeyspaces() + { + Keyspaces keyspaces = Schema.instance.getNonLocalStrategyKeyspaces(); + return keyspaces.stream().flatMap(ks -> ks.tables.stream()) + .filter(tbm -> AccordService.instance().isAccordManagedTable(tbm.id)) + .map(tbm -> tbm.keyspace) + .distinct() + .sorted() + .collect(toList()); + } + + @Override + public List getAccordManagedTables() { // TODO (review) These are really just the ones Accord is aware of not necessarily managed - Set keyspaces = Schema.instance.getNonLocalStrategyKeyspaces().names(); - return keyspaces.stream() - .filter(AccordService.instance()::isAccordManagedKeyspace) + Keyspaces keyspaces = Schema.instance.getNonLocalStrategyKeyspaces(); + return keyspaces.stream().flatMap(ks -> ks.tables.stream()) + .filter(tbm -> AccordService.instance().isAccordManagedTable(tbm.id)) + .map(tbm -> tbm.keyspace + '.' + tbm.name) .collect(toList()); } diff --git a/src/java/org/apache/cassandra/service/StorageServiceMBean.java b/src/java/org/apache/cassandra/service/StorageServiceMBean.java index d11ca1bfb4..b4e28c3e9b 100644 --- a/src/java/org/apache/cassandra/service/StorageServiceMBean.java +++ b/src/java/org/apache/cassandra/service/StorageServiceMBean.java @@ -1158,6 +1158,7 @@ public interface StorageServiceMBean extends NotificationEmitter String listConsensusMigrations(@Nullable Set keyspaceNames, @Nullable Set tableNames, @Nonnull String format); List getAccordManagedKeyspaces(); + List getAccordManagedTables(); /** Gets the concurrency settings for processing stages*/ static class StageConcurrency implements Serializable diff --git a/src/java/org/apache/cassandra/service/accord/AccordCommandStores.java b/src/java/org/apache/cassandra/service/accord/AccordCommandStores.java index d5f1ed3b35..cf4cda992b 100644 --- a/src/java/org/apache/cassandra/service/accord/AccordCommandStores.java +++ b/src/java/org/apache/cassandra/service/accord/AccordCommandStores.java @@ -33,6 +33,7 @@ import accord.utils.RandomSource; import org.apache.cassandra.cache.CacheSize; import org.apache.cassandra.metrics.AccordStateCacheMetrics; import org.apache.cassandra.metrics.CacheSizeMetrics; +import org.apache.cassandra.schema.TableId; import org.apache.cassandra.service.accord.api.AccordRoutingKey; public class AccordCommandStores extends CommandStores implements CacheSize @@ -62,15 +63,15 @@ public class AccordCommandStores extends CommandStores implements CacheSize if (!super.shouldBootstrap(node, previous, updated, range)) return false; // we see new ranges when a new keyspace is added, so avoid bootstrap in these cases - return contains(previous, ((AccordRoutingKey) range.start()).keyspace()); + return contains(previous, ((AccordRoutingKey) range.start()).table()); } - private static boolean contains(Topology previous, String searchKeyspace) + private static boolean contains(Topology previous, TableId searchTable) { for (Range range : previous.ranges()) { - String keyspace = ((AccordRoutingKey) range.start()).keyspace(); - if (keyspace.equals(searchKeyspace)) + TableId table = ((AccordRoutingKey) range.start()).table(); + if (table.equals(searchTable)) return true; } return false; diff --git a/src/java/org/apache/cassandra/service/accord/AccordCommandsForKeys.java b/src/java/org/apache/cassandra/service/accord/AccordCommandsForKeys.java index e8a35f4174..340b8396d3 100644 --- a/src/java/org/apache/cassandra/service/accord/AccordCommandsForKeys.java +++ b/src/java/org/apache/cassandra/service/accord/AccordCommandsForKeys.java @@ -192,9 +192,9 @@ public class AccordCommandsForKeys } // update in memory cfk data with the update results - protected void maybeUpdateCommands(CommandsForKeyUpdate update) + protected void maybeUpdateCommands(CommandsForKeyUpdate update, AccordStateCache.Instance cache) { - CommandsCachingState commands = (CommandsCachingState) commandStore.depsCommandsForKeyCache().getUnsafe(key()); + CommandsCachingState commands = (CommandsCachingState) cache.getUnsafe(key()); if (commands == null) return; @@ -214,7 +214,8 @@ public class AccordCommandsForKeys Modified modified = (Modified) next; CommandsForKeyUpdate current = modified.current; - maybeUpdateCommands(current); + maybeUpdateCommands(current, commandStore.depsCommandsForKeyCache()); + maybeUpdateCommands(current, commandStore.allCommandsForKeyCache()); // combine in memory updates current = CommandsForKeyGroupUpdater.Immutable.merge(modified.original, current, this); diff --git a/src/java/org/apache/cassandra/service/accord/AccordConfigurationService.java b/src/java/org/apache/cassandra/service/accord/AccordConfigurationService.java index 5b9ea24ab8..ad20fea043 100644 --- a/src/java/org/apache/cassandra/service/accord/AccordConfigurationService.java +++ b/src/java/org/apache/cassandra/service/accord/AccordConfigurationService.java @@ -153,15 +153,15 @@ public class AccordConfigurationService extends AbstractConfigurationService +{ + public static final AccordFastPath EMPTY = new AccordFastPath(ImmutableMap.of(), Epoch.EMPTY); + + public enum Status + { + NORMAL, SHUTDOWN, UNAVAILABLE; + + public boolean isUnavailable() + { + switch (this) + { + case UNAVAILABLE: + case SHUTDOWN: + return true; + default: + return false; + } + } + + public static final MetadataSerializer serializer = new MetadataSerializer() + { + @Override + public void serialize(Status status, DataOutputPlus out, Version version) throws IOException + { + switch (status) + { + case NORMAL: out.write(0); break; + case SHUTDOWN: out.write(1); break; + case UNAVAILABLE: out.write(2); break; + default: throw new IllegalStateException("Unhandled status: " + this); + } + } + + @Override + public Status deserialize(DataInputPlus in, Version version) throws IOException + { + byte b = in.readByte(); + switch (b) + { + case 0: return NORMAL; + case 1: return SHUTDOWN; + case 2: return UNAVAILABLE; + default: throw new IllegalArgumentException("Unhandled status byte: " + b); + } + } + + @Override + public long serializedSize(Status status, Version version) + { + return TypeSizes.BYTE_SIZE; + } + }; + }; + + public static class NodeInfo + { + public final Status status; + public final long updated; + + public NodeInfo(Status status, long updated) + { + this.status = status; + this.updated = updated; + } + + @Override + public boolean equals(Object o) + { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + NodeInfo nodeInfo = (NodeInfo) o; + return updated == nodeInfo.updated && status == nodeInfo.status; + } + + @Override + public int hashCode() + { + return Objects.hash(status, updated); + } + + private static final MetadataSerializer serializer = new MetadataSerializer() + { + @Override + public void serialize(NodeInfo info, DataOutputPlus out, Version version) throws IOException + { + Status.serializer.serialize(info.status, out, version); + out.writeUnsignedVInt(info.updated); + } + + @Override + public NodeInfo deserialize(DataInputPlus in, Version version) throws IOException + { + return new NodeInfo(Status.serializer.deserialize(in, version), in.readUnsignedVInt()); + } + + @Override + public long serializedSize(NodeInfo info, Version version) + { + return Status.serializer.serializedSize(info.status, version) + TypeSizes.sizeofUnsignedVInt(info.updated); + } + }; + } + + public final ImmutableMap info; + + private final Epoch lastModified; + + AccordFastPath(ImmutableMap info, Epoch lastModified) + { + this.info = info; + this.lastModified = lastModified; + } + + @Override + public boolean equals(Object o) + { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + AccordFastPath that = (AccordFastPath) o; + return info.equals(that.info) && lastModified.equals(that.lastModified); + } + + @Override + public int hashCode() + { + return Objects.hash(info, lastModified); + } + + public AccordFastPath withoutNode(NodeId tcmId) + { + Node.Id node = AccordTopology.tcmIdToAccord(tcmId); + if (!info.containsKey(node)) + return this; + + ImmutableMap.Builder builder = ImmutableMap.builder(); + info.forEach((n, info) -> { + if (!n.equals(node)) + builder.put(n, info); + }); + return new AccordFastPath(builder.build(), lastModified); + } + + public AccordFastPath withNodeStatusSince(Node.Id node, Status status, long updateTimeMillis, long updateDelayMillis) + { + NodeInfo current = info.get(node); + if (status == Status.SHUTDOWN && current != null) + { + // nodes report when they're being shutdown and aren't superseded + updateTimeMillis = Math.max(updateTimeMillis, current.updated + 1); + } + + if (!canUpdateNodeTo(current, status, updateTimeMillis, updateDelayMillis)) + throw new InvalidRequestException(String.format("cannot transition %s to %s at %s", node, status, updateTimeMillis)); + + ImmutableMap.Builder builder = ImmutableMap.builder(); + builder.put(node, new NodeInfo(status, updateTimeMillis)); + info.forEach((n, info) -> { + if (!n.equals(node)) + builder.put(n, info); + }); + return new AccordFastPath(builder.build(), lastModified); + } + + public boolean canUpdateNodeTo(NodeInfo current, Status status, long updateTimeMillis, long updateDelayMillis) + { + if (current == null) + return status != Status.NORMAL; + + if (current.status == status) + return false; + + return updateTimeMillis > current.updated + (status == Status.SHUTDOWN ? 0 : updateDelayMillis); + } + + public AccordFastPath withLastModified(Epoch epoch) + { + return new AccordFastPath(info, epoch); + } + + public Epoch lastModified() + { + return lastModified; + } + + public ImmutableSet unavailableIds() + { + ImmutableSet.Builder builder = ImmutableSet.builder(); + info.entrySet().stream() + .filter(entry -> entry.getValue().status.isUnavailable()) + .map(Map.Entry::getKey) + .forEach(builder::add); + return builder.build(); + } + + public static final MetadataSerializer serializer = new MetadataSerializer() + { + private void serializeMap(Map map, DataOutputPlus out, Version version) throws IOException + { + out.writeInt(map.size()); + for (Map.Entry entry : map.entrySet()) + { + TopologySerializers.nodeId.serialize(entry.getKey(), out, version); + NodeInfo.serializer.serialize(entry.getValue(), out, version); + } + } + + public void serialize(AccordFastPath accordFastPath, DataOutputPlus out, Version version) throws IOException + { + serializeMap(accordFastPath.info, out, version); + Epoch.serializer.serialize(accordFastPath.lastModified, out, version); + } + + private ImmutableMap deserializeMap(DataInputPlus in, Version version) throws IOException + { + int size = in.readInt(); + if (size == 0) + return ImmutableMap.of(); + + ImmutableMap.Builder builder = ImmutableMap.builder(); + for (int i=0; i map, Version version) + { + long size = TypeSizes.INT_SIZE; + for (Map.Entry entry : map.entrySet()) + { + size += TopologySerializers.nodeId.serializedSize(entry.getKey(), version); + size += NodeInfo.serializer.serializedSize(entry.getValue(), version); + } + return size; + } + + public long serializedSize(AccordFastPath accordFastPath, Version version) + { + return serializedMapSize(accordFastPath.info, version) + + Epoch.serializer.serializedSize(accordFastPath.lastModified, version); + } + }; +} diff --git a/src/java/org/apache/cassandra/service/accord/AccordFastPathCoordinator.java b/src/java/org/apache/cassandra/service/accord/AccordFastPathCoordinator.java new file mode 100644 index 0000000000..c1fc73d80f --- /dev/null +++ b/src/java/org/apache/cassandra/service/accord/AccordFastPathCoordinator.java @@ -0,0 +1,345 @@ +/* + * 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.service.accord; + +import accord.api.ConfigurationService; +import accord.local.Node; +import accord.primitives.Ranges; +import accord.topology.Topology; +import accord.utils.Invariants; +import accord.utils.async.AsyncResult; +import accord.utils.async.AsyncResults; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableSet; +import org.apache.cassandra.concurrent.ScheduledExecutors; +import org.apache.cassandra.concurrent.Stage; +import org.apache.cassandra.config.DatabaseDescriptor; +import org.apache.cassandra.gms.EndpointState; +import org.apache.cassandra.gms.Gossiper; +import org.apache.cassandra.gms.IEndpointStateChangeSubscriber; +import org.apache.cassandra.locator.InetAddressAndPort; +import org.apache.cassandra.service.StorageService; +import org.apache.cassandra.service.accord.AccordFastPath.NodeInfo; +import org.apache.cassandra.service.accord.AccordFastPath.Status; +import org.apache.cassandra.tcm.ClusterMetadata; +import org.apache.cassandra.tcm.ClusterMetadataService; +import org.apache.cassandra.tcm.Epoch; +import org.apache.cassandra.tcm.listeners.ChangeListener; +import org.apache.cassandra.tcm.transformations.ReconfigureAccordFastPath; +import org.apache.cassandra.utils.Clock; + +import java.util.*; +import java.util.concurrent.TimeUnit; + +/** + * Listens to availability status of peers and updates tcm fast path data accordingly + */ +public abstract class AccordFastPathCoordinator implements ChangeListener, ConfigurationService.Listener +{ + private static final AsyncResult SUCCESS = AsyncResults.success(null); + + private static class PeerStatus + { + final Node.Id peer; + final Status status; + + public PeerStatus(Node.Id peer, Status status) + { + this.peer = peer; + this.status = status; + } + + boolean shouldUpdateFastPath(AccordFastPath fastPath, long nowMillis, long delayMillis) + { + NodeInfo info = fastPath.info.get(peer); + + if (info == null) + return status != Status.NORMAL; + + if (info.status == status || info.status == Status.SHUTDOWN) + return false; + + return nowMillis - info.updated > delayMillis; + } + } + + private static class Peers + { + static final Peers EMPTY = new Peers(0, ImmutableSet.of(), Collections.emptyMap()); + final long epoch; + final ImmutableSet peers; + final Map statusMap; + + public Peers(long epoch, ImmutableSet peers, Map statusMap) + { + this.epoch = epoch; + this.peers = peers; + this.statusMap = statusMap; + } + + public boolean contains(Node.Id node) + { + return peers.contains(node); + } + + public static Peers from(Node.Id localId, Topology topology, Peers prev) + { + Set peers = new HashSet<>(); + topology.forEachOn(localId, (shard, index) -> peers.addAll(shard.nodes)); + peers.remove(localId); + + Map statusMap = new HashMap<>(); + for (Node.Id peer : peers) + { + PeerStatus status = prev.statusMap.get(peer); + if (status != null) + statusMap.put(peer, status); + } + + return new Peers(topology.epoch(), ImmutableSet.copyOf(peers), statusMap); + } + + public PeerStatus onUpdate(Node.Id node, Status status) + { + Invariants.checkArgument(contains(node)); + PeerStatus peerStatus = new PeerStatus(node, status); + statusMap.put(node, peerStatus); + return peerStatus; + } + + public Iterable statusIterable() + { + return statusMap.values(); + } + } + + private boolean receivedShutdownSignal = false; + private volatile Epoch startupEpoch = null; + private volatile boolean issuedStartupUpdate = false; + private boolean hasRegistered = false; + private Peers peers = Peers.EMPTY; + private final Node.Id localId; + + public AccordFastPathCoordinator(Node.Id localId) + { + this.localId = localId; + } + + private boolean isShutdown(AccordFastPath fastPath) + { + NodeInfo info = fastPath.info.get(localId); + return info != null && info.status == Status.SHUTDOWN; + } + + public synchronized void start() + { + if (hasRegistered) + return; + + ClusterMetadata cm = currentMetadata(); + startupEpoch = cm.epoch; + registerAsListener(); + + // TODO: start check routine + + hasRegistered = true; + + AccordFastPath fastPath = cm.accordFastPath; + + long updateDelayMillis = getAccordFastPathUpdateDelayMillis(); + if (isShutdown(fastPath)) + { + updateFastPath(localId, Status.NORMAL, Clock.Global.currentTimeMillis(), updateDelayMillis); + issuedStartupUpdate = true; + } + + scheduleMaintenanceTask(updateDelayMillis); + } + + abstract ClusterMetadata currentMetadata(); + abstract void registerAsListener(); + abstract void updateFastPath(Node.Id node, Status status, long updateTimeMillis, long updateDelayMillis); + abstract long getAccordFastPathUpdateDelayMillis(); + + private static class Impl extends AccordFastPathCoordinator implements IEndpointStateChangeSubscriber + { + private final AccordConfigurationService configService; + + public Impl(Node.Id localId, AccordConfigurationService configService) + { + super(localId); + this.configService = configService; + } + + @Override + ClusterMetadata currentMetadata() + { + return ClusterMetadata.current(); + } + + @Override + void registerAsListener() + { + Gossiper.instance.register(this); + StorageService.instance.addPreShutdownHook(this::onShutdown); + configService.registerListener(this); + } + + @Override + void updateFastPath(Node.Id node, Status status, long updateTimeMillis, long updateDelayMillis) + { + Stage.MISC.submit(() -> { + ClusterMetadataService.instance().commit(new ReconfigureAccordFastPath(node, status, updateTimeMillis, updateDelayMillis), + metadata -> metadata, ((code, message) -> null)); + }); + } + + @Override + long getAccordFastPathUpdateDelayMillis() + { + return DatabaseDescriptor.getAccordFastPathUpdateDelayMillis(); + } + + @Override + public void onAlive(InetAddressAndPort endpoint, EndpointState state) + { + Node.Id node = configService.mappedIdOrNull(endpoint); + if (node != null) onAlive(node); + } + + @Override + public void onDead(InetAddressAndPort endpoint, EndpointState state) + { + Node.Id node = configService.mappedIdOrNull(endpoint); + if (node != null) onDead(node); + } + } + + public static AccordFastPathCoordinator create(Node.Id localId, AccordConfigurationService configService) + { + return new Impl(localId, configService); + } + + synchronized void maybeUpdateFastPath(Node.Id node, Status status) + { + long nowMillis = Clock.Global.currentTimeMillis(); + long delayMillis = getAccordFastPathUpdateDelayMillis(); + + // don't schedule updates for nodes we don't share shards with + if (!peers.contains(node)) + return; + + PeerStatus peerStatus = peers.onUpdate(node, status); + ClusterMetadata metadata = currentMetadata(); + if (peerStatus.shouldUpdateFastPath(metadata.accordFastPath, nowMillis, delayMillis)) + updateFastPath(node, status, nowMillis, delayMillis); + } + + private void scheduleMaintenanceTask(long delayMillis) + { + ScheduledExecutors.scheduledTasks.schedule(this::maintenance, delayMillis, TimeUnit.MILLISECONDS); + } + + synchronized void maintenance() + { + long nowMillis = Clock.Global.currentTimeMillis(); + long delayMillis = getAccordFastPathUpdateDelayMillis(); + try + { + ClusterMetadata metadata = currentMetadata(); + for (PeerStatus status : peers.statusIterable()) + { + if (status.shouldUpdateFastPath(metadata.accordFastPath, nowMillis, delayMillis)) + updateFastPath(status.peer, status.status, nowMillis, delayMillis); + } + } + finally + { + scheduleMaintenanceTask(delayMillis); + } + } + + void onAlive(Node.Id node) + { + maybeUpdateFastPath(node, Status.NORMAL); + } + + public void onDead(Node.Id node) + { + maybeUpdateFastPath(node, Status.UNAVAILABLE); + } + + public void onShutdown() + { + synchronized (this) + { + receivedShutdownSignal = true; + } + + updateFastPath(localId, Status.SHUTDOWN, Clock.Global.currentTimeMillis(), getAccordFastPathUpdateDelayMillis()); + } + + /** + * In case we somehow missed that we've marked ourselves shutdown on startup + */ + @Override + public void notifyPostCommit(ClusterMetadata prev, ClusterMetadata next, boolean fromSnapshot) + { + if (next.epoch.compareTo(startupEpoch) <= 0) + return; + + if (!isShutdown(next.accordFastPath)) + return; + + synchronized (this) + { + if (receivedShutdownSignal || issuedStartupUpdate) + return; + issuedStartupUpdate = true; + } + + updateFastPath(localId, Status.NORMAL, Clock.Global.currentTimeMillis(), getAccordFastPathUpdateDelayMillis()); + } + + synchronized void updatePeers(Topology topology) + { + if (topology.epoch() <= peers.epoch) + return; + + peers = Peers.from(localId, topology, peers); + } + + @VisibleForTesting + synchronized boolean isPeer(Node.Id node) + { + return peers.contains(node); + } + + @Override + public AsyncResult onTopologyUpdate(Topology topology, boolean startSync) + { + updatePeers(topology); + return SUCCESS; + } + + @Override public void onRemoteSyncComplete(Node.Id node, long epoch) {} + @Override public void truncateTopologyUntil(long epoch) {} + @Override public void onEpochClosed(Ranges ranges, long epoch) {} + @Override public void onEpochRedundant(Ranges ranges, long epoch) {} +} diff --git a/src/java/org/apache/cassandra/service/accord/AccordFetchCoordinator.java b/src/java/org/apache/cassandra/service/accord/AccordFetchCoordinator.java index 8b6162f227..088c6c1331 100644 --- a/src/java/org/apache/cassandra/service/accord/AccordFetchCoordinator.java +++ b/src/java/org/apache/cassandra/service/accord/AccordFetchCoordinator.java @@ -52,7 +52,8 @@ import org.apache.cassandra.io.util.DataInputPlus; import org.apache.cassandra.io.util.DataOutputPlus; import org.apache.cassandra.locator.InetAddressAndPort; import org.apache.cassandra.locator.RangesAtEndpoint; -import org.apache.cassandra.schema.KeyspaceMetadata; +import org.apache.cassandra.schema.TableId; +import org.apache.cassandra.schema.TableMetadata; import org.apache.cassandra.service.accord.serializers.CommandSerializers; import org.apache.cassandra.service.accord.serializers.KeySerializers; import org.apache.cassandra.streaming.PreviewKind; @@ -267,16 +268,16 @@ public class AccordFetchCoordinator extends AbstractFetchCoordinator implements // TODO (correctness): check epoch // TODO (correctness): handle dropped tables - KeyspaceMetadata ksm = ClusterMetadata.current().schema.getKeyspaceMetadata(range.keyspace()); - Invariants.checkState(ksm != null, "Keyspace %s not found", range.keyspace()); - Invariants.checkState(ksm.tables.size() > 0, "Keyspace '%s' has no tables", range.keyspace()); + TableId tableId = range.table(); + TableMetadata table = ClusterMetadata.current().schema.getKeyspaces().getTableOrViewNullable(tableId); + Invariants.checkState(table != null, "Table with id %s not found", tableId); // FIXME: may also be relocation StreamPlan plan = new StreamPlan(StreamOperation.BOOTSTRAP, 1, false, null, PreviewKind.NONE).flushBeforeTransfer(true); RangesAtEndpoint ranges = RangesAtEndpoint.toDummyList(Collections.singleton(range.toKeyspaceRange())); - ksm.tables.forEach(table -> plan.transferRanges(to, table.keyspace, ranges, table.name)); + plan.transferRanges(to, table.keyspace, ranges, table.name); StreamResultFuture future = plan.execute(); return AsyncChains.success(StreamData.of(range, future.planId, hasDataToStream(future.getCoordinator(), to))); } diff --git a/src/java/org/apache/cassandra/service/accord/AccordKeyspace.java b/src/java/org/apache/cassandra/service/accord/AccordKeyspace.java index 0bf3f686c5..963a20adb1 100644 --- a/src/java/org/apache/cassandra/service/accord/AccordKeyspace.java +++ b/src/java/org/apache/cassandra/service/accord/AccordKeyspace.java @@ -862,7 +862,7 @@ public class AccordKeyspace private static ByteBuffer serializeKey(PartitionKey key) { - return TupleType.pack(ByteBufferAccessor.instance, Arrays.asList(UUIDSerializer.instance.serialize(key.tableId().asUUID()), key.partitionKey().getKey())); + return TupleType.pack(ByteBufferAccessor.instance, Arrays.asList(UUIDSerializer.instance.serialize(key.table().asUUID()), key.partitionKey().getKey())); } private static ByteBuffer serializeTimestamp(Timestamp timestamp) @@ -1303,7 +1303,7 @@ public class AccordKeyspace TableMetadata metadata = Schema.instance.getTableMetadata(tableId); if (metadata == null) throw new IllegalStateException("Table with id " + tableId + " could not be found; was it deleted?"); - return new PartitionKey(metadata.keyspace, tableId, metadata.partitioner.decorateKey(key)); + return new PartitionKey(tableId, metadata.partitioner.decorateKey(key)); } public static PartitionKey deserializeKey(UntypedResultSet.Row row) @@ -1358,7 +1358,7 @@ public class AccordKeyspace return executeInternal(format(cql, ACCORD_KEYSPACE_NAME, TIMESTAMPS_FOR_KEY), commandStore.id(), serializeToken(key.token()), - key.tableId().asUUID(), key.partitionKey().getKey()); + key.table().asUUID(), key.partitionKey().getKey()); } public static TimestampsForKey loadTimestampsForKey(AccordCommandStore commandStore, PartitionKey key) diff --git a/src/java/org/apache/cassandra/service/accord/AccordObjectSizes.java b/src/java/org/apache/cassandra/service/accord/AccordObjectSizes.java index dc7a3c9e3b..095781f46a 100644 --- a/src/java/org/apache/cassandra/service/accord/AccordObjectSizes.java +++ b/src/java/org/apache/cassandra/service/accord/AccordObjectSizes.java @@ -20,6 +20,7 @@ package org.apache.cassandra.service.accord; import java.nio.ByteBuffer; import java.util.Map; +import java.util.UUID; import java.util.function.ToLongFunction; import com.google.common.collect.ImmutableSortedMap; @@ -58,6 +59,7 @@ import accord.primitives.Txn.Kind; import accord.primitives.TxnId; import accord.primitives.Unseekables; import accord.primitives.Writes; +import org.apache.cassandra.schema.TableId; import org.apache.cassandra.service.accord.api.AccordRoutingKey; import org.apache.cassandra.service.accord.api.AccordRoutingKey.TokenKey; import org.apache.cassandra.service.accord.api.PartitionKey; @@ -84,7 +86,8 @@ public class AccordObjectSizes return ((AccordRoutingKey) key).estimatedSizeOnHeap(); } - private static final long EMPTY_RANGE_SIZE = measure(TokenRange.fullRange("")); + private static final TableId EMPTY_ID = TableId.fromUUID(new UUID(0, 0)); + private static final long EMPTY_RANGE_SIZE = measure(TokenRange.fullRange(EMPTY_ID)); public static long range(Range range) { return EMPTY_RANGE_SIZE + key(range.start()) + key(range.end()); @@ -271,7 +274,7 @@ public class AccordObjectSizes private static class CommandEmptySizes { - private final static TokenKey EMPTY_KEY = new TokenKey("doesnotexist", null); + private final static TokenKey EMPTY_KEY = new TokenKey(EMPTY_ID, null); private final static TxnId EMPTY_TXNID = new TxnId(42, 42, Kind.Read, Domain.Key, new Node.Id(42)); private static CommonAttributes attrs(boolean hasDeps, boolean hasTxn) diff --git a/src/java/org/apache/cassandra/service/accord/AccordSafeCommandsForKey.java b/src/java/org/apache/cassandra/service/accord/AccordSafeCommandsForKey.java index e57a94f863..97fc604649 100644 --- a/src/java/org/apache/cassandra/service/accord/AccordSafeCommandsForKey.java +++ b/src/java/org/apache/cassandra/service/accord/AccordSafeCommandsForKey.java @@ -68,6 +68,20 @@ public class AccordSafeCommandsForKey extends SafeCommandsForKey implements Acco '}'; } + @Override + public boolean hasUpdate() + { + boolean hasUpdate = AccordSafeState.super.hasUpdate(); + + // cfk initialization is legal, but doesn't need to be propagated to the cache (and would + // cause an exception to be thrown if it were). Making an exception on the cache side could + // throw away applied cfk updates as well, so it's special cased here + if (hasUpdate && original == null && current != null && current.commands().isEmpty()) + return false; + + return hasUpdate; + } + @Override public AccordCachingState global() { diff --git a/src/java/org/apache/cassandra/service/accord/AccordService.java b/src/java/org/apache/cassandra/service/accord/AccordService.java index ce0f6f6f1e..93f5422f82 100644 --- a/src/java/org/apache/cassandra/service/accord/AccordService.java +++ b/src/java/org/apache/cassandra/service/accord/AccordService.java @@ -28,6 +28,7 @@ import javax.annotation.Nonnull; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; +import org.apache.cassandra.tcm.transformations.AddAccordTable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -76,6 +77,7 @@ import org.apache.cassandra.net.IVerbHandler; import org.apache.cassandra.net.Message; import org.apache.cassandra.net.MessageDelivery; import org.apache.cassandra.net.MessagingService; +import org.apache.cassandra.schema.TableId; import org.apache.cassandra.service.accord.AccordSyncPropagator.Notification; import org.apache.cassandra.service.accord.api.AccordAgent; import org.apache.cassandra.service.accord.api.AccordRoutingKey.KeyspaceSplitter; @@ -92,7 +94,6 @@ import org.apache.cassandra.tcm.ClusterMetadata; import org.apache.cassandra.tcm.ClusterMetadataService; import org.apache.cassandra.tcm.Epoch; import org.apache.cassandra.tcm.membership.NodeId; -import org.apache.cassandra.tcm.transformations.AddAccordKeyspace; import org.apache.cassandra.transport.Dispatcher; import org.apache.cassandra.utils.Clock; import org.apache.cassandra.utils.ExecutorUtils; @@ -122,6 +123,7 @@ public class AccordService implements IAccordService, Shutdownable private final Shutdownable nodeShutdown; private final AccordMessageSink messageSink; private final AccordConfigurationService configService; + private final AccordFastPathCoordinator fastPathCoordinator; private final AccordScheduler scheduler; private final AccordDataStore dataStore; private final AccordJournal journal; @@ -139,7 +141,7 @@ public class AccordService implements IAccordService, Shutdownable @Override public long barrier(@Nonnull Seekables keysOrRanges, long minEpoch, Dispatcher.RequestTime requestTime, long timeoutNanos, BarrierType barrierType, boolean isForWrite) { - throw new UnsupportedOperationException("No accord barriers should be executed when accord_transactions_enabled = false in cassandra.yaml"); + throw new UnsupportedOperationException("No accord barriers should be executed when accord.enabled = false in cassandra.yaml"); } @Override @@ -195,7 +197,7 @@ public class AccordService implements IAccordService, Shutdownable public void receive(Message> message) {} @Override - public boolean isAccordManagedKeyspace(String keyspace) + public boolean isAccordManagedTable(TableId keyspace) { return false; } @@ -207,7 +209,7 @@ public class AccordService implements IAccordService, Shutdownable } @Override - public void ensureKeyspaceIsAccordManaged(String keyspace) {} + public void ensureTableIsAccordManaged(TableId tableId) {} }; private static volatile IAccordService instance = null; @@ -236,7 +238,7 @@ public class AccordService implements IAccordService, Shutdownable instance = NOOP_SERVICE; return; } - AccordService as = new AccordService(AccordTopologyUtils.tcmIdToAccord(tcmId)); + AccordService as = new AccordService(AccordTopology.tcmIdToAccord(tcmId)); as.startup(); instance = as; } @@ -276,6 +278,7 @@ public class AccordService implements IAccordService, Shutdownable logger.info("Starting accord with nodeId {}", localId); AccordAgent agent = new AccordAgent(); this.configService = new AccordConfigurationService(localId); + this.fastPathCoordinator = AccordFastPathCoordinator.create(localId, configService); this.messageSink = new AccordMessageSink(agent, configService); this.scheduler = new AccordScheduler(); this.dataStore = new AccordDataStore(); @@ -310,6 +313,8 @@ public class AccordService implements IAccordService, Shutdownable journal.start(); configService.start(); ClusterMetadataService.instance().log().addListener(configService); + fastPathCoordinator.start(); + ClusterMetadataService.instance().log().addListener(fastPathCoordinator); } @Override @@ -666,17 +671,18 @@ public class AccordService implements IAccordService, Shutdownable return configService; } - public boolean isAccordManagedKeyspace(String keyspace) + @Override + public boolean isAccordManagedTable(TableId tableId) { - return ClusterMetadata.current().accordKeyspaces.contains(keyspace); + return ClusterMetadata.current().accordTables.contains(tableId); } @Override - public void ensureKeyspaceIsAccordManaged(String keyspace) + public void ensureTableIsAccordManaged(TableId tableId) { - if (isAccordManagedKeyspace(keyspace)) + if (isAccordManagedTable(tableId)) return; - ClusterMetadataService.instance().commit(new AddAccordKeyspace(keyspace), + ClusterMetadataService.instance().commit(new AddAccordTable(tableId), metadata -> null, (code, message) -> { Invariants.checkState(code == ExceptionCode.ALREADY_EXISTS, diff --git a/src/java/org/apache/cassandra/service/accord/AccordTopology.java b/src/java/org/apache/cassandra/service/accord/AccordTopology.java new file mode 100644 index 0000000000..46b4d026bf --- /dev/null +++ b/src/java/org/apache/cassandra/service/accord/AccordTopology.java @@ -0,0 +1,277 @@ +/* + * 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.service.accord; + +import java.util.*; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import accord.primitives.Ranges; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Sets; + +import accord.local.Node; +import accord.topology.Shard; +import accord.topology.Topology; +import accord.utils.Invariants; +import org.apache.cassandra.db.Keyspace; +import org.apache.cassandra.dht.Range; +import org.apache.cassandra.dht.Token; +import org.apache.cassandra.locator.InetAddressAndPort; +import org.apache.cassandra.schema.*; +import org.apache.cassandra.service.accord.api.AccordRoutingKey.SentinelKey; +import org.apache.cassandra.service.accord.api.AccordRoutingKey.TokenKey; +import org.apache.cassandra.service.accord.fastpath.FastPathStrategy; +import org.apache.cassandra.tcm.ClusterMetadata; +import org.apache.cassandra.tcm.Epoch; +import org.apache.cassandra.tcm.membership.Directory; +import org.apache.cassandra.tcm.membership.NodeId; +import org.apache.cassandra.tcm.ownership.DataPlacement; +import org.apache.cassandra.tcm.ownership.DataPlacements; +import org.apache.cassandra.tcm.ownership.VersionedEndpoints; + +/** + * Deterministically computes accord topology from a ClusterMetadata instance + */ +public class AccordTopology +{ + public static Node.Id tcmIdToAccord(NodeId nodeId) + { + return new Node.Id(nodeId.id()); + } + + private static class ShardLookup extends HashMap + { + private Shard createOrReuse(accord.primitives.Range range, List nodes, Set fastPathElectorate, Set joining) + { + Shard prev = get(range); + if (prev != null + && Objects.equals(prev.nodes, nodes) + && Objects.equals(prev.fastPathElectorate, fastPathElectorate) + && Objects.equals(prev.joining, joining)) + return prev; + + return new Shard(range, nodes, fastPathElectorate, joining); + } + } + + static class KeyspaceShard + { + private final KeyspaceMetadata keyspace; + private final Range range; + private final List nodes; + private final Set pending; + + private KeyspaceShard(KeyspaceMetadata keyspace, Range range, List nodes, Set pending) + { + this.keyspace = keyspace; + this.range = range; + this.nodes = nodes; + this.pending = pending; + } + + // return the keyspace fast path strategy if the inherit keyspace strategy is used + private FastPathStrategy strategyFor(TableMetadata metadata) + { + FastPathStrategy tableStrategy = metadata.params.fastPath; + FastPathStrategy strategy = tableStrategy.kind() != FastPathStrategy.Kind.INHERIT_KEYSPACE + ? tableStrategy : keyspace.params.fastPath; + Invariants.checkState(strategy.kind() != FastPathStrategy.Kind.INHERIT_KEYSPACE);; + return strategy; + } + + Shard createForTable(TableMetadata metadata, Set unavailable, Map dcMap, ShardLookup lookup) + { + TokenRange tokenRange = AccordTopology.range(metadata.id, range); + + Set fastPath = strategyFor(metadata).calculateFastPath(nodes, unavailable, dcMap); + + return lookup.createOrReuse(tokenRange, nodes, fastPath, pending); + } + + private static KeyspaceShard forRange(KeyspaceMetadata keyspace, Range range, Directory directory, VersionedEndpoints.ForRange reads, VersionedEndpoints.ForRange writes) + { + // TCM doesn't create wrap around ranges + Invariants.checkArgument(!range.isWrapAround() || range.right.equals(range.right.minValue()), + "wrap around range %s found", range); + + Set readEndpoints = reads.endpoints(); + Set writeEndpoints = writes.endpoints(); + Sets.SetView readOnly = Sets.difference(readEndpoints, writeEndpoints); + Invariants.checkState(readOnly.isEmpty(), "Read only replicas detected: %s", readOnly); + + List nodes = writes.endpoints().stream() + .map(directory::peerId) + .map(AccordTopology::tcmIdToAccord) + .sorted().collect(Collectors.toList()); + + Set pending = readEndpoints.equals(writeEndpoints) ? + Collections.emptySet() : + writeEndpoints.stream() + .filter(e -> !readEndpoints.contains(e)) + .map(directory::peerId) + .map(AccordTopology::tcmIdToAccord) + .collect(Collectors.toSet()); + + return new KeyspaceShard(keyspace, range, nodes, pending); + } + + public static List forKeyspace(KeyspaceMetadata keyspace, DataPlacements placements, Directory directory, ShardLookup lookup) + { + ReplicationParams replication = keyspace.params.replication; + DataPlacement placement = placements.get(replication); + + List> ranges = placement.reads.ranges(); + List shards = new ArrayList<>(ranges.size()); + for (Range range : ranges) + { + VersionedEndpoints.ForRange reads = placement.reads.forRange(range); + VersionedEndpoints.ForRange writes = placement.writes.forRange(range); + shards.add(forRange(keyspace, range, directory, reads, writes)); + } + return shards; + } + } + + static TokenRange minRange(TableId table, Token token) + { + return new TokenRange(SentinelKey.min(table), new TokenKey(table, token)); + } + + static TokenRange maxRange(TableId table, Token token) + { + return new TokenRange(new TokenKey(table, token), SentinelKey.max(table)); + } + + static TokenRange fullRange(TableId table) + { + return new TokenRange(SentinelKey.min(table), SentinelKey.max(table)); + } + + static TokenRange range(TableId table, Range range) + { + Token minToken = range.left.minValue(); + return new TokenRange(range.left.equals(minToken) ? SentinelKey.min(table) : new TokenKey(table, range.left), + range.right.equals(minToken) ? SentinelKey.max(table) : new TokenKey(table, range.right)); + } + + public static accord.primitives.Ranges toAccordRanges(TableId tableId, Collection> ranges) + { + List> normalizedRanges = Range.normalize(ranges); + TokenRange[] tokenRanges = new TokenRange[normalizedRanges.size()]; + for (int i = 0; i < normalizedRanges.size(); i++) + tokenRanges[i] = range(tableId, normalizedRanges.get(i)); + return Ranges.of(tokenRanges); + } + + public static accord.primitives.Ranges toAccordRanges(String keyspace, Collection> ranges) + { + Keyspace ks = Keyspace.open(keyspace); + Ranges accordRanges = Ranges.EMPTY; + if (ks == null) + return accordRanges; + + for (TableMetadata tbm : ks.getMetadata().tables) + { + accordRanges = accordRanges.with(toAccordRanges(tbm.id, ranges)); + } + + return accordRanges; + } + + private static Map createDCMap(Directory directory) + { + ImmutableMap.Builder builder = ImmutableMap.builder(); + directory.knownDatacenters().forEach(dc -> { + Set dcEndpoints = directory.datacenterEndpoints(dc); + // nodes aren't added to the endpointsToDCMap until they've joined + if (dcEndpoints == null) + return; + dcEndpoints.forEach(ep -> { + NodeId tid = directory.peerId(ep); + Node.Id aid = tcmIdToAccord(tid); + builder.put(aid, dc); + }); + }); + return builder.build(); + } + + public static Topology createAccordTopology(Epoch epoch, DistributedSchema schema, DataPlacements placements, Directory directory, AccordFastPath accordFastPath, Predicate tablePredicate, ShardLookup lookup) + { + List shards = new ArrayList<>(); + Set unavailable = accordFastPath.unavailableIds(); + Map dcMap = createDCMap(directory); + + for (KeyspaceMetadata keyspace : schema.getKeyspaces()) + { + List tables = keyspace.tables.stream().filter(tbl -> tablePredicate.test(tbl.id)).collect(Collectors.toList()); + if (tables.isEmpty()) + continue; + List ksShards = KeyspaceShard.forKeyspace(keyspace, placements, directory, lookup); + tables.forEach(table -> ksShards.forEach(shard -> shards.add(shard.createForTable(table, unavailable, dcMap, lookup)))); + } + + shards.sort((a, b) -> a.range.compare(b.range)); + return new Topology(epoch.getEpoch(), shards.toArray(new Shard[0])); + } + + public static Topology createAccordTopology(ClusterMetadata metadata, Predicate tablePredicate, ShardLookup lookup) + { + return createAccordTopology(metadata.epoch, metadata.schema, metadata.placements, metadata.directory, metadata.accordFastPath, tablePredicate, lookup); + } + + public static Topology createAccordTopology(ClusterMetadata metadata, Predicate tablePredicate) + { + return createAccordTopology(metadata, tablePredicate, new ShardLookup()); + } + + public static Topology createAccordTopology(ClusterMetadata metadata, Topology current) + { + return createAccordTopology(metadata, metadata.accordTables::contains, createShardLookup(current)); + } + + public static Topology createAccordTopology(ClusterMetadata metadata) + { + return createAccordTopology(metadata, (Topology) null); + } + + public static EndpointMapping directoryToMapping(EndpointMapping mapping, long epoch, Directory directory) + { + EndpointMapping.Builder builder = EndpointMapping.builder(epoch); + for (NodeId id : directory.peerIds()) + builder.add(directory.endpoint(id), tcmIdToAccord(id)); + + // There are cases where nodes are removed from the cluster (host replacement, decom, etc.), but inflight events may still be happening; + // keep the ids around so pending events do not fail with a mapping error + for (Node.Id id : mapping.differenceIds(builder)) + builder.add(mapping.mappedEndpoint(id), id); + return builder.build(); + } + + private static ShardLookup createShardLookup(Topology topology) + { + ShardLookup map = new ShardLookup(); + + if (topology == null) + return map; + + topology.forEach(shard -> map.put(shard.range, shard)); + return map; + } +} diff --git a/src/java/org/apache/cassandra/service/accord/AccordTopologyUtils.java b/src/java/org/apache/cassandra/service/accord/AccordTopologyUtils.java deleted file mode 100644 index e88587411b..0000000000 --- a/src/java/org/apache/cassandra/service/accord/AccordTopologyUtils.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * 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.service.accord; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -import com.google.common.collect.Sets; - -import accord.local.Node; -import accord.primitives.Ranges; -import accord.topology.Shard; -import accord.topology.Topology; -import accord.utils.Invariants; -import org.apache.cassandra.dht.Range; -import org.apache.cassandra.dht.Token; -import org.apache.cassandra.locator.EndpointsForRange; -import org.apache.cassandra.locator.InetAddressAndPort; -import org.apache.cassandra.schema.KeyspaceMetadata; -import org.apache.cassandra.schema.ReplicationParams; -import org.apache.cassandra.service.accord.api.AccordRoutingKey.SentinelKey; -import org.apache.cassandra.service.accord.api.AccordRoutingKey.TokenKey; -import org.apache.cassandra.tcm.ClusterMetadata; -import org.apache.cassandra.tcm.membership.Directory; -import org.apache.cassandra.tcm.membership.NodeId; -import org.apache.cassandra.tcm.ownership.DataPlacement; -import org.apache.cassandra.tcm.ownership.DataPlacements; - -public class AccordTopologyUtils -{ - public static Node.Id tcmIdToAccord(NodeId nodeId) - { - return new Node.Id(nodeId.id()); - } - - private static Shard createShard(TokenRange range, Directory directory, EndpointsForRange reads, EndpointsForRange writes) - { - Function endpointMapper = e -> { - NodeId tcmId = directory.peerId(e); - return tcmIdToAccord(tcmId); - }; - Set endpoints = reads.endpoints(); - Set writeEndpoints = writes.endpoints(); - List nodes = endpoints.stream().map(endpointMapper).sorted().collect(Collectors.toList()); - Set fastPath = new HashSet<>(nodes); // TODO: support fast path updates - Set pending = endpoints.equals(writeEndpoints) ? - Collections.emptySet() : - writeEndpoints.stream().filter(e -> !endpoints.contains(e)).map(endpointMapper).collect(Collectors.toSet()); - - Sets.SetView readOnly = Sets.difference(endpoints, writeEndpoints); - Invariants.checkState(readOnly.isEmpty(), "Read only replicas detected: %s", readOnly); - return new Shard(range, nodes, fastPath, pending); - } - - static TokenRange minRange(String keyspace, Token token) - { - return new TokenRange(SentinelKey.min(keyspace), new TokenKey(keyspace, token)); - } - - static TokenRange maxRange(String keyspace, Token token) - { - return new TokenRange(new TokenKey(keyspace, token), SentinelKey.max(keyspace)); - } - - static TokenRange fullRange(String keyspace) - { - return new TokenRange(SentinelKey.min(keyspace), SentinelKey.max(keyspace)); - } - - static TokenRange range(String keyspace, Range range) - { - Token minToken = range.left.minValue(); - return new TokenRange(range.left.equals(minToken) ? SentinelKey.min(keyspace) : new TokenKey(keyspace, range.left), - range.right.equals(minToken) ? SentinelKey.max(keyspace) : new TokenKey(keyspace, range.right)); - } - - public static accord.primitives.Ranges toAccordRanges(String keyspace, Collection> ranges) - { - List> normalizedRanges = Range.normalize(ranges); - TokenRange[] tokenRanges = new TokenRange[normalizedRanges.size()]; - for (int i = 0; i < normalizedRanges.size(); i++) - tokenRanges[i] = range(keyspace, normalizedRanges.get(i)); - return Ranges.of(tokenRanges); - } - - public static List createShards(KeyspaceMetadata keyspace, DataPlacements placements, Directory directory) - { - ReplicationParams replication = keyspace.params.replication; - DataPlacement placement = placements.get(replication); - - List> ranges = placement.reads.ranges(); - List shards = new ArrayList<>(ranges.size()); - for (Range range : ranges) - { - // TODO (consider, low priority): flesh out how Accord and Transient Replicas work together - // Accord needs to be able to read the full data from a single replica, but with transient ones they may only have a hash. - EndpointsForRange reads = placement.reads.forRange(range).get().filter(r -> r.isFull()); - EndpointsForRange writes = placement.writes.forRange(range).get().filter(r -> r.isFull()); - - // TCM doesn't create wrap around ranges - Invariants.checkArgument(!range.isWrapAround() || range.right.equals(range.right.minValue()), - "wrap around range %s found", range); - shards.add(createShard(range(keyspace.name, range), directory, reads, writes)); - } - - return shards; - } - - public static Topology createAccordTopology(ClusterMetadata cm, Predicate keyspacePredicate) - { - List shards = new ArrayList<>(); - for (KeyspaceMetadata keyspace : cm.schema.getKeyspaces()) - { - if (!keyspacePredicate.test(keyspace.name)) - continue; - shards.addAll(createShards(keyspace, cm.placements, cm.directory)); - } - shards.sort((a, b) -> a.range.compare(b.range)); - return new Topology(cm.epoch.getEpoch(), shards.toArray(new Shard[0])); - } - - public static EndpointMapping directoryToMapping(EndpointMapping mapping, long epoch, Directory directory) - { - EndpointMapping.Builder builder = EndpointMapping.builder(epoch); - for (NodeId id : directory.peerIds()) - builder.add(directory.endpoint(id), tcmIdToAccord(id)); - - // There are cases where nodes are removed from the cluster (host replacement, decom, etc.), but inflight events may still be happening; - // keep the ids around so pending events do not fail with a mapping error - for (Node.Id id : mapping.differenceIds(builder)) - builder.add(mapping.mappedEndpoint(id), id); - return builder.build(); - } - - public static Topology createAccordTopology(ClusterMetadata metadata) - { - return createAccordTopology(metadata, metadata.accordKeyspaces::contains); - } -} diff --git a/src/java/org/apache/cassandra/service/accord/CommandsForRanges.java b/src/java/org/apache/cassandra/service/accord/CommandsForRanges.java index c1da9da190..8cfd3581ee 100644 --- a/src/java/org/apache/cassandra/service/accord/CommandsForRanges.java +++ b/src/java/org/apache/cassandra/service/accord/CommandsForRanges.java @@ -59,6 +59,7 @@ import accord.primitives.Seekables; import accord.primitives.Timestamp; import accord.primitives.TxnId; import accord.utils.Invariants; +import org.apache.cassandra.schema.TableId; import org.apache.cassandra.service.accord.api.AccordRoutingKey; import org.apache.cassandra.service.accord.api.AccordRoutingKey.TokenKey; import org.apache.cassandra.service.accord.api.PartitionKey; @@ -407,13 +408,13 @@ public class CommandsForRanges public Iterable search(AbstractKeys keys) { - // group by the keyspace, as ranges are based off TokenKey, which is scoped to a range - Map> groupByKeyspace = new TreeMap<>(); + // group by the table, as ranges are based off TokenKey, which is scoped to a range + Map> groupByTable = new TreeMap<>(); for (Key key : keys) - groupByKeyspace.computeIfAbsent(((PartitionKey) key).keyspace(), ignore -> new ArrayList<>()).add(key); + groupByTable.computeIfAbsent(((PartitionKey) key).table(), ignore -> new ArrayList<>()).add(key); return () -> new AbstractIterator() { - Iterator ksIt = groupByKeyspace.keySet().iterator(); + Iterator tblIt = groupByTable.keySet().iterator(); Iterator>> rangeIt; @Override @@ -427,13 +428,13 @@ public class CommandsForRanges return result(next.getKey(), next.getValue()); } rangeIt = null; - if (!ksIt.hasNext()) + if (!tblIt.hasNext()) { - ksIt = null; + tblIt = null; return endOfData(); } - String ks = ksIt.next(); - List keys = groupByKeyspace.get(ks); + TableId tbl = tblIt.next(); + List keys = groupByTable.get(tbl); Map> groupByRange = new TreeMap<>(Range::compare); for (Key key : keys) { diff --git a/src/java/org/apache/cassandra/service/accord/EndpointMapping.java b/src/java/org/apache/cassandra/service/accord/EndpointMapping.java index 0c964d3204..916cea43bf 100644 --- a/src/java/org/apache/cassandra/service/accord/EndpointMapping.java +++ b/src/java/org/apache/cassandra/service/accord/EndpointMapping.java @@ -58,13 +58,13 @@ class EndpointMapping implements AccordEndpointMapper } @Override - public Node.Id mappedId(InetAddressAndPort endpoint) + public Node.Id mappedIdOrNull(InetAddressAndPort endpoint) { return mapping.inverse().get(endpoint); } @Override - public InetAddressAndPort mappedEndpoint(Node.Id id) + public InetAddressAndPort mappedEndpointOrNull(Node.Id id) { return mapping.get(id); } diff --git a/src/java/org/apache/cassandra/service/accord/IAccordService.java b/src/java/org/apache/cassandra/service/accord/IAccordService.java index 5610ebd9c2..e0025b46a3 100644 --- a/src/java/org/apache/cassandra/service/accord/IAccordService.java +++ b/src/java/org/apache/cassandra/service/accord/IAccordService.java @@ -40,16 +40,23 @@ import accord.topology.TopologyManager; import org.agrona.collections.Int2ObjectHashMap; import org.apache.cassandra.db.ColumnFamilyStore; import org.apache.cassandra.db.ConsistencyLevel; +import org.apache.cassandra.db.Keyspace; import org.apache.cassandra.dht.Range; import org.apache.cassandra.dht.Token; import org.apache.cassandra.net.IVerbHandler; import org.apache.cassandra.net.Message; +import org.apache.cassandra.schema.Schema; +import org.apache.cassandra.schema.TableMetadata; import org.apache.cassandra.service.accord.api.AccordRoutableKey; import org.apache.cassandra.service.accord.api.AccordRoutingKey.TokenKey; +import org.apache.cassandra.schema.TableId; import org.apache.cassandra.service.accord.api.AccordScheduler; import org.apache.cassandra.service.accord.txn.TxnResult; +import org.apache.cassandra.tcm.ClusterMetadata; import org.apache.cassandra.tcm.Epoch; import org.apache.cassandra.transport.Dispatcher; +import org.apache.cassandra.tcm.transformations.AddAccordTable; +import org.apache.cassandra.utils.FBUtilities; import org.apache.cassandra.utils.Pair; import org.apache.cassandra.utils.concurrent.Future; @@ -72,7 +79,7 @@ public interface IAccordService String ks = cfs.keyspace.getName(); Ranges accordRanges = Ranges.of(ranges .stream() - .map(r -> new TokenRange(new TokenKey(ks, r.left), new TokenKey(ks, r.right))) + .map(r -> new TokenRange(new TokenKey(cfs.getTableId(), r.left), new TokenKey(cfs.getTableId(), r.right))) .collect(Collectors.toList()) .toArray(new accord.primitives.Range[0])); try @@ -109,10 +116,10 @@ public interface IAccordService /** * Temporary method to avoid double-streaming keyspaces - * @param keyspace + * @param tableId * @return */ - boolean isAccordManagedKeyspace(String keyspace); + boolean isAccordManagedTable(TableId tableId); /** * Fetch the redundnant befores for every command store @@ -121,23 +128,45 @@ public interface IAccordService default Id nodeId() { throw new UnsupportedOperationException(); } - default void maybeConvertKeyspacesToAccord(Txn txn) + default void maybeConvertTablesToAccord(Txn txn) { - Set allKeyspaces = new HashSet<>(); - txn.keys().forEach(key -> allKeyspaces.add(((AccordRoutableKey) key).keyspace())); + Set allTables = new HashSet<>(); + Set newTables = new HashSet<>(); + txn.keys().forEach(key -> { + TableId table = ((AccordRoutableKey) key).table(); + if (allTables.add(table) && !isAccordManagedTable(table)) + newTables.add(table); + }); - for (String keyspace : allKeyspaces) + if (newTables.isEmpty()) + return; + + for (TableId table : newTables) + AddAccordTable.addTable(table); + + // we need to avoid creating a txnId in an epoch when no one has any ranges + FBUtilities.waitOnFuture(epochReady(ClusterMetadata.current().epoch)); + + for (TableId table : allTables) { - - ensureKeyspaceIsAccordManaged(keyspace); - } - - for (String keyspace : allKeyspaces) - { - if (!AccordService.instance().isAccordManagedKeyspace(keyspace)) - throw new IllegalStateException(keyspace + " is not an accord managed keyspace"); + if (!isAccordManagedTable(table)) + throw new IllegalStateException(table + " is not an accord managed table"); } } - void ensureKeyspaceIsAccordManaged(String keyspace); + void ensureTableIsAccordManaged(TableId tableId); + + default void ensureTableIsAccordManaged(String keyspace, String table) + { + // TODO: remove when accord enabled is handled via schema + TableMetadata metadata = Schema.instance.getTableMetadata(keyspace, table); + ensureTableIsAccordManaged(metadata.id); + } + + default void ensureKeyspaceIsAccordManaged(String keyspace) + { + // TODO: remove when accord enabled is handled via schema + Keyspace ks = Keyspace.open(keyspace); + ks.getMetadata().tables.forEach(metadata -> ensureTableIsAccordManaged(metadata.id)); + } } diff --git a/src/java/org/apache/cassandra/service/accord/TokenRange.java b/src/java/org/apache/cassandra/service/accord/TokenRange.java index 613c30f97f..b03eaf39d9 100644 --- a/src/java/org/apache/cassandra/service/accord/TokenRange.java +++ b/src/java/org/apache/cassandra/service/accord/TokenRange.java @@ -32,6 +32,7 @@ import org.apache.cassandra.dht.Token; import org.apache.cassandra.io.IVersionedSerializer; import org.apache.cassandra.io.util.DataInputPlus; import org.apache.cassandra.io.util.DataOutputPlus; +import org.apache.cassandra.schema.TableId; import org.apache.cassandra.service.accord.api.AccordRoutingKey; import org.apache.cassandra.service.accord.api.AccordRoutingKey.SentinelKey; @@ -40,25 +41,25 @@ public class TokenRange extends Range.EndInclusive public TokenRange(AccordRoutingKey start, AccordRoutingKey end) { super(start, end); - Invariants.checkArgument(start.keyspace().equals(end.keyspace()), + Invariants.checkArgument(start.table().equals(end.table()), "Token ranges cannot cover more than one keyspace start:%s, end:%s", start, end); } - public String keyspace() + public TableId table() { - return ((AccordRoutingKey) start()).keyspace(); + return ((AccordRoutingKey) start()).table(); } @VisibleForTesting - public Range withKeyspace(String ks) + public Range withTable(TableId table) { - return new TokenRange(((AccordRoutingKey) start()).withKeyspace(ks), ((AccordRoutingKey) end()).withKeyspace(ks)); + return new TokenRange(((AccordRoutingKey) start()).withTable(table), ((AccordRoutingKey) end()).withTable(table)); } - public static TokenRange fullRange(String keyspace) + public static TokenRange fullRange(TableId table) { - return new TokenRange(SentinelKey.min(keyspace), SentinelKey.max(keyspace)); + return new TokenRange(SentinelKey.min(table), SentinelKey.max(table)); } @Override diff --git a/src/java/org/apache/cassandra/service/accord/api/AccordAgent.java b/src/java/org/apache/cassandra/service/accord/api/AccordAgent.java index f24b30fa99..f9ab58387d 100644 --- a/src/java/org/apache/cassandra/service/accord/api/AccordAgent.java +++ b/src/java/org/apache/cassandra/service/accord/api/AccordAgent.java @@ -103,7 +103,7 @@ public class AccordAgent implements Agent @Override public void onUncaughtException(Throwable t) { - // TODO: this + logger.error("Uncaught accord exception", t); JVMStabilityInspector.uncaughtException(Thread.currentThread(), t); } diff --git a/src/java/org/apache/cassandra/service/accord/api/AccordRoutableKey.java b/src/java/org/apache/cassandra/service/accord/api/AccordRoutableKey.java index 6ce68db838..1869310f5b 100644 --- a/src/java/org/apache/cassandra/service/accord/api/AccordRoutableKey.java +++ b/src/java/org/apache/cassandra/service/accord/api/AccordRoutableKey.java @@ -22,25 +22,30 @@ import java.util.Objects; import accord.primitives.RoutableKey; import org.apache.cassandra.dht.Token; +import org.apache.cassandra.schema.TableId; import org.apache.cassandra.service.accord.api.AccordRoutingKey.SentinelKey; import org.apache.cassandra.service.accord.api.AccordRoutingKey.TokenKey; public abstract class AccordRoutableKey implements RoutableKey { - final String keyspace; // TODO (desired): use an id (TrM) + final TableId table; // TODO (desired): use an id (TrM) - protected AccordRoutableKey(String keyspace) + protected AccordRoutableKey(TableId table) { - this.keyspace = keyspace; + this.table = table; + } + + public TableId table() + { + return table; } - public final String keyspace() { return keyspace; } public abstract Token token(); @Override public Object prefix() { - return keyspace; + return table; } @Override @@ -52,7 +57,7 @@ public abstract class AccordRoutableKey implements RoutableKey @Override public int hashCode() { - return Objects.hash(keyspace, token().tokenHash()); + return Objects.hash(table, token().tokenHash()); } @Override @@ -63,7 +68,7 @@ public abstract class AccordRoutableKey implements RoutableKey public final int compareTo(AccordRoutableKey that) { - int cmp = this.keyspace().compareTo(that.keyspace()); + int cmp = this.table().compareTo(that.table()); if (cmp != 0) return cmp; @@ -80,7 +85,7 @@ public abstract class AccordRoutableKey implements RoutableKey if (this.getClass() == TokenKey.class) return that.getClass() == TokenKey.class ? 0 : 1; - return that.getClass() == TokenKey.class ? -1 : ((PartitionKey)this).tableId.compareTo(((PartitionKey)that).tableId); + return that.getClass() == TokenKey.class ? -1 : 0; } @Override diff --git a/src/java/org/apache/cassandra/service/accord/api/AccordRoutingKey.java b/src/java/org/apache/cassandra/service/accord/api/AccordRoutingKey.java index b18dcafeca..5b089267a1 100644 --- a/src/java/org/apache/cassandra/service/accord/api/AccordRoutingKey.java +++ b/src/java/org/apache/cassandra/service/accord/api/AccordRoutingKey.java @@ -40,6 +40,7 @@ import org.apache.cassandra.io.util.DataInputBuffer; import org.apache.cassandra.io.util.DataInputPlus; import org.apache.cassandra.io.util.DataOutputBuffer; import org.apache.cassandra.io.util.DataOutputPlus; +import org.apache.cassandra.schema.TableId; import org.apache.cassandra.service.accord.TokenRange; import org.apache.cassandra.utils.ByteBufferUtil; import org.apache.cassandra.utils.ObjectSizes; @@ -53,14 +54,14 @@ public abstract class AccordRoutingKey extends AccordRoutableKey implements Rout TOKEN, SENTINEL } - protected AccordRoutingKey(String keyspace) + protected AccordRoutingKey(TableId table) { - super(keyspace); + super(table); } public abstract RoutingKeyKind kindOfRoutingKey(); public abstract long estimatedSizeOnHeap(); - public abstract AccordRoutingKey withKeyspace(String ks); + public abstract AccordRoutingKey withTable(TableId table); public SentinelKey asSentinelKey() { @@ -84,16 +85,16 @@ public abstract class AccordRoutingKey extends AccordRoutableKey implements Rout private final boolean isMin; - private SentinelKey(String keyspace, boolean isMin) + private SentinelKey(TableId table, boolean isMin) { - super(keyspace); + super(table); this.isMin = isMin; } @Override public int hashCode() { - return Objects.hash(keyspace, isMin); + return Objects.hash(table, isMin); } @Override @@ -108,26 +109,25 @@ public abstract class AccordRoutingKey extends AccordRoutableKey implements Rout return EMPTY_SIZE; } - @Override - public AccordRoutingKey withKeyspace(String ks) + public AccordRoutingKey withTable(TableId table) { - return new SentinelKey(ks, isMin); + return new SentinelKey(table, isMin); } - public static SentinelKey min(String keyspace) + public static SentinelKey min(TableId table) { - return new SentinelKey(keyspace, true); + return new SentinelKey(table, true); } - public static SentinelKey max(String keyspace) + public static SentinelKey max(TableId table) { - return new SentinelKey(keyspace, false); + return new SentinelKey(table, false); } public TokenKey toTokenKey() { IPartitioner partitioner = getPartitioner(); - return new TokenKey(keyspace, isMin ? + return new TokenKey(table, isMin ? partitioner.getMinimumToken().nextValidToken() : partitioner.getMaximumToken().decreaseSlightly()); } @@ -154,22 +154,22 @@ public abstract class AccordRoutingKey extends AccordRoutableKey implements Rout @Override public void serialize(SentinelKey key, DataOutputPlus out, int version) throws IOException { + key.table.serialize(out); out.writeBoolean(key.isMin); - out.writeUTF(key.keyspace); } @Override public SentinelKey deserialize(DataInputPlus in, int version) throws IOException { + TableId table = TableId.deserialize(in); boolean isMin = in.readBoolean(); - String keyspace = in.readUTF(); - return new SentinelKey(keyspace, isMin); + return new SentinelKey(table, isMin); } @Override public long serializedSize(SentinelKey key, int version) { - return TypeSizes.BOOL_SIZE + TypeSizes.sizeof(key.keyspace); + return key.table().serializedSize() + TypeSizes.BOOL_SIZE; } }; @@ -189,8 +189,8 @@ public abstract class AccordRoutingKey extends AccordRoutableKey implements Rout public Range asRange() { AccordRoutingKey before = token.isMinimum() - ? new SentinelKey(keyspace, true) - : new TokenKey(keyspace, token.decreaseSlightly()); + ? new SentinelKey(table, true) + : new TokenKey(table, token.decreaseSlightly()); return new TokenRange(before, this); } @@ -202,15 +202,15 @@ public abstract class AccordRoutingKey extends AccordRoutableKey implements Rout } final Token token; - public TokenKey(String keyspace, Token token) + public TokenKey(TableId tableId, Token token) { - super(keyspace); + super(tableId); this.token = token; } public TokenKey withToken(Token token) { - return new TokenKey(keyspace, token); + return new TokenKey(table, token); } @Override @@ -236,10 +236,9 @@ public abstract class AccordRoutingKey extends AccordRoutableKey implements Rout return EMPTY_SIZE + token().getHeapSize(); } - @Override - public AccordRoutingKey withKeyspace(String ks) + public AccordRoutingKey withTable(TableId table) { - return new TokenKey(ks, token); + return new TokenKey(table, token); } public static final Serializer serializer = new Serializer(); @@ -250,22 +249,22 @@ public abstract class AccordRoutingKey extends AccordRoutableKey implements Rout @Override public void serialize(TokenKey key, DataOutputPlus out, int version) throws IOException { - out.writeUTF(key.keyspace); + key.table.serialize(out); Token.compactSerializer.serialize(key.token, out, version); } @Override public TokenKey deserialize(DataInputPlus in, int version) throws IOException { - String keyspace = in.readUTF(); + TableId table = TableId.deserialize(in); Token token = Token.compactSerializer.deserialize(in, getPartitioner(), version); - return new TokenKey(keyspace, token); + return new TokenKey(table, token); } @Override public long serializedSize(TokenKey key, int version) { - return TypeSizes.sizeof(key.keyspace) + Token.compactSerializer.serializedSize(key.token(), version); + return key.table.serializedSize() + Token.compactSerializer.serializedSize(key.token(), version); } } } @@ -370,15 +369,15 @@ public abstract class AccordRoutingKey extends AccordRoutableKey implements Rout @Override public List split(Ranges ranges) { - Map> byKeyspace = new TreeMap<>(); + Map> byTable = new TreeMap<>(); for (Range range : ranges) { - byKeyspace.computeIfAbsent(((AccordRoutableKey)range.start()).keyspace, ignore -> new ArrayList<>()) + byTable.computeIfAbsent(((AccordRoutableKey)range.start()).table, ignore -> new ArrayList<>()) .add(range); } List results = new ArrayList<>(); - for (List keyspaceRanges : byKeyspace.values()) + for (List keyspaceRanges : byTable.values()) { List splits = subSplitter.split(Ranges.ofSortedAndDeoverlapped(keyspaceRanges.toArray(new Range[0]))); diff --git a/src/java/org/apache/cassandra/service/accord/api/PartitionKey.java b/src/java/org/apache/cassandra/service/accord/api/PartitionKey.java index a8dac58234..d54afba171 100644 --- a/src/java/org/apache/cassandra/service/accord/api/PartitionKey.java +++ b/src/java/org/apache/cassandra/service/accord/api/PartitionKey.java @@ -53,16 +53,14 @@ public final class PartitionKey extends AccordRoutableKey implements Key static { DecoratedKey key = DatabaseDescriptor.getPartitioner().decorateKey(ByteBufferUtil.EMPTY_BYTE_BUFFER); - EMPTY_SIZE = ObjectSizes.measureDeep(new PartitionKey(null, null, key)); + EMPTY_SIZE = ObjectSizes.measureDeep(new PartitionKey(null, key)); } - final TableId tableId; // TODO (expected): move to PartitionKey final DecoratedKey key; - public PartitionKey(String keyspace, TableId tableId, DecoratedKey key) + public PartitionKey(TableId tableId, DecoratedKey key) { - super(keyspace); - this.tableId = tableId; + super(tableId); this.key = key; } @@ -73,21 +71,19 @@ public final class PartitionKey extends AccordRoutableKey implements Key public static PartitionKey of(PartitionUpdate update) { - return new PartitionKey(update.metadata().keyspace, update.metadata().id, update.partitionKey()); + return new PartitionKey(update.metadata().id, update.partitionKey()); } public static PartitionKey of(Partition partition) { - return new PartitionKey(partition.metadata().keyspace, partition.metadata().id, partition.partitionKey()); + return new PartitionKey(partition.metadata().id, partition.partitionKey()); } public static PartitionKey of(SinglePartitionReadCommand command) { - return new PartitionKey(command.metadata().keyspace, command.metadata().id, command.partitionKey()); + return new PartitionKey(command.metadata().id, command.partitionKey()); } - public final TableId tableId() { return tableId; } - @Override public Token token() { @@ -102,7 +98,7 @@ public final class PartitionKey extends AccordRoutableKey implements Key @Override public RoutingKey toUnseekable() { - return new TokenKey(keyspace, token()); + return new TokenKey(table, token()); } public long estimatedSizeOnHeap() @@ -131,14 +127,14 @@ public final class PartitionKey extends AccordRoutableKey implements Key @Override public void serialize(PartitionKey key, DataOutputPlus out, int version) throws IOException { - key.tableId().serialize(out); + key.table().serialize(out); ByteBufferUtil.writeWithShortLength(key.partitionKey().getKey(), out); } public int serialize(PartitionKey key, V dst, ValueAccessor accessor, int offset) { int position = offset; - position += key.tableId().serialize(dst, accessor, position); + position += key.table().serialize(dst, accessor, position); ByteBuffer bytes = key.partitionKey().getKey(); int numBytes = ByteBufferAccessor.instance.size(bytes); Preconditions.checkState(numBytes <= Short.MAX_VALUE); @@ -154,7 +150,7 @@ public final class PartitionKey extends AccordRoutableKey implements Key TableId tableId = TableId.deserialize(in); TableMetadata metadata = Schema.instance.getExistingTableMetadata(tableId); DecoratedKey key = metadata.partitioner.decorateKey(ByteBufferUtil.readWithShortLength(in)); - return new PartitionKey(metadata.keyspace, tableId, key); + return new PartitionKey(tableId, key); } public PartitionKey deserialize(V src, ValueAccessor accessor, int offset) throws IOException @@ -167,7 +163,7 @@ public final class PartitionKey extends AccordRoutableKey implements Key ByteBuffer bytes = ByteBuffer.allocate(numBytes); accessor.copyTo(src, offset, bytes, ByteBufferAccessor.instance, 0, numBytes); DecoratedKey key = metadata.partitioner.decorateKey(bytes); - return new PartitionKey(metadata.keyspace, tableId, key); + return new PartitionKey(tableId, key); } @Override @@ -178,7 +174,7 @@ public final class PartitionKey extends AccordRoutableKey implements Key public long serializedSize(PartitionKey key) { - return key.tableId().serializedSize() + ByteBufferUtil.serializedSizeWithShortLength(key.partitionKey().getKey()); + return key.table().serializedSize() + ByteBufferUtil.serializedSizeWithShortLength(key.partitionKey().getKey()); } } } diff --git a/src/java/org/apache/cassandra/service/accord/async/AsyncLoader.java b/src/java/org/apache/cassandra/service/accord/async/AsyncLoader.java index 16b2e86730..52f632c6c5 100644 --- a/src/java/org/apache/cassandra/service/accord/async/AsyncLoader.java +++ b/src/java/org/apache/cassandra/service/accord/async/AsyncLoader.java @@ -125,10 +125,17 @@ public class AsyncLoader List> listenChains) { referenceAndAssembleReadsForKey(key, context.timestampsForKey, commandStore.timestampsForKeyCache(), listenChains); - if (keyHistory == KeyHistory.DEPS) - referenceAndAssembleReadsForKey(key, context.depsCommandsForKeys, commandStore.depsCommandsForKeyCache(), listenChains); - if (keyHistory == KeyHistory.ALL) - referenceAndAssembleReadsForKey(key, context.allCommandsForKeys, commandStore.allCommandsForKeyCache(), listenChains); + // recovery operations also need the deps data for their preaccept logic + switch (keyHistory) + { + case ALL: + referenceAndAssembleReadsForKey(key, context.allCommandsForKeys, commandStore.allCommandsForKeyCache(), listenChains); + case DEPS: + referenceAndAssembleReadsForKey(key, context.depsCommandsForKeys, commandStore.depsCommandsForKeyCache(), listenChains); + case NONE: + break; + default: throw new IllegalArgumentException("Unhandled keyhistory: " + keyHistory); + } referenceAndAssembleReadsForKey(key, context.updatesForKeys, commandStore.updatesForKeyCache(), listenChains); } diff --git a/src/java/org/apache/cassandra/service/accord/async/AsyncOperation.java b/src/java/org/apache/cassandra/service/accord/async/AsyncOperation.java index e93c1dd20b..69002b1fef 100644 --- a/src/java/org/apache/cassandra/service/accord/async/AsyncOperation.java +++ b/src/java/org/apache/cassandra/service/accord/async/AsyncOperation.java @@ -210,6 +210,7 @@ public abstract class AsyncOperation extends AsyncChains.Head implements R private void fail(Throwable throwable) { + commandStore.agent().onUncaughtException(throwable); commandStore.checkInStoreThread(); Invariants.nonNull(throwable); diff --git a/src/java/org/apache/cassandra/service/accord/fastpath/FastPathStrategy.java b/src/java/org/apache/cassandra/service/accord/fastpath/FastPathStrategy.java new file mode 100644 index 0000000000..e8d47f9178 --- /dev/null +++ b/src/java/org/apache/cassandra/service/accord/fastpath/FastPathStrategy.java @@ -0,0 +1,184 @@ +/* + * 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.service.accord.fastpath; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.annotation.Nullable; + +import com.google.common.collect.ImmutableMap; + +import accord.local.Node; +import org.apache.cassandra.db.TypeSizes; +import org.apache.cassandra.exceptions.ConfigurationException; +import org.apache.cassandra.io.util.DataInputPlus; +import org.apache.cassandra.io.util.DataOutputPlus; +import org.apache.cassandra.tcm.serialization.MetadataSerializer; +import org.apache.cassandra.tcm.serialization.Version; +import org.apache.cassandra.utils.LocalizeString; + +public interface FastPathStrategy +{ + enum Kind + { + SIMPLE, PARAMETERIZED, INHERIT_KEYSPACE; + + static final String KEY = "kind"; + private static final Map LOOKUP; + static + { + ImmutableMap.Builder builder = ImmutableMap.builder(); + builder.put(SIMPLE.name(), SIMPLE); + builder.put(PARAMETERIZED.name(), PARAMETERIZED); + builder.put(INHERIT_KEYSPACE.name(), INHERIT_KEYSPACE); + LOOKUP = builder.build(); + } + + public byte asByte() + { + return (byte) ordinal(); + } + + public static Kind fromByte(byte i) + { + return values()[i]; + } + + @Nullable + public static Kind fromString(String s) + { + return LOOKUP.get(LocalizeString.toUpperCaseLocalized(s)); + } + + @Nullable + private static Kind fromMap(Map map) + { + String name = map.remove(KEY); + return name != null ? fromString(name) : null; + } + } + + /** + * @param nodes expected to be sorted deterministically + * @param unavailable + * @param dcMap + * @return + */ + Set calculateFastPath(List nodes, Set unavailable, Map dcMap); + + Kind kind(); + + Map asMap(); + + String asCQL(); + + static FastPathStrategy fromMap(Map map) + { + if (map == null || map.isEmpty()) + return SimpleFastPathStrategy.instance; + + map = new HashMap<>(map); + Kind kind = Kind.fromMap(map); + if (kind == null) + return map.isEmpty() + ? simple() + : ParameterizedFastPathStrategy.fromMap(map); + + switch (kind) + { + case SIMPLE: + return simple(); + case PARAMETERIZED: + return ParameterizedFastPathStrategy.fromMap(map); + case INHERIT_KEYSPACE: + return inheritKeyspace(); + default: + throw new IllegalArgumentException("Unhandled strategy kind: " + kind); + } + } + + static FastPathStrategy tableStrategyFromString(String s) + { + s = LocalizeString.toLowerCaseLocalized(s).trim(); + if (s.equals("keyspace")) + return InheritKeyspaceFastPathStrategy.instance; + if (s.equals("simple")) + return SimpleFastPathStrategy.instance; + + throw new ConfigurationException("Fast path strategy must either be 'keyspace', `default` or a map size and optional dcs {'size':n, 'dcs': dc0,dc1..."); + } + + static FastPathStrategy keyspaceStrategyFromString(String s) + { + s = LocalizeString.toLowerCaseLocalized(s).trim(); + if (s.equals("simple")) + return SimpleFastPathStrategy.instance; + + throw new ConfigurationException("Fast path strategy must either be `default` or a map size and optional dcs {'size':n, 'dcs': dc0,dc1..."); + } + + static FastPathStrategy simple() + { + return SimpleFastPathStrategy.instance; + } + + static FastPathStrategy inheritKeyspace() + { + return InheritKeyspaceFastPathStrategy.instance; + } + + MetadataSerializer serializer = new MetadataSerializer() + { + public void serialize(FastPathStrategy strategy, DataOutputPlus out, Version version) throws IOException + { + Kind type = strategy.kind(); + out.write(type.asByte()); + if (type == Kind.PARAMETERIZED) + ParameterizedFastPathStrategy.serializer.serialize((ParameterizedFastPathStrategy) strategy, out, version); + } + + public FastPathStrategy deserialize(DataInputPlus in, Version version) throws IOException + { + Kind type = Kind.fromByte(in.readByte()); + switch (type) + { + case SIMPLE: + return simple(); + case PARAMETERIZED: + return ParameterizedFastPathStrategy.serializer.deserialize(in, version); + case INHERIT_KEYSPACE: + return inheritKeyspace(); + default: + throw new IllegalArgumentException("Unhandled type: " + type); + } + } + + public long serializedSize(FastPathStrategy strategy, Version version) + { + long size = TypeSizes.BYTE_SIZE; + if (strategy.kind() == Kind.PARAMETERIZED) + size += ParameterizedFastPathStrategy.serializer.serializedSize((ParameterizedFastPathStrategy) strategy, version); + return size; + } + }; +} diff --git a/src/java/org/apache/cassandra/service/accord/fastpath/InheritKeyspaceFastPathStrategy.java b/src/java/org/apache/cassandra/service/accord/fastpath/InheritKeyspaceFastPathStrategy.java new file mode 100644 index 0000000000..08b7763a93 --- /dev/null +++ b/src/java/org/apache/cassandra/service/accord/fastpath/InheritKeyspaceFastPathStrategy.java @@ -0,0 +1,65 @@ +/* + * 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.service.accord.fastpath; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.google.common.collect.ImmutableMap; + +import accord.local.Node; + +public class InheritKeyspaceFastPathStrategy implements FastPathStrategy +{ + static final FastPathStrategy instance = new InheritKeyspaceFastPathStrategy(); + + private static final Map SCHEMA_PARAMS = ImmutableMap.of(Kind.KEY, Kind.INHERIT_KEYSPACE.name()); + + private InheritKeyspaceFastPathStrategy() {} + + @Override + public Set calculateFastPath(List nodes, Set unavailable, Map dcMap) + { + throw new IllegalStateException("InheritKeyspaceFastPathStrategy should be replaced before calculateFastPath is called"); + } + + @Override + public Kind kind() + { + return Kind.INHERIT_KEYSPACE; + } + + @Override + public String toString() + { + return "keyspace"; + } + + public Map asMap() + { + return SCHEMA_PARAMS; + } + + @Override + public String asCQL() + { + return "'keyspace'"; + } +} diff --git a/src/java/org/apache/cassandra/service/accord/fastpath/ParameterizedFastPathStrategy.java b/src/java/org/apache/cassandra/service/accord/fastpath/ParameterizedFastPathStrategy.java new file mode 100644 index 0000000000..8e9d00bbe6 --- /dev/null +++ b/src/java/org/apache/cassandra/service/accord/fastpath/ParameterizedFastPathStrategy.java @@ -0,0 +1,375 @@ +/* + * 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.service.accord.fastpath; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; + +import accord.api.VisibleForImplementation; +import accord.local.Node; +import accord.topology.Shard; +import accord.utils.Invariants; +import org.apache.cassandra.db.TypeSizes; +import org.apache.cassandra.exceptions.ConfigurationException; +import org.apache.cassandra.io.util.DataInputPlus; +import org.apache.cassandra.io.util.DataOutputPlus; +import org.apache.cassandra.tcm.serialization.MetadataSerializer; +import org.apache.cassandra.tcm.serialization.Version; + +import javax.annotation.Nonnull; + +public class ParameterizedFastPathStrategy implements FastPathStrategy +{ + static final String SIZE = "size"; + static final String DCS = "dcs"; + private static final Joiner DC_JOINER = Joiner.on(','); + private static final Pattern COMMA_SEPARATOR = Pattern.compile(","); + private static final Pattern COLON_SEPARATOR = Pattern.compile(":"); + + static class WeightedDc implements Comparable + { + private static final WeightedDc UNSPECIFIED = new WeightedDc("", Integer.MAX_VALUE, true); + private static final MetadataSerializer serializer = new MetadataSerializer() + { + public void serialize(WeightedDc dc, DataOutputPlus out, Version version) throws IOException + { + out.writeUTF(dc.name); + out.writeUnsignedVInt(dc.weight); + out.writeBoolean(dc.autoWeight); + } + + public WeightedDc deserialize(DataInputPlus in, Version version) throws IOException + { + return new WeightedDc(in.readUTF(), + in.readUnsignedVInt32(), + in.readBoolean()); + } + + public long serializedSize(WeightedDc dc, Version version) + { + return TypeSizes.sizeof(dc.name) + TypeSizes.sizeofUnsignedVInt(dc.weight) + TypeSizes.BOOL_SIZE; + } + }; + + final String name; + final int weight; + final boolean autoWeight; + + public WeightedDc(String name, int weight, boolean autoWeight) + { + this.name = name; + this.weight = weight; + this.autoWeight = autoWeight; + } + + public boolean equals(Object o) + { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + WeightedDc that = (WeightedDc) o; + return weight == that.weight && autoWeight == that.autoWeight && Objects.equals(name, that.name); + } + + public int hashCode() + { + return Objects.hash(name, weight, autoWeight); + } + + @Override + public int compareTo(@Nonnull WeightedDc that) + { + int cmp = Integer.compare(this.weight, that.weight); + if (cmp != 0) return cmp; + return this.name.compareTo(that.name); + } + + public String toString() + { + return autoWeight ? name : name + ':' + weight; + } + + static String validateDC(String dc) + { + dc = dc.trim(); + if (dc.isEmpty()) + throw cfe("dc name must not be empty", DCS); + return dc; + } + + static int validateWeight(String w) + { + int weight = Integer.parseInt(w); + if (weight < 0) + throw cfe("DC weights must be zero or positive"); + return weight; + } + + static WeightedDc fromString(String s, int idx) + { + s = s.trim(); + if (s.isEmpty()) + throw cfe("%s entries must not be empty", DCS); + + String[] parts = COLON_SEPARATOR.split(s); + if (parts.length == 1) + return new WeightedDc(validateDC(parts[0]), idx, true); + else if (parts.length == 2) + return new WeightedDc(validateDC(parts[0]), validateWeight(parts[1]), false); + else + throw cfe("Invalid dc weighting syntax %s, use :"); + } + } + + public final int size; + private final ImmutableMap dcs; + + ParameterizedFastPathStrategy(int size, ImmutableMap dcs) + { + this.size = size; + this.dcs = dcs; + } + + public boolean equals(Object o) + { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ParameterizedFastPathStrategy that = (ParameterizedFastPathStrategy) o; + return size == that.size && Objects.equals(dcs, that.dcs); + } + + public int hashCode() + { + return Objects.hash(size, dcs); + } + + private static class NodeSorter implements Comparable + { + private final Node.Id id; + private final int sortPos; + private final int dcIndex; + private final int health; + + public NodeSorter(Node.Id id, int sortPos, int dcIndex, int health) + { + this.id = id; + this.sortPos = sortPos; + this.dcIndex = dcIndex; + this.health = health; + } + + @Override + public int compareTo(@Nonnull NodeSorter that) + { + int cmp = this.health - that.health; + if (cmp != 0) return cmp; + + cmp = this.dcIndex - that.dcIndex; + if (cmp != 0) return cmp; + + cmp = this.sortPos - that.sortPos; + if (cmp != 0) return cmp; + + Invariants.checkState(this.id.equals(that.id)); + return 0; + } + } + + @Override + public Set calculateFastPath(List nodes, Set unavailable, Map dcMap) + { + List sorters = new ArrayList<>(nodes.size()); + + for (int i = 0, mi = nodes.size(); i < mi; i++) + { + Node.Id node = nodes.get(i); + String dc = dcMap.get(node); + int dcScore = dcs.getOrDefault(dc, WeightedDc.UNSPECIFIED).weight; + NodeSorter sorter = new NodeSorter(node, i, dcScore, unavailable.contains(node) ? 1 : 0); + sorters.add(sorter); + } + + sorters.sort(Comparator.naturalOrder()); + + int slowQuorum = Shard.slowPathQuorumSize(nodes.size()); + int fpSize = Math.max(size, slowQuorum); + ImmutableSet.Builder builder = ImmutableSet.builder(); + + for (int i=0; i fastPath = builder.build(); + Invariants.checkState(fastPath.size() >= slowQuorum); + return fastPath; + } + + private static ConfigurationException cfe(String fmt, Object... args) + { + return new ConfigurationException(String.format(fmt, args)); + } + + static ParameterizedFastPathStrategy fromMap(Map map) + { + if (!map.containsKey(SIZE)) + throw cfe("fast_path must be set to 'keyspace' or 'default' or a map defining '%s' and optionally '%s'", SIZE, DCS); + + int size; + try + { + size = Integer.parseInt(map.get(SIZE)); + } + catch (NumberFormatException e) + { + throw cfe("%s must be a positive number, got %s", SIZE, map.get(SIZE)); + } + + if (size < 1) + throw cfe("%s must be greater than zero", SIZE); + + ImmutableMap dcMap; + if (map.containsKey(DCS)) + { + + Map mutableDcs = new HashMap<>(); + String dcsString = map.get(DCS); + if (dcsString.trim().isEmpty()) + throw cfe("%s must specify at least one DC", DCS); + + int autoIdx = 0; + boolean hasAuto = false; + boolean hasManual = false; + for (String dcString : COMMA_SEPARATOR.split(dcsString)) + { + WeightedDc dc = WeightedDc.fromString(dcString, autoIdx++); + if (mutableDcs.containsKey(dc.name)) + throw cfe("Multiple entries for DC %s", dc.name); + + if (dc.autoWeight) + { + if (hasManual) throw cfe("Cannot mix auto and manual DC weights"); + hasAuto = true; + } + else + { + if (hasAuto) throw cfe("Cannot mix auto and manual DC weights"); + hasManual = true; + } + + mutableDcs.put(dc.name, dc); + } + dcMap = ImmutableMap.copyOf(mutableDcs); + } + else + { + dcMap = ImmutableMap.of(); + } + + Set keys = new HashSet<>(map.keySet()); + keys.remove(SIZE); + keys.remove(DCS); + if (!keys.isEmpty()) + throw cfe("Unrecognized fast path options provided: ", keys); + + return new ParameterizedFastPathStrategy(size, dcMap); + } + + @Override + public Kind kind() + { + return Kind.PARAMETERIZED; + } + + @VisibleForImplementation + public Iterable dcStrings() + { + return dcs.values().stream().sorted().map(Object::toString).collect(Collectors.toList()); + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder("{"); + sb.append('\'').append(SIZE).append("':").append(size); + if (!dcs.isEmpty()) + sb.append(", ").append(DCS).append(':').append('\'').append(DC_JOINER.join(dcStrings())).append('\''); + + return sb.append('}').toString(); + } + + public Map asMap() + { + Map params = new HashMap<>(); + params.put(Kind.KEY, kind().name()); + params.put(SIZE, Integer.toString(size)); + params.put(DCS, DC_JOINER.join(dcStrings())); + return params; + } + + @Override + public String asCQL() + { + return toString(); + } + + public static final MetadataSerializer serializer = new MetadataSerializer() + { + public void serialize(ParameterizedFastPathStrategy strategy, DataOutputPlus out, Version version) throws IOException + { + out.writeUnsignedVInt32(strategy.size); + out.writeUnsignedVInt32(strategy.dcs.size()); + for (WeightedDc dc : strategy.dcs.values()) + WeightedDc.serializer.serialize(dc, out, version); + } + + public ParameterizedFastPathStrategy deserialize(DataInputPlus in, Version version) throws IOException + { + int size = in.readUnsignedVInt32(); + int numDCs = in.readUnsignedVInt32(); + ImmutableMap.Builder builder = ImmutableMap.builder(); + for (int i=0; i SCHEMA_PARAMS = ImmutableMap.of(Kind.KEY, Kind.SIMPLE.name()); + + private SimpleFastPathStrategy() {} + + @Override + public Set calculateFastPath(List nodes, Set unavailable, Map dcMap) + { + int maxFailures = Shard.maxToleratedFailures(nodes.size()); + int discarded = 0; + + ImmutableSet.Builder builder = ImmutableSet.builder(); + + for (int i=0,mi=nodes.size(); i fastPath = builder.build(); + Invariants.checkState(fastPath.size() >= Shard.slowPathQuorumSize(nodes.size())); + return fastPath; + } + + @Override + public Kind kind() + { + return Kind.SIMPLE; + } + + @Override + public String toString() + { + return "simple"; + } + + public Map asMap() + { + return SCHEMA_PARAMS; + } + + @Override + public String asCQL() + { + return "'simple'"; + } +} diff --git a/src/java/org/apache/cassandra/service/accord/interop/AccordInteropExecution.java b/src/java/org/apache/cassandra/service/accord/interop/AccordInteropExecution.java index 71757ed106..9aa9179b38 100644 --- a/src/java/org/apache/cassandra/service/accord/interop/AccordInteropExecution.java +++ b/src/java/org/apache/cassandra/service/accord/interop/AccordInteropExecution.java @@ -28,6 +28,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.BiConsumer; +import org.apache.cassandra.schema.TableId; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -229,9 +230,9 @@ public class AccordInteropExecution implements Execute, ReadCoordinator, Maximal } @Override - public EndpointsForToken forNonLocalStrategyTokenRead(ClusterMetadata doNotUse, KeyspaceMetadata keyspace, Token token) + public EndpointsForToken forNonLocalStrategyTokenRead(ClusterMetadata doNotUse, KeyspaceMetadata keyspace, TableId tableId, Token token) { - AccordRoutingKey.TokenKey key = new AccordRoutingKey.TokenKey(keyspace.name, token); + AccordRoutingKey.TokenKey key = new AccordRoutingKey.TokenKey(tableId, token); Shard shard = executeTopology.forKey(key); Range range = ((TokenRange) shard.range).toKeyspaceRange(); diff --git a/src/java/org/apache/cassandra/service/accord/serializers/CommandStoreSerializers.java b/src/java/org/apache/cassandra/service/accord/serializers/CommandStoreSerializers.java index 34dfced93d..1770ae75a5 100644 --- a/src/java/org/apache/cassandra/service/accord/serializers/CommandStoreSerializers.java +++ b/src/java/org/apache/cassandra/service/accord/serializers/CommandStoreSerializers.java @@ -90,8 +90,8 @@ public class CommandStoreSerializers public long serializedSize(R map, int version) { long size = TypeSizes.BOOL_SIZE; - size += TypeSizes.sizeofUnsignedVInt(size); int mapSize = map.size(); + size += TypeSizes.sizeofUnsignedVInt(mapSize); for (int i=0; i + public static class NodeIdSerializer implements IVersionedSerializer, MetadataSerializer { private NodeIdSerializer() {} + private static void serialize(Node.Id id, DataOutputPlus out) throws IOException + { + out.writeInt(id.id); + } + @Override public void serialize(Node.Id id, DataOutputPlus out, int version) throws IOException { - out.writeInt(id.id); + serialize(id, out); + } + + @Override + public void serialize(Node.Id id, DataOutputPlus out, Version version) throws IOException + { + serialize(id, out); } public int serialize(Node.Id id, V dst, ValueAccessor accessor, int offset) @@ -55,10 +68,21 @@ public class TopologySerializers return accessor.putInt(dst, offset, id.id); } + private static Node.Id deserialize(DataInputPlus in) throws IOException + { + return new Node.Id(in.readInt()); + } + @Override public Node.Id deserialize(DataInputPlus in, int version) throws IOException { - return new Node.Id(in.readInt()); + return deserialize(in); + } + + @Override + public Node.Id deserialize(DataInputPlus in, Version version) throws IOException + { + return deserialize(in); } public Node.Id deserialize(V src, ValueAccessor accessor, int offset) @@ -66,15 +90,21 @@ public class TopologySerializers return new Node.Id(accessor.getInt(src, offset)); } + public int serializedSize() + { + return TypeSizes.INT_SIZE; // id.id + } + @Override public long serializedSize(Node.Id id, int version) { return serializedSize(); } - public int serializedSize() + @Override + public long serializedSize(Node.Id t, Version version) { - return TypeSizes.INT_SIZE; // id.id + return serializedSize(); } }; diff --git a/src/java/org/apache/cassandra/service/accord/txn/TxnNamedRead.java b/src/java/org/apache/cassandra/service/accord/txn/TxnNamedRead.java index df41e78b53..bbb1076b23 100644 --- a/src/java/org/apache/cassandra/service/accord/txn/TxnNamedRead.java +++ b/src/java/org/apache/cassandra/service/accord/txn/TxnNamedRead.java @@ -63,7 +63,7 @@ public class TxnNamedRead extends AbstractSerialized { super(value); this.name = name; - this.key = new PartitionKey(value.metadata().keyspace, value.metadata().id, value.partitionKey()); + this.key = new PartitionKey(value.metadata().id, value.partitionKey()); } private TxnNamedRead(TxnDataName name, PartitionKey key, ByteBuffer bytes) diff --git a/src/java/org/apache/cassandra/service/accord/txn/TxnQuery.java b/src/java/org/apache/cassandra/service/accord/txn/TxnQuery.java index 6005673fa6..0742071b10 100644 --- a/src/java/org/apache/cassandra/service/accord/txn/TxnQuery.java +++ b/src/java/org/apache/cassandra/service/accord/txn/TxnQuery.java @@ -216,6 +216,6 @@ public abstract class TxnQuery implements Query // and transaction statement will generate an error when it sees // the RetryOnNewProtocolResult PartitionKey partitionKey = (PartitionKey)keys.get(0); - return ConsensusRequestRouter.instance.isKeyInMigratingOrMigratedRangeFromAccord(epoch, partitionKey.tableId(), partitionKey.partitionKey()); + return ConsensusRequestRouter.instance.isKeyInMigratingOrMigratedRangeFromAccord(epoch, partitionKey.table(), partitionKey.partitionKey()); } } diff --git a/src/java/org/apache/cassandra/service/consensus/migration/ConsensusKeyMigrationState.java b/src/java/org/apache/cassandra/service/consensus/migration/ConsensusKeyMigrationState.java index 512943e463..d3651015c2 100644 --- a/src/java/org/apache/cassandra/service/consensus/migration/ConsensusKeyMigrationState.java +++ b/src/java/org/apache/cassandra/service/consensus/migration/ConsensusKeyMigrationState.java @@ -211,7 +211,7 @@ public abstract class ConsensusKeyMigrationState public static void maybeSaveAccordKeyMigrationLocally(PartitionKey partitionKey, Epoch epoch) { - TableId tableId = partitionKey.tableId(); + TableId tableId = partitionKey.table(); UUID tableUUID = tableId.asUUID(); DecoratedKey dk = partitionKey.partitionKey(); ByteBuffer key = dk.getKey(); @@ -280,7 +280,7 @@ public abstract class ConsensusKeyMigrationState // will soon be ready to execute, but only waits for the local replica to be ready // Local will only create a transaction if it can't find an existing one to wait on BarrierType barrierType = global ? BarrierType.global_async : BarrierType.local; - AccordService.instance().barrier(Seekables.of(new PartitionKey(keyspace, tableId, key)), minEpoch, requestTime, DatabaseDescriptor.getTransactionTimeout(TimeUnit.NANOSECONDS), barrierType, isForWrite); + AccordService.instance().barrier(Seekables.of(new PartitionKey(tableId, key)), minEpoch, requestTime, DatabaseDescriptor.getTransactionTimeout(TimeUnit.NANOSECONDS), barrierType, isForWrite); // We don't save the state to the cache here. Accord will notify the agent every time a barrier happens. } finally diff --git a/src/java/org/apache/cassandra/service/reads/AbstractReadExecutor.java b/src/java/org/apache/cassandra/service/reads/AbstractReadExecutor.java index 286a5b85d7..1e2d06cfb0 100644 --- a/src/java/org/apache/cassandra/service/reads/AbstractReadExecutor.java +++ b/src/java/org/apache/cassandra/service/reads/AbstractReadExecutor.java @@ -204,6 +204,7 @@ public abstract class AbstractReadExecutor ReplicaPlan.ForTokenRead replicaPlan = ReplicaPlans.forRead(metadata, keyspace, + command.metadata().id, command.partitionKey().getToken(), command.indexQueryPlan(), consistencyLevel, diff --git a/src/java/org/apache/cassandra/service/reads/ReadCoordinator.java b/src/java/org/apache/cassandra/service/reads/ReadCoordinator.java index 8f41464779..d9d8a7b562 100644 --- a/src/java/org/apache/cassandra/service/reads/ReadCoordinator.java +++ b/src/java/org/apache/cassandra/service/reads/ReadCoordinator.java @@ -29,6 +29,7 @@ import org.apache.cassandra.net.Message; import org.apache.cassandra.net.MessagingService; import org.apache.cassandra.net.RequestCallback; import org.apache.cassandra.schema.KeyspaceMetadata; +import org.apache.cassandra.schema.TableId; import org.apache.cassandra.tcm.ClusterMetadata; public interface ReadCoordinator @@ -40,7 +41,7 @@ public interface ReadCoordinator return true; } - public EndpointsForToken forNonLocalStrategyTokenRead(ClusterMetadata metadata, KeyspaceMetadata keyspace, Token token) + public EndpointsForToken forNonLocalStrategyTokenRead(ClusterMetadata metadata, KeyspaceMetadata keyspace, TableId tableId, Token token) { return ReplicaLayout.forNonLocalStrategyTokenRead(metadata, keyspace, token); } @@ -62,7 +63,7 @@ public interface ReadCoordinator }; boolean localReadSupported(); - EndpointsForToken forNonLocalStrategyTokenRead(ClusterMetadata metadata, KeyspaceMetadata keyspace, Token token); + EndpointsForToken forNonLocalStrategyTokenRead(ClusterMetadata metadata, KeyspaceMetadata keyspace, TableId tableId, Token token); default ReadCommand maybeAllowOutOfRangeReads(ReadCommand command) { return command; diff --git a/src/java/org/apache/cassandra/service/reads/range/RangeCommands.java b/src/java/org/apache/cassandra/service/reads/range/RangeCommands.java index cebd3bdf68..bd2acfbd6f 100644 --- a/src/java/org/apache/cassandra/service/reads/range/RangeCommands.java +++ b/src/java/org/apache/cassandra/service/reads/range/RangeCommands.java @@ -76,6 +76,7 @@ public class RangeCommands ReplicaPlanIterator replicaPlans = new ReplicaPlanIterator(command.dataRange().keyRange(), command.indexQueryPlan(), keyspace, + command.metadata().id(), consistencyLevel); if (command.isTopK()) @@ -107,7 +108,7 @@ public class RangeCommands Tracing.trace("Submitting range requests on {} ranges with a concurrency of {}", replicaPlans.size(), concurrencyFactor); } - ReplicaPlanMerger mergedReplicaPlans = new ReplicaPlanMerger(replicaPlans, keyspace, consistencyLevel); + ReplicaPlanMerger mergedReplicaPlans = new ReplicaPlanMerger(replicaPlans, keyspace, command.metadata().id(), consistencyLevel); return new RangeCommandIterator(mergedReplicaPlans, command, concurrencyFactor, @@ -147,11 +148,12 @@ public class RangeCommands ReplicaPlanIterator rangeIterator = new ReplicaPlanIterator(DataRange.allData(metadata.partitioner).keyRange(), null, keyspace, + metadata.id, consistency); // Called for the side effect of running assureSufficientLiveReplicasForRead. // Deliberately called with an invalid vnode count in case it is used elsewhere in the future.. - rangeIterator.forEachRemaining(r -> ReplicaPlans.forRangeRead(keyspace, null, consistency, r.range(), -1)); + rangeIterator.forEachRemaining(r -> ReplicaPlans.forRangeRead(keyspace, metadata.id, null, consistency, r.range(), -1)); return true; } catch (UnavailableException e) diff --git a/src/java/org/apache/cassandra/service/reads/range/ReplicaPlanIterator.java b/src/java/org/apache/cassandra/service/reads/range/ReplicaPlanIterator.java index 969247b722..e138fab4f1 100644 --- a/src/java/org/apache/cassandra/service/reads/range/ReplicaPlanIterator.java +++ b/src/java/org/apache/cassandra/service/reads/range/ReplicaPlanIterator.java @@ -37,6 +37,7 @@ import org.apache.cassandra.index.Index; import org.apache.cassandra.locator.ReplicaPlan; import org.apache.cassandra.locator.ReplicaPlans; import org.apache.cassandra.schema.ReplicationParams; +import org.apache.cassandra.schema.TableId; import org.apache.cassandra.tcm.ClusterMetadata; import org.apache.cassandra.tcm.compatibility.TokenRingUtils; import org.apache.cassandra.utils.AbstractIterator; @@ -46,6 +47,7 @@ class ReplicaPlanIterator extends AbstractIterator { private final Keyspace keyspace; private final ConsistencyLevel consistency; + private final TableId tableId; private final Index.QueryPlan indexQueryPlan; @VisibleForTesting final Iterator> ranges; @@ -54,10 +56,12 @@ class ReplicaPlanIterator extends AbstractIterator ReplicaPlanIterator(AbstractBounds keyRange, @Nullable Index.QueryPlan indexQueryPlan, Keyspace keyspace, + TableId tableId, ConsistencyLevel consistency) { this.indexQueryPlan = indexQueryPlan; this.keyspace = keyspace; + this.tableId = tableId; this.consistency = consistency; ReplicationParams replication = keyspace.getMetadata().params.replication; @@ -82,7 +86,7 @@ class ReplicaPlanIterator extends AbstractIterator if (!ranges.hasNext()) return endOfData(); - return ReplicaPlans.forRangeRead(keyspace, indexQueryPlan, consistency, ranges.next(), 1); + return ReplicaPlans.forRangeRead(keyspace, tableId, indexQueryPlan, consistency, ranges.next(), 1); } /** diff --git a/src/java/org/apache/cassandra/service/reads/range/ReplicaPlanMerger.java b/src/java/org/apache/cassandra/service/reads/range/ReplicaPlanMerger.java index 20e9562f93..743ac8d8e6 100644 --- a/src/java/org/apache/cassandra/service/reads/range/ReplicaPlanMerger.java +++ b/src/java/org/apache/cassandra/service/reads/range/ReplicaPlanMerger.java @@ -27,6 +27,7 @@ import org.apache.cassandra.db.ConsistencyLevel; import org.apache.cassandra.db.Keyspace; import org.apache.cassandra.locator.ReplicaPlan; import org.apache.cassandra.locator.ReplicaPlans; +import org.apache.cassandra.schema.TableId; import org.apache.cassandra.tcm.ClusterMetadata; import org.apache.cassandra.utils.AbstractIterator; @@ -34,11 +35,13 @@ class ReplicaPlanMerger extends AbstractIterator { private final Keyspace keyspace; private final ConsistencyLevel consistency; + private final TableId tableId; private final PeekingIterator ranges; - ReplicaPlanMerger(Iterator iterator, Keyspace keyspace, ConsistencyLevel consistency) + ReplicaPlanMerger(Iterator iterator, Keyspace keyspace, TableId tableId, ConsistencyLevel consistency) { this.keyspace = keyspace; + this.tableId = tableId; this.consistency = consistency; this.ranges = Iterators.peekingIterator(iterator); } @@ -66,7 +69,7 @@ class ReplicaPlanMerger extends AbstractIterator break; ReplicaPlan.ForRangeRead next = ranges.peek(); - ReplicaPlan.ForRangeRead merged = ReplicaPlans.maybeMerge(metadata, keyspace, consistency, current, next); + ReplicaPlan.ForRangeRead merged = ReplicaPlans.maybeMerge(metadata, keyspace, tableId, consistency, current, next); if (merged == null) break; diff --git a/src/java/org/apache/cassandra/streaming/StreamPlan.java b/src/java/org/apache/cassandra/streaming/StreamPlan.java index 47fa9e1463..88f77e8867 100644 --- a/src/java/org/apache/cassandra/streaming/StreamPlan.java +++ b/src/java/org/apache/cassandra/streaming/StreamPlan.java @@ -24,6 +24,8 @@ import com.google.common.annotations.VisibleForTesting; import org.apache.cassandra.locator.InetAddressAndPort; import org.apache.cassandra.locator.RangesAtEndpoint; import org.apache.cassandra.locator.Replica; +import org.apache.cassandra.schema.KeyspaceMetadata; +import org.apache.cassandra.service.accord.AccordService; import org.apache.cassandra.utils.TimeUUID; import static com.google.common.collect.Iterables.all; @@ -225,4 +227,31 @@ public class StreamPlan { return coordinator; } + + /** + * Returns an array containing the non-accord tables for the given keyspace. Since the relevant StreamPlan methods + * interpret an empty array to mean all tables, null is returned if there are no non-accord tables in + * the given keyspace + * @param ksm + * @return + */ + public static String[] nonAccordTablesForKeyspace(KeyspaceMetadata ksm) + { + String[] result = ksm.tables.stream() + .filter(tbl -> !AccordService.instance().isAccordManagedTable(tbl.id)) + .map(tbl -> tbl.name) + .toArray(String[]::new); + + return result.length > 0 ? result : null; + } + + public static boolean hasNonAccordTables(KeyspaceMetadata ksm) + { + return ksm.tables.stream().anyMatch(tbl -> !AccordService.instance().isAccordManagedTable(tbl.id)); + } + + public static boolean hasAccordTables(KeyspaceMetadata ksm) + { + return ksm.tables.stream().anyMatch(tbl -> AccordService.instance().isAccordManagedTable(tbl.id)); + } } diff --git a/src/java/org/apache/cassandra/tcm/ClusterMetadata.java b/src/java/org/apache/cassandra/tcm/ClusterMetadata.java index 8dfe9a6790..2c2e3b7d30 100644 --- a/src/java/org/apache/cassandra/tcm/ClusterMetadata.java +++ b/src/java/org/apache/cassandra/tcm/ClusterMetadata.java @@ -32,10 +32,12 @@ import java.util.Set; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import accord.local.Node; import org.apache.cassandra.config.CassandraRelevantProperties; import org.apache.cassandra.db.TypeSizes; import org.apache.cassandra.dht.IPartitioner; @@ -59,13 +61,9 @@ import org.apache.cassandra.service.consensus.migration.ConsensusTableMigrationS import org.apache.cassandra.service.consensus.migration.ConsensusTableMigrationState.TableMigrationState; import org.apache.cassandra.tcm.extensions.ExtensionKey; import org.apache.cassandra.tcm.extensions.ExtensionValue; -import org.apache.cassandra.tcm.membership.Directory; -import org.apache.cassandra.tcm.membership.Location; -import org.apache.cassandra.tcm.membership.NodeAddresses; -import org.apache.cassandra.tcm.membership.NodeId; -import org.apache.cassandra.tcm.membership.NodeState; -import org.apache.cassandra.tcm.membership.NodeVersion; -import org.apache.cassandra.tcm.ownership.AccordKeyspaces; +import org.apache.cassandra.service.accord.AccordFastPath; +import org.apache.cassandra.tcm.membership.*; +import org.apache.cassandra.tcm.ownership.AccordTables; import org.apache.cassandra.tcm.ownership.DataPlacement; import org.apache.cassandra.tcm.ownership.DataPlacements; import org.apache.cassandra.tcm.ownership.PrimaryRangeComparator; @@ -82,6 +80,7 @@ import org.apache.cassandra.utils.Pair; import static com.google.common.collect.ImmutableSet.toImmutableSet; import static org.apache.cassandra.config.CassandraRelevantProperties.LINE_SEPARATOR; import static org.apache.cassandra.db.TypeSizes.sizeof; +import static org.apache.cassandra.tcm.serialization.Version.V2; public class ClusterMetadata { @@ -97,7 +96,8 @@ public class ClusterMetadata public final Directory directory; public final TokenMap tokenMap; public final DataPlacements placements; - public final AccordKeyspaces accordKeyspaces; + public final AccordTables accordTables; + public final AccordFastPath accordFastPath; public final LockedRanges lockedRanges; public final InProgressSequences inProgressSequences; public final ConsensusMigrationState consensusMigrationState; @@ -133,7 +133,8 @@ public class ClusterMetadata directory, new TokenMap(partitioner), DataPlacements.EMPTY, - AccordKeyspaces.EMPTY, + AccordTables.EMPTY, + AccordFastPath.EMPTY, LockedRanges.EMPTY, InProgressSequences.EMPTY, ConsensusMigrationState.EMPTY, @@ -146,7 +147,8 @@ public class ClusterMetadata Directory directory, TokenMap tokenMap, DataPlacements placements, - AccordKeyspaces accordKeyspaces, + AccordTables accordTables, + AccordFastPath accordFastPath, LockedRanges lockedRanges, InProgressSequences inProgressSequences, ConsensusMigrationState consensusMigrationState, @@ -159,7 +161,8 @@ public class ClusterMetadata directory, tokenMap, placements, - accordKeyspaces, + accordTables, + accordFastPath, lockedRanges, inProgressSequences, consensusMigrationState, @@ -173,7 +176,8 @@ public class ClusterMetadata Directory directory, TokenMap tokenMap, DataPlacements placements, - AccordKeyspaces accordKeyspaces, + AccordTables accordTables, + AccordFastPath accordFastPath, LockedRanges lockedRanges, InProgressSequences inProgressSequences, ConsensusMigrationState consensusMigrationState, @@ -190,7 +194,8 @@ public class ClusterMetadata this.directory = directory; this.tokenMap = tokenMap; this.placements = placements; - this.accordKeyspaces = accordKeyspaces; + this.accordTables = accordTables; + this.accordFastPath = accordFastPath; this.lockedRanges = lockedRanges; this.inProgressSequences = inProgressSequences; this.consensusMigrationState = consensusMigrationState; @@ -200,12 +205,12 @@ public class ClusterMetadata public ClusterMetadata withDirectory(Directory directory) { - return new ClusterMetadata(epoch, partitioner, schema, directory, tokenMap, placements, accordKeyspaces, lockedRanges, inProgressSequences, consensusMigrationState, extensions); + return new ClusterMetadata(epoch, partitioner, schema, directory, tokenMap, placements, accordTables, accordFastPath, lockedRanges, inProgressSequences, consensusMigrationState, extensions); } public ClusterMetadata withPlacements(DataPlacements placements) { - return new ClusterMetadata(epoch, partitioner, schema, directory, tokenMap, placements, accordKeyspaces, lockedRanges, inProgressSequences, consensusMigrationState, extensions); + return new ClusterMetadata(epoch, partitioner, schema, directory, tokenMap, placements, accordTables, accordFastPath, lockedRanges, inProgressSequences, consensusMigrationState, extensions); } public Set fullCMSMembers() @@ -257,7 +262,8 @@ public class ClusterMetadata capLastModified(directory, epoch), capLastModified(tokenMap, epoch), capLastModified(placements, epoch), - capLastModified(accordKeyspaces, epoch), + capLastModified(accordTables, epoch), + capLastModified(accordFastPath, epoch), capLastModified(lockedRanges, epoch), capLastModified(inProgressSequences, epoch), capLastModified(consensusMigrationState, epoch), @@ -279,7 +285,8 @@ public class ClusterMetadata directory, tokenMap, placements, - accordKeyspaces, + accordTables, + accordFastPath, lockedRanges, inProgressSequences, consensusMigrationState, @@ -406,7 +413,8 @@ public class ClusterMetadata private Directory directory; private TokenMap tokenMap; private DataPlacements placements; - private AccordKeyspaces accordKeyspaces; + private AccordTables accordTables; + private AccordFastPath accordFastPath; private LockedRanges lockedRanges; private InProgressSequences inProgressSequences; private ConsensusMigrationState consensusMigrationState; @@ -422,7 +430,8 @@ public class ClusterMetadata this.directory = metadata.directory; this.tokenMap = metadata.tokenMap; this.placements = metadata.placements; - this.accordKeyspaces = metadata.accordKeyspaces; + this.accordTables = metadata.accordTables; + this.accordFastPath = metadata.accordFastPath; this.lockedRanges = metadata.lockedRanges; this.inProgressSequences = metadata.inProgressSequences; this.consensusMigrationState = metadata.consensusMigrationState; @@ -543,9 +552,15 @@ public class ClusterMetadata return this; } - public Transformer withAccordKeyspace(String keyspace) + public Transformer withAccordTable(TableId table) { - accordKeyspaces = accordKeyspaces.with(keyspace); + accordTables = accordTables.with(table); + return this; + } + + public Transformer withFastPathStatusSince(Node.Id node, AccordFastPath.Status status, long updateTimeMillis, long updateDelayMillis) + { + accordFastPath = accordFastPath.withNodeStatusSince(node, status, updateTimeMillis, updateDelayMillis); return this; } @@ -640,6 +655,9 @@ public class ClusterMetadata { modifiedKeys.add(MetadataKeys.NODE_DIRECTORY); directory = directory.withLastModified(epoch); + + for (NodeId peer : Sets.difference(base.directory.peerIds(), directory.peerIds())) + accordFastPath = accordFastPath.withoutNode(peer); } if (tokenMap != base.tokenMap) @@ -660,10 +678,16 @@ public class ClusterMetadata placements = placements.withLastModified(epoch); } - if (accordKeyspaces != base.accordKeyspaces) + if (accordTables != base.accordTables) { - modifiedKeys.add(MetadataKeys.ACCORD_KEYSPACES); - accordKeyspaces = accordKeyspaces.withLastModified(epoch); + modifiedKeys.add(MetadataKeys.ACCORD_TABLES); + accordTables = accordTables.withLastModified(epoch); + } + + if (accordFastPath != base.accordFastPath) + { + modifiedKeys.add(MetadataKeys.ACCORD_FAST_PATH); + accordFastPath = accordFastPath.withLastModified(epoch); } if (lockedRanges != base.lockedRanges) @@ -691,7 +715,8 @@ public class ClusterMetadata directory, tokenMap, placements, - accordKeyspaces, + accordTables, + accordFastPath, lockedRanges, inProgressSequences, consensusMigrationState, @@ -708,7 +733,8 @@ public class ClusterMetadata directory, tokenMap, placements, - accordKeyspaces, + accordTables, + accordFastPath, lockedRanges, inProgressSequences, consensusMigrationState, @@ -726,6 +752,7 @@ public class ClusterMetadata ", directory=" + schema + ", tokenMap=" + tokenMap + ", placement=" + placements + + ", availability=" + accordFastPath + ", lockedRanges=" + lockedRanges + ", inProgressSequences=" + inProgressSequences + ", consensusMigrationState=" + consensusMigrationState + @@ -839,7 +866,7 @@ public class ClusterMetadata directory.equals(that.directory) && tokenMap.equals(that.tokenMap) && placements.equals(that.placements) && - accordKeyspaces.equals(that.accordKeyspaces) && + accordTables.equals(that.accordTables) && lockedRanges.equals(that.lockedRanges) && inProgressSequences.equals(that.inProgressSequences) && consensusMigrationState.equals(that.consensusMigrationState) && @@ -891,7 +918,7 @@ public class ClusterMetadata @Override public int hashCode() { - return Objects.hash(epoch, schema, directory, tokenMap, placements, accordKeyspaces, lockedRanges, inProgressSequences, consensusMigrationState, extensions); + return Objects.hash(epoch, schema, directory, tokenMap, placements, accordTables, lockedRanges, inProgressSequences, consensusMigrationState, extensions); } public static ClusterMetadata current() @@ -968,7 +995,11 @@ public class ClusterMetadata Directory.serializer.serialize(metadata.directory, out, version); TokenMap.serializer.serialize(metadata.tokenMap, out, version); DataPlacements.serializer.serialize(metadata.placements, out, version); - AccordKeyspaces.serializer.serialize(metadata.accordKeyspaces, out, version); + if (version.isAtLeast(V2)) + { + AccordTables.serializer.serialize(metadata.accordTables, out, version); + AccordFastPath.serializer.serialize(metadata.accordFastPath, out, version); + } LockedRanges.serializer.serialize(metadata.lockedRanges, out, version); InProgressSequences.serializer.serialize(metadata.inProgressSequences, out, version); ConsensusMigrationState.serializer.serialize(metadata.consensusMigrationState, out, version); @@ -1006,7 +1037,18 @@ public class ClusterMetadata Directory dir = Directory.serializer.deserialize(in, version); TokenMap tokenMap = TokenMap.serializer.deserialize(in, version); DataPlacements placements = DataPlacements.serializer.deserialize(in, version); - AccordKeyspaces accordKeyspaces = AccordKeyspaces.serializer.deserialize(in, version); + AccordTables accordTables; + AccordFastPath accordFastPath; + if (version.isAtLeast(V2)) + { + accordTables = AccordTables.serializer.deserialize(in, version); + accordFastPath = AccordFastPath.serializer.deserialize(in, version); + } + else + { + accordTables = AccordTables.EMPTY; + accordFastPath = AccordFastPath.EMPTY; + } LockedRanges lockedRanges = LockedRanges.serializer.deserialize(in, version); InProgressSequences ips = InProgressSequences.serializer.deserialize(in, version); ConsensusMigrationState consensusMigrationState = ConsensusMigrationState.serializer.deserialize(in, version); @@ -1026,7 +1068,8 @@ public class ClusterMetadata dir, tokenMap, placements, - accordKeyspaces, + accordTables, + accordFastPath, lockedRanges, ips, consensusMigrationState, @@ -1050,10 +1093,17 @@ public class ClusterMetadata Directory.serializer.serializedSize(metadata.directory, version) + TokenMap.serializer.serializedSize(metadata.tokenMap, version) + DataPlacements.serializer.serializedSize(metadata.placements, version) + - AccordKeyspaces.serializer.serializedSize(metadata.accordKeyspaces, version) + - LockedRanges.serializer.serializedSize(metadata.lockedRanges, version) + - InProgressSequences.serializer.serializedSize(metadata.inProgressSequences, version) + ConsensusMigrationState.serializer.serializedSize(metadata.consensusMigrationState, version); + DataPlacements.serializer.serializedSize(metadata.placements, version); + + if (version.isAtLeast(V2)) + { + size += AccordTables.serializer.serializedSize(metadata.accordTables, version) + + AccordFastPath.serializer.serializedSize(metadata.accordFastPath, version); + } + + size += LockedRanges.serializer.serializedSize(metadata.lockedRanges, version) + + InProgressSequences.serializer.serializedSize(metadata.inProgressSequences, version); return size; } diff --git a/src/java/org/apache/cassandra/tcm/MetadataKeys.java b/src/java/org/apache/cassandra/tcm/MetadataKeys.java index df65474a53..1794a63889 100644 --- a/src/java/org/apache/cassandra/tcm/MetadataKeys.java +++ b/src/java/org/apache/cassandra/tcm/MetadataKeys.java @@ -39,7 +39,8 @@ public class MetadataKeys public static final MetadataKey NODE_DIRECTORY = make(CORE_NS, "membership", "node_directory"); public static final MetadataKey TOKEN_MAP = make(CORE_NS, "ownership", "token_map"); public static final MetadataKey DATA_PLACEMENTS = make(CORE_NS, "ownership", "data_placements"); - public static final MetadataKey ACCORD_KEYSPACES = make(CORE_NS, "ownership", "accord_keyspaces"); + public static final MetadataKey ACCORD_TABLES = make(CORE_NS, "ownership", "accord_tables"); + public static final MetadataKey ACCORD_FAST_PATH = make(CORE_NS, "ownership", "accord_fast_path"); public static final MetadataKey LOCKED_RANGES = make(CORE_NS, "sequences", "locked_ranges"); public static final MetadataKey IN_PROGRESS_SEQUENCES = make(CORE_NS, "sequences", "in_progress"); public static final MetadataKey CONSENSUS_MIGRATION_STATE = make(CORE_NS, "consensus", "migration_state"); @@ -48,7 +49,8 @@ public class MetadataKeys NODE_DIRECTORY, TOKEN_MAP, DATA_PLACEMENTS, - ACCORD_KEYSPACES, + ACCORD_TABLES, + ACCORD_FAST_PATH, LOCKED_RANGES, IN_PROGRESS_SEQUENCES, CONSENSUS_MIGRATION_STATE); diff --git a/src/java/org/apache/cassandra/tcm/StubClusterMetadataService.java b/src/java/org/apache/cassandra/tcm/StubClusterMetadataService.java index 34799e9b56..150b3934bb 100644 --- a/src/java/org/apache/cassandra/tcm/StubClusterMetadataService.java +++ b/src/java/org/apache/cassandra/tcm/StubClusterMetadataService.java @@ -28,12 +28,13 @@ import org.apache.cassandra.schema.DistributedMetadataLogKeyspace; import org.apache.cassandra.schema.DistributedSchema; import org.apache.cassandra.schema.KeyspaceMetadata; import org.apache.cassandra.schema.Keyspaces; +import org.apache.cassandra.service.accord.AccordFastPath; import org.apache.cassandra.service.consensus.migration.ConsensusTableMigrationState; import org.apache.cassandra.tcm.Commit.Replicator; import org.apache.cassandra.tcm.log.Entry; import org.apache.cassandra.tcm.log.LocalLog; import org.apache.cassandra.tcm.membership.Directory; -import org.apache.cassandra.tcm.ownership.AccordKeyspaces; +import org.apache.cassandra.tcm.ownership.AccordTables; import org.apache.cassandra.tcm.ownership.DataPlacements; import org.apache.cassandra.tcm.ownership.PlacementProvider; import org.apache.cassandra.tcm.ownership.TokenMap; @@ -174,7 +175,8 @@ public class StubClusterMetadataService extends ClusterMetadataService Directory.EMPTY, new TokenMap(partitioner), DataPlacements.EMPTY, - AccordKeyspaces.EMPTY, + AccordTables.EMPTY, + AccordFastPath.EMPTY, LockedRanges.EMPTY, InProgressSequences.EMPTY, ConsensusTableMigrationState.ConsensusMigrationState.EMPTY, diff --git a/src/java/org/apache/cassandra/tcm/Transformation.java b/src/java/org/apache/cassandra/tcm/Transformation.java index cdbf44fcb6..f6f0aa226d 100644 --- a/src/java/org/apache/cassandra/tcm/Transformation.java +++ b/src/java/org/apache/cassandra/tcm/Transformation.java @@ -38,7 +38,7 @@ import org.apache.cassandra.tcm.sequences.LockedRanges; import org.apache.cassandra.tcm.serialization.AsymmetricMetadataSerializer; import org.apache.cassandra.tcm.serialization.VerboseMetadataSerializer; import org.apache.cassandra.tcm.serialization.Version; -import org.apache.cassandra.tcm.transformations.AddAccordKeyspace; +import org.apache.cassandra.tcm.transformations.AddAccordTable; import org.apache.cassandra.tcm.transformations.AlterSchema; import org.apache.cassandra.tcm.transformations.AlterTopology; import org.apache.cassandra.tcm.transformations.Assassinate; @@ -51,6 +51,7 @@ import org.apache.cassandra.tcm.transformations.PrepareJoin; import org.apache.cassandra.tcm.transformations.PrepareLeave; import org.apache.cassandra.tcm.transformations.PrepareMove; import org.apache.cassandra.tcm.transformations.PrepareReplace; +import org.apache.cassandra.tcm.transformations.ReconfigureAccordFastPath; import org.apache.cassandra.tcm.transformations.Register; import org.apache.cassandra.tcm.transformations.SetConsensusMigrationTargetProtocol; import org.apache.cassandra.tcm.transformations.Startup; @@ -239,10 +240,11 @@ public interface Transformation CANCEL_CMS_RECONFIGURATION(34, () -> CancelCMSReconfiguration.serializer), ALTER_TOPOLOGY(35, () -> AlterTopology.serializer), - ADD_ACCORD_KEYSPACE(36, () -> AddAccordKeyspace.serializer), - BEGIN_CONSENSUS_MIGRATION_FOR_TABLE_AND_RANGE(37, () -> BeginConsensusMigrationForTableAndRange.serializer), - MAYBE_FINISH_CONSENSUS_MIGRATION_FOR_TABLE_AND_RANGE(38, () -> MaybeFinishConsensusMigrationForTableAndRange.serializer), - SET_CONSENSUS_MIGRATION_TARGET_PROTOCOL(39, () -> SetConsensusMigrationTargetProtocol.serializer) + ADD_ACCORD_TABLE(36, () -> AddAccordTable.serializer), + UPDATE_AVAILABILITY(37, () -> ReconfigureAccordFastPath.serializer), + BEGIN_CONSENSUS_MIGRATION_FOR_TABLE_AND_RANGE(38, () -> BeginConsensusMigrationForTableAndRange.serializer), + MAYBE_FINISH_CONSENSUS_MIGRATION_FOR_TABLE_AND_RANGE(39, () -> MaybeFinishConsensusMigrationForTableAndRange.serializer), + SET_CONSENSUS_MIGRATION_TARGET_PROTOCOL(40, () -> SetConsensusMigrationTargetProtocol.serializer) ; private final Supplier> serializer; diff --git a/src/java/org/apache/cassandra/tcm/compatibility/GossipHelper.java b/src/java/org/apache/cassandra/tcm/compatibility/GossipHelper.java index f87278d4b3..390ead6f4d 100644 --- a/src/java/org/apache/cassandra/tcm/compatibility/GossipHelper.java +++ b/src/java/org/apache/cassandra/tcm/compatibility/GossipHelper.java @@ -60,13 +60,14 @@ import org.apache.cassandra.tcm.Epoch; import org.apache.cassandra.tcm.MultiStepOperation; import org.apache.cassandra.tcm.extensions.ExtensionKey; import org.apache.cassandra.tcm.extensions.ExtensionValue; +import org.apache.cassandra.service.accord.AccordFastPath; import org.apache.cassandra.tcm.membership.Directory; import org.apache.cassandra.tcm.membership.Location; import org.apache.cassandra.tcm.membership.NodeAddresses; import org.apache.cassandra.tcm.membership.NodeId; import org.apache.cassandra.tcm.membership.NodeState; import org.apache.cassandra.tcm.membership.NodeVersion; -import org.apache.cassandra.tcm.ownership.AccordKeyspaces; +import org.apache.cassandra.tcm.ownership.AccordTables; import org.apache.cassandra.tcm.ownership.DataPlacements; import org.apache.cassandra.tcm.ownership.TokenMap; import org.apache.cassandra.tcm.ownership.UniformRangePlacement; @@ -296,7 +297,8 @@ public class GossipHelper Directory.EMPTY, new TokenMap(DatabaseDescriptor.getPartitioner()), DataPlacements.empty(), - AccordKeyspaces.EMPTY, + AccordTables.EMPTY, + AccordFastPath.EMPTY, LockedRanges.EMPTY, InProgressSequences.EMPTY, ConsensusMigrationState.EMPTY, @@ -385,7 +387,8 @@ public class GossipHelper directory, tokenMap, DataPlacements.empty(), - AccordKeyspaces.EMPTY, + AccordTables.EMPTY, + AccordFastPath.EMPTY, LockedRanges.EMPTY, InProgressSequences.EMPTY, ConsensusMigrationState.EMPTY, @@ -399,7 +402,8 @@ public class GossipHelper directory, tokenMap, placements, - AccordKeyspaces.EMPTY, + AccordTables.EMPTY, + AccordFastPath.EMPTY, LockedRanges.EMPTY, InProgressSequences.EMPTY, ConsensusMigrationState.EMPTY, diff --git a/src/java/org/apache/cassandra/tcm/ownership/AccordKeyspaces.java b/src/java/org/apache/cassandra/tcm/ownership/AccordKeyspaces.java deleted file mode 100644 index 76e9d8ab8e..0000000000 --- a/src/java/org/apache/cassandra/tcm/ownership/AccordKeyspaces.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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.tcm.ownership; - -import java.io.IOException; -import java.util.Arrays; - -import com.google.common.collect.ImmutableSet; - -import org.apache.cassandra.db.TypeSizes; -import org.apache.cassandra.io.util.DataInputPlus; -import org.apache.cassandra.io.util.DataOutputPlus; -import org.apache.cassandra.tcm.Epoch; -import org.apache.cassandra.tcm.MetadataValue; -import org.apache.cassandra.tcm.serialization.MetadataSerializer; -import org.apache.cassandra.tcm.serialization.Version; - -public class AccordKeyspaces implements MetadataValue -{ - public static final AccordKeyspaces EMPTY = new AccordKeyspaces(Epoch.EMPTY, ImmutableSet.of()); - private final Epoch lastModified; - private final ImmutableSet keyspaces; - - public AccordKeyspaces(Epoch lastModified, ImmutableSet keyspaces) - { - this.lastModified = lastModified; - this.keyspaces = keyspaces; - } - - public String toString() - { - return "AccordKeyspaces{" + lastModified + keyspaces + '}'; - } - - public AccordKeyspaces withLastModified(Epoch epoch) - { - return new AccordKeyspaces(epoch, keyspaces); - } - - public Epoch lastModified() - { - return lastModified; - } - - public boolean contains(String keyspace) - { - return keyspaces.contains(keyspace); - } - - public AccordKeyspaces with(String keyspace) - { - if (keyspaces.contains(keyspace)) - return this; - - return new AccordKeyspaces(lastModified, ImmutableSet.builder().addAll(keyspaces).add(keyspace).build()); - } - - public static final MetadataSerializer serializer = new MetadataSerializer() - { - public void serialize(AccordKeyspaces accordKeyspaces, DataOutputPlus out, Version version) throws IOException - { - int size = accordKeyspaces.keyspaces.size(); - out.writeInt(size); - String[] keyspaces = new String[size]; - accordKeyspaces.keyspaces.toArray(keyspaces); - Arrays.sort(keyspaces); - for (String keyspace : keyspaces) - out.writeUTF(keyspace); - Epoch.serializer.serialize(accordKeyspaces.lastModified, out, version); - } - - public AccordKeyspaces deserialize(DataInputPlus in, Version version) throws IOException - { - int size = in.readInt(); - ImmutableSet.Builder builder = ImmutableSet.builder(); - for (int i=0; i +{ + public static final AccordTables EMPTY = new AccordTables(Epoch.EMPTY, ImmutableSet.of()); + private final Epoch lastModified; + private final ImmutableSet tables; + + public AccordTables(Epoch lastModified, ImmutableSet tables) + { + this.lastModified = lastModified; + this.tables = tables; + } + + public String toString() + { + return "AccordTables{" + lastModified + ", " + tables + '}'; + } + + public AccordTables withLastModified(Epoch epoch) + { + return new AccordTables(epoch, tables); + } + + public Epoch lastModified() + { + return lastModified; + } + + public boolean contains(TableId table) + { + return tables.contains(table); + } + + public AccordTables with(TableId table) + { + if (tables.contains(table)) + return this; + + return new AccordTables(lastModified, ImmutableSet.builder().addAll(tables).add(table).build()); + } + + public static final MetadataSerializer serializer = new MetadataSerializer() + { + public void serialize(AccordTables accordTables, DataOutputPlus out, Version version) throws IOException + { + int size = accordTables.tables.size(); + out.writeUnsignedVInt32(size); + TableId[] tables = new TableId[size]; + accordTables.tables.toArray(tables); + Arrays.sort(tables); + for (TableId table : tables) + table.serialize(out); + Epoch.serializer.serialize(accordTables.lastModified, out, version); + } + + public AccordTables deserialize(DataInputPlus in, Version version) throws IOException + { + int size = in.readUnsignedVInt32(); + ImmutableSet.Builder builder = ImmutableSet.builder(); + for (int i=0; i for (KeyspaceMetadata ks : keyspaces) { - if (AccordService.instance().isAccordManagedKeyspace(ks.name)) - continue; ReplicationParams replicationParams = ks.params.replication; - if (replicationParams.isMeta()) + if (replicationParams.isMeta() || !StreamPlan.hasNonAccordTables(ks)) continue; + EndpointsByReplica endpoints = movementMap.get(replicationParams); + + String[] cfNames = StreamPlan.nonAccordTablesForKeyspace(ks); for (Map.Entry e : endpoints.flattenEntries()) { Replica destination = e.getKey(); @@ -242,13 +243,13 @@ public class Move extends MultiStepOperation logger.info("Stream source: {} destination: {}", source, destination); assert !source.endpoint().equals(destination.endpoint()) : String.format("Source %s should not be the same as destionation %s", source, destination); if (source.isSelf()) - streamPlan.transferRanges(destination.endpoint(), ks.name, RangesAtEndpoint.of(destination)); + streamPlan.transferRanges(destination.endpoint(), ks.name, RangesAtEndpoint.of(destination), cfNames); else if (destination.isSelf()) { if (destination.isFull()) - streamPlan.requestRanges(source.endpoint(), ks.name, RangesAtEndpoint.of(destination), RangesAtEndpoint.empty(destination.endpoint())); + streamPlan.requestRanges(source.endpoint(), ks.name, RangesAtEndpoint.of(destination), RangesAtEndpoint.empty(destination.endpoint()), cfNames); else - streamPlan.requestRanges(source.endpoint(), ks.name, RangesAtEndpoint.empty(destination.endpoint()), RangesAtEndpoint.of(destination)); + streamPlan.requestRanges(source.endpoint(), ks.name, RangesAtEndpoint.empty(destination.endpoint()), RangesAtEndpoint.of(destination), cfNames); } else throw new IllegalStateException("Node should be either source or destination in the movement map " + endpoints); diff --git a/src/java/org/apache/cassandra/tcm/serialization/Version.java b/src/java/org/apache/cassandra/tcm/serialization/Version.java index 50e1792e23..da99e726a0 100644 --- a/src/java/org/apache/cassandra/tcm/serialization/Version.java +++ b/src/java/org/apache/cassandra/tcm/serialization/Version.java @@ -36,6 +36,7 @@ public enum Version /** * - Added version to PlacementForRange serializer * - Serialize MemtableParams when serializing TableParams + * - Added AccordFastPath */ V2(2), /** diff --git a/src/java/org/apache/cassandra/tcm/transformations/AddAccordKeyspace.java b/src/java/org/apache/cassandra/tcm/transformations/AddAccordTable.java similarity index 53% rename from src/java/org/apache/cassandra/tcm/transformations/AddAccordKeyspace.java rename to src/java/org/apache/cassandra/tcm/transformations/AddAccordTable.java index 4057d7eccf..91eacd87e8 100644 --- a/src/java/org/apache/cassandra/tcm/transformations/AddAccordKeyspace.java +++ b/src/java/org/apache/cassandra/tcm/transformations/AddAccordTable.java @@ -20,59 +20,72 @@ package org.apache.cassandra.tcm.transformations; import java.io.IOException; -import org.apache.cassandra.db.TypeSizes; +import accord.utils.Invariants; import org.apache.cassandra.exceptions.ExceptionCode; import org.apache.cassandra.io.util.DataInputPlus; import org.apache.cassandra.io.util.DataOutputPlus; +import org.apache.cassandra.schema.TableId; import org.apache.cassandra.tcm.ClusterMetadata; +import org.apache.cassandra.tcm.ClusterMetadataService; import org.apache.cassandra.tcm.Transformation; import org.apache.cassandra.tcm.sequences.LockedRanges; import org.apache.cassandra.tcm.serialization.AsymmetricMetadataSerializer; import org.apache.cassandra.tcm.serialization.Version; // TODO (expected, interop): improve mechanism for adding tables (probably want table level granularity, option to not-auto-add, and option to remove) -public class AddAccordKeyspace implements Transformation +public class AddAccordTable implements Transformation { - private final String keyspace; + private final TableId table; - public AddAccordKeyspace(String keyspace) + public AddAccordTable(TableId table) { - this.keyspace = keyspace; + this.table = table; } public Kind kind() { - return Kind.ADD_ACCORD_KEYSPACE; + return Kind.ADD_ACCORD_TABLE; } @Override public Result execute(ClusterMetadata metadata) { - if (metadata.accordKeyspaces.contains(keyspace)) - return new Rejected(ExceptionCode.ALREADY_EXISTS, keyspace + " is already an accord keyspaces"); + if (metadata.accordTables.contains(table)) + return new Rejected(ExceptionCode.ALREADY_EXISTS, table + " is already an accord table"); - return Transformation.success(metadata.transformer().withAccordKeyspace(keyspace), LockedRanges.AffectedRanges.EMPTY); + return Transformation.success(metadata.transformer().withAccordTable(table), LockedRanges.AffectedRanges.EMPTY); } - public static final AsymmetricMetadataSerializer serializer = new AsymmetricMetadataSerializer() + public static void addTable(TableId table) + { + ClusterMetadataService.instance().commit(new AddAccordTable(table), + metadata -> null, + (code, message) -> { + Invariants.checkState(code == ExceptionCode.ALREADY_EXISTS, + "Expected %s, got %s", ExceptionCode.ALREADY_EXISTS, code); + return null; + }); + } + + public static final AsymmetricMetadataSerializer serializer = new AsymmetricMetadataSerializer() { public void serialize(Transformation t, DataOutputPlus out, Version version) throws IOException { - assert t instanceof AddAccordKeyspace; - AddAccordKeyspace addKeyspace = (AddAccordKeyspace) t; - out.writeUTF(addKeyspace.keyspace); + assert t instanceof AddAccordTable; + AddAccordTable addTable = (AddAccordTable) t; + addTable.table.serialize(out); } - public AddAccordKeyspace deserialize(DataInputPlus in, Version version) throws IOException + public AddAccordTable deserialize(DataInputPlus in, Version version) throws IOException { - return new AddAccordKeyspace(in.readUTF()); + return new AddAccordTable(TableId.deserialize(in)); } public long serializedSize(Transformation t, Version version) { - assert t instanceof AddAccordKeyspace; - AddAccordKeyspace addKeyspace = (AddAccordKeyspace) t; - return TypeSizes.sizeof(addKeyspace.keyspace); + assert t instanceof AddAccordTable; + AddAccordTable addTable = (AddAccordTable) t; + return addTable.table.serializedSize(); } }; } diff --git a/src/java/org/apache/cassandra/tcm/transformations/ReconfigureAccordFastPath.java b/src/java/org/apache/cassandra/tcm/transformations/ReconfigureAccordFastPath.java new file mode 100644 index 0000000000..628f4482f1 --- /dev/null +++ b/src/java/org/apache/cassandra/tcm/transformations/ReconfigureAccordFastPath.java @@ -0,0 +1,97 @@ +/* + * 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.tcm.transformations; + +import java.io.IOException; + +import accord.local.Node; +import org.apache.cassandra.db.TypeSizes; +import org.apache.cassandra.exceptions.ExceptionCode; +import org.apache.cassandra.exceptions.InvalidRequestException; +import org.apache.cassandra.io.util.DataInputPlus; +import org.apache.cassandra.io.util.DataOutputPlus; +import org.apache.cassandra.service.accord.AccordFastPath; +import org.apache.cassandra.service.accord.serializers.TopologySerializers; +import org.apache.cassandra.tcm.ClusterMetadata; +import org.apache.cassandra.tcm.Transformation; +import org.apache.cassandra.tcm.sequences.LockedRanges; +import org.apache.cassandra.tcm.serialization.AsymmetricMetadataSerializer; +import org.apache.cassandra.tcm.serialization.Version; + +public class ReconfigureAccordFastPath implements Transformation +{ + private final Node.Id node; + private final AccordFastPath.Status status; + private final long updateTimeMillis; + private final long updateDelayMillis; + + public ReconfigureAccordFastPath(Node.Id node, AccordFastPath.Status status, long updateTimeMillis, long updateDelayMillis) + { + this.node = node; + this.status = status; + this.updateTimeMillis = updateTimeMillis; + this.updateDelayMillis = updateDelayMillis; + } + + public Kind kind() + { + return Kind.UPDATE_AVAILABILITY; + } + + public Result execute(ClusterMetadata metadata) + { + try + { + return Transformation.success(metadata.transformer().withFastPathStatusSince(node, status, updateTimeMillis, updateDelayMillis), LockedRanges.AffectedRanges.EMPTY); + } + catch (InvalidRequestException e) + { + return new Rejected(ExceptionCode.INVALID, e.getMessage()); + } + } + + public static final AsymmetricMetadataSerializer serializer = new AsymmetricMetadataSerializer() + { + public void serialize(Transformation t, DataOutputPlus out, Version version) throws IOException + { + ReconfigureAccordFastPath update = (ReconfigureAccordFastPath) t; + TopologySerializers.nodeId.serialize(update.node, out, version); + AccordFastPath.Status.serializer.serialize(update.status, out, version); + out.writeUnsignedVInt(update.updateTimeMillis); + out.writeUnsignedVInt(update.updateDelayMillis); + + } + + public ReconfigureAccordFastPath deserialize(DataInputPlus in, Version version) throws IOException + { + return new ReconfigureAccordFastPath(TopologySerializers.nodeId.deserialize(in, version), + AccordFastPath.Status.serializer.deserialize(in, version), + in.readUnsignedVInt(), in.readUnsignedVInt()); + } + + public long serializedSize(Transformation t, Version version) + { + ReconfigureAccordFastPath update = (ReconfigureAccordFastPath) t; + return TopologySerializers.nodeId.serializedSize(update.node, version) + + AccordFastPath.Status.serializer.serializedSize(update.status, version) + + TypeSizes.sizeofUnsignedVInt(update.updateTimeMillis) + + TypeSizes.sizeofUnsignedVInt(update.updateDelayMillis); + } + }; +} diff --git a/src/java/org/apache/cassandra/tcm/transformations/cms/PrepareCMSReconfiguration.java b/src/java/org/apache/cassandra/tcm/transformations/cms/PrepareCMSReconfiguration.java index c8b15c4fa5..e94292831e 100644 --- a/src/java/org/apache/cassandra/tcm/transformations/cms/PrepareCMSReconfiguration.java +++ b/src/java/org/apache/cassandra/tcm/transformations/cms/PrepareCMSReconfiguration.java @@ -45,6 +45,7 @@ import org.apache.cassandra.schema.KeyspaceMetadata; import org.apache.cassandra.schema.KeyspaceParams; import org.apache.cassandra.schema.ReplicationParams; import org.apache.cassandra.schema.SchemaConstants; +import org.apache.cassandra.service.accord.fastpath.FastPathStrategy; import org.apache.cassandra.tcm.ClusterMetadata; import org.apache.cassandra.tcm.Transformation; import org.apache.cassandra.tcm.membership.NodeId; @@ -263,7 +264,7 @@ public abstract class PrepareCMSReconfiguration implements Transformation // In a complex reconfiguration, in addition to initiating the sequence of membership changes, // we're modifying the replication params of the metadata keyspace so we supply a function to do that KeyspaceMetadata keyspace = prev.schema.getKeyspaceMetadata(SchemaConstants.METADATA_KEYSPACE_NAME); - KeyspaceMetadata newKeyspace = keyspace.withSwapped(new KeyspaceParams(keyspace.params.durableWrites, replicationParams)); + KeyspaceMetadata newKeyspace = keyspace.withSwapped(new KeyspaceParams(keyspace.params.durableWrites, replicationParams, FastPathStrategy.simple())); return executeInternal(prev, transformer -> transformer.with(prev.placements.replaceParams(prev.nextEpoch(), ReplicationParams.meta(prev), replicationParams)) diff --git a/src/java/org/apache/cassandra/tools/NodeProbe.java b/src/java/org/apache/cassandra/tools/NodeProbe.java index b90be2cf1b..9c8fd50391 100644 --- a/src/java/org/apache/cassandra/tools/NodeProbe.java +++ b/src/java/org/apache/cassandra/tools/NodeProbe.java @@ -1332,12 +1332,16 @@ public class NodeProbe implements AutoCloseable return ssProxy.getNonLocalStrategyKeyspaces(); } - - public List getAccordManagedKeyspace() + public List getAccordManagedKeyspaces() { return ssProxy.getAccordManagedKeyspaces(); } + public List getAccordManagedTables() + { + return ssProxy.getAccordManagedTables(); + } + public String getClusterName() { return ssProxy.getClusterName(); diff --git a/src/java/org/apache/cassandra/tools/NodeTool.java b/src/java/org/apache/cassandra/tools/NodeTool.java index 9f72c59eab..0c933fdf7d 100644 --- a/src/java/org/apache/cassandra/tools/NodeTool.java +++ b/src/java/org/apache/cassandra/tools/NodeTool.java @@ -498,7 +498,7 @@ public class NodeTool else if (defaultKeyspaceSet == KeyspaceSet.NON_SYSTEM) keyspaces.addAll(keyspaces = nodeProbe.getNonSystemKeyspaces()); else if (defaultKeyspaceSet == KeyspaceSet.ACCORD_MANAGED) - keyspaces.addAll(nodeProbe.getAccordManagedKeyspace()); + keyspaces.addAll(nodeProbe.getAccordManagedKeyspaces()); else keyspaces.addAll(nodeProbe.getKeyspaces()); } diff --git a/test/distributed/org/apache/cassandra/distributed/test/ReadRepairTest.java b/test/distributed/org/apache/cassandra/distributed/test/ReadRepairTest.java index 6364401de5..5c6e276db3 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/ReadRepairTest.java +++ b/test/distributed/org/apache/cassandra/distributed/test/ReadRepairTest.java @@ -27,6 +27,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import com.google.common.util.concurrent.FutureCallback; +import org.apache.cassandra.distributed.test.accord.AccordTestBase; import org.junit.Assert; import org.junit.Ignore; import org.junit.Test; @@ -54,7 +55,6 @@ import org.apache.cassandra.distributed.api.TokenSupplier; import org.apache.cassandra.distributed.shared.NetworkTopology; import org.apache.cassandra.locator.Replica; import org.apache.cassandra.locator.ReplicaPlan; -import org.apache.cassandra.service.accord.AccordService; import org.apache.cassandra.service.reads.repair.BlockingReadRepair; import org.apache.cassandra.service.reads.repair.ReadRepairStrategy; import org.apache.cassandra.utils.concurrent.Condition; @@ -108,9 +108,9 @@ public class ReadRepairTest extends TestBaseImpl { try (Cluster cluster = init(Cluster.create(3, config -> config.set("non_serial_write_strategy", brrThroughAccord ? "migration" : "normal")))) { - cluster.get(1).runOnInstance(() -> AccordService.instance().ensureKeyspaceIsAccordManaged(KEYSPACE)); cluster.schemaChange(withKeyspace("CREATE TABLE %s.t (k int, c int, v int, PRIMARY KEY (k, c)) " + String.format("WITH read_repair='%s'", strategy))); + AccordTestBase.ensureTableIsAccordManaged(cluster, KEYSPACE, "t"); Object[] row = row(1, 1, 1); String insertQuery = withKeyspace("INSERT INTO %s.t (k, c, v) VALUES (?, ?, ?)"); diff --git a/test/distributed/org/apache/cassandra/distributed/test/ReadSpeculationTest.java b/test/distributed/org/apache/cassandra/distributed/test/ReadSpeculationTest.java index f6f5e2a812..98b98aa1e5 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/ReadSpeculationTest.java +++ b/test/distributed/org/apache/cassandra/distributed/test/ReadSpeculationTest.java @@ -25,7 +25,6 @@ import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; -import org.apache.cassandra.service.reads.ReadCoordinator; import org.junit.Assert; import org.junit.Test; @@ -54,6 +53,7 @@ import org.apache.cassandra.locator.ReplicaCollection; import org.apache.cassandra.locator.ReplicaPlan; import org.apache.cassandra.locator.ReplicaPlans; import org.apache.cassandra.service.CassandraDaemon; +import org.apache.cassandra.service.reads.ReadCoordinator; import org.apache.cassandra.transport.Dispatcher; import static net.bytebuddy.matcher.ElementMatchers.named; @@ -86,7 +86,7 @@ public class ReadSpeculationTest extends TestBaseImpl Keyspace keyspace = Keyspace.openIfExists(KEYSPACE); ColumnFamilyStore cfs = keyspace.getColumnFamilyStore(TABLE); DecoratedKey dk = cfs.decorateKey(bytes(PK_VALUE)); - ReplicaPlan.ForTokenRead plan = ReplicaPlans.forRead(keyspace, dk.getToken(), null, + ReplicaPlan.ForTokenRead plan = ReplicaPlans.forRead(keyspace, cfs.getTableId(), dk.getToken(), null, QUORUM, cfs.metadata().params.speculativeRetry, ReadCoordinator.DEFAULT); return plan.contacts().endpointList().stream().map(InetSocketAddress::getAddress).collect(Collectors.toList()); diff --git a/test/distributed/org/apache/cassandra/distributed/test/ShortReadProtectionTest.java b/test/distributed/org/apache/cassandra/distributed/test/ShortReadProtectionTest.java index c6c9413285..6d192db112 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/ShortReadProtectionTest.java +++ b/test/distributed/org/apache/cassandra/distributed/test/ShortReadProtectionTest.java @@ -28,6 +28,7 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; import java.util.stream.IntStream; +import org.apache.cassandra.distributed.test.accord.AccordTestBase; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; @@ -44,7 +45,6 @@ import org.apache.cassandra.distributed.Cluster; import org.apache.cassandra.distributed.api.ConsistencyLevel; import org.apache.cassandra.distributed.api.IInvokableInstance; import org.apache.cassandra.distributed.shared.AssertUtils; -import org.apache.cassandra.service.accord.AccordService; import org.apache.cassandra.utils.ByteBufferUtil; import org.apache.cassandra.utils.Pair; @@ -111,7 +111,6 @@ public class ShortReadProtectionTest extends TestBaseImpl .withNodes(NUM_NODES) .withConfig(config -> config.set("hinted_handoff_enabled", false)) .start()); - cluster.get(1).runOnInstance(() -> AccordService.instance().ensureKeyspaceIsAccordManaged(KEYSPACE)); } @AfterClass @@ -437,6 +436,7 @@ public class ShortReadProtectionTest extends TestBaseImpl private final ConsistencyLevel readConsistencyLevel; private final boolean flush, paging; + private final String table; private final String qualifiedTableName; private boolean flushed = false; @@ -446,7 +446,8 @@ public class ShortReadProtectionTest extends TestBaseImpl this.readConsistencyLevel = readConsistencyLevel; this.flush = flush; this.paging = paging; - qualifiedTableName = KEYSPACE + ".t_" + seqNumber.getAndIncrement(); + this.table = "t_" + seqNumber.getAndIncrement(); + qualifiedTableName = KEYSPACE + '.' + table; assert readConsistencyLevel == ALL || readConsistencyLevel == QUORUM || readConsistencyLevel == SERIAL : "Only ALL and QUORUM consistency levels are supported"; @@ -455,6 +456,7 @@ public class ShortReadProtectionTest extends TestBaseImpl private Tester createTable(String query) { cluster.schemaChange(format(query) + " WITH read_repair='NONE'"); + AccordTestBase.ensureTableIsAccordManaged(cluster, KEYSPACE, table); return this; } diff --git a/test/distributed/org/apache/cassandra/distributed/test/accord/AccordBootstrapTest.java b/test/distributed/org/apache/cassandra/distributed/test/accord/AccordBootstrapTest.java index 8dff79cd86..7d246a2b6c 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/accord/AccordBootstrapTest.java +++ b/test/distributed/org/apache/cassandra/distributed/test/accord/AccordBootstrapTest.java @@ -78,7 +78,7 @@ public class AccordBootstrapTest extends TestBaseImpl private static PartitionKey pk(int key, String keyspace, String table) { TableId tid = Schema.instance.getTableMetadata(keyspace, table).id; - return new PartitionKey(keyspace, tid, dk(key)); + return new PartitionKey(tid, dk(key)); } protected void bootstrapAndJoinNode(Cluster cluster) @@ -451,7 +451,7 @@ public class AccordBootstrapTest extends TestBaseImpl Assert.assertEquals(key, row.getInt("c")); Assert.assertEquals(key, row.getInt("v")); - PartitionKey partitionKey = new PartitionKey("ks", tableId, dk); + PartitionKey partitionKey = new PartitionKey(tableId, dk); awaitUninterruptiblyAndRethrow(service().node().commandStores().forEach(PreLoadContext.contextFor(partitionKey), partitionKey.toUnseekable(), moveMax, moveMax, diff --git a/test/distributed/org/apache/cassandra/distributed/test/accord/AccordCQLTest.java b/test/distributed/org/apache/cassandra/distributed/test/accord/AccordCQLTest.java index db8f1c21d9..5eeee8108a 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/accord/AccordCQLTest.java +++ b/test/distributed/org/apache/cassandra/distributed/test/accord/AccordCQLTest.java @@ -123,11 +123,11 @@ public class AccordCQLTest extends AccordTestBase for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) - cluster.coordinator(1).execute("INSERT INTO " + currentTable + "(k, c, v) VALUES (?, ?, ?);", ConsistencyLevel.ALL, i, j, i + j); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + "(k, c, v) VALUES (?, ?, ?);", ConsistencyLevel.ALL, i, j, i + j); } // multi row String cql = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k=? AND c IN (?, ?);\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k=? AND c IN (?, ?);\n" + "COMMIT TRANSACTION"; SimpleQueryResult result = cluster.coordinator(1).executeWithResult(cql, ConsistencyLevel.ANY, 0, 0, 1); assertThat(result).isEqualTo(QueryResults.builder() @@ -138,7 +138,7 @@ public class AccordCQLTest extends AccordTestBase // Results should be in Partiton/Clustering order, so make sure // multi partition cql = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k IN (?, ?) AND c = ?;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k IN (?, ?) AND c = ?;\n" + "COMMIT TRANSACTION"; for (boolean asc : Arrays.asList(true, false)) { @@ -153,7 +153,7 @@ public class AccordCQLTest extends AccordTestBase // multi-partition, multi-clustering cql = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k IN (?, ?) AND c IN (?, ?);\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k IN (?, ?) AND c IN (?, ?);\n" + "COMMIT TRANSACTION"; for (boolean asc : Arrays.asList(true, false)) { @@ -232,14 +232,14 @@ public class AccordCQLTest extends AccordTestBase { test(cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, c, v) VALUES (1, 0, 3);", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, c, v) VALUES (1, 0, 3);", ConsistencyLevel.ALL); String query = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT v FROM " + currentTable + " WHERE k = ? AND c = ?);\n" + - " LET row2 = (SELECT v FROM " + currentTable + " WHERE k = ? AND c = ?);\n" + - " SELECT v FROM " + currentTable + " WHERE k = ? AND c = ?;\n" + + " LET row1 = (SELECT v FROM " + qualifiedTableName + " WHERE k = ? AND c = ?);\n" + + " LET row2 = (SELECT v FROM " + qualifiedTableName + " WHERE k = ? AND c = ?);\n" + + " SELECT v FROM " + qualifiedTableName + " WHERE k = ? AND c = ?;\n" + " IF row1 IS NULL AND row2.v = ? THEN\n" + - " INSERT INTO " + currentTable + " (k, c, v) VALUES (?, ?, ?);\n" + + " INSERT INTO " + qualifiedTableName + " (k, c, v) VALUES (?, ?, ?);\n" + " END IF\n" + "COMMIT TRANSACTION"; @@ -253,7 +253,7 @@ public class AccordCQLTest extends AccordTestBase assertEquals(3, result[0][0]); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k=0 AND c=0;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k=0 AND c=0;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 0, 0, 1 }, check); }); @@ -262,13 +262,13 @@ public class AccordCQLTest extends AccordTestBase @Test public void testRegularScalarIsNull() throws Throwable { - testScalarIsNull("CREATE TABLE " + currentTable + " (k int, c int, v int, primary key (k, c))"); + testScalarIsNull("CREATE TABLE " + qualifiedTableName + " (k int, c int, v int, primary key (k, c))"); } @Test public void testStaticScalarIsNull() throws Throwable { - testScalarIsNull("CREATE TABLE " + currentTable + " (k int, c int, v int static, primary key (k, c))"); + testScalarIsNull("CREATE TABLE " + qualifiedTableName + " (k int, c int, v int static, primary key (k, c))"); } private void testScalarIsNull(String tableDDL) throws Exception { @@ -276,25 +276,25 @@ public class AccordCQLTest extends AccordTestBase cluster -> { String insertNull = "BEGIN TRANSACTION\n" + - " LET row0 = (SELECT * FROM " + currentTable + " WHERE k = 0 LIMIT 1);\n" + + " LET row0 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 0 LIMIT 1);\n" + " SELECT row0.k, row0.v;\n" + " IF row0.v IS NULL THEN\n" + - " INSERT INTO " + currentTable + " (k, c, v) VALUES (?, ?, null);\n" + + " INSERT INTO " + qualifiedTableName + " (k, c, v) VALUES (?, ?, null);\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { null, null }, insertNull, 0, 0); String insert = "BEGIN TRANSACTION\n" + - " LET row0 = (SELECT * FROM " + currentTable + " WHERE k = 0 LIMIT 1);\n" + + " LET row0 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 0 LIMIT 1);\n" + " SELECT row0.k, row0.v;\n" + " IF row0.v IS NULL THEN\n" + - " INSERT INTO " + currentTable + " (k, c, v) VALUES (?, ?, ?);\n" + + " INSERT INTO " + qualifiedTableName + " (k, c, v) VALUES (?, ?, ?);\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 0, null }, insert, 0, 0, 1); String check = "BEGIN TRANSACTION\n" + - " SELECT k, c, v FROM " + currentTable + " WHERE k=0 AND c=0;\n" + + " SELECT k, c, v FROM " + qualifiedTableName + " WHERE k=0 AND c=0;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 0, 0, 1 }, check); }); @@ -303,36 +303,36 @@ public class AccordCQLTest extends AccordTestBase @Test public void testQueryStaticColumn() throws Exception { - test("CREATE TABLE " + currentTable + " (k int, c int, s int static, v int, primary key (k, c))", + test("CREATE TABLE " + qualifiedTableName + " (k int, c int, s int static, v int, primary key (k, c))", cluster -> { // select partition key, clustering key and static column, restrict on partition and clustering testQueryStaticColumn(cluster, - "LET row0 = (SELECT k, c, s, v FROM " + currentTable + " WHERE k = ? AND c = 0);\n" + + "LET row0 = (SELECT k, c, s, v FROM " + qualifiedTableName + " WHERE k = ? AND c = 0);\n" + "SELECT row0.k, row0.c, row0.s, row0.v;\n", - "SELECT k, c, s, v FROM " + currentTable + " WHERE k = ? AND c = 0"); + "SELECT k, c, s, v FROM " + qualifiedTableName + " WHERE k = ? AND c = 0"); // select partition key, clustering key and static column, restrict on partition and limit to 1 row testQueryStaticColumn(cluster, - "LET row0 = (SELECT k, c, s, v FROM " + currentTable + " WHERE k = ? LIMIT 1);\n" + + "LET row0 = (SELECT k, c, s, v FROM " + qualifiedTableName + " WHERE k = ? LIMIT 1);\n" + "SELECT row0.k, row0.c, row0.s, row0.v;\n", - "SELECT k, c, s, v FROM " + currentTable + " WHERE k = ? LIMIT 1"); + "SELECT k, c, s, v FROM " + qualifiedTableName + " WHERE k = ? LIMIT 1"); // select static column and regular column, restrict on partition and clustering testQueryStaticColumn(cluster, - "LET row0 = (SELECT s, v FROM " + currentTable + " WHERE k = ? AND c = 0);\n" + + "LET row0 = (SELECT s, v FROM " + qualifiedTableName + " WHERE k = ? AND c = 0);\n" + "SELECT row0.s, row0.v;\n", - "SELECT s, v FROM " + currentTable + " WHERE k = ? AND c = 0"); + "SELECT s, v FROM " + qualifiedTableName + " WHERE k = ? AND c = 0"); // select just static column, restrict on partition and limit to 1 row testQueryStaticColumn(cluster, - "LET row0 = (SELECT s FROM " + currentTable + " WHERE k = ? LIMIT 1);\n" + + "LET row0 = (SELECT s FROM " + qualifiedTableName + " WHERE k = ? LIMIT 1);\n" + "SELECT row0.s;\n", - "SELECT s FROM " + currentTable + " WHERE k = ? LIMIT 1"); + "SELECT s FROM " + qualifiedTableName + " WHERE k = ? LIMIT 1"); }); } @@ -342,22 +342,22 @@ public class AccordCQLTest extends AccordTestBase int key = 10; assertResultsFromAccordMatches(cluster, accordReadQuery, simpleReadQuery, key++); - cluster.get(1).coordinator().execute("INSERT INTO " + currentTable + " (k, s) VALUES (?, null);", ConsistencyLevel.ALL, key); + cluster.get(1).coordinator().execute("INSERT INTO " + qualifiedTableName + " (k, s) VALUES (?, null);", ConsistencyLevel.ALL, key); logger().info("null -> static column"); assertResultsFromAccordMatches(cluster, accordReadQuery, simpleReadQuery, key++); - cluster.get(1).coordinator().execute("INSERT INTO " + currentTable + " (k, s) VALUES (?, 1);", ConsistencyLevel.ALL, key); + cluster.get(1).coordinator().execute("INSERT INTO " + qualifiedTableName + " (k, s) VALUES (?, 1);", ConsistencyLevel.ALL, key); logger().info("Inserted 1 -> static column"); assertResultsFromAccordMatches(cluster, accordReadQuery, simpleReadQuery, key++); - cluster.get(1).coordinator().execute("INSERT INTO " + currentTable + " (k, c) VALUES (?, 0);", ConsistencyLevel.ALL, key); + cluster.get(1).coordinator().execute("INSERT INTO " + qualifiedTableName + " (k, c) VALUES (?, 0);", ConsistencyLevel.ALL, key); logger().info("Inserted 0 -> clustering"); assertResultsFromAccordMatches(cluster, accordReadQuery, simpleReadQuery, key); } @Test public void testUpdateStaticColumn() throws Exception { - test("CREATE TABLE " + currentTable + " (k int, c int, s int static, v int, primary key (k, c))", + test("CREATE TABLE " + qualifiedTableName + " (k int, c int, s int static, v int, primary key (k, c))", cluster -> { checkUpdateStatic(cluster, "SET s=1 WHERE k=?", 101, "[[101, null, 1, null]]", "[]"); @@ -373,16 +373,16 @@ public class AccordCQLTest extends AccordTestBase private void checkUpdateStatic(Cluster cluster, String update, int key, String expPart, String expClust) { Object[][] r1, r2, r3, r4, r; - r = cluster.get(1).coordinator().execute("UPDATE " + currentTable + " " + update + " IF s = NULL;", ConsistencyLevel.QUORUM, key); + r = cluster.get(1).coordinator().execute("UPDATE " + qualifiedTableName + " " + update + " IF s = NULL;", ConsistencyLevel.QUORUM, key); Assertions.assertThat(Arrays.deepToString(r)).isEqualTo("[[true]]"); - r1 = cluster.get(1).coordinator().execute("SELECT * FROM " + currentTable + " WHERE k = ? LIMIT 1;", ConsistencyLevel.SERIAL, key); - r2 = cluster.get(1).coordinator().execute("SELECT * FROM " + currentTable + " WHERE k = ? AND c = 0;", ConsistencyLevel.SERIAL, key); - cluster.get(1).coordinator().execute("TRUNCATE " + currentTable, ConsistencyLevel.ALL); + r1 = cluster.get(1).coordinator().execute("SELECT * FROM " + qualifiedTableName + " WHERE k = ? LIMIT 1;", ConsistencyLevel.SERIAL, key); + r2 = cluster.get(1).coordinator().execute("SELECT * FROM " + qualifiedTableName + " WHERE k = ? AND c = 0;", ConsistencyLevel.SERIAL, key); + cluster.get(1).coordinator().execute("TRUNCATE " + qualifiedTableName, ConsistencyLevel.ALL); - executeAsTxn(cluster, "UPDATE " + currentTable + " " + update + ";", key); - r3 = executeAsTxn(cluster, "SELECT * FROM " + currentTable + " WHERE k = ? LIMIT 1;", key).toObjectArrays(); - r4 = executeAsTxn(cluster, "SELECT * FROM " + currentTable + " WHERE k = ? AND c = 0;", key).toObjectArrays(); - cluster.get(1).coordinator().execute("TRUNCATE " + currentTable, ConsistencyLevel.ALL); + executeAsTxn(cluster, "UPDATE " + qualifiedTableName + " " + update + ";", key); + r3 = executeAsTxn(cluster, "SELECT * FROM " + qualifiedTableName + " WHERE k = ? LIMIT 1;", key).toObjectArrays(); + r4 = executeAsTxn(cluster, "SELECT * FROM " + qualifiedTableName + " WHERE k = ? AND c = 0;", key).toObjectArrays(); + cluster.get(1).coordinator().execute("TRUNCATE " + qualifiedTableName, ConsistencyLevel.ALL); Assertions.assertThat(Arrays.deepToString(r1)).isEqualTo(expPart); Assertions.assertThat(Arrays.deepToString(r2)).isEqualTo(expClust); @@ -453,12 +453,12 @@ public class AccordCQLTest extends AccordTestBase @Test public void testStaticScalarEQ() throws Throwable { - testScalarCondition("CREATE TABLE " + currentTable + " (k int, c int, v int static, primary key (k, c))", 3, "=", 3, "="); + testScalarCondition("CREATE TABLE " + qualifiedTableName + " (k int, c int, v int static, primary key (k, c))", 3, "=", 3, "="); } private void testScalarCondition(int lhs, String operator, int rhs, String reversedOperator) throws Exception { - testScalarCondition("CREATE TABLE " + currentTable + " (k int, c int, v int, primary key (k, c))", lhs, operator, rhs, reversedOperator); + testScalarCondition("CREATE TABLE " + qualifiedTableName + " (k int, c int, v int, primary key (k, c))", lhs, operator, rhs, reversedOperator); } private void testScalarCondition(String tableDDL, int lhs, String operator, int rhs, String reversedOperator) throws Exception @@ -466,27 +466,27 @@ public class AccordCQLTest extends AccordTestBase test(tableDDL, cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, c, v) VALUES (0, 0, " + lhs + ");", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, c, v) VALUES (0, 0, " + lhs + ");", ConsistencyLevel.ALL); String query = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT v FROM " + currentTable + " WHERE k = ? LIMIT 1);\n" + + " LET row1 = (SELECT v FROM " + qualifiedTableName + " WHERE k = ? LIMIT 1);\n" + " SELECT row1.v;\n" + " IF row1.v " + operator + " ? THEN\n" + - " INSERT INTO " + currentTable + " (k, c, v) VALUES (?, ?, ?);\n" + + " INSERT INTO " + qualifiedTableName + " (k, c, v) VALUES (?, ?, ?);\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { lhs }, query, 0, rhs, 1, 0, 1); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = ? AND c = ?;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = ? AND c = ?;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 1, 0, 1 }, check, 1, 0); String queryWithReversed = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT v FROM " + currentTable + " WHERE k = ? LIMIT 1);\n" + + " LET row1 = (SELECT v FROM " + qualifiedTableName + " WHERE k = ? LIMIT 1);\n" + " SELECT row1.v;\n" + " IF ? " + reversedOperator + " row1.v THEN\n" + - " INSERT INTO " + currentTable + " (k, c, v) VALUES (?, ?, ?);\n" + + " INSERT INTO " + qualifiedTableName + " (k, c, v) VALUES (?, ?, ?);\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { lhs }, queryWithReversed, 0, rhs, 2, 0, 1); @@ -500,7 +500,7 @@ public class AccordCQLTest extends AccordTestBase test(cluster -> { String query = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k=0 AND c=0;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k=0 AND c=0;\n" + "COMMIT TRANSACTION"; SimpleQueryResult result = cluster.coordinator(1).executeWithResult(query, ConsistencyLevel.ANY); assertFalse(result.hasNext()); @@ -513,13 +513,13 @@ public class AccordCQLTest extends AccordTestBase test(cluster -> { String query = "BEGIN TRANSACTION\n" + - " INSERT INTO " + currentTable + " (k, c, v) VALUES (?, ?, ?);\n" + + " INSERT INTO " + qualifiedTableName + " (k, c, v) VALUES (?, ?, ?);\n" + "COMMIT TRANSACTION"; SimpleQueryResult result = cluster.coordinator(1).executeWithResult(query, ConsistencyLevel.ANY, 0, 0, 1); assertFalse(result.hasNext()); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k=? AND c=?;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k=? AND c=?;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] {0, 0, 1}, check, 0, 0); }); @@ -530,14 +530,14 @@ public class AccordCQLTest extends AccordTestBase { test(cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, c, v) VALUES (1, 0, 3);", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, c, v) VALUES (1, 0, 3);", ConsistencyLevel.ALL); String query = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = ? AND c = ?);\n" + - " LET row2 = (SELECT * FROM " + currentTable + " WHERE k = ? AND c = ?);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = ? AND c = ?);\n" + + " LET row2 = (SELECT * FROM " + qualifiedTableName + " WHERE k = ? AND c = ?);\n" + " SELECT row1.v, row2.k, row2.c, row2.v;\n" + " IF row1 IS NULL AND row2.v = ? THEN\n" + - " INSERT INTO " + currentTable + " (k, c, v) VALUES (?, ?, ?);\n" + + " INSERT INTO " + qualifiedTableName + " (k, c, v) VALUES (?, ?, ?);\n" + " END IF\n" + "COMMIT TRANSACTION"; SimpleQueryResult result = cluster.coordinator(1).executeWithResult(query, ConsistencyLevel.ANY, 0, 0, 1, 0, 3, 0, 0, 1); @@ -545,7 +545,7 @@ public class AccordCQLTest extends AccordTestBase assertThat(result).hasSize(1).contains(null, 1, 0, 3); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k=0 AND c=0;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k=0 AND c=0;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] {0, 0, 1}, check); }); @@ -556,14 +556,14 @@ public class AccordCQLTest extends AccordTestBase { test(cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, c, v) VALUES (1, 0, 3);", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, c, v) VALUES (1, 0, 3);", ConsistencyLevel.ALL); String query = "BEGIN TRANSACTION\n" + - " LET row0 = (SELECT * FROM " + currentTable + " WHERE k = ? AND c = ?);\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = ? AND c = ?);\n" + + " LET row0 = (SELECT * FROM " + qualifiedTableName + " WHERE k = ? AND c = ?);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = ? AND c = ?);\n" + " SELECT row1.v;\n" + " IF row0 IS NULL AND row1.v = ? THEN\n" + - " INSERT INTO " + currentTable + " (k, c, v) VALUES (?, ?, ?);\n" + + " INSERT INTO " + qualifiedTableName + " (k, c, v) VALUES (?, ?, ?);\n" + " END IF\n" + "COMMIT TRANSACTION"; SimpleQueryResult result = cluster.coordinator(1).executeWithResult(query, ConsistencyLevel.ANY, 0, 0, 1, 0, 2, 0, 0, 1); @@ -571,7 +571,7 @@ public class AccordCQLTest extends AccordTestBase assertThat(result).hasSize(1).contains(3); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k=0 AND c=0;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k=0 AND c=0;\n" + "COMMIT TRANSACTION"; assertEmptyWithPreemptedRetry(cluster, check); }); @@ -580,22 +580,22 @@ public class AccordCQLTest extends AccordTestBase @Test public void testReversedClusteringReference() throws Exception { - test("CREATE TABLE " + currentTable + " (k int, c int, v int, PRIMARY KEY (k, c)) WITH CLUSTERING ORDER BY (c DESC)", + test("CREATE TABLE " + qualifiedTableName + " (k int, c int, v int, PRIMARY KEY (k, c)) WITH CLUSTERING ORDER BY (c DESC)", cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, c, v) VALUES (1, 1, 1)", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, c, v) VALUES (1, 1, 1)", ConsistencyLevel.ALL); String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = 1 AND c = 1);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 1 AND c = 1);\n" + " SELECT row1.k, row1.c, row1.v;\n" + " IF row1.c = 1 THEN\n" + - " UPDATE " + currentTable + " SET v += row1.c WHERE k=1 AND c=1;\n" + + " UPDATE " + qualifiedTableName + " SET v += row1.c WHERE k=1 AND c=1;\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[]{1, 1, 1}, update); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = 1 AND c = 1;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = 1 AND c = 1;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[]{1, 1, 2}, check); }); @@ -615,20 +615,20 @@ public class AccordCQLTest extends AccordTestBase private void testScalarShorthandOperation(int startingValue, String operation, int endingvalue) throws Exception { - test("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, v int)", + test("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, v int)", cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, v) VALUES (1, ?)", ConsistencyLevel.ALL, startingValue); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, v) VALUES (1, ?)", ConsistencyLevel.ALL, startingValue); String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = 1);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 1);\n" + " SELECT row1.v;\n" + - " UPDATE " + currentTable + " SET v " + operation + " 1 WHERE k = 1;\n" + + " UPDATE " + qualifiedTableName + " SET v " + operation + " 1 WHERE k = 1;\n" + "COMMIT TRANSACTION"; assertRowEquals(cluster, new Object[] { startingValue }, update); String check = "BEGIN TRANSACTION\n" + - " SELECT v FROM " + currentTable + " WHERE k = 1;\n" + + " SELECT v FROM " + qualifiedTableName + " WHERE k = 1;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 2 }, check); }); @@ -637,20 +637,20 @@ public class AccordCQLTest extends AccordTestBase @Test public void testConstantNonStaticRowReadBeforeUpdate() throws Exception { - test("CREATE TABLE " + currentTable + " (k int, c int, v int, PRIMARY KEY (k, c))", + test("CREATE TABLE " + qualifiedTableName + " (k int, c int, v int, PRIMARY KEY (k, c))", cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, c, v) VALUES (1, 2, ?)", ConsistencyLevel.ALL, 3); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, c, v) VALUES (1, 2, ?)", ConsistencyLevel.ALL, 3); String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = 1 AND c = 2);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 1 AND c = 2);\n" + " SELECT row1.v;\n" + - " UPDATE " + currentTable + " SET v += 1 WHERE k = 1 AND c = 2;\n" + + " UPDATE " + qualifiedTableName + " SET v += 1 WHERE k = 1 AND c = 2;\n" + "COMMIT TRANSACTION"; assertRowEquals(cluster, new Object[] { 3 }, update); String check = "BEGIN TRANSACTION\n" + - " SELECT v FROM " + currentTable + " WHERE k = 1 AND c = 2;\n" + + " SELECT v FROM " + qualifiedTableName + " WHERE k = 1 AND c = 2;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 4 }, check); }); @@ -659,21 +659,21 @@ public class AccordCQLTest extends AccordTestBase @Test public void testRangeDeletion() throws Exception { - test("CREATE TABLE " + currentTable + " (k int, c int, v int, PRIMARY KEY (k, c))", + test("CREATE TABLE " + qualifiedTableName + " (k int, c int, v int, PRIMARY KEY (k, c))", cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, c, v) VALUES (1, 2, ?)", ConsistencyLevel.ALL, 3); - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, c, v) VALUES (1, 3, ?)", ConsistencyLevel.ALL, 4); - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, c, v) VALUES (1, 4, ?)", ConsistencyLevel.ALL, 5); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, c, v) VALUES (1, 2, ?)", ConsistencyLevel.ALL, 3); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, c, v) VALUES (1, 3, ?)", ConsistencyLevel.ALL, 4); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, c, v) VALUES (1, 4, ?)", ConsistencyLevel.ALL, 5); String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = 1 AND c = 2);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 1 AND c = 2);\n" + " SELECT row1.v;\n" + - " DELETE FROM " + currentTable + " WHERE k = 1 AND c >=3 AND c <= 4;\n" + + " DELETE FROM " + qualifiedTableName + " WHERE k = 1 AND c >=3 AND c <= 4;\n" + "COMMIT TRANSACTION"; assertRowEquals(cluster, new Object[] { 3 }, update); - Object[][] check = cluster.coordinator(1).execute("SELECT * FROM " + currentTable + " WHERE k = 1;", ConsistencyLevel.SERIAL); + Object[][] check = cluster.coordinator(1).execute("SELECT * FROM " + qualifiedTableName + " WHERE k = 1;", ConsistencyLevel.SERIAL); assertArrayEquals(new Object[] { 1, 2, 3 }, check[0]); assertEquals(1, check.length); }); @@ -683,22 +683,22 @@ public class AccordCQLTest extends AccordTestBase @Test public void testPartitionKeyReferenceCondition() throws Exception { - test("CREATE TABLE " + currentTable + " (k INT, c INT, v INT, PRIMARY KEY (k, c)) WITH CLUSTERING ORDER BY (c DESC)", + test("CREATE TABLE " + qualifiedTableName + " (k INT, c INT, v INT, PRIMARY KEY (k, c)) WITH CLUSTERING ORDER BY (c DESC)", cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, c, v) VALUES (1, 1, 1)", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, c, v) VALUES (1, 1, 1)", ConsistencyLevel.ALL); String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = 1 AND c = 1);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 1 AND c = 1);\n" + " SELECT row1.k, row1.c, row1.v;\n" + " IF row1.k = 1 THEN\n" + - " UPDATE " + currentTable + " SET v += row1.k WHERE k=1 AND c=1;\n" + + " UPDATE " + qualifiedTableName + " SET v += row1.k WHERE k=1 AND c=1;\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[]{1, 1, 1}, update); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = 1 AND c = 1;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = 1 AND c = 1;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[]{1, 1, 2}, check); }); @@ -707,22 +707,22 @@ public class AccordCQLTest extends AccordTestBase @Test public void testMultiPartitionKeyReferenceCondition() throws Exception { - test("CREATE TABLE " + currentTable + " (pk1 INT, pk2 INT, c INT, v INT, PRIMARY KEY ((pk1, pk2), c)) WITH CLUSTERING ORDER BY (c DESC)", + test("CREATE TABLE " + qualifiedTableName + " (pk1 INT, pk2 INT, c INT, v INT, PRIMARY KEY ((pk1, pk2), c)) WITH CLUSTERING ORDER BY (c DESC)", cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (pk1, pk2, c, v) VALUES (1, 1, 1, 1)", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (pk1, pk2, c, v) VALUES (1, 1, 1, 1)", ConsistencyLevel.ALL); String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE pk1 = 1 AND pk2 = 1 AND c = 1);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE pk1 = 1 AND pk2 = 1 AND c = 1);\n" + " SELECT row1.pk1, row1.pk2, row1.c, row1.v;\n" + " IF row1.pk1 = 1 THEN\n" + - " UPDATE " + currentTable + " SET v += row1.pk2 WHERE pk1 = 1 AND pk2 = 1 AND c=1;\n" + + " UPDATE " + qualifiedTableName + " SET v += row1.pk2 WHERE pk1 = 1 AND pk2 = 1 AND c=1;\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[]{1, 1, 1, 1}, update); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE pk1 = 1 AND pk2 = 1 AND c = 1;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE pk1 = 1 AND pk2 = 1 AND c = 1;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[]{1, 1, 1, 2}, check); }); @@ -731,13 +731,13 @@ public class AccordCQLTest extends AccordTestBase @Test public void testMultiCellListEqCondition() throws Exception { - testListEqCondition("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_list list)"); + testListEqCondition("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_list list)"); } @Test public void testFrozenListEqCondition() throws Exception { - testListEqCondition("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_list frozen>)"); + testListEqCondition("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_list frozen>)"); } private void testListEqCondition(String ddl) throws Exception @@ -750,7 +750,7 @@ public class AccordCQLTest extends AccordTestBase ByteBuffer initialListBytes = listType.getSerializer().serialize(initialList); String insert = "BEGIN TRANSACTION\n" + - " INSERT INTO " + currentTable + " (k, int_list) VALUES (?, ?);\n" + + " INSERT INTO " + qualifiedTableName + " (k, int_list) VALUES (?, ?);\n" + "COMMIT TRANSACTION"; SimpleQueryResult result = cluster.coordinator(1).executeWithResult(insert, ConsistencyLevel.ANY, 0, initialListBytes); assertFalse(result.hasNext()); @@ -759,16 +759,16 @@ public class AccordCQLTest extends AccordTestBase ByteBuffer updatedListBytes = listType.getSerializer().serialize(updatedList); String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = ?);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = ?);\n" + " SELECT row1.int_list;\n" + " IF row1.int_list = ? THEN\n" + - " UPDATE " + currentTable + " SET int_list = ? WHERE k = ?;\n" + + " UPDATE " + qualifiedTableName + " SET int_list = ? WHERE k = ?;\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] {initialList}, update, 0, initialListBytes, updatedListBytes, 0); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = ?;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = ?;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] {0, updatedList}, check, 0); } @@ -778,13 +778,13 @@ public class AccordCQLTest extends AccordTestBase @Test public void testMultiCellSetEqCondition() throws Exception { - testSetEqCondition("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_set set)"); + testSetEqCondition("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_set set)"); } @Test public void testFrozenSetEqCondition() throws Exception { - testSetEqCondition("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_set frozen>)"); + testSetEqCondition("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_set frozen>)"); } private void testSetEqCondition(String ddl) throws Exception @@ -797,7 +797,7 @@ public class AccordCQLTest extends AccordTestBase ByteBuffer initialSetBytes = setType.getSerializer().serialize(initialSet); String insert = "BEGIN TRANSACTION\n" + - " INSERT INTO " + currentTable + " (k, int_set) VALUES (?, ?);\n" + + " INSERT INTO " + qualifiedTableName + " (k, int_set) VALUES (?, ?);\n" + "COMMIT TRANSACTION"; SimpleQueryResult result = cluster.coordinator(1).executeWithResult(insert, ConsistencyLevel.ANY, 0, initialSetBytes); assertFalse(result.hasNext()); @@ -806,16 +806,16 @@ public class AccordCQLTest extends AccordTestBase ByteBuffer updatedSetBytes = setType.getSerializer().serialize(updatedSet); String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = ?);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = ?);\n" + " SELECT row1.int_set;\n" + " IF row1.int_set = ? THEN\n" + - " UPDATE " + currentTable + " SET int_set = ? WHERE k = ?;\n" + + " UPDATE " + qualifiedTableName + " SET int_set = ? WHERE k = ?;\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] {initialSet}, update, 0, initialSetBytes, updatedSetBytes, 0); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = ?;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = ?;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] {0, updatedSet}, check, 0); } @@ -825,13 +825,13 @@ public class AccordCQLTest extends AccordTestBase @Test public void testMultiCellMapEqCondition() throws Exception { - testMapEqCondition("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_map map)", true); + testMapEqCondition("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_map map)", true); } @Test public void testFrozenMapEqCondition() throws Exception { - testMapEqCondition("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_map frozen>)", false); + testMapEqCondition("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_map frozen>)", false); } private void testMapEqCondition(String ddl, boolean isMultiCell) throws Exception @@ -844,7 +844,7 @@ public class AccordCQLTest extends AccordTestBase ByteBuffer initialMapBytes = mapType.getSerializer().serialize(initialMap); String insert = "BEGIN TRANSACTION\n" + - " INSERT INTO " + currentTable + " (k, int_map) VALUES (?, ?);\n" + + " INSERT INTO " + qualifiedTableName + " (k, int_map) VALUES (?, ?);\n" + "COMMIT TRANSACTION"; SimpleQueryResult result = cluster.coordinator(1).executeWithResult(insert, ConsistencyLevel.ANY, 0, initialMapBytes); assertFalse(result.hasNext()); @@ -853,16 +853,16 @@ public class AccordCQLTest extends AccordTestBase ByteBuffer updatedMapBytes = mapType.getSerializer().serialize(updatedMap); String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = ?);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = ?);\n" + " SELECT row1.int_map;\n" + " IF row1.int_map = ? THEN\n" + - " UPDATE " + currentTable + " SET int_map = ? WHERE k = ?;\n" + + " UPDATE " + qualifiedTableName + " SET int_map = ? WHERE k = ?;\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { initialMap }, update, 0, initialMapBytes, updatedMapBytes, 0); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = ?;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = ?;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 0, updatedMap }, check, 0); } @@ -872,13 +872,13 @@ public class AccordCQLTest extends AccordTestBase @Test public void testMultiCellUDTEqCondition() throws Exception { - testUDTEqCondition("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, customer person)"); + testUDTEqCondition("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, customer person)"); } @Test public void testFrozenUDTEqCondition() throws Exception { - testUDTEqCondition("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, customer frozen)"); + testUDTEqCondition("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, customer frozen)"); } private void testUDTEqCondition(String tableDDL) throws Exception @@ -890,7 +890,7 @@ public class AccordCQLTest extends AccordTestBase ByteBuffer initialPersonBuffer = CQLTester.makeByteBuffer(initialPersonValue, null); String insert = "BEGIN TRANSACTION\n" + - " INSERT INTO " + currentTable + " (k, customer) VALUES (?, ?);\n" + + " INSERT INTO " + qualifiedTableName + " (k, customer) VALUES (?, ?);\n" + "COMMIT TRANSACTION"; SimpleQueryResult result = cluster.coordinator(1).executeWithResult(insert, ConsistencyLevel.ANY, 0, initialPersonBuffer); assertFalse(result.hasNext()); @@ -899,16 +899,16 @@ public class AccordCQLTest extends AccordTestBase ByteBuffer updatedPersonBuffer = CQLTester.makeByteBuffer(updatedPersonValue, null); String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = ?);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = ?);\n" + " SELECT row1.customer;\n" + " IF row1.customer = ? THEN\n" + - " UPDATE " + currentTable + " SET customer = ? WHERE k = ?;\n" + + " UPDATE " + qualifiedTableName + " SET customer = ? WHERE k = ?;\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { initialPersonBuffer }, update, 0, initialPersonBuffer, updatedPersonBuffer, 0); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = ?;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = ?;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 0, updatedPersonBuffer }, check, 0); } @@ -918,14 +918,14 @@ public class AccordCQLTest extends AccordTestBase @Test public void testTupleEqCondition() throws Exception { - test("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, pair tuple)", + test("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, pair tuple)", cluster -> { Object initialTupleValue = CQLTester.tuple("age", 37); ByteBuffer initialTupleBuffer = CQLTester.makeByteBuffer(initialTupleValue, null); String insert = "BEGIN TRANSACTION\n" + - " INSERT INTO " + currentTable + " (k, pair) VALUES (?, ?);\n" + + " INSERT INTO " + qualifiedTableName + " (k, pair) VALUES (?, ?);\n" + "COMMIT TRANSACTION"; SimpleQueryResult result = cluster.coordinator(1).executeWithResult(insert, ConsistencyLevel.ANY, 0, initialTupleBuffer); assertFalse(result.hasNext()); @@ -934,16 +934,16 @@ public class AccordCQLTest extends AccordTestBase ByteBuffer updatedTupleBuffer = CQLTester.makeByteBuffer(updatedTupleValue, null); String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = ?);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = ?);\n" + " SELECT row1.pair;\n" + " IF row1.pair = ? THEN\n" + - " UPDATE " + currentTable + " SET pair = ? WHERE k = ?;\n" + + " UPDATE " + qualifiedTableName + " SET pair = ? WHERE k = ?;\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { initialTupleBuffer }, update, 0, initialTupleBuffer, updatedTupleBuffer, 0); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = ?;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = ?;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 0, updatedTupleBuffer }, check, 0); } @@ -953,31 +953,31 @@ public class AccordCQLTest extends AccordTestBase @Test public void testIsNullWithComplexDeletion() throws Exception { - test("CREATE TABLE " + currentTable + " (k int, c int, int_list list, PRIMARY KEY (k, c))", + test("CREATE TABLE " + qualifiedTableName + " (k int, c int, int_list list, PRIMARY KEY (k, c))", cluster -> { ListType listType = ListType.getInstance(Int32Type.instance, true); List initialList = Arrays.asList(1, 2); ByteBuffer initialListBytes = listType.getSerializer().serialize(initialList); - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, c, int_list) VALUES (0, 0, ?);", ConsistencyLevel.ALL, initialListBytes); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, c, int_list) VALUES (0, 0, ?);", ConsistencyLevel.ALL, initialListBytes); cluster.forEach(i -> i.flush(KEYSPACE)); - cluster.coordinator(1).execute("DELETE int_list FROM " + currentTable + " WHERE k = 0 AND c = 0;", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("DELETE int_list FROM " + qualifiedTableName + " WHERE k = 0 AND c = 0;", ConsistencyLevel.ALL); List updatedList = Arrays.asList(1, 2, 3); ByteBuffer updatedListBytes = listType.getSerializer().serialize(updatedList); String insert = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = ? AND c = ?);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = ? AND c = ?);\n" + " SELECT row1.int_list;\n" + " IF row1.int_list IS NULL THEN\n" + - " INSERT INTO " + currentTable + " (k, c, int_list) VALUES (?, ?, ?);\n" + + " INSERT INTO " + qualifiedTableName + " (k, c, int_list) VALUES (?, ?, ?);\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { null }, insert, 0, 0, 0, 0, updatedListBytes); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = ? AND c = ?;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = ? AND c = ?;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 0, 0, updatedList }, check, 0, 0); } @@ -987,13 +987,13 @@ public class AccordCQLTest extends AccordTestBase @Test public void testNullMultiCellListConditions() throws Exception { - testNullListConditions("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_list list)"); + testNullListConditions("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_list list)"); } @Test public void testNullFrozenListConditions() throws Exception { - testNullListConditions("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_list frozen>)"); + testNullListConditions("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_list frozen>)"); } private void testNullListConditions(String ddl) throws Exception @@ -1001,31 +1001,31 @@ public class AccordCQLTest extends AccordTestBase test(ddl, cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, int_list) VALUES (0, null);", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, int_list) VALUES (0, null);", ConsistencyLevel.ALL); ListType listType = ListType.getInstance(Int32Type.instance, true); List initialList = Arrays.asList(1, 2); ByteBuffer initialListBytes = listType.getSerializer().serialize(initialList); String insert = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = ?);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = ?);\n" + " SELECT row1.int_list;\n" + " IF row1.int_list IS NULL THEN\n" + - " INSERT INTO " + currentTable + " (k, int_list) VALUES (?, ?);\n" + + " INSERT INTO " + qualifiedTableName + " (k, int_list) VALUES (?, ?);\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] {null}, insert, 0, 0, initialListBytes); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = ?;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = ?;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] {0, initialList}, check, 0); String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = ?);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = ?);\n" + " SELECT row1.int_list;\n" + " IF row1.int_list IS NOT NULL THEN\n" + - " UPDATE " + currentTable + " SET int_list = ? WHERE k = ?;\n" + + " UPDATE " + qualifiedTableName + " SET int_list = ? WHERE k = ?;\n" + " END IF\n" + "COMMIT TRANSACTION"; @@ -1039,13 +1039,13 @@ public class AccordCQLTest extends AccordTestBase @Test public void testNullMultiCellSetConditions() throws Exception { - testNullSetConditions("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_set set)"); + testNullSetConditions("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_set set)"); } @Test public void testNullFrozenSetConditions() throws Exception { - testNullSetConditions("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_set frozen>)"); + testNullSetConditions("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_set frozen>)"); } private void testNullSetConditions(String ddl) throws Exception @@ -1053,31 +1053,31 @@ public class AccordCQLTest extends AccordTestBase test(ddl, cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, int_set) VALUES (0, null);", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, int_set) VALUES (0, null);", ConsistencyLevel.ALL); SetType setType = SetType.getInstance(Int32Type.instance, true); Set initialSet = ImmutableSet.of(1, 2); ByteBuffer initialSetBytes = setType.getSerializer().serialize(initialSet); String insert = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = ?);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = ?);\n" + " SELECT row1.int_set;\n" + " IF row1.int_set IS NULL THEN\n" + - " INSERT INTO " + currentTable + " (k, int_set) VALUES (?, ?);\n" + + " INSERT INTO " + qualifiedTableName + " (k, int_set) VALUES (?, ?);\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] {null}, insert, 0, 0, initialSetBytes); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = ?;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = ?;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] {0, initialSet}, check, 0); String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = ?);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = ?);\n" + " SELECT row1.int_set;\n" + " IF row1.int_set IS NOT NULL THEN\n" + - " UPDATE " + currentTable + " SET int_set = ? WHERE k = ?;\n" + + " UPDATE " + qualifiedTableName + " SET int_set = ? WHERE k = ?;\n" + " END IF\n" + "COMMIT TRANSACTION"; @@ -1091,13 +1091,13 @@ public class AccordCQLTest extends AccordTestBase @Test public void testNullMultiCellMapConditions() throws Exception { - testNullMapConditions("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_map map)", true); + testNullMapConditions("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_map map)", true); } @Test public void testNullFrozenMapConditions() throws Exception { - testNullMapConditions("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_map frozen>)", false); + testNullMapConditions("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_map frozen>)", false); } private void testNullMapConditions(String ddl, boolean isMultiCell) throws Exception @@ -1105,31 +1105,31 @@ public class AccordCQLTest extends AccordTestBase test(ddl, cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, int_map) VALUES (0, null);", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, int_map) VALUES (0, null);", ConsistencyLevel.ALL); MapType mapType = MapType.getInstance(UTF8Type.instance, Int32Type.instance, isMultiCell); Map initialMap = ImmutableMap.of("one", 1, "two", 2); ByteBuffer initialMapBytes = mapType.getSerializer().serialize(initialMap); String insert = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = ?);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = ?);\n" + " SELECT row1.int_map;\n" + " IF row1.int_map IS NULL THEN\n" + - " INSERT INTO " + currentTable + " (k, int_map) VALUES (?, ?);\n" + + " INSERT INTO " + qualifiedTableName + " (k, int_map) VALUES (?, ?);\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { null }, insert, 0, 0, initialMapBytes); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = ?;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = ?;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 0, initialMap }, check, 0); String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = ?);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = ?);\n" + " SELECT row1.int_map;\n" + " IF row1.int_map IS NOT NULL THEN\n" + - " UPDATE " + currentTable + " SET int_map = ? WHERE k = ?;\n" + + " UPDATE " + qualifiedTableName + " SET int_map = ? WHERE k = ?;\n" + " END IF\n" + "COMMIT TRANSACTION"; @@ -1138,7 +1138,7 @@ public class AccordCQLTest extends AccordTestBase assertRowEqualsWithPreemptedRetry(cluster, new Object[] { initialMap }, update, 0, updatedMapBytes, 0); String checkUpdate = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = ?;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = ?;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 0, updatedMap }, checkUpdate, 0); } @@ -1148,13 +1148,13 @@ public class AccordCQLTest extends AccordTestBase @Test public void testNullMultiCellUDTCondition() throws Exception { - testNullUDTCondition("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, customer person)"); + testNullUDTCondition("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, customer person)"); } @Test public void testNullFrozenUDTCondition() throws Exception { - testNullUDTCondition("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, customer frozen)"); + testNullUDTCondition("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, customer frozen)"); } private void testNullUDTCondition(String tableDDL) throws Exception @@ -1166,24 +1166,24 @@ public class AccordCQLTest extends AccordTestBase ByteBuffer initialPersonBuffer = CQLTester.makeByteBuffer(initialPersonValue, null); String insert = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = ?);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = ?);\n" + " SELECT row1.customer;\n" + " IF row1.customer IS NULL THEN\n" + - " INSERT INTO " + currentTable + " (k, customer) VALUES (?, ?);\n" + + " INSERT INTO " + qualifiedTableName + " (k, customer) VALUES (?, ?);\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { null }, insert, 0, 0, initialPersonBuffer); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = ?;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = ?;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 0, initialPersonBuffer }, check, 0); String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = ?);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = ?);\n" + " SELECT row1.customer;\n" + " IF row1.customer IS NOT NULL THEN\n" + - " UPDATE " + currentTable + " SET customer = ? WHERE k = ?;\n" + + " UPDATE " + qualifiedTableName + " SET customer = ? WHERE k = ?;\n" + " END IF\n" + "COMMIT TRANSACTION"; @@ -1192,7 +1192,7 @@ public class AccordCQLTest extends AccordTestBase assertRowEqualsWithPreemptedRetry(cluster, new Object[] { initialPersonBuffer }, update, 0, updatedPersonBuffer, 0); String checkUpdate = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = ?;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = ?;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 0, updatedPersonBuffer }, checkUpdate, 0); } @@ -1202,13 +1202,13 @@ public class AccordCQLTest extends AccordTestBase @Test public void testNullMultiCellSetElementConditions() throws Exception { - testNullSetElementConditions("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_set set)"); + testNullSetElementConditions("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_set set)"); } @Test public void testNullFrozenSetElementConditions() throws Exception { - testNullSetElementConditions("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_set frozen>)"); + testNullSetElementConditions("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_set frozen>)"); } private void testNullSetElementConditions(String ddl) throws Exception @@ -1216,31 +1216,31 @@ public class AccordCQLTest extends AccordTestBase test(ddl, cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, int_set) VALUES (0, {1});", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, int_set) VALUES (0, {1});", ConsistencyLevel.ALL); SetType setType = SetType.getInstance(Int32Type.instance, true); Set initialSet = ImmutableSet.of(1, 2); ByteBuffer initialSetBytes = setType.getSerializer().serialize(initialSet); String insert = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = ?);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = ?);\n" + " SELECT row1.int_set[2];\n" + " IF row1.int_set[2] IS NULL THEN\n" + - " INSERT INTO " + currentTable + " (k, int_set) VALUES (?, ?);\n" + + " INSERT INTO " + qualifiedTableName + " (k, int_set) VALUES (?, ?);\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] {null}, insert, 0, 0, initialSetBytes); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = ?;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = ?;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] {0, initialSet}, check, 0); String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = ?);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = ?);\n" + " SELECT row1.int_set;\n" + " IF row1.int_set[2] IS NOT NULL THEN\n" + - " UPDATE " + currentTable + " SET int_set = ? WHERE k = ?;\n" + + " UPDATE " + qualifiedTableName + " SET int_set = ? WHERE k = ?;\n" + " END IF\n" + "COMMIT TRANSACTION"; @@ -1254,13 +1254,13 @@ public class AccordCQLTest extends AccordTestBase @Test public void testNullMultiCellMapElementConditions() throws Exception { - testNullMapElementConditions("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_map map)", true); + testNullMapElementConditions("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_map map)", true); } @Test public void testNullFrozenMapElementConditions() throws Exception { - testNullMapElementConditions("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_map frozen>)", false); + testNullMapElementConditions("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_map frozen>)", false); } private void testNullMapElementConditions(String ddl, boolean isMultiCell) throws Exception @@ -1268,31 +1268,31 @@ public class AccordCQLTest extends AccordTestBase test(ddl, cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, int_map) VALUES (0, null);", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, int_map) VALUES (0, null);", ConsistencyLevel.ALL); MapType mapType = MapType.getInstance(UTF8Type.instance, Int32Type.instance, isMultiCell); Map initialMap = ImmutableMap.of("one", 1, "two", 2); ByteBuffer initialMapBytes = mapType.getSerializer().serialize(initialMap); String insert = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = ?);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = ?);\n" + " SELECT row1.int_map;\n" + " IF row1.int_map[?] IS NULL THEN\n" + - " INSERT INTO " + currentTable + " (k, int_map) VALUES (?, ?);\n" + + " INSERT INTO " + qualifiedTableName + " (k, int_map) VALUES (?, ?);\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { null }, insert, 0, "one", 0, initialMapBytes); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = ?;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = ?;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 0, initialMap }, check, 0); String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = ?);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = ?);\n" + " SELECT row1.int_map;\n" + " IF row1.int_map[?] IS NOT NULL THEN\n" + - " UPDATE " + currentTable + " SET int_map = ? WHERE k = ?;\n" + + " UPDATE " + qualifiedTableName + " SET int_map = ? WHERE k = ?;\n" + " END IF\n" + "COMMIT TRANSACTION"; @@ -1301,7 +1301,7 @@ public class AccordCQLTest extends AccordTestBase assertRowEqualsWithPreemptedRetry(cluster, new Object[] { initialMap }, update, 0, "two", updatedMapBytes, 0); String checkUpdate = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = ?;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = ?;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 0, updatedMap }, checkUpdate, 0); } @@ -1311,13 +1311,13 @@ public class AccordCQLTest extends AccordTestBase @Test public void testNullMultiCellUDTFieldCondition() throws Exception { - testNullUDTFieldCondition("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, customer person)"); + testNullUDTFieldCondition("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, customer person)"); } @Test public void testNullFrozenUDTFieldCondition() throws Exception { - testNullUDTFieldCondition("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, customer frozen)"); + testNullUDTFieldCondition("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, customer frozen)"); } private void testNullUDTFieldCondition(String tableDDL) throws Exception @@ -1329,24 +1329,24 @@ public class AccordCQLTest extends AccordTestBase ByteBuffer initialPersonBuffer = CQLTester.makeByteBuffer(initialPersonValue, null); String insert = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = ?);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = ?);\n" + " SELECT row1.customer;\n" + " IF row1.customer.age IS NULL THEN\n" + - " INSERT INTO " + currentTable + " (k, customer) VALUES (?, ?);\n" + + " INSERT INTO " + qualifiedTableName + " (k, customer) VALUES (?, ?);\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { null }, insert, 0, 0, initialPersonBuffer); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = ?;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = ?;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 0, initialPersonBuffer }, check, 0); String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = ?);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = ?);\n" + " SELECT row1.customer;\n" + " IF row1.customer.age IS NOT NULL THEN\n" + - " UPDATE " + currentTable + " SET customer = ? WHERE k = ?;\n" + + " UPDATE " + qualifiedTableName + " SET customer = ? WHERE k = ?;\n" + " END IF\n" + "COMMIT TRANSACTION"; @@ -1355,7 +1355,7 @@ public class AccordCQLTest extends AccordTestBase assertRowEqualsWithPreemptedRetry(cluster, new Object[] { initialPersonBuffer }, update, 0, updatedPersonBuffer, 0); String checkUpdate = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = ?;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = ?;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 0, updatedPersonBuffer }, checkUpdate, 0); } @@ -1365,13 +1365,13 @@ public class AccordCQLTest extends AccordTestBase @Test public void testMultiCellListSubstitution() throws Exception { - testListSubstitution("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_list list)", true); + testListSubstitution("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_list list)", true); } @Test public void testFrozenListSubstitution() throws Exception { - testListSubstitution("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_list frozen>)", false); + testListSubstitution("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_list frozen>)", false); } private void testListSubstitution(String ddl, boolean isMultiCell) throws Exception @@ -1383,19 +1383,19 @@ public class AccordCQLTest extends AccordTestBase List initialList = Arrays.asList(1, 2); ByteBuffer initialListBytes = listType.getSerializer().serialize(initialList); - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, int_list) VALUES (0, ?);", ConsistencyLevel.ALL, initialListBytes); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, int_list) VALUES (0, ?);", ConsistencyLevel.ALL, initialListBytes); String insert = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = ?);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = ?);\n" + " SELECT row1.int_list;\n" + " IF row1.int_list IS NOT NULL THEN\n" + - " INSERT INTO " + currentTable + " (k, int_list) VALUES (?, row1.int_list);\n" + + " INSERT INTO " + qualifiedTableName + " (k, int_list) VALUES (?, row1.int_list);\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { initialList }, insert, 0, 1); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = ?;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = ?;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 1, initialList }, check, 1); } @@ -1405,13 +1405,13 @@ public class AccordCQLTest extends AccordTestBase @Test public void testMultiCellSetSubstitution() throws Exception { - testSetSubstitution("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_set set)", true); + testSetSubstitution("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_set set)", true); } @Test public void testFrozenSetSubstitution() throws Exception { - testSetSubstitution("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_set frozen>)", false); + testSetSubstitution("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_set frozen>)", false); } private void testSetSubstitution(String ddl, boolean isMultiCell) throws Exception @@ -1423,19 +1423,19 @@ public class AccordCQLTest extends AccordTestBase Set initialSet = ImmutableSet.of(1, 2); ByteBuffer initialSetBytes = setType.getSerializer().serialize(initialSet); - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, int_set) VALUES (0, ?);", ConsistencyLevel.ALL, initialSetBytes); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, int_set) VALUES (0, ?);", ConsistencyLevel.ALL, initialSetBytes); String insert = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = ?);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = ?);\n" + " SELECT row1.int_set;\n" + " IF row1.int_set IS NOT NULL THEN\n" + - " INSERT INTO " + currentTable + " (k, int_set) VALUES (?, row1.int_set);\n" + + " INSERT INTO " + qualifiedTableName + " (k, int_set) VALUES (?, row1.int_set);\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { initialSet }, insert, 0, 1); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = ?;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = ?;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 1, initialSet }, check, 1); } @@ -1445,13 +1445,13 @@ public class AccordCQLTest extends AccordTestBase @Test public void testMultiCellMapSubstitution() throws Exception { - testMapSubstitution("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_map map)", true); + testMapSubstitution("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_map map)", true); } @Test public void testFrozenMapSubstitution() throws Exception { - testMapSubstitution("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_map frozen>)", false); + testMapSubstitution("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_map frozen>)", false); } private void testMapSubstitution(String ddl, boolean isMultiCell) throws Exception @@ -1463,19 +1463,19 @@ public class AccordCQLTest extends AccordTestBase Map initialMap = ImmutableMap.of("one", 1, "two", 2); ByteBuffer initialMapBytes = mapType.getSerializer().serialize(initialMap); - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, int_map) VALUES (0, ?);", ConsistencyLevel.ALL, initialMapBytes); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, int_map) VALUES (0, ?);", ConsistencyLevel.ALL, initialMapBytes); String insert = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = ?);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = ?);\n" + " SELECT row1.int_map;\n" + " IF row1.int_map IS NOT NULL THEN\n" + - " INSERT INTO " + currentTable + " (k, int_map) VALUES (?, row1.int_map);\n" + + " INSERT INTO " + qualifiedTableName + " (k, int_map) VALUES (?, row1.int_map);\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[]{ initialMap }, insert, 0, 1); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = ?;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = ?;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 1, initialMap }, check, 1); } @@ -1485,13 +1485,13 @@ public class AccordCQLTest extends AccordTestBase @Test public void testMultiCellUDTSubstitution() throws Exception { - testUDTSubstitution("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, customer person)"); + testUDTSubstitution("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, customer person)"); } @Test public void testFrozenUDTSubstitution() throws Exception { - testUDTSubstitution("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, customer frozen)"); + testUDTSubstitution("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, customer frozen)"); } private void testUDTSubstitution(String tableDDL) throws Exception @@ -1501,19 +1501,19 @@ public class AccordCQLTest extends AccordTestBase { Object initialPersonValue = CQLTester.userType("height", 74, "age", 37); ByteBuffer initialPersonBuffer = CQLTester.makeByteBuffer(initialPersonValue, null); - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, customer) VALUES (0, ?);", ConsistencyLevel.ALL, initialPersonBuffer); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, customer) VALUES (0, ?);", ConsistencyLevel.ALL, initialPersonBuffer); String insert = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = ?);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = ?);\n" + " SELECT row1.customer;\n" + " IF row1.customer IS NOT NULL THEN\n" + - " INSERT INTO " + currentTable + " (k, customer) VALUES (?, row1.customer);\n" + + " INSERT INTO " + qualifiedTableName + " (k, customer) VALUES (?, row1.customer);\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[]{ initialPersonBuffer }, insert, 0, 1); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = ?;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = ?;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 1, initialPersonBuffer }, check, 1); } @@ -1523,24 +1523,24 @@ public class AccordCQLTest extends AccordTestBase @Test public void testTupleSubstitution() throws Exception { - test("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, pair tuple)", + test("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, pair tuple)", cluster -> { Object initialTupleValue = CQLTester.tuple("age", 37); ByteBuffer initialTupleBuffer = CQLTester.makeByteBuffer(initialTupleValue, null); - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, pair) VALUES (0, ?);", ConsistencyLevel.ALL, initialTupleBuffer); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, pair) VALUES (0, ?);", ConsistencyLevel.ALL, initialTupleBuffer); String insert = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = ?);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = ?);\n" + " SELECT row1.pair;\n" + " IF row1.pair IS NOT NULL THEN\n" + - " INSERT INTO " + currentTable + " (k, pair) VALUES (?, row1.pair);\n" + + " INSERT INTO " + qualifiedTableName + " (k, pair) VALUES (?, row1.pair);\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { initialTupleBuffer }, insert, 0, 1); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = ?;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = ?;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 1, initialTupleBuffer }, check, 1); } @@ -1550,13 +1550,13 @@ public class AccordCQLTest extends AccordTestBase @Test public void testMultiCellListReplacement() throws Exception { - testListReplacement("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_list list)"); + testListReplacement("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_list list)"); } @Test public void testFrozenListReplacement() throws Exception { - testListReplacement("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_list frozen>)"); + testListReplacement("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_list frozen>)"); } private void testListReplacement(String ddl) throws Exception @@ -1564,20 +1564,20 @@ public class AccordCQLTest extends AccordTestBase test(ddl, cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, int_list) VALUES (0, [1, 2]);", ConsistencyLevel.ALL); - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, int_list) VALUES (1, [3, 4]);", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, int_list) VALUES (0, [1, 2]);", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, int_list) VALUES (1, [3, 4]);", ConsistencyLevel.ALL); String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = 1);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 1);\n" + " SELECT row1.int_list;\n" + " IF row1.int_list = [3, 4] THEN\n" + - " UPDATE " + currentTable + " SET int_list = row1.int_list WHERE k=0;\n" + + " UPDATE " + qualifiedTableName + " SET int_list = row1.int_list WHERE k=0;\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] {Arrays.asList(3, 4)}, update); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = 0;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = 0;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] {0, Arrays.asList(3, 4)}, check); } @@ -1587,13 +1587,13 @@ public class AccordCQLTest extends AccordTestBase @Test public void testMultiCellSetReplacement() throws Exception { - testSetReplacement("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_set set)"); + testSetReplacement("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_set set)"); } @Test public void testFrozenSetReplacement() throws Exception { - testSetReplacement("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_set frozen>)"); + testSetReplacement("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_set frozen>)"); } private void testSetReplacement(String ddl) throws Exception @@ -1601,20 +1601,20 @@ public class AccordCQLTest extends AccordTestBase test(ddl, cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, int_set) VALUES (0, {1, 2});", ConsistencyLevel.ALL); - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, int_set) VALUES (1, {3, 4});", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, int_set) VALUES (0, {1, 2});", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, int_set) VALUES (1, {3, 4});", ConsistencyLevel.ALL); String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = 1);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 1);\n" + " SELECT row1.int_set;\n" + " IF row1.int_set = {3, 4} THEN\n" + - " UPDATE " + currentTable + " SET int_set = row1.int_set WHERE k=0;\n" + + " UPDATE " + qualifiedTableName + " SET int_set = row1.int_set WHERE k=0;\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { ImmutableSet.of(3, 4) }, update); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = 0;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = 0;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 0, ImmutableSet.of(3, 4) }, check); } @@ -1624,23 +1624,23 @@ public class AccordCQLTest extends AccordTestBase @Test public void testListAppendFromReference() throws Exception { - test("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_list list)", + test("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_list list)", cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, int_list) VALUES (0, [1, 2]);", ConsistencyLevel.ALL); - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, int_list) VALUES (1, [3, 4]);", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, int_list) VALUES (0, [1, 2]);", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, int_list) VALUES (1, [3, 4]);", ConsistencyLevel.ALL); String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = 1);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 1);\n" + " SELECT row1.int_list;\n" + " IF row1.int_list = [3, 4] THEN\n" + - " UPDATE " + currentTable + " SET int_list += row1.int_list WHERE k=0;\n" + + " UPDATE " + qualifiedTableName + " SET int_list += row1.int_list WHERE k=0;\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] {Arrays.asList(3, 4)}, update); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = 0;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = 0;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] {0, Arrays.asList(1, 2, 3, 4)}, check); } @@ -1650,13 +1650,13 @@ public class AccordCQLTest extends AccordTestBase @Test public void testSetByIndexFromMultiCellListElement() throws Exception { - testListSetByIndexFromListElement("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, src_int_list list, dest_int_list list)"); + testListSetByIndexFromListElement("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, src_int_list list, dest_int_list list)"); } @Test public void testSetByIndexFromFrozenListElement() throws Exception { - testListSetByIndexFromListElement("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, src_int_list frozen>, dest_int_list list)"); + testListSetByIndexFromListElement("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, src_int_list frozen>, dest_int_list list)"); } private void testListSetByIndexFromListElement(String ddl) throws Exception @@ -1664,18 +1664,18 @@ public class AccordCQLTest extends AccordTestBase test(ddl, cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, dest_int_list) VALUES (0, [1, 2]);", ConsistencyLevel.ALL); - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, src_int_list) VALUES (1, [3, 4]);", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, dest_int_list) VALUES (0, [1, 2]);", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, src_int_list) VALUES (1, [3, 4]);", ConsistencyLevel.ALL); String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = 1);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 1);\n" + " SELECT row1.src_int_list;\n" + - " UPDATE " + currentTable + " SET dest_int_list[0] = row1.src_int_list[0] WHERE k = 0;\n" + + " UPDATE " + qualifiedTableName + " SET dest_int_list[0] = row1.src_int_list[0] WHERE k = 0;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] {Arrays.asList(3, 4)}, update); String check = "BEGIN TRANSACTION\n" + - " SELECT dest_int_list FROM " + currentTable + " WHERE k = 0;\n" + + " SELECT dest_int_list FROM " + qualifiedTableName + " WHERE k = 0;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] {Arrays.asList(3, 2)}, check); } @@ -1685,20 +1685,20 @@ public class AccordCQLTest extends AccordTestBase @Test public void testListSetByIndexFromScalar() throws Exception { - test("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_list list)", + test("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_list list)", cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, int_list) VALUES (0, [1, 2]);", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, int_list) VALUES (0, [1, 2]);", ConsistencyLevel.ALL); String update = "BEGIN TRANSACTION\n" + - " LET row0 = (SELECT * FROM " + currentTable + " WHERE k = 0);\n" + + " LET row0 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 0);\n" + " SELECT row0.int_list;\n" + - " UPDATE " + currentTable + " SET int_list[0] = 2 WHERE k = 0;\n" + + " UPDATE " + qualifiedTableName + " SET int_list[0] = 2 WHERE k = 0;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] {Arrays.asList(1, 2)}, update); String check = "BEGIN TRANSACTION\n" + - " SELECT int_list FROM " + currentTable + " WHERE k = 0;\n" + + " SELECT int_list FROM " + qualifiedTableName + " WHERE k = 0;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] {Arrays.asList(2, 2)}, check); } @@ -1708,21 +1708,21 @@ public class AccordCQLTest extends AccordTestBase @Test public void testAutoReadSelectionConstruction() throws Exception { - test("CREATE TABLE " + currentTable + " (k int, c int, counter int, other_counter int, PRIMARY KEY (k, c))", + test("CREATE TABLE " + qualifiedTableName + " (k int, c int, counter int, other_counter int, PRIMARY KEY (k, c))", cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, c, counter, other_counter) VALUES (0, 0, 1, 1);", ConsistencyLevel.ALL); - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, c, counter, other_counter) VALUES (0, 1, 1, 1);", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, c, counter, other_counter) VALUES (0, 0, 1, 1);", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, c, counter, other_counter) VALUES (0, 1, 1, 1);", ConsistencyLevel.ALL); String update = "BEGIN TRANSACTION\n" + - " LET row0 = (SELECT * FROM " + currentTable + " WHERE k = 0 AND c = 0);\n" + + " LET row0 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 0 AND c = 0);\n" + " SELECT row0.counter, row0.other_counter;\n" + - " UPDATE " + currentTable + " SET other_counter += 1, counter += row0.counter WHERE k = 0 AND c = 1;\n" + + " UPDATE " + qualifiedTableName + " SET other_counter += 1, counter += row0.counter WHERE k = 0 AND c = 1;\n" + "COMMIT TRANSACTION"; assertRowEquals(cluster, new Object[] { 1, 1 }, update); String check = "BEGIN TRANSACTION\n" + - " SELECT counter, other_counter FROM " + currentTable + " WHERE k = 0 AND c = 1;\n" + + " SELECT counter, other_counter FROM " + qualifiedTableName + " WHERE k = 0 AND c = 1;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 2, 2 }, check); } @@ -1732,21 +1732,21 @@ public class AccordCQLTest extends AccordTestBase @Test public void testMultiMutationsSameKey() throws Exception { - test("CREATE TABLE " + currentTable + " (k int, c int, counter int, int_list list, PRIMARY KEY (k, c))", + test("CREATE TABLE " + qualifiedTableName + " (k int, c int, counter int, int_list list, PRIMARY KEY (k, c))", cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, c, counter, int_list) VALUES (0, 0, 0, [1, 2]);", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, c, counter, int_list) VALUES (0, 0, 0, [1, 2]);", ConsistencyLevel.ALL); String update = "BEGIN TRANSACTION\n" + - " LET row0 = (SELECT * FROM " + currentTable + " WHERE k = 0 AND c = 0);\n" + + " LET row0 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 0 AND c = 0);\n" + " SELECT row0.counter, row0.int_list;\n" + - " UPDATE " + currentTable + " SET int_list[0] = 42 WHERE k = 0 AND c = 0;\n" + - " UPDATE " + currentTable + " SET counter += 1 WHERE k = 0 AND c = 0;\n" + + " UPDATE " + qualifiedTableName + " SET int_list[0] = 42 WHERE k = 0 AND c = 0;\n" + + " UPDATE " + qualifiedTableName + " SET counter += 1 WHERE k = 0 AND c = 0;\n" + "COMMIT TRANSACTION"; assertRowEquals(cluster, new Object[] { 0, Arrays.asList(1, 2) }, update); String check = "BEGIN TRANSACTION\n" + - " SELECT counter, int_list FROM " + currentTable + " WHERE k = 0 AND c = 0;\n" + + " SELECT counter, int_list FROM " + qualifiedTableName + " WHERE k = 0 AND c = 0;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] {1, Arrays.asList(42, 2)}, check); } @@ -1757,10 +1757,10 @@ public class AccordCQLTest extends AccordTestBase public void testLetLargerThanOneWithPK() throws Exception { test(cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, c, v) VALUES (0, 0, 0);", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, c, v) VALUES (0, 0, 0);", ConsistencyLevel.ALL); String cql = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k=0 AND c=0 LIMIT 2);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k=0 AND c=0 LIMIT 2);\n" + " SELECT row1.v;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[]{ 0 }, cql, 1); @@ -1771,10 +1771,10 @@ public class AccordCQLTest extends AccordTestBase public void testLetLimitUsingBind() throws Exception { test(cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, c, v) VALUES (0, 0, 0);", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, c, v) VALUES (0, 0, 0);", ConsistencyLevel.ALL); String cql = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = 0 LIMIT ?);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 0 LIMIT ?);\n" + " SELECT row1.v;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 0 }, cql, 1); @@ -1784,24 +1784,24 @@ public class AccordCQLTest extends AccordTestBase @Test public void testListSetByIndexMultiRow() throws Exception { - test("CREATE TABLE " + currentTable + " (k int, c int, int_list list, PRIMARY KEY (k, c))", + test("CREATE TABLE " + qualifiedTableName + " (k int, c int, int_list list, PRIMARY KEY (k, c))", cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, c, int_list) VALUES (0, 0, [1, 2]);", ConsistencyLevel.ALL); - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, c, int_list) VALUES (0, 1, [3, 4]);", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, c, int_list) VALUES (0, 0, [1, 2]);", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, c, int_list) VALUES (0, 1, [3, 4]);", ConsistencyLevel.ALL); String update = "BEGIN TRANSACTION\n" + - " LET row0 = (SELECT * FROM " + currentTable + " WHERE k = 0 AND c = 0);\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = 0 AND c = 1);\n" + + " LET row0 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 0 AND c = 0);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 0 AND c = 1);\n" + " SELECT row0.int_list;\n" + - " UPDATE " + currentTable + " SET int_list[0] = row1.int_list[0] WHERE k = 0 AND c = 0;\n" + - " UPDATE " + currentTable + " SET int_list[0] = row0.int_list[0] WHERE k = 0 AND c = 1;\n" + + " UPDATE " + qualifiedTableName + " SET int_list[0] = row1.int_list[0] WHERE k = 0 AND c = 0;\n" + + " UPDATE " + qualifiedTableName + " SET int_list[0] = row0.int_list[0] WHERE k = 0 AND c = 1;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { Arrays.asList(1, 2) }, update); String check = "BEGIN TRANSACTION\n" + - " LET row0 = (SELECT * FROM " + currentTable + " WHERE k = 0 AND c = 0);\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = 0 AND c = 1);\n" + + " LET row0 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 0 AND c = 0);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 0 AND c = 1);\n" + " SELECT row0.int_list, row1.int_list;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] {Arrays.asList(3, 2), Arrays.asList(1, 4)}, check); @@ -1812,21 +1812,21 @@ public class AccordCQLTest extends AccordTestBase @Test public void testSetAppend() throws Exception { - test("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_set set)", + test("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_set set)", cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, int_set) VALUES (0, {1, 2});", ConsistencyLevel.ALL); - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, int_set) VALUES (1, {3, 4});", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, int_set) VALUES (0, {1, 2});", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, int_set) VALUES (1, {3, 4});", ConsistencyLevel.ALL); String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = 1);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 1);\n" + " SELECT row1.int_set;\n" + - " UPDATE " + currentTable + " SET int_set += row1.int_set WHERE k=0;\n" + + " UPDATE " + qualifiedTableName + " SET int_set += row1.int_set WHERE k=0;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { ImmutableSet.of(3, 4) }, update); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = 0;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = 0;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 0, ImmutableSet.of(1, 2, 3, 4) }, check); } @@ -1836,13 +1836,13 @@ public class AccordCQLTest extends AccordTestBase @Test public void testAssignmentFromMultiCellSetElement() throws Exception { - testAssignmentFromSetElement("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, v int, int_set set)"); + testAssignmentFromSetElement("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, v int, int_set set)"); } @Test public void testAssignmentFromFrozenSetElement() throws Exception { - testAssignmentFromSetElement("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, v int, int_set frozen>)"); + testAssignmentFromSetElement("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, v int, int_set frozen>)"); } private void testAssignmentFromSetElement(String ddl) throws Exception @@ -1850,18 +1850,18 @@ public class AccordCQLTest extends AccordTestBase test(ddl, cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, v, int_set) VALUES (0, 0, {1, 2});", ConsistencyLevel.ALL); - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, v, int_set) VALUES (1, 0, {3, 4});", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, v, int_set) VALUES (0, 0, {1, 2});", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, v, int_set) VALUES (1, 0, {3, 4});", ConsistencyLevel.ALL); String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = 1);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 1);\n" + " SELECT row1.int_set;\n" + - " UPDATE " + currentTable + " SET v = row1.int_set[4] WHERE k=0;\n" + + " UPDATE " + qualifiedTableName + " SET v = row1.int_set[4] WHERE k=0;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { ImmutableSet.of(3, 4) }, update); String check = "BEGIN TRANSACTION\n" + - " SELECT v FROM " + currentTable + " WHERE k = 0;\n" + + " SELECT v FROM " + qualifiedTableName + " WHERE k = 0;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 4 }, check); } @@ -1871,21 +1871,21 @@ public class AccordCQLTest extends AccordTestBase @Test public void testMapAppend() throws Exception { - test("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_map map)", + test("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_map map)", cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, int_map) VALUES (0, {'one': 2});", ConsistencyLevel.ALL); - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, int_map) VALUES (1, {'three': 4});", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, int_map) VALUES (0, {'one': 2});", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, int_map) VALUES (1, {'three': 4});", ConsistencyLevel.ALL); String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = 1);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 1);\n" + " SELECT row1.int_map;\n" + - " UPDATE " + currentTable + " SET int_map += row1.int_map WHERE k=0;\n" + + " UPDATE " + qualifiedTableName + " SET int_map += row1.int_map WHERE k=0;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { ImmutableMap.of("three", 4) }, update); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = 0;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = 0;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 0, ImmutableMap.of("one", 2, "three", 4) }, check); } @@ -1895,13 +1895,13 @@ public class AccordCQLTest extends AccordTestBase @Test public void testAssignmentFromMultiCellMapElement() throws Exception { - testAssignmentFromMapElement("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, v int, int_map map)"); + testAssignmentFromMapElement("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, v int, int_map map)"); } @Test public void testAssignmentFromFrozenMapElement() throws Exception { - testAssignmentFromMapElement("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, v int, int_map frozen>)"); + testAssignmentFromMapElement("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, v int, int_map frozen>)"); } private void testAssignmentFromMapElement(String ddl) throws Exception @@ -1909,18 +1909,18 @@ public class AccordCQLTest extends AccordTestBase test(ddl, cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, v, int_map) VALUES (0, 0, {'one': 2});", ConsistencyLevel.ALL); - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, v, int_map) VALUES (1, 0, {'three': 4});", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, v, int_map) VALUES (0, 0, {'one': 2});", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, v, int_map) VALUES (1, 0, {'three': 4});", ConsistencyLevel.ALL); String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = 1);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 1);\n" + " SELECT row1.int_map;\n" + - " UPDATE " + currentTable + " SET v = row1.int_map[?] WHERE k=0;\n" + + " UPDATE " + qualifiedTableName + " SET v = row1.int_map[?] WHERE k=0;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { ImmutableMap.of("three", 4) }, update, "three"); String check = "BEGIN TRANSACTION\n" + - " SELECT v FROM " + currentTable + " WHERE k = 0;\n" + + " SELECT v FROM " + qualifiedTableName + " WHERE k = 0;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 4 }, check); } @@ -1930,13 +1930,13 @@ public class AccordCQLTest extends AccordTestBase @Test public void testAssignmentFromMultiCellUDTField() throws Exception { - testAssignmentFromUDTField("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, v int, customer person)"); + testAssignmentFromUDTField("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, v int, customer person)"); } @Test public void testAssignmentFromFrozenUDTField() throws Exception { - testAssignmentFromUDTField("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, v int, customer frozen)"); + testAssignmentFromUDTField("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, v int, customer frozen)"); } private void testAssignmentFromUDTField(String tableDDL) throws Exception @@ -1946,18 +1946,18 @@ public class AccordCQLTest extends AccordTestBase { Object initialPersonValue = CQLTester.userType("height", 74, "age", 37); ByteBuffer initialPersonBuffer = CQLTester.makeByteBuffer(initialPersonValue, null); - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, v, customer) VALUES (0, 0, null);", ConsistencyLevel.ALL); - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, v, customer) VALUES (1, 0, ?);", ConsistencyLevel.ALL, initialPersonBuffer); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, v, customer) VALUES (0, 0, null);", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, v, customer) VALUES (1, 0, ?);", ConsistencyLevel.ALL, initialPersonBuffer); String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = 1);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 1);\n" + " SELECT row1.customer;\n" + - " UPDATE " + currentTable + " SET v = row1.customer.age WHERE k=0;\n" + + " UPDATE " + qualifiedTableName + " SET v = row1.customer.age WHERE k=0;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { initialPersonBuffer }, update); String check = "BEGIN TRANSACTION\n" + - " SELECT v FROM " + currentTable + " WHERE k = 0;\n" + + " SELECT v FROM " + qualifiedTableName + " WHERE k = 0;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 37 }, check); } @@ -1967,21 +1967,21 @@ public class AccordCQLTest extends AccordTestBase @Test public void testSetMapElementFromMapElementReference() throws Exception { - test("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_map map)", + test("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_map map)", cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, int_map) VALUES (0, {'one': 2});", ConsistencyLevel.ALL); - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, int_map) VALUES (1, {'three': 4});", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, int_map) VALUES (0, {'one': 2});", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, int_map) VALUES (1, {'three': 4});", ConsistencyLevel.ALL); String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = 1);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 1);\n" + " SELECT row1.int_map;\n" + - " UPDATE " + currentTable + " SET int_map[?] = row1.int_map[?] WHERE k=0;\n" + + " UPDATE " + qualifiedTableName + " SET int_map[?] = row1.int_map[?] WHERE k=0;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { ImmutableMap.of("three", 4) }, update, "one", "three"); String check = "BEGIN TRANSACTION\n" + - " SELECT int_map[?] FROM " + currentTable + " WHERE k = 0;\n" + + " SELECT int_map[?] FROM " + qualifiedTableName + " WHERE k = 0;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 4 }, check, "one"); } @@ -1991,7 +1991,7 @@ public class AccordCQLTest extends AccordTestBase @Test public void testSetUDTFieldFromUDTFieldReference() throws Exception { - test("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, customer person)", + test("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, customer person)", cluster -> { Object youngPerson = CQLTester.userType("height", 58, "age", 9); @@ -1999,18 +1999,18 @@ public class AccordCQLTest extends AccordTestBase Object adultPerson = CQLTester.userType("height", 74, "age", 37); ByteBuffer adultPersonBuffer = CQLTester.makeByteBuffer(adultPerson, null); - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, customer) VALUES (0, ?);", ConsistencyLevel.ALL, youngPersonBuffer); - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, customer) VALUES (1, ?);", ConsistencyLevel.ALL, adultPersonBuffer); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, customer) VALUES (0, ?);", ConsistencyLevel.ALL, youngPersonBuffer); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, customer) VALUES (1, ?);", ConsistencyLevel.ALL, adultPersonBuffer); String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = 1);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 1);\n" + " SELECT row1.customer;\n" + - " UPDATE " + currentTable + " SET customer.age = row1.customer.age WHERE k = 0;\n" + + " UPDATE " + qualifiedTableName + " SET customer.age = row1.customer.age WHERE k = 0;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { adultPersonBuffer }, update); String check = "BEGIN TRANSACTION\n" + - " SELECT customer.height, customer.age FROM " + currentTable + " WHERE k = 0;\n" + + " SELECT customer.height, customer.age FROM " + qualifiedTableName + " WHERE k = 0;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 58, 37 }, check); } @@ -2020,13 +2020,13 @@ public class AccordCQLTest extends AccordTestBase @Test public void testMultiCellListElementCondition() throws Exception { - testListElementCondition("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_list list)"); + testListElementCondition("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_list list)"); } @Test public void testFrozenListElementCondition() throws Exception { - testListElementCondition("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_list frozen>)"); + testListElementCondition("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_list frozen>)"); } private void testListElementCondition(String ddl) throws Exception @@ -2034,20 +2034,20 @@ public class AccordCQLTest extends AccordTestBase test(ddl, cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, int_list) VALUES (0, [1, 2]);", ConsistencyLevel.ALL); - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, int_list) VALUES (1, [3, 4]);", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, int_list) VALUES (0, [1, 2]);", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, int_list) VALUES (1, [3, 4]);", ConsistencyLevel.ALL); String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = 1);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 1);\n" + " SELECT row1.int_list;\n" + " IF row1.int_list[1] = 4 THEN\n" + - " UPDATE " + currentTable + " SET int_list = [3, 4] WHERE k = 0;\n" + + " UPDATE " + qualifiedTableName + " SET int_list = [3, 4] WHERE k = 0;\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { ImmutableList.of(3, 4) }, update); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = 0;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = 0;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 0, ImmutableList.of(3, 4) }, check); } @@ -2057,13 +2057,13 @@ public class AccordCQLTest extends AccordTestBase @Test public void testMultiCellMapElementCondition() throws Exception { - testMapElementCondition("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_map map)"); + testMapElementCondition("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_map map)"); } @Test public void testFrozenMapElementCondition() throws Exception { - testMapElementCondition("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_map frozen>)"); + testMapElementCondition("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_map frozen>)"); } private void testMapElementCondition(String ddl) throws Exception @@ -2071,20 +2071,20 @@ public class AccordCQLTest extends AccordTestBase test(ddl, cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, int_map) VALUES (0, {'one': 2});", ConsistencyLevel.ALL); - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, int_map) VALUES (1, {'three': 4});", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, int_map) VALUES (0, {'one': 2});", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, int_map) VALUES (1, {'three': 4});", ConsistencyLevel.ALL); String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = 1);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 1);\n" + " SELECT row1.int_map;\n" + " IF row1.int_map[?] = 4 THEN\n" + - " UPDATE " + currentTable + " SET int_map = {'three': 4} WHERE k = 0;\n" + + " UPDATE " + qualifiedTableName + " SET int_map = {'three': 4} WHERE k = 0;\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { ImmutableMap.of("three", 4) }, update, "three"); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = 0;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = 0;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 0, ImmutableMap.of("three", 4) }, check); } @@ -2094,13 +2094,13 @@ public class AccordCQLTest extends AccordTestBase @Test public void testMultiCellUDTFieldCondition() throws Exception { - testUDTFieldCondition("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, customer person)"); + testUDTFieldCondition("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, customer person)"); } @Test public void testFrozenUDTFieldCondition() throws Exception { - testUDTFieldCondition("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, customer frozen)"); + testUDTFieldCondition("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, customer frozen)"); } private void testUDTFieldCondition(String tableDDL) throws Exception @@ -2112,21 +2112,21 @@ public class AccordCQLTest extends AccordTestBase ByteBuffer initialPersonBuffer = CQLTester.makeByteBuffer(initialPersonValue, null); String insert = "BEGIN TRANSACTION\n" + - " INSERT INTO " + currentTable + " (k, customer) VALUES (?, ?);\n" + + " INSERT INTO " + qualifiedTableName + " (k, customer) VALUES (?, ?);\n" + "COMMIT TRANSACTION"; SimpleQueryResult result = cluster.coordinator(1).executeWithResult(insert, ConsistencyLevel.ANY, 0, initialPersonBuffer); assertFalse(result.hasNext()); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = ?;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = ?;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 0, initialPersonBuffer }, check, 0); String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = ?);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = ?);\n" + " SELECT row1.customer;\n" + " IF row1.customer.age = 37 THEN\n" + - " UPDATE " + currentTable + " SET customer = ? WHERE k = ?;\n" + + " UPDATE " + qualifiedTableName + " SET customer = ? WHERE k = ?;\n" + " END IF\n" + "COMMIT TRANSACTION"; @@ -2135,7 +2135,7 @@ public class AccordCQLTest extends AccordTestBase assertRowEqualsWithPreemptedRetry(cluster, new Object[] { initialPersonBuffer }, update, 0, updatedPersonBuffer, 0); String checkUpdate = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = ?;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = ?;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 0, updatedPersonBuffer }, checkUpdate, 0); } @@ -2145,23 +2145,23 @@ public class AccordCQLTest extends AccordTestBase @Test public void testListSubtraction() throws Exception { - test("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_list list)", + test("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_list list)", cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, int_list) VALUES (0, [1, 2, 3, 4]);", ConsistencyLevel.ALL); - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, int_list) VALUES (1, [3, 4]);", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, int_list) VALUES (0, [1, 2, 3, 4]);", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, int_list) VALUES (1, [3, 4]);", ConsistencyLevel.ALL); String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = 1);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 1);\n" + " SELECT row1.int_list;\n" + " IF row1.int_list = [3, 4] THEN\n" + - " UPDATE " + currentTable + " SET int_list -= row1.int_list WHERE k=0;\n" + + " UPDATE " + qualifiedTableName + " SET int_list -= row1.int_list WHERE k=0;\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] {Arrays.asList(3, 4)}, update); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = 0;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = 0;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] {0, Arrays.asList(1, 2)}, check); } @@ -2171,23 +2171,23 @@ public class AccordCQLTest extends AccordTestBase @Test public void testSetSubtraction() throws Exception { - test("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_set set)", + test("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_set set)", cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, int_set) VALUES (0, {1, 2, 3, 4});", ConsistencyLevel.ALL); - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, int_set) VALUES (1, {3, 4});", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, int_set) VALUES (0, {1, 2, 3, 4});", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, int_set) VALUES (1, {3, 4});", ConsistencyLevel.ALL); String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = 1);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 1);\n" + " SELECT row1.int_set;\n" + " IF row1.int_set = {3, 4} THEN\n" + - " UPDATE " + currentTable + " SET int_set -= row1.int_set WHERE k=0;\n" + + " UPDATE " + qualifiedTableName + " SET int_set -= row1.int_set WHERE k=0;\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { ImmutableSet.of(3, 4) }, update); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = 0;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = 0;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 0, ImmutableSet.of(1, 2) }, check); } @@ -2197,13 +2197,13 @@ public class AccordCQLTest extends AccordTestBase @Test public void testMultiCellMapSubtraction() throws Exception { - testMapSubtraction("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_map map, int_set set)"); + testMapSubtraction("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_map map, int_set set)"); } @Test public void testFrozenMapSubtraction() throws Exception { - testMapSubtraction("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_map map, int_set frozen>)"); + testMapSubtraction("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_map map, int_set frozen>)"); } private void testMapSubtraction(String ddl) throws Exception @@ -2211,20 +2211,20 @@ public class AccordCQLTest extends AccordTestBase test(ddl, cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, int_map) VALUES (0, { 'one': 2, 'three': 4 });", ConsistencyLevel.ALL); - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, int_set) VALUES (1, { 'three' });", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, int_map) VALUES (0, { 'one': 2, 'three': 4 });", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, int_set) VALUES (1, { 'three' });", ConsistencyLevel.ALL); String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = 1);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 1);\n" + " SELECT row1.int_set;\n" + " IF row1.int_set = { 'three' } THEN\n" + - " UPDATE " + currentTable + " SET int_map -= row1.int_set WHERE k=0;\n" + + " UPDATE " + qualifiedTableName + " SET int_map -= row1.int_set WHERE k=0;\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { ImmutableSet.of("three") }, update); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = 0;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = 0;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 0, ImmutableMap.of("one", 2), null}, check); } @@ -2234,13 +2234,13 @@ public class AccordCQLTest extends AccordTestBase @Test public void testMultiCellListSelection() throws Exception { - testListSelection("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_list list)"); + testListSelection("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_list list)"); } @Test public void testFrozenListSelection() throws Exception { - testListSelection("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_list frozen>)"); + testListSelection("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_list frozen>)"); } private void testListSelection(String ddl) throws Exception @@ -2248,16 +2248,16 @@ public class AccordCQLTest extends AccordTestBase test(ddl, cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, int_list) VALUES (1, [10, 20, 30, 40]);", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, int_list) VALUES (1, [10, 20, 30, 40]);", ConsistencyLevel.ALL); String selectEntireSet = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = 1);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 1);\n" + " SELECT row1.int_list;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { ImmutableList.of(10, 20, 30, 40) }, selectEntireSet); String selectSingleElement = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = 1);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 1);\n" + " SELECT row1.int_list[0];\n" + "COMMIT TRANSACTION"; @@ -2272,13 +2272,13 @@ public class AccordCQLTest extends AccordTestBase @Test public void testMultiCellSetSelection() throws Exception { - testSetSelection("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_set set)"); + testSetSelection("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_set set)"); } @Test public void testFrozenSetSelection() throws Exception { - testSetSelection("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_set frozen>)"); + testSetSelection("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_set frozen>)"); } private void testSetSelection(String ddl) throws Exception @@ -2286,16 +2286,16 @@ public class AccordCQLTest extends AccordTestBase test(ddl, cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, int_set) VALUES (1, {10, 20, 30, 40});", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, int_set) VALUES (1, {10, 20, 30, 40});", ConsistencyLevel.ALL); String selectEntireSet = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = 1);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 1);\n" + " SELECT row1.int_set;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { ImmutableSet.of(10, 20, 30, 40) }, selectEntireSet); String selectSingleElement = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = 1);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 1);\n" + " SELECT row1.int_set[10];\n" + "COMMIT TRANSACTION"; @@ -2310,13 +2310,13 @@ public class AccordCQLTest extends AccordTestBase @Test public void testMultiCellMapSelection() throws Exception { - testMapSelection("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_map map)"); + testMapSelection("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_map map)"); } @Test public void testFrozenMapSelection() throws Exception { - testMapSelection("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, int_map frozen>)"); + testMapSelection("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, int_map frozen>)"); } private void testMapSelection(String ddl) throws Exception @@ -2324,16 +2324,16 @@ public class AccordCQLTest extends AccordTestBase test(ddl, cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, int_map) VALUES (1, { 'ten': 20, 'thirty': 40 });", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, int_map) VALUES (1, { 'ten': 20, 'thirty': 40 });", ConsistencyLevel.ALL); String selectEntireMap = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = 1);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 1);\n" + " SELECT row1.int_map;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { ImmutableMap.of("ten", 20, "thirty", 40) }, selectEntireMap); String selectSingleElement = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = 1);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 1);\n" + " SELECT row1.int_map['ten'];\n" + "COMMIT TRANSACTION"; @@ -2349,25 +2349,25 @@ public class AccordCQLTest extends AccordTestBase { String KEYSPACE = "ks" + System.currentTimeMillis(); SHARED_CLUSTER.schemaChange("CREATE KEYSPACE " + KEYSPACE + " WITH REPLICATION={'class':'SimpleStrategy', 'replication_factor': 2}"); - SHARED_CLUSTER.schemaChange("CREATE TABLE " + currentTable + "1 (k int, c int, v int, primary key (k, c))"); - SHARED_CLUSTER.schemaChange("CREATE TABLE " + currentTable + "2 (k int, c int, v int, primary key (k, c))"); + SHARED_CLUSTER.schemaChange("CREATE TABLE " + qualifiedTableName + "1 (k int, c int, v int, primary key (k, c))"); + SHARED_CLUSTER.schemaChange("CREATE TABLE " + qualifiedTableName + "2 (k int, c int, v int, primary key (k, c))"); SHARED_CLUSTER.forEach(node -> node.runOnInstance(() -> AccordService.instance().setCacheSize(0))); - SHARED_CLUSTER.coordinator(1).execute("INSERT INTO " + currentTable + "1 (k, c, v) VALUES (1, 2, 3);", ConsistencyLevel.ALL); - SHARED_CLUSTER.coordinator(1).execute("INSERT INTO " + currentTable + "2 (k, c, v) VALUES (2, 2, 4);", ConsistencyLevel.ALL); + SHARED_CLUSTER.coordinator(1).execute("INSERT INTO " + qualifiedTableName + "1 (k, c, v) VALUES (1, 2, 3);", ConsistencyLevel.ALL); + SHARED_CLUSTER.coordinator(1).execute("INSERT INTO " + qualifiedTableName + "2 (k, c, v) VALUES (2, 2, 4);", ConsistencyLevel.ALL); String query = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + "1 WHERE k=1 AND c=2);\n" + - " LET row2 = (SELECT * FROM " + currentTable + "2 WHERE k=2 AND c=2);\n" + - " SELECT v FROM " + currentTable + "1 WHERE k=1 AND c=2;\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + "1 WHERE k=1 AND c=2);\n" + + " LET row2 = (SELECT * FROM " + qualifiedTableName + "2 WHERE k=2 AND c=2);\n" + + " SELECT v FROM " + qualifiedTableName + "1 WHERE k=1 AND c=2;\n" + " IF row1.v = 3 AND row2.v = 4 THEN\n" + - " UPDATE " + currentTable + "1 SET v = row2.v WHERE k=1 AND c=2;\n" + + " UPDATE " + qualifiedTableName + "1 SET v = row2.v WHERE k=1 AND c=2;\n" + " END IF\n" + "COMMIT TRANSACTION"; Object[][] result = SHARED_CLUSTER.coordinator(1).execute(query, ConsistencyLevel.ANY); assertEquals(3, result[0][0]); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + "1 WHERE k=1 AND c=2;\n" + + " SELECT * FROM " + qualifiedTableName + "1 WHERE k=1 AND c=2;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(SHARED_CLUSTER, new Object[]{1, 2, 4}, check); } @@ -2375,13 +2375,13 @@ public class AccordCQLTest extends AccordTestBase @Test public void testRegularScalarInsertSubstitution() throws Exception { - testScalarInsertSubstitution("CREATE TABLE " + currentTable + " (k int, c int, v int, PRIMARY KEY (k, c))"); + testScalarInsertSubstitution("CREATE TABLE " + qualifiedTableName + " (k int, c int, v int, PRIMARY KEY (k, c))"); } @Test public void testStaticScalarInsertSubstitution() throws Exception { - testScalarInsertSubstitution("CREATE TABLE " + currentTable + " (k int, c int, v int static, PRIMARY KEY (k, c))"); + testScalarInsertSubstitution("CREATE TABLE " + qualifiedTableName + " (k int, c int, v int static, PRIMARY KEY (k, c))"); } private void testScalarInsertSubstitution(String tableDDL) throws Exception @@ -2389,19 +2389,19 @@ public class AccordCQLTest extends AccordTestBase test(tableDDL, cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, c, v) VALUES (0, 0, 1);", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, c, v) VALUES (0, 0, 1);", ConsistencyLevel.ALL); String insert = "BEGIN TRANSACTION\n" + - " LET row0 = (SELECT * FROM " + currentTable + " WHERE k = 0 LIMIT 1);\n" + + " LET row0 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 0 LIMIT 1);\n" + " SELECT row0.v;\n" + " IF row0.v IS NOT NULL THEN\n" + - " INSERT INTO " + currentTable + " (k, c, v) VALUES (0, 1, row0.v);\n" + + " INSERT INTO " + qualifiedTableName + " (k, c, v) VALUES (0, 1, row0.v);\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 1 }, insert); String check = "BEGIN TRANSACTION\n" + - " SELECT k, c, v FROM " + currentTable + " WHERE k = 0 AND c = 1;\n" + + " SELECT k, c, v FROM " + qualifiedTableName + " WHERE k = 0 AND c = 1;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 0, 1, 1 }, check); } @@ -2411,13 +2411,13 @@ public class AccordCQLTest extends AccordTestBase @Test public void testSelectMultiCellUDTReference() throws Exception { - testSelectUDTReference("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, customer person)"); + testSelectUDTReference("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, customer person)"); } @Test public void testSelectFrozenUDTReference() throws Exception { - testSelectUDTReference("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, customer frozen)"); + testSelectUDTReference("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, customer frozen)"); } private void testSelectUDTReference(String tableDDL) throws Exception @@ -2429,13 +2429,13 @@ public class AccordCQLTest extends AccordTestBase ByteBuffer personBuffer = CQLTester.makeByteBuffer(personValue, null); String insert = "BEGIN TRANSACTION\n" + - " INSERT INTO " + currentTable + " (k, customer) VALUES (?, ?);\n" + + " INSERT INTO " + qualifiedTableName + " (k, customer) VALUES (?, ?);\n" + "COMMIT TRANSACTION"; SimpleQueryResult result = cluster.coordinator(1).executeWithResult(insert, ConsistencyLevel.ANY, 0, personBuffer); assertFalse(result.hasNext()); String read = "BEGIN TRANSACTION\n" + - " LET row0 = (SELECT * FROM " + currentTable + " WHERE k = ?);\n" + + " LET row0 = (SELECT * FROM " + qualifiedTableName + " WHERE k = ?);\n" + " SELECT row0.customer;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { personBuffer }, read, 0); @@ -2446,13 +2446,13 @@ public class AccordCQLTest extends AccordTestBase @Test public void testSelectMultiCellUDTFieldReference() throws Exception { - testSelectUDTFieldReference("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, customer person)"); + testSelectUDTFieldReference("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, customer person)"); } @Test public void testSelectFrozenUDTFieldReference() throws Exception { - testSelectUDTFieldReference("CREATE TABLE " + currentTable + " (k int PRIMARY KEY, customer frozen)"); + testSelectUDTFieldReference("CREATE TABLE " + qualifiedTableName + " (k int PRIMARY KEY, customer frozen)"); } private void testSelectUDTFieldReference(String tableDDL) throws Exception @@ -2464,13 +2464,13 @@ public class AccordCQLTest extends AccordTestBase ByteBuffer personBuffer = CQLTester.makeByteBuffer(personValue, null); String insert = "BEGIN TRANSACTION\n" + - " INSERT INTO " + currentTable + " (k, customer) VALUES (?, ?);\n" + + " INSERT INTO " + qualifiedTableName + " (k, customer) VALUES (?, ?);\n" + "COMMIT TRANSACTION"; SimpleQueryResult result = cluster.coordinator(1).executeWithResult(insert, ConsistencyLevel.ANY, 0, personBuffer); assertFalse(result.hasNext()); String read = "BEGIN TRANSACTION\n" + - " LET row0 = (SELECT * FROM " + currentTable + " WHERE k = ?);\n" + + " LET row0 = (SELECT * FROM " + qualifiedTableName + " WHERE k = ?);\n" + " SELECT row0.customer.age;\n" + "COMMIT TRANSACTION"; result = assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 37 }, read, 0); @@ -2483,33 +2483,33 @@ public class AccordCQLTest extends AccordTestBase @Test public void testMultiKeyQueryAndInsert() throws Throwable { - test("CREATE TABLE " + currentTable + " (k int, c int, v int, primary key (k, c))", + test("CREATE TABLE " + qualifiedTableName + " (k int, c int, v int, primary key (k, c))", cluster -> { String query1 = "BEGIN TRANSACTION\n" + - " LET select1 = (SELECT * FROM " + currentTable + " WHERE k=0 AND c=0);\n" + - " LET select2 = (SELECT * FROM " + currentTable + " WHERE k=1 AND c=0);\n" + - " SELECT v FROM " + currentTable + " WHERE k=0 AND c=0;\n" + + " LET select1 = (SELECT * FROM " + qualifiedTableName + " WHERE k=0 AND c=0);\n" + + " LET select2 = (SELECT * FROM " + qualifiedTableName + " WHERE k=1 AND c=0);\n" + + " SELECT v FROM " + qualifiedTableName + " WHERE k=0 AND c=0;\n" + " IF select1 IS NULL THEN\n" + - " INSERT INTO " + currentTable + " (k, c, v) VALUES (0, 0, 0);\n" + - " INSERT INTO " + currentTable + " (k, c, v) VALUES (1, 0, 0);\n" + + " INSERT INTO " + qualifiedTableName + " (k, c, v) VALUES (0, 0, 0);\n" + + " INSERT INTO " + qualifiedTableName + " (k, c, v) VALUES (1, 0, 0);\n" + " END IF\n" + "COMMIT TRANSACTION"; assertEmptyWithPreemptedRetry(cluster, query1); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = ? AND c = ?;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = ? AND c = ?;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] {0, 0, 0}, check, 0, 0); assertRowEqualsWithPreemptedRetry(cluster, new Object[] {1, 0, 0}, check, 1, 0); String query2 = "BEGIN TRANSACTION\n" + - " LET select1 = (SELECT * FROM " + currentTable + " WHERE k=1 AND c=0);\n" + - " LET select2 = (SELECT * FROM " + currentTable + " WHERE k=2 AND c=0);\n" + - " SELECT v FROM " + currentTable + " WHERE k=1 AND c=0;\n" + + " LET select1 = (SELECT * FROM " + qualifiedTableName + " WHERE k=1 AND c=0);\n" + + " LET select2 = (SELECT * FROM " + qualifiedTableName + " WHERE k=2 AND c=0);\n" + + " SELECT v FROM " + qualifiedTableName + " WHERE k=1 AND c=0;\n" + " IF select1.v = ? THEN\n" + - " INSERT INTO " + currentTable + " (k, c, v) VALUES (1, 0, 1);\n" + - " INSERT INTO " + currentTable + " (k, c, v) VALUES (2, 0, 1);\n" + + " INSERT INTO " + qualifiedTableName + " (k, c, v) VALUES (1, 0, 1);\n" + + " INSERT INTO " + qualifiedTableName + " (k, c, v) VALUES (2, 0, 1);\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 0 }, query2, 0); @@ -2525,11 +2525,12 @@ public class AccordCQLTest extends AccordTestBase { SHARED_CLUSTER.schemaChange("DROP KEYSPACE IF EXISTS demo_ks;"); SHARED_CLUSTER.schemaChange("CREATE KEYSPACE demo_ks WITH REPLICATION={'class':'SimpleStrategy', 'replication_factor':2};"); - SHARED_CLUSTER.get(1).runOnInstance(() -> AccordService.instance().ensureKeyspaceIsAccordManaged("demo_ks")); SHARED_CLUSTER.schemaChange("CREATE TABLE demo_ks.org_docs ( org_name text, doc_id int, contents_version int static, title text, permissions int, PRIMARY KEY (org_name, doc_id) );"); SHARED_CLUSTER.schemaChange("CREATE TABLE demo_ks.org_users ( org_name text, user text, members_version int static, permissions int, PRIMARY KEY (org_name, user) );"); SHARED_CLUSTER.schemaChange("CREATE TABLE demo_ks.user_docs ( user text, doc_id int, title text, org_name text, permissions int, PRIMARY KEY (user, doc_id) );"); + SHARED_CLUSTER.get(1).runOnInstance(() -> AccordService.instance().ensureKeyspaceIsAccordManaged("demo_ks")); + SHARED_CLUSTER.forEach(node -> node.runOnInstance(() -> AccordService.instance().setCacheSize(0))); SHARED_CLUSTER.coordinator(1).execute("INSERT INTO demo_ks.org_users (org_name, user, members_version, permissions) VALUES ('demo', 'blake', 5, 777);\n", ConsistencyLevel.ALL); @@ -2571,12 +2572,12 @@ public class AccordCQLTest extends AccordTestBase public void testReferenceArithmeticInInsert() throws Exception { test(cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, c, v) VALUES (0, 0, 0)", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, c, v) VALUES (0, 0, 0)", ConsistencyLevel.ALL); String cql = "BEGIN TRANSACTION\n" + - " LET a = (SELECT * FROM " + currentTable + " WHERE k=0 AND c=0);\n" + + " LET a = (SELECT * FROM " + qualifiedTableName + " WHERE k=0 AND c=0);\n" + " IF a IS NOT NULL THEN\n" + - " INSERT INTO " + currentTable + " (k, c, v) VALUES (0, 1, a.v + 1);\n" + + " INSERT INTO " + qualifiedTableName + " (k, c, v) VALUES (0, 1, a.v + 1);\n" + " END IF\n" + "COMMIT TRANSACTION"; assertEmptyWithPreemptedRetry(cluster, cql); @@ -2589,12 +2590,12 @@ public class AccordCQLTest extends AccordTestBase public void testReferenceArithmeticInUpdate() throws Exception { test(cluster -> { - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, c, v) VALUES (0, 0, 0)", ConsistencyLevel.ALL); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, c, v) VALUES (0, 0, 0)", ConsistencyLevel.ALL); String cql = "BEGIN TRANSACTION\n" + - " LET a = (SELECT * FROM " + currentTable + " WHERE k=0 AND c=0);\n" + + " LET a = (SELECT * FROM " + qualifiedTableName + " WHERE k=0 AND c=0);\n" + " IF a IS NOT NULL THEN\n" + - " UPDATE " + currentTable + " SET v = a.v + 1 WHERE k = 0 and c = 1;\n" + + " UPDATE " + qualifiedTableName + " SET v = a.v + 1 WHERE k = 0 and c = 1;\n" + " END IF\n" + "COMMIT TRANSACTION"; assertEmptyWithPreemptedRetry(cluster, cql); @@ -2606,39 +2607,39 @@ public class AccordCQLTest extends AccordTestBase @Test public void testCASAndSerialRead() throws Exception { - test("CREATE TABLE " + currentTable + " (id int, c int, v int, s int static, PRIMARY KEY ((id), c));", + test("CREATE TABLE " + qualifiedTableName + " (id int, c int, v int, s int static, PRIMARY KEY ((id), c));", cluster -> { ICoordinator coordinator = cluster.coordinator(1); int startingAccordCoordinateCount = getAccordCoordinateCount(); - assertRowEquals(cluster, new Object[]{false}, "UPDATE " + currentTable + " SET v = 4 WHERE id = 1 AND c = 2 IF EXISTS"); - assertRowEquals(cluster, new Object[]{false}, "UPDATE " + currentTable + " SET v = 4 WHERE id = 1 AND c = 2 IF v = 3"); - coordinator.execute("INSERT INTO " + currentTable + " (id, c, v, s) VALUES (1, 2, 3, 5);", ConsistencyLevel.ALL); - assertRowSerial(cluster, "SELECT id, c, v, s FROM " + currentTable + " WHERE id = 1 AND c = 2", 1, 2, 3, 5); - assertRowEquals(cluster, new Object[]{true}, "UPDATE " + currentTable + " SET v = 4 WHERE id = 1 AND c = 2 IF v = 3"); - assertRowSerial(cluster, "SELECT id, c, v, s FROM " + currentTable + " WHERE id = 1 AND c = 2", 1, 2, 4, 5); - assertRowEquals(cluster, new Object[]{ false, 4 }, "UPDATE " + currentTable + " SET v = 4 WHERE id = 1 AND c = 2 IF v = 3"); - assertRowSerial(cluster, "SELECT id, c, v, s FROM " + currentTable + " WHERE id = 1 AND c = 2", 1, 2, 4, 5); + assertRowEquals(cluster, new Object[]{false}, "UPDATE " + qualifiedTableName + " SET v = 4 WHERE id = 1 AND c = 2 IF EXISTS"); + assertRowEquals(cluster, new Object[]{false}, "UPDATE " + qualifiedTableName + " SET v = 4 WHERE id = 1 AND c = 2 IF v = 3"); + coordinator.execute("INSERT INTO " + qualifiedTableName + " (id, c, v, s) VALUES (1, 2, 3, 5);", ConsistencyLevel.ALL); + assertRowSerial(cluster, "SELECT id, c, v, s FROM " + qualifiedTableName + " WHERE id = 1 AND c = 2", 1, 2, 3, 5); + assertRowEquals(cluster, new Object[]{true}, "UPDATE " + qualifiedTableName + " SET v = 4 WHERE id = 1 AND c = 2 IF v = 3"); + assertRowSerial(cluster, "SELECT id, c, v, s FROM " + qualifiedTableName + " WHERE id = 1 AND c = 2", 1, 2, 4, 5); + assertRowEquals(cluster, new Object[]{ false, 4 }, "UPDATE " + qualifiedTableName + " SET v = 4 WHERE id = 1 AND c = 2 IF v = 3"); + assertRowSerial(cluster, "SELECT id, c, v, s FROM " + qualifiedTableName + " WHERE id = 1 AND c = 2", 1, 2, 4, 5); // Test working with a static column - assertRowEquals(cluster, new Object[]{ false, 5 }, "UPDATE " + currentTable + " SET v = 5 WHERE id = 1 AND c = 2 IF s = 4"); - assertRowSerial(cluster, "SELECT id, c, v, s FROM " + currentTable + " WHERE id = 1 AND c = 2", 1, 2, 4, 5); - assertRowEquals(cluster, new Object[]{true}, "UPDATE " + currentTable + " SET v = 5 WHERE id = 1 AND c = 2 IF s = 5"); - assertRowSerial(cluster, "SELECT id, c, v, s FROM " + currentTable + " WHERE id = 1 AND c = 2", 1, 2, 5, 5); - assertRowEquals(cluster, new Object[]{true}, "UPDATE " + currentTable + " SET s = 6 WHERE id = 1 IF s = 5"); - assertRowSerial(cluster, "SELECT id, c, v, s FROM " + currentTable + " WHERE id = 1 AND c = 2", 1, 2, 5, 6); + assertRowEquals(cluster, new Object[]{ false, 5 }, "UPDATE " + qualifiedTableName + " SET v = 5 WHERE id = 1 AND c = 2 IF s = 4"); + assertRowSerial(cluster, "SELECT id, c, v, s FROM " + qualifiedTableName + " WHERE id = 1 AND c = 2", 1, 2, 4, 5); + assertRowEquals(cluster, new Object[]{true}, "UPDATE " + qualifiedTableName + " SET v = 5 WHERE id = 1 AND c = 2 IF s = 5"); + assertRowSerial(cluster, "SELECT id, c, v, s FROM " + qualifiedTableName + " WHERE id = 1 AND c = 2", 1, 2, 5, 5); + assertRowEquals(cluster, new Object[]{true}, "UPDATE " + qualifiedTableName + " SET s = 6 WHERE id = 1 IF s = 5"); + assertRowSerial(cluster, "SELECT id, c, v, s FROM " + qualifiedTableName + " WHERE id = 1 AND c = 2", 1, 2, 5, 6); // Test that read before write works with CAS - assertRowEquals(cluster, new Object[]{true}, "UPDATE " + currentTable + " SET s +=1, v += 1 WHERE id = 1 AND c = 2 IF EXISTS"); - assertRowSerial(cluster, "SELECT id, c, v, s FROM " + currentTable + " WHERE id = 1 AND c = 2", 1, 2, 6, 7); + assertRowEquals(cluster, new Object[]{true}, "UPDATE " + qualifiedTableName + " SET s +=1, v += 1 WHERE id = 1 AND c = 2 IF EXISTS"); + assertRowSerial(cluster, "SELECT id, c, v, s FROM " + qualifiedTableName + " WHERE id = 1 AND c = 2", 1, 2, 6, 7); // Check range deletion works - coordinator.execute("INSERT INTO " + currentTable + " (id, c, v, s) VALUES (1, 2, 6, 7);", ConsistencyLevel.ALL); - coordinator.execute("INSERT INTO " + currentTable + " (id, c, v) VALUES (1, 3, 3);", ConsistencyLevel.ALL); + coordinator.execute("INSERT INTO " + qualifiedTableName + " (id, c, v, s) VALUES (1, 2, 6, 7);", ConsistencyLevel.ALL); + coordinator.execute("INSERT INTO " + qualifiedTableName + " (id, c, v) VALUES (1, 3, 3);", ConsistencyLevel.ALL); assertRowEquals(cluster, new Object[]{true}, "BEGIN BATCH \n" + - "UPDATE " + currentTable + " SET s +=1, v += 1 WHERE id = 1 AND c = 2 IF EXISTS; \n" + - "DELETE FROM " + currentTable + " WHERE id = 1 AND c > 0 AND c < 10; \n" + + "UPDATE " + qualifiedTableName + " SET s +=1, v += 1 WHERE id = 1 AND c = 2 IF EXISTS; \n" + + "DELETE FROM " + qualifiedTableName + " WHERE id = 1 AND c > 0 AND c < 10; \n" + "APPLY BATCH;"); - Object[][] rangeDeletionCheck = coordinator.execute("SELECT id, c, v, s FROM " + currentTable + " WHERE id = 1", ConsistencyLevel.SERIAL); + Object[][] rangeDeletionCheck = coordinator.execute("SELECT id, c, v, s FROM " + qualifiedTableName + " WHERE id = 1", ConsistencyLevel.SERIAL); assertArrayEquals(new Object[] { 1, 2, 7, 8 }, rangeDeletionCheck[0]); assertEquals(1, rangeDeletionCheck.length); @@ -2655,10 +2656,10 @@ public class AccordCQLTest extends AccordTestBase @Test public void testCASSimulatorLite() throws Exception { - test("CREATE TABLE " + currentTable + " (pk int, count int, seq1 text, seq2 list, PRIMARY KEY (pk))", + test("CREATE TABLE " + qualifiedTableName + " (pk int, count int, seq1 text, seq2 list, PRIMARY KEY (pk))", cluster -> { ICoordinator coordinator = cluster.coordinator(1); - coordinator.execute("INSERT INTO " + currentTable + " (pk, count, seq1, seq2) VALUES (1, 0, '', []) USING TIMESTAMP 0", ConsistencyLevel.ALL); + coordinator.execute("INSERT INTO " + qualifiedTableName + " (pk, count, seq1, seq2) VALUES (1, 0, '', []) USING TIMESTAMP 0", ConsistencyLevel.ALL); ListType LIST_TYPE = ListType.getInstance(Int32Type.instance, true); ExecutorService es = Executors.newCachedThreadPool(); @@ -2666,12 +2667,12 @@ public class AccordCQLTest extends AccordTestBase for (int ii = 0; ii < 10; ii++) { int id = ii; - futures.add(es.submit(() -> coordinator.execute("UPDATE " + currentTable + " SET count = count + 1, seq1 = seq1 + ?, seq2 = seq2 + ? WHERE pk = ? IF EXISTS", ConsistencyLevel.ALL, id + ",", ByteBufferUtil.getArray(LIST_TYPE.decompose(singletonList(id))), 1))); + futures.add(es.submit(() -> coordinator.execute("UPDATE " + qualifiedTableName + " SET count = count + 1, seq1 = seq1 + ?, seq2 = seq2 + ? WHERE pk = ? IF EXISTS", ConsistencyLevel.ALL, id + ",", ByteBufferUtil.getArray(LIST_TYPE.decompose(singletonList(id))), 1))); } for (Future f : futures) f.get(); - Object[][] result = coordinator.execute("SELECT pk, count, seq1, seq2 FROM " + currentTable + " WHERE pk = 1", ConsistencyLevel.SERIAL); + Object[][] result = coordinator.execute("SELECT pk, count, seq1, seq2 FROM " + qualifiedTableName + " WHERE pk = 1", ConsistencyLevel.SERIAL); int[] seq1 = Arrays.stream(((String) result[0][2]).split(",")) .filter(s -> !s.isEmpty()) @@ -2687,11 +2688,11 @@ public class AccordCQLTest extends AccordTestBase @Test public void testTransactionCasSimulatorLite() throws Exception { - test("CREATE TABLE " + currentTable + " (pk int, count int, seq1 text, seq2 list, PRIMARY KEY (pk))", + test("CREATE TABLE " + qualifiedTableName + " (pk int, count int, seq1 text, seq2 list, PRIMARY KEY (pk))", cluster -> { ICoordinator coordinator = cluster.coordinator(1); - coordinator.execute("INSERT INTO " + currentTable + " (pk, count, seq1, seq2) VALUES (1, 0, '', []) USING TIMESTAMP 0", ConsistencyLevel.ALL); + coordinator.execute("INSERT INTO " + qualifiedTableName + " (pk, count, seq1, seq2) VALUES (1, 0, '', []) USING TIMESTAMP 0", ConsistencyLevel.ALL); ListType LIST_TYPE = ListType.getInstance(Int32Type.instance, true); ExecutorService es = Executors.newCachedThreadPool(); @@ -2700,8 +2701,8 @@ public class AccordCQLTest extends AccordTestBase { int id = ii; String update = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE pk = 1);\n" + - " UPDATE " + currentTable + " SET count += 1, seq1 = seq1 + ?, seq2 = seq2 + ? WHERE pk=1;\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE pk = 1);\n" + + " UPDATE " + qualifiedTableName + " SET count += 1, seq1 = seq1 + ?, seq2 = seq2 + ? WHERE pk=1;\n" + "COMMIT TRANSACTION"; futures.add(es.submit(() -> coordinator.executeWithResult(update, ConsistencyLevel.ANY, id + ",", ByteBufferUtil.getArray(LIST_TYPE.decompose(singletonList(id)))))); } @@ -2709,7 +2710,7 @@ public class AccordCQLTest extends AccordTestBase f.get(); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE pk = 1;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE pk = 1;\n" + "COMMIT TRANSACTION"; Object[][] result = coordinator.execute(check, ConsistencyLevel.ALL); @@ -2728,15 +2729,15 @@ public class AccordCQLTest extends AccordTestBase @Test public void testSerialReadDescending() throws Throwable { - test("CREATE TABLE " + currentTable + " (k int, c int, v int, PRIMARY KEY(k, c))", + test("CREATE TABLE " + qualifiedTableName + " (k int, c int, v int, PRIMARY KEY(k, c))", cluster -> { ICoordinator coordinator = cluster.coordinator(1); for (int i = 1; i <= 10; i++) - coordinator.execute("INSERT INTO " + currentTable + " (k, c, v) VALUES (0, ?, ?) USING TIMESTAMP 0;", ConsistencyLevel.ALL, i, i * 10); - assertRowSerial(cluster, "SELECT c, v FROM " + currentTable + " WHERE k=0 ORDER BY c DESC LIMIT 1", AssertUtils.row(10, 100)); - assertRowSerial(cluster, "SELECT c, v FROM " + currentTable + " WHERE k=0 ORDER BY c DESC LIMIT 2", AssertUtils.row(10, 100), AssertUtils.row(9, 90)); - assertRowSerial(cluster, "SELECT c, v FROM " + currentTable + " WHERE k=0 ORDER BY c DESC LIMIT 3", AssertUtils.row(10, 100), AssertUtils.row(9, 90), AssertUtils.row(8, 80)); - assertRowSerial(cluster, "SELECT c, v FROM " + currentTable + " WHERE k=0 ORDER BY c DESC LIMIT 4", AssertUtils.row(10, 100), AssertUtils.row(9, 90), AssertUtils.row(8, 80), AssertUtils.row(7, 70)); + coordinator.execute("INSERT INTO " + qualifiedTableName + " (k, c, v) VALUES (0, ?, ?) USING TIMESTAMP 0;", ConsistencyLevel.ALL, i, i * 10); + assertRowSerial(cluster, "SELECT c, v FROM " + qualifiedTableName + " WHERE k=0 ORDER BY c DESC LIMIT 1", AssertUtils.row(10, 100)); + assertRowSerial(cluster, "SELECT c, v FROM " + qualifiedTableName + " WHERE k=0 ORDER BY c DESC LIMIT 2", AssertUtils.row(10, 100), AssertUtils.row(9, 90)); + assertRowSerial(cluster, "SELECT c, v FROM " + qualifiedTableName + " WHERE k=0 ORDER BY c DESC LIMIT 3", AssertUtils.row(10, 100), AssertUtils.row(9, 90), AssertUtils.row(8, 80)); + assertRowSerial(cluster, "SELECT c, v FROM " + qualifiedTableName + " WHERE k=0 ORDER BY c DESC LIMIT 4", AssertUtils.row(10, 100), AssertUtils.row(9, 90), AssertUtils.row(8, 80), AssertUtils.row(7, 70)); } ); } diff --git a/test/distributed/org/apache/cassandra/distributed/test/accord/AccordIntegrationTest.java b/test/distributed/org/apache/cassandra/distributed/test/accord/AccordIntegrationTest.java index 7315df858a..e269e4e27a 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/accord/AccordIntegrationTest.java +++ b/test/distributed/org/apache/cassandra/distributed/test/accord/AccordIntegrationTest.java @@ -59,10 +59,10 @@ public class AccordIntegrationTest extends AccordTestBase IMessageFilters.Filter lostCommit = cluster.filters().verbs(Verb.ACCORD_COMMIT_REQ.id).to(2).drop(); String query = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT v FROM " + currentTable + " WHERE k=0 AND c=0);\n" + + " LET row1 = (SELECT v FROM " + qualifiedTableName + " WHERE k=0 AND c=0);\n" + " SELECT row1.v;\n" + " IF row1 IS NULL THEN\n" + - " INSERT INTO " + currentTable + " (k, c, v) VALUES (0, 0, 1);\n" + + " INSERT INTO " + qualifiedTableName + " (k, c, v) VALUES (0, 0, 1);\n" + " END IF\n" + "COMMIT TRANSACTION"; // row1.v shouldn't have existed when the txn's SELECT was executed @@ -73,24 +73,24 @@ public class AccordIntegrationTest extends AccordTestBase // Querying again should trigger recovery... query = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT v FROM " + currentTable + " WHERE k=0 AND c=0);\n" + + " LET row1 = (SELECT v FROM " + qualifiedTableName + " WHERE k=0 AND c=0);\n" + " SELECT row1.v;\n" + " IF row1.v = 1 THEN\n" + - " UPDATE " + currentTable + " SET v=2 WHERE k = 0 AND c = 0;\n" + + " UPDATE " + qualifiedTableName + " SET v=2 WHERE k = 0 AND c = 0;\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 1 }, query); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = ? AND c = ?;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = ? AND c = ?;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] {0, 0, 2}, check, 0, 0); query = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT v FROM " + currentTable + " WHERE k=0 AND c=0);\n" + + " LET row1 = (SELECT v FROM " + qualifiedTableName + " WHERE k=0 AND c=0);\n" + " SELECT row1.v;\n" + " IF row1 IS NULL THEN\n" + - " INSERT INTO " + currentTable + " (k, c, v) VALUES (0, 0, 3);\n" + + " INSERT INTO " + qualifiedTableName + " (k, c, v) VALUES (0, 0, 3);\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 2 }, query); @@ -113,16 +113,16 @@ public class AccordIntegrationTest extends AccordTestBase })).drop(); String query = "BEGIN TRANSACTION\n" + - " LET row1 = (SELECT * FROM " + currentTable + " WHERE k = 0 AND c = 0);\n" + + " LET row1 = (SELECT * FROM " + qualifiedTableName + " WHERE k = 0 AND c = 0);\n" + " SELECT row1.v;\n" + " IF row1 IS NULL THEN\n" + - " INSERT INTO " + currentTable + " (k, c, v) VALUES (0, 0, 1);\n" + + " INSERT INTO " + qualifiedTableName + " (k, c, v) VALUES (0, 0, 1);\n" + " END IF\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { null }, query); String check = "BEGIN TRANSACTION\n" + - " SELECT * FROM " + currentTable + " WHERE k = ? AND c = ?;\n" + + " SELECT * FROM " + qualifiedTableName + " WHERE k = ? AND c = ?;\n" + "COMMIT TRANSACTION"; assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 0, 0, 1 }, check, 0, 0); }); diff --git a/test/distributed/org/apache/cassandra/distributed/test/accord/AccordInteroperabilityTest.java b/test/distributed/org/apache/cassandra/distributed/test/accord/AccordInteroperabilityTest.java index 74c64c3b13..320a9f4e09 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/accord/AccordInteroperabilityTest.java +++ b/test/distributed/org/apache/cassandra/distributed/test/accord/AccordInteroperabilityTest.java @@ -28,7 +28,6 @@ import org.slf4j.LoggerFactory; import org.apache.cassandra.distributed.api.ConsistencyLevel; import org.apache.cassandra.distributed.api.ICoordinator; import org.apache.cassandra.distributed.shared.AssertUtils; -import org.apache.cassandra.service.accord.AccordService; public class AccordInteroperabilityTest extends AccordTestBase { @@ -45,21 +44,20 @@ public class AccordInteroperabilityTest extends AccordTestBase { AccordTestBase.setupCluster(builder -> builder.appendConfig(config -> config.set("lwt_strategy", "accord") .set("non_serial_write_strategy", "accord")), 3); - SHARED_CLUSTER.get(1).runOnInstance(() -> AccordService.instance().ensureKeyspaceIsAccordManaged(KEYSPACE)); } @Test public void testSerialReadDescending() throws Throwable { - test("CREATE TABLE " + currentTable + " (k int, c int, v int, PRIMARY KEY(k, c))", + test("CREATE TABLE " + qualifiedTableName + " (k int, c int, v int, PRIMARY KEY(k, c))", cluster -> { ICoordinator coordinator = cluster.coordinator(1); for (int i = 1; i <= 10; i++) - coordinator.execute("INSERT INTO " + currentTable + " (k, c, v) VALUES (0, ?, ?) USING TIMESTAMP 0;", ConsistencyLevel.ALL, i, i * 10); - assertRowSerial(cluster, "SELECT c, v FROM " + currentTable + " WHERE k=0 ORDER BY c DESC LIMIT 1", AssertUtils.row(10, 100)); - assertRowSerial(cluster, "SELECT c, v FROM " + currentTable + " WHERE k=0 ORDER BY c DESC LIMIT 2", AssertUtils.row(10, 100), AssertUtils.row(9, 90)); - assertRowSerial(cluster, "SELECT c, v FROM " + currentTable + " WHERE k=0 ORDER BY c DESC LIMIT 3", AssertUtils.row(10, 100), AssertUtils.row(9, 90), AssertUtils.row(8, 80)); - assertRowSerial(cluster, "SELECT c, v FROM " + currentTable + " WHERE k=0 ORDER BY c DESC LIMIT 4", AssertUtils.row(10, 100), AssertUtils.row(9, 90), AssertUtils.row(8, 80), AssertUtils.row(7, 70)); + coordinator.execute("INSERT INTO " + qualifiedTableName + " (k, c, v) VALUES (0, ?, ?) USING TIMESTAMP 0;", ConsistencyLevel.ALL, i, i * 10); + assertRowSerial(cluster, "SELECT c, v FROM " + qualifiedTableName + " WHERE k=0 ORDER BY c DESC LIMIT 1", AssertUtils.row(10, 100)); + assertRowSerial(cluster, "SELECT c, v FROM " + qualifiedTableName + " WHERE k=0 ORDER BY c DESC LIMIT 2", AssertUtils.row(10, 100), AssertUtils.row(9, 90)); + assertRowSerial(cluster, "SELECT c, v FROM " + qualifiedTableName + " WHERE k=0 ORDER BY c DESC LIMIT 3", AssertUtils.row(10, 100), AssertUtils.row(9, 90), AssertUtils.row(8, 80)); + assertRowSerial(cluster, "SELECT c, v FROM " + qualifiedTableName + " WHERE k=0 ORDER BY c DESC LIMIT 4", AssertUtils.row(10, 100), AssertUtils.row(9, 90), AssertUtils.row(8, 80), AssertUtils.row(7, 70)); } ); } diff --git a/test/distributed/org/apache/cassandra/distributed/test/accord/AccordMetricsTest.java b/test/distributed/org/apache/cassandra/distributed/test/accord/AccordMetricsTest.java index 496e8d08e4..028bcfbf32 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/accord/AccordMetricsTest.java +++ b/test/distributed/org/apache/cassandra/distributed/test/accord/AccordMetricsTest.java @@ -69,16 +69,16 @@ public class AccordMetricsTest extends AccordTestBase String writeCql() { return "BEGIN TRANSACTION\n" + - " LET val = (SELECT v FROM " + currentTable + " WHERE k=? AND c=?);\n" + + " LET val = (SELECT v FROM " + qualifiedTableName + " WHERE k=? AND c=?);\n" + " SELECT val.v;\n" + - " UPDATE " + currentTable + " SET v = v + 1 WHERE k=? AND c=?;\n" + + " UPDATE " + qualifiedTableName + " SET v = v + 1 WHERE k=? AND c=?;\n" + "COMMIT TRANSACTION"; } String readCql() { return "BEGIN TRANSACTION\n" + - " LET val = (SELECT v FROM " + currentTable + " WHERE k=? AND c=?);\n" + + " LET val = (SELECT v FROM " + qualifiedTableName + " WHERE k=? AND c=?);\n" + " SELECT val.v;\n" + "COMMIT TRANSACTION"; } @@ -89,8 +89,8 @@ public class AccordMetricsTest extends AccordTestBase public void beforeTest() { SHARED_CLUSTER.filters().reset(); - SHARED_CLUSTER.schemaChange("CREATE TABLE " + currentTable + " (k int, c int, v int, PRIMARY KEY (k, c))"); - SHARED_CLUSTER.coordinator(1).execute("INSERT INTO " + currentTable + " (k, c, v) VALUES (0, 0, 0)", ConsistencyLevel.ALL); + SHARED_CLUSTER.schemaChange("CREATE TABLE " + qualifiedTableName + " (k int, c int, v int, PRIMARY KEY (k, c))"); + SHARED_CLUSTER.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, c, v) VALUES (0, 0, 0)", ConsistencyLevel.ALL); } @Test diff --git a/test/distributed/org/apache/cassandra/distributed/test/accord/AccordMigrationTest.java b/test/distributed/org/apache/cassandra/distributed/test/accord/AccordMigrationTest.java index 69c550f633..d11d364181 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/accord/AccordMigrationTest.java +++ b/test/distributed/org/apache/cassandra/distributed/test/accord/AccordMigrationTest.java @@ -61,7 +61,6 @@ import org.apache.cassandra.locator.InetAddressAndPort; import org.apache.cassandra.schema.TableId; import org.apache.cassandra.schema.TableMetadata; import org.apache.cassandra.service.StorageService; -import org.apache.cassandra.service.accord.AccordService; import org.apache.cassandra.service.consensus.migration.ConsensusKeyMigrationState; import org.apache.cassandra.service.consensus.migration.ConsensusRequestRouter; import org.apache.cassandra.service.consensus.migration.ConsensusTableMigrationState; @@ -161,7 +160,6 @@ public class AccordMigrationTest extends AccordTestBase upperMidToken = partitioner.midpoint(midToken, maxToken); lowerMidToken = partitioner.midpoint(minToken, midToken); coordinator = SHARED_CLUSTER.coordinator(1); - SHARED_CLUSTER.get(1).runOnInstance(() -> AccordService.instance().ensureKeyspaceIsAccordManaged(KEYSPACE)); } @AfterClass @@ -343,13 +341,13 @@ public class AccordMigrationTest extends AccordTestBase @Test public void testPaxosToAccordCAS() throws Exception { - test(format(TABLE_FMT, currentTable), + test(format(TABLE_FMT, qualifiedTableName), cluster -> { - String casCQL = format(CAS_FMT, currentTable, CLUSTERING_VALUE); + String casCQL = format(CAS_FMT, qualifiedTableName, CLUSTERING_VALUE); Consumer runCasNoApply = key -> assertRowEquals(cluster, new Object[]{false}, casCQL, key); Consumer runCasApplies = key -> assertRowEquals(cluster, new Object[]{true}, casCQL, key); Consumer runCasOnSecondNode = key -> assertEquals( "[applied]", cluster.coordinator(2).executeWithResult(casCQL, ANY, key).names().get(0)); - String tableName = currentTable.split("\\.")[1]; + String tableName = qualifiedTableName.split("\\.")[1]; int migratingKey = getKeyBetweenTokens(midToken, maxToken); int notMigratingKey = getKeyBetweenTokens(minToken, midToken); Range migratingRange = new Range(midToken, maxToken); @@ -420,7 +418,7 @@ public class AccordMigrationTest extends AccordTestBase // Update inserted row so the condition can apply, if the condition check doesn't apply // then it won't get to propose/accept migratingKey = testingKeys.next(); - Consumer makeCASApply = key -> cluster.coordinator(1).execute("UPDATE " + currentTable + " SET v = 42 WHERE id = ? AND c = ?", ALL, key, CLUSTERING_VALUE); + Consumer makeCASApply = key -> cluster.coordinator(1).execute("UPDATE " + qualifiedTableName + " SET v = 42 WHERE id = ? AND c = ?", ALL, key, CLUSTERING_VALUE); makeCASApply.accept(migratingKey); assertTargetAccordWrite(runCasApplies, 1, migratingKey, 1, 1, 1, 0, 1); @@ -469,10 +467,10 @@ public class AccordMigrationTest extends AccordTestBase @Test public void testPaxosToAccordSerialRead() throws Exception { - test(format(TABLE_FMT, currentTable), + test(format(TABLE_FMT, qualifiedTableName), cluster -> { - String tableName = currentTable.split("\\.")[1]; - String readCQL = format("SELECT * FROM %s WHERE id = ? and c = %s", currentTable, CLUSTERING_VALUE); + String tableName = qualifiedTableName.split("\\.")[1]; + String readCQL = format("SELECT * FROM %s WHERE id = ? and c = %s", qualifiedTableName, CLUSTERING_VALUE); Function runRead = key -> cluster.coordinator(1).execute(readCQL, SERIAL, key); Range migratingRange = new Range<>(new LongToken(Long.MIN_VALUE + 1), new LongToken(Long.MIN_VALUE)); List> migratingRanges = ImmutableList.of(migratingRange); @@ -495,11 +493,11 @@ public class AccordMigrationTest extends AccordTestBase @Test public void testAccordToPaxos() throws Exception { - test(format(TABLE_FMT, currentTable), + test(format(TABLE_FMT, qualifiedTableName), cluster -> { - String casCQL = format(CAS_FMT, currentTable, CLUSTERING_VALUE); + String casCQL = format(CAS_FMT, qualifiedTableName, CLUSTERING_VALUE); Consumer runCasNoApply = key -> assertRowEquals(cluster, new Object[]{false}, casCQL, key); - String tableName = currentTable.split("\\.")[1]; + String tableName = qualifiedTableName.split("\\.")[1]; // Mark a subrange as migrating and finish migrating half of it nodetool(coordinator, "consensus_admin", "begin-migration", "-st", midToken.toString(), "-et", maxToken.toString(), "-tp", "accord", KEYSPACE, tableName); diff --git a/test/distributed/org/apache/cassandra/distributed/test/accord/AccordSimpleFastPathTest.java b/test/distributed/org/apache/cassandra/distributed/test/accord/AccordSimpleFastPathTest.java new file mode 100644 index 0000000000..19d562a21c --- /dev/null +++ b/test/distributed/org/apache/cassandra/distributed/test/accord/AccordSimpleFastPathTest.java @@ -0,0 +1,153 @@ +/* + * 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.distributed.test.accord; + +import java.net.UnknownHostException; +import java.util.Comparator; +import java.util.HashSet; +import java.util.Set; + +import org.apache.cassandra.service.accord.AccordFastPath; +import org.apache.cassandra.tcm.ClusterMetadataService; +import org.apache.cassandra.tcm.Epoch; +import org.apache.cassandra.utils.FBUtilities; +import org.junit.Assert; +import org.junit.Test; + +import accord.local.Node; +import accord.topology.Topology; +import org.apache.cassandra.distributed.Cluster; +import org.apache.cassandra.distributed.api.ConsistencyLevel; +import org.apache.cassandra.distributed.api.Feature; +import org.apache.cassandra.distributed.test.TestBaseImpl; +import org.apache.cassandra.gms.FailureDetector; +import org.apache.cassandra.locator.InetAddressAndPort; +import org.apache.cassandra.service.accord.AccordConfigurationService; +import org.apache.cassandra.service.accord.AccordService; +import org.apache.cassandra.tcm.ClusterMetadata; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AccordSimpleFastPathTest extends TestBaseImpl +{ + private static final Logger logger = LoggerFactory.getLogger(AccordSimpleFastPathTest.class); + + private static Node.Id id(int i) + { + return new Node.Id(i); + } + + private static Set idSet(int... ids) + { + Set result = new HashSet<>(); + for (int id: ids) + result.add(id(id)); + return result; + } + + private static InetAddressAndPort ep(int i) + { + try + { + return InetAddressAndPort.getByName(String.format("127.0.0.%s:7012", i)); + } + catch (UnknownHostException e) + { + throw new RuntimeException(e); + } + } + + private static Set epSet(int... eps) + { + Set result = new HashSet<>(); + for (int ep: eps) + result.add(ep(ep)); + return result; + } + + @Test + public void downNodesRemovedFromFastPath() throws Throwable + { + try (Cluster cluster = init(Cluster.build(3) + .withoutVNodes() + .withConfig(c -> c.with(Feature.NETWORK).set("accord.enabled", "true")) + .start())) + { + cluster.schemaChange("CREATE KEYSPACE ks WITH replication={'class':'SimpleStrategy', 'replication_factor': 3}"); + cluster.schemaChange("CREATE TABLE ks.tbl (k int, c int, v int, primary key (k, c))"); + String query = "BEGIN TRANSACTION\n" + + " SELECT * FROM ks.tbl WHERE k=0 AND c=0;\n" + + "COMMIT TRANSACTION"; + cluster.coordinator(1).executeWithResult(query, ConsistencyLevel.ANY); + + InetAddressAndPort node1Addr = InetAddressAndPort.getByAddress(cluster.get(1).broadcastAddress()); + InetAddressAndPort node2Addr = InetAddressAndPort.getByAddress(cluster.get(2).broadcastAddress()); + InetAddressAndPort node3Addr = InetAddressAndPort.getByAddress(cluster.get(3).broadcastAddress()); + int node3Id = cluster.get(3).callOnInstance(() -> ClusterMetadata.current().directory.peerId(FBUtilities.getBroadcastAddressAndPort()).id()); + long preShutDownEpoch = cluster.stream().map(ii -> ii.callOnInstance(() -> { + ClusterMetadata cm = ClusterMetadata.current(); + AccordFastPath accordFastPath = cm.accordFastPath; + Assert.assertEquals(idSet(), accordFastPath.unavailableIds()); + + long epoch = cm.epoch.getEpoch(); + AccordConfigurationService configService = ((AccordService) AccordService.instance()).configurationService(); + Topology topology = configService.getTopologyForEpoch(epoch); + Assert.assertFalse(topology.shards().isEmpty()); + topology.shards().forEach(shard -> Assert.assertEquals(idSet(1, 2, 3), shard.fastPathElectorate)); + return cm.epoch.getEpoch(); + })).max(Comparator.naturalOrder()).get(); + + cluster.get(1).runOnInstance(() -> { + FailureDetector.instance.forceConviction(InetAddressAndPort.getByAddress(node3Addr)); + // update is performed in another thread, wait for it to be applied locally before returning + for (int i=0; i<10; i++) + { + if (ClusterMetadata.current().epoch.getEpoch() == preShutDownEpoch) + FBUtilities.sleepQuietly(100); + else + break; + } + assert ClusterMetadata.current().epoch.getEpoch() > preShutDownEpoch; + }); + + cluster.get(1, 2).forEach(ii -> { + logger.info("Checking instance {} -> {}", ii, ii.broadcastAddress()); + ii.runOnInstance(() -> { + ClusterMetadataService.instance().fetchLogFromCMS(Epoch.create(preShutDownEpoch + 1)); + ClusterMetadata cm = ClusterMetadata.current(); + AccordFastPath accordFastPath = cm.accordFastPath; + Assert.assertEquals(preShutDownEpoch + 1, cm.epoch.getEpoch()); + Assert.assertEquals(idSet(node3Id), accordFastPath.unavailableIds()); + }); + + } + ); + + // confirm a duplicate conviction doesn't create a new epoch + cluster.get(2).runOnInstance(() -> { + FailureDetector.instance.forceConviction(InetAddressAndPort.getByAddress(node3Addr)); + }); + + cluster.get(1, 2).forEach(ii -> ii.runOnInstance(() -> { + ClusterMetadata cm = ClusterMetadata.current(); + Assert.assertEquals(preShutDownEpoch + 1, cm.epoch.getEpoch()); + })); + } + } +} diff --git a/test/distributed/org/apache/cassandra/distributed/test/accord/AccordTestBase.java b/test/distributed/org/apache/cassandra/distributed/test/accord/AccordTestBase.java index 8010a7e581..9cb218dab3 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/accord/AccordTestBase.java +++ b/test/distributed/org/apache/cassandra/distributed/test/accord/AccordTestBase.java @@ -30,6 +30,7 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.StreamSupport; +import accord.coordinate.Invalidated; import com.google.common.base.Splitter; import com.google.common.primitives.Ints; import org.junit.After; @@ -85,7 +86,8 @@ public abstract class AccordTestBase extends TestBaseImpl protected static Cluster SHARED_CLUSTER; - protected String currentTable; + protected String tableName; + protected String qualifiedTableName; public static void setupCluster(Function options, int nodes) throws IOException { @@ -102,7 +104,8 @@ public abstract class AccordTestBase extends TestBaseImpl @Before public void setup() { - currentTable = KEYSPACE + ".tbl" + COUNTER.getAndIncrement(); + tableName = "tbl" + COUNTER.getAndIncrement(); + qualifiedTableName = KEYSPACE + '.' + tableName; } @After @@ -129,11 +132,17 @@ public abstract class AccordTestBase extends TestBaseImpl test(Collections.singletonList(tableDDL), fn); } + public static void ensureTableIsAccordManaged(Cluster cluster, String ksname, String tableName) + { + cluster.get(1).runOnInstance(() -> AccordService.instance().ensureTableIsAccordManaged(ksname, tableName)); + } + protected void test(List ddls, FailingConsumer fn) throws Exception { for (String ddl : ddls) SHARED_CLUSTER.schemaChange(ddl); + ensureTableIsAccordManaged(SHARED_CLUSTER, KEYSPACE, tableName); // Evict commands from the cache immediately to expose problems loading from disk. SHARED_CLUSTER.forEach(node -> node.runOnInstance(() -> AccordService.instance().setCacheSize(0))); @@ -149,7 +158,7 @@ public abstract class AccordTestBase extends TestBaseImpl protected void test(FailingConsumer fn) throws Exception { - test("CREATE TABLE " + currentTable + " (k int, c int, v int, primary key (k, c))", fn); + test("CREATE TABLE " + qualifiedTableName + " (k int, c int, v int, primary key (k, c))", fn); } protected static ConsensusMigrationState getMigrationStateSnapshot(IInvokableInstance instance) throws IOException @@ -331,6 +340,12 @@ public abstract class AccordTestBase extends TestBaseImpl return result; } + private static boolean hasRootCause(RuntimeException ex, Class klass) + { + return AssertionUtils.rootCauseIs(klass).matches(ex); + + } + private static SimpleQueryResult executeWithRetry0(int count, Cluster cluster, String check, Object... boundValues) { try @@ -339,7 +354,7 @@ public abstract class AccordTestBase extends TestBaseImpl } catch (RuntimeException ex) { - if (count <= MAX_RETRIES && (AssertionUtils.rootCauseIs(ReadPreemptedException.class).matches(ex) || AssertionUtils.rootCauseIs(WritePreemptedException.class).matches(ex))) + if (count <= MAX_RETRIES && (hasRootCause(ex, ReadPreemptedException.class) || hasRootCause(ex, WritePreemptedException.class) || hasRootCause(ex, Invalidated.class))) { logger.warn("[Retry attempt={}] Preempted failure for\n{}", count, check); return executeWithRetry0(count + 1, cluster, check, boundValues); diff --git a/test/distributed/org/apache/cassandra/distributed/test/log/ClusterMetadataTestHelper.java b/test/distributed/org/apache/cassandra/distributed/test/log/ClusterMetadataTestHelper.java index de4b6541ed..381ea8c6be 100644 --- a/test/distributed/org/apache/cassandra/distributed/test/log/ClusterMetadataTestHelper.java +++ b/test/distributed/org/apache/cassandra/distributed/test/log/ClusterMetadataTestHelper.java @@ -63,12 +63,13 @@ import org.apache.cassandra.tcm.RegistrationStatus; import org.apache.cassandra.tcm.Transformation; import org.apache.cassandra.tcm.log.LocalLog; import org.apache.cassandra.tcm.membership.Directory; +import org.apache.cassandra.service.accord.AccordFastPath; import org.apache.cassandra.tcm.membership.Location; import org.apache.cassandra.tcm.membership.NodeAddresses; import org.apache.cassandra.tcm.membership.NodeId; import org.apache.cassandra.tcm.membership.NodeState; import org.apache.cassandra.tcm.membership.NodeVersion; -import org.apache.cassandra.tcm.ownership.AccordKeyspaces; +import org.apache.cassandra.tcm.ownership.AccordTables; import org.apache.cassandra.tcm.ownership.DataPlacements; import org.apache.cassandra.tcm.ownership.TokenMap; import org.apache.cassandra.tcm.ownership.UniformRangePlacement; @@ -149,7 +150,8 @@ public class ClusterMetadataTestHelper Directory.EMPTY, new TokenMap(partitioner), DataPlacements.empty(), - AccordKeyspaces.EMPTY, + AccordTables.EMPTY, + AccordFastPath.EMPTY, LockedRanges.EMPTY, InProgressSequences.EMPTY, null, @@ -164,7 +166,8 @@ public class ClusterMetadataTestHelper null, null, DataPlacements.empty(), - AccordKeyspaces.EMPTY, + AccordTables.EMPTY, + AccordFastPath.EMPTY, null, null, null, @@ -179,7 +182,8 @@ public class ClusterMetadataTestHelper null, null, DataPlacements.empty(), - AccordKeyspaces.EMPTY, + AccordTables.EMPTY, + AccordFastPath.EMPTY, null, null, null, diff --git a/test/simulator/test/org/apache/cassandra/simulator/test/AccordJournalSimulationTest.java b/test/simulator/test/org/apache/cassandra/simulator/test/AccordJournalSimulationTest.java index c73eead744..f4739bca6d 100644 --- a/test/simulator/test/org/apache/cassandra/simulator/test/AccordJournalSimulationTest.java +++ b/test/simulator/test/org/apache/cassandra/simulator/test/AccordJournalSimulationTest.java @@ -207,7 +207,7 @@ public class AccordJournalSimulationTest extends SimulationTestBase private static TxnRequest toRequest(int event) { TxnId id = toTxnId(event); - Ranges ranges = Ranges.of(new TokenRange(AccordRoutingKey.SentinelKey.min("system"), AccordRoutingKey.SentinelKey.max("system"))); + Ranges ranges = Ranges.of(new TokenRange(AccordRoutingKey.SentinelKey.min(tableId), AccordRoutingKey.SentinelKey.max(tableId))); Topologies topologies = Utils.topologies(TopologyUtils.initialTopology(new Node.Id[] {node}, ranges, 3)); Keys keys = Keys.of(toKey(0)); Txn txn = new Txn.InMemory(keys, new TxnRead(new TxnNamedRead[0], keys, null), TxnQuery.ALL, new NoopUpdate()); @@ -222,7 +222,7 @@ public class AccordJournalSimulationTest extends SimulationTestBase private static PartitionKey toKey(int a) { - return new PartitionKey(KEYSPACE, tableId, Murmur3Partitioner.instance.decorateKey(ByteBufferUtil.bytes(a))); + return new PartitionKey(tableId, Murmur3Partitioner.instance.decorateKey(ByteBufferUtil.bytes(a))); } private static final TableId tableId = TableId.fromUUID(new UUID(0, 0)); @@ -233,7 +233,7 @@ public class AccordJournalSimulationTest extends SimulationTestBase return new FullKeyRoute(key, true, new RoutingKey[]{ key }); } - private static final RoutingKey key = new AccordRoutingKey.TokenKey("system", new Murmur3Partitioner.LongToken(42)); + private static final RoutingKey key = new AccordRoutingKey.TokenKey(tableId, new Murmur3Partitioner.LongToken(42)); } public static class NoopUpdate implements Update diff --git a/test/unit/org/apache/cassandra/cql3/statements/DescribeStatementTest.java b/test/unit/org/apache/cassandra/cql3/statements/DescribeStatementTest.java index 2d5d1aadb2..ccf3d9a288 100644 --- a/test/unit/org/apache/cassandra/cql3/statements/DescribeStatementTest.java +++ b/test/unit/org/apache/cassandra/cql3/statements/DescribeStatementTest.java @@ -291,11 +291,11 @@ public class DescribeStatementTest extends CQLTester row(KEYSPACE, "keyspace", KEYSPACE, "CREATE KEYSPACE " + KEYSPACE + " WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'}" + - " AND durable_writes = true;"), + " AND durable_writes = true AND fast_path = 'simple';"), row(KEYSPACE_PER_TEST, "keyspace", KEYSPACE_PER_TEST, "CREATE KEYSPACE " + KEYSPACE_PER_TEST + " WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'}" + - " AND durable_writes = true;"), + " AND durable_writes = true AND fast_path = 'simple';"), row("test", "keyspace", "test", keyspaceOutput()), row("test", "table", "has_all_types", allTypesTable()), row("test", "table", "\"Test\"", testTableOutput()), @@ -697,7 +697,8 @@ public class DescribeStatementTest extends CQLTester assertRowsNet(executeDescribeNet(KEYSPACE_PER_TEST, "DESCRIBE KEYSPACE " + KEYSPACE_PER_TEST), row(KEYSPACE_PER_TEST, "keyspace", KEYSPACE_PER_TEST, "CREATE KEYSPACE " + KEYSPACE_PER_TEST + " WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'}" + - " AND durable_writes = true;"), + " AND durable_writes = true" + + " AND fast_path = 'simple';"), row(KEYSPACE_PER_TEST, "type", type2, "CREATE TYPE " + KEYSPACE_PER_TEST + "." + type2 + " (\n" + " x text,\n" + " y text\n" + @@ -802,7 +803,8 @@ public class DescribeStatementTest extends CQLTester String expectedKeyspaceStmt = "CREATE KEYSPACE " + KEYSPACE_PER_TEST + " WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'}" + - " AND durable_writes = true;"; + " AND durable_writes = true" + + " AND fast_path = 'simple';"; String expectedTableStmt = "CREATE TABLE " + KEYSPACE_PER_TEST + "." + table + " (\n" + " id int PRIMARY KEY,\n" + @@ -1130,6 +1132,7 @@ public class DescribeStatementTest extends CQLTester " AND compression = {'chunk_length_in_kb': '16', 'class': 'org.apache.cassandra.io.compress.LZ4Compressor'}\n" + " AND memtable = 'default'\n" + " AND crc_check_chance = 1.0\n" + + " AND fast_path = 'keyspace'\n" + " AND default_time_to_live = 0\n" + " AND extensions = {}\n" + " AND gc_grace_seconds = 864000\n" + @@ -1170,7 +1173,7 @@ public class DescribeStatementTest extends CQLTester private static String keyspaceOutput() { - return "CREATE KEYSPACE test WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'} AND durable_writes = true;"; + return "CREATE KEYSPACE test WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'} AND durable_writes = true AND fast_path = 'simple';"; } private void describeError(String cql, String msg) throws Throwable diff --git a/test/unit/org/apache/cassandra/db/SchemaCQLHelperTest.java b/test/unit/org/apache/cassandra/db/SchemaCQLHelperTest.java index d045584412..d0d2295e42 100644 --- a/test/unit/org/apache/cassandra/db/SchemaCQLHelperTest.java +++ b/test/unit/org/apache/cassandra/db/SchemaCQLHelperTest.java @@ -22,6 +22,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.io.Files; +import org.apache.cassandra.service.accord.fastpath.FastPathStrategy; import org.junit.Assert; import org.junit.Test; @@ -309,6 +310,7 @@ public class SchemaCQLHelperTest extends CQLTester .compaction(CompactionParams.lcs(Collections.singletonMap("sstable_size_in_mb", "1"))) .compression(CompressionParams.lz4(1 << 16, 1 << 15)) .crcCheckChance(0.3) + .fastPath(FastPathStrategy.simple()) .defaultTimeToLive(4) .gcGraceSeconds(5) .minIndexInterval(6) @@ -336,6 +338,7 @@ public class SchemaCQLHelperTest extends CQLTester " AND compression = {'chunk_length_in_kb': '64', 'class': 'org.apache.cassandra.io.compress.LZ4Compressor', 'min_compress_ratio': '2.0'}\n" + " AND memtable = 'default'\n" + " AND crc_check_chance = 0.3\n" + + " AND fast_path = 'simple'\n" + " AND default_time_to_live = 4\n" + " AND extensions = {'ext1': 0x76616c31}\n" + " AND gc_grace_seconds = 5\n" + diff --git a/test/unit/org/apache/cassandra/dht/BootStrapperTest.java b/test/unit/org/apache/cassandra/dht/BootStrapperTest.java index 00885d8c1f..9739d3ed59 100644 --- a/test/unit/org/apache/cassandra/dht/BootStrapperTest.java +++ b/test/unit/org/apache/cassandra/dht/BootStrapperTest.java @@ -212,7 +212,8 @@ public class BootStrapperTest extends CassandraTestBase false, 1, movements.left, - movements.right); + movements.right, + true); } private boolean includesWraparound(Collection> toFetch) diff --git a/test/unit/org/apache/cassandra/dht/PartitionerTestCase.java b/test/unit/org/apache/cassandra/dht/PartitionerTestCase.java index ace18db549..1d68475cd9 100644 --- a/test/unit/org/apache/cassandra/dht/PartitionerTestCase.java +++ b/test/unit/org/apache/cassandra/dht/PartitionerTestCase.java @@ -37,6 +37,7 @@ import org.apache.cassandra.service.StorageService; import org.apache.cassandra.service.accord.TokenRange; import org.apache.cassandra.service.accord.api.AccordRoutingKey.TokenKey; +import static org.apache.cassandra.service.accord.AccordTestUtils.TABLE_ID1; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; @@ -288,9 +289,9 @@ public abstract class PartitionerTestCase if (less.equals(more) && less.isMinimum()) ranges = Ranges.EMPTY; else if (less.equals(more)) - ranges = Ranges.of(new TokenRange(new TokenKey("", partitioner.getMinimumToken()), new TokenKey("", less))); + ranges = Ranges.of(new TokenRange(new TokenKey(TABLE_ID1, partitioner.getMinimumToken()), new TokenKey(TABLE_ID1, less))); else - ranges = Ranges.of(new TokenRange(new TokenKey("", less), new TokenKey("", more))); + ranges = Ranges.of(new TokenRange(new TokenKey(TABLE_ID1, less), new TokenKey(TABLE_ID1, more))); AccordSplitter splitter = partitioner.accordSplitter().apply(ranges); BigInteger lv = splitter.valueForToken(less); @@ -303,11 +304,11 @@ public abstract class PartitionerTestCase void testSplitter(Token start, Token end) { - accord.primitives.Range range = new TokenRange(new TokenKey("", start), new TokenKey("", end)); + accord.primitives.Range range = new TokenRange(new TokenKey(TABLE_ID1, start), new TokenKey(TABLE_ID1, end)); AccordSplitter splitter = partitioner.accordSplitter().apply(Ranges.of(range)); if (!start.isMinimum()) - testSplitter(new TokenRange(new TokenKey("", partitioner.getMinimumToken()), new TokenKey("", start))); - testSplitter(new TokenRange(new TokenKey("", start), new TokenKey("", splitter.tokenForValue(splitter.maximumValue())))); + testSplitter(new TokenRange(new TokenKey(TABLE_ID1, partitioner.getMinimumToken()), new TokenKey(TABLE_ID1, start))); + testSplitter(new TokenRange(new TokenKey(TABLE_ID1, start), new TokenKey(TABLE_ID1, splitter.tokenForValue(splitter.maximumValue())))); checkRoundTrip(start, splitter.tokenForValue(splitter.valueForToken(start))); checkRoundTrip(end, splitter.tokenForValue(splitter.valueForToken(end))); } diff --git a/test/unit/org/apache/cassandra/locator/AssureSufficientLiveNodesTest.java b/test/unit/org/apache/cassandra/locator/AssureSufficientLiveNodesTest.java index 20da42dd12..008c3854e2 100644 --- a/test/unit/org/apache/cassandra/locator/AssureSufficientLiveNodesTest.java +++ b/test/unit/org/apache/cassandra/locator/AssureSufficientLiveNodesTest.java @@ -32,6 +32,7 @@ import java.util.function.Supplier; import com.google.common.collect.ImmutableList; import com.google.common.util.concurrent.Uninterruptibles; +import org.apache.cassandra.schema.*; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; @@ -45,10 +46,6 @@ import org.apache.cassandra.dht.Murmur3Partitioner; import org.apache.cassandra.dht.Token; import org.apache.cassandra.distributed.test.log.ClusterMetadataTestHelper; import org.apache.cassandra.exceptions.UnavailableException; -import org.apache.cassandra.schema.KeyspaceMetadata; -import org.apache.cassandra.schema.KeyspaceParams; -import org.apache.cassandra.schema.SchemaTestUtil; -import org.apache.cassandra.schema.Tables; import org.apache.cassandra.service.reads.NeverSpeculativeRetryPolicy; import org.apache.cassandra.service.reads.ReadCoordinator; import org.apache.cassandra.utils.FBUtilities; @@ -82,6 +79,7 @@ public class AssureSufficientLiveNodesTest extends CassandraTestBase private static final String DC3 = "datacenter3"; private static final int RACE_TEST_LOOPS = 100; private static final Token tk = new Murmur3Partitioner.LongToken(0); + private static final TableId TABLE_ID = TableId.generate(); @BeforeClass public static void setUpClass() throws Throwable @@ -140,7 +138,7 @@ public class AssureSufficientLiveNodesTest extends CassandraTestBase // alter to KeyspaceParams.nts(DC1, 3, DC2, 3), // test - keyspace -> ReplicaPlans.forRead(keyspace, tk, null, EACH_QUORUM, NeverSpeculativeRetryPolicy.INSTANCE, ReadCoordinator.DEFAULT) + keyspace -> ReplicaPlans.forRead(keyspace, TABLE_ID, tk, null, EACH_QUORUM, NeverSpeculativeRetryPolicy.INSTANCE, ReadCoordinator.DEFAULT) ); } @@ -173,7 +171,7 @@ public class AssureSufficientLiveNodesTest extends CassandraTestBase // alter to KeyspaceParams.nts(DC1, 3, DC2, 3), // test - keyspace -> ReplicaPlans.forRead(keyspace, tk, null, QUORUM, NeverSpeculativeRetryPolicy.INSTANCE, ReadCoordinator.DEFAULT) + keyspace -> ReplicaPlans.forRead(keyspace, TABLE_ID, tk, null, QUORUM, NeverSpeculativeRetryPolicy.INSTANCE, ReadCoordinator.DEFAULT) ); raceOfReplicationStrategyTest( // init. The # of live endpoints is 3 = 2 + 1 @@ -181,7 +179,7 @@ public class AssureSufficientLiveNodesTest extends CassandraTestBase // alter to. (3 + 3) / 2 + 1 > 3 KeyspaceParams.nts(DC1, 2, DC2, 1, DC3, 3), // test - keyspace -> ReplicaPlans.forRead(keyspace, tk, null, QUORUM, NeverSpeculativeRetryPolicy.INSTANCE, ReadCoordinator.DEFAULT) + keyspace -> ReplicaPlans.forRead(keyspace, TABLE_ID, tk, null, QUORUM, NeverSpeculativeRetryPolicy.INSTANCE, ReadCoordinator.DEFAULT) ); } @@ -205,7 +203,7 @@ public class AssureSufficientLiveNodesTest extends CassandraTestBase // alter to KeyspaceParams.nts(DC1, 3), // test - keyspace -> ReplicaPlans.forRead(keyspace, tk, null, EACH_QUORUM, NeverSpeculativeRetryPolicy.INSTANCE, ReadCoordinator.DEFAULT) + keyspace -> ReplicaPlans.forRead(keyspace, TABLE_ID, tk, null, EACH_QUORUM, NeverSpeculativeRetryPolicy.INSTANCE, ReadCoordinator.DEFAULT) ); } @@ -229,7 +227,7 @@ public class AssureSufficientLiveNodesTest extends CassandraTestBase // alter to KeyspaceParams.nts(DC1, 3), // test - keyspace -> ReplicaPlans.forRead(keyspace, tk, null, LOCAL_QUORUM, NeverSpeculativeRetryPolicy.INSTANCE, ReadCoordinator.DEFAULT) + keyspace -> ReplicaPlans.forRead(keyspace, TABLE_ID, tk, null, LOCAL_QUORUM, NeverSpeculativeRetryPolicy.INSTANCE, ReadCoordinator.DEFAULT) ); } diff --git a/test/unit/org/apache/cassandra/locator/MetaStrategyTest.java b/test/unit/org/apache/cassandra/locator/MetaStrategyTest.java index babb7d659b..63f91b6729 100644 --- a/test/unit/org/apache/cassandra/locator/MetaStrategyTest.java +++ b/test/unit/org/apache/cassandra/locator/MetaStrategyTest.java @@ -26,6 +26,8 @@ import java.util.Map; import java.util.Set; import com.google.common.collect.ImmutableMap; +import org.apache.cassandra.service.accord.AccordFastPath; +import org.apache.cassandra.tcm.ownership.AccordTables; import org.junit.Assert; import org.junit.Test; @@ -39,7 +41,6 @@ import org.apache.cassandra.tcm.membership.Directory; import org.apache.cassandra.tcm.membership.Location; import org.apache.cassandra.tcm.membership.NodeAddresses; import org.apache.cassandra.tcm.membership.NodeId; -import org.apache.cassandra.tcm.ownership.AccordKeyspaces; import org.apache.cassandra.tcm.ownership.DataPlacements; import org.apache.cassandra.tcm.ownership.TokenMap; import org.apache.cassandra.tcm.sequences.InProgressSequences; @@ -89,7 +90,8 @@ public class MetaStrategyTest directory, tokenMap, DataPlacements.EMPTY, - AccordKeyspaces.EMPTY, + AccordTables.EMPTY, + AccordFastPath.EMPTY, LockedRanges.EMPTY, InProgressSequences.EMPTY, ConsensusMigrationState.EMPTY, diff --git a/test/unit/org/apache/cassandra/schema/FastPathSchemaTest.java b/test/unit/org/apache/cassandra/schema/FastPathSchemaTest.java new file mode 100644 index 0000000000..1a2dc1132d --- /dev/null +++ b/test/unit/org/apache/cassandra/schema/FastPathSchemaTest.java @@ -0,0 +1,121 @@ +/* + * 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.schema; + +import java.util.Arrays; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import org.apache.cassandra.ServerTestUtils; +import org.apache.cassandra.config.DatabaseDescriptor; +import org.apache.cassandra.cql3.QueryProcessor; +import org.apache.cassandra.db.ConsistencyLevel; +import org.apache.cassandra.exceptions.ConfigurationException; +import org.apache.cassandra.service.accord.fastpath.FastPathStrategy; +import org.apache.cassandra.service.accord.fastpath.ParameterizedFastPathStrategy; +import org.apache.cassandra.tcm.ClusterMetadata; +import org.apache.cassandra.tcm.Epoch; +import org.apache.cassandra.tcm.transformations.AddAccordTable; + +import static java.lang.String.format; + +public class FastPathSchemaTest +{ + private static String KEYSPACE = "ks"; + private static int ksCount = 0; + + @BeforeClass + public static void setupClass() + { + DatabaseDescriptor.daemonInitialization(); + ServerTestUtils.prepareServer(); + SchemaTestUtil.addOrUpdateKeyspace(KeyspaceMetadata.create(KEYSPACE, KeyspaceParams.simple(1), Tables.of())); + } + + @Before + public void setup() + { + KEYSPACE = format("ks_%s", ksCount++); + } + + + private static void process(String fmt, Object... objects) + { + QueryProcessor.process(format(fmt, objects), ConsistencyLevel.ANY); + } + + @Test + public void keyspaceInheriting() + { + process("CREATE KEYSPACE %s with replication={'class':'SimpleStrategy', 'replication_factor':1} AND fast_path='simple'", KEYSPACE); + KeyspaceMetadata ksm = Schema.instance.getKeyspaceMetadata(KEYSPACE); + Assert.assertSame(FastPathStrategy.simple(), ksm.params.fastPath); + + process("CREATE TABLE %s.tbl (k int primary key, v int)", KEYSPACE); + TableMetadata tbm = Schema.instance.getTableMetadata(KEYSPACE, "tbl"); + Assert.assertSame(FastPathStrategy.inheritKeyspace(), tbm.params.fastPath); + + Epoch epoch = ClusterMetadata.current().epoch; + AddAccordTable.addTable(tbm.id); + + Assert.assertEquals(epoch.getEpoch() + 1, ClusterMetadata.current().epoch.getEpoch()); + } + + @Test + public void keyspaceModification() + { + process("CREATE KEYSPACE %s with replication={'class':'SimpleStrategy', 'replication_factor':1} AND fast_path='simple'", KEYSPACE); + KeyspaceMetadata ksm = Schema.instance.getKeyspaceMetadata(KEYSPACE); + Assert.assertSame(FastPathStrategy.simple(), ksm.params.fastPath); + process("ALTER KEYSPACE %s with fast_path={'size':2, 'dcs':'dc1,dc2'}", KEYSPACE); + + ksm = Schema.instance.getKeyspaceMetadata(KEYSPACE); + Assert.assertSame(FastPathStrategy.Kind.PARAMETERIZED, ksm.params.fastPath.kind()); + ParameterizedFastPathStrategy strategy = (ParameterizedFastPathStrategy) ksm.params.fastPath; + Assert.assertEquals(2, strategy.size); + Assert.assertEquals(Arrays.asList("dc1", "dc2"), strategy.dcStrings()); + } + + @Test(expected = ConfigurationException.class) + public void keyspaceInheritingFailure() + { + process("CREATE KEYSPACE %s with replication={'class':'SimpleStrategy', 'replication_factor':1} AND fast_path='keyspace'", KEYSPACE); + } + + @Test + public void tableModification() + { + process("CREATE KEYSPACE %s with replication={'class':'SimpleStrategy', 'replication_factor':1} AND fast_path='simple'", KEYSPACE); + KeyspaceMetadata ksm = Schema.instance.getKeyspaceMetadata(KEYSPACE); + Assert.assertSame(FastPathStrategy.simple(), ksm.params.fastPath); + + process("CREATE TABLE %s.tbl (k int primary key, v int)", KEYSPACE); + TableMetadata tbm = Schema.instance.getTableMetadata(KEYSPACE, "tbl"); + Assert.assertSame(FastPathStrategy.inheritKeyspace(), tbm.params.fastPath); + + AddAccordTable.addTable(tbm.id); + + process("ALTER TABLE %s.tbl WITH fast_path='simple'", KEYSPACE); + tbm = Schema.instance.getTableMetadata(KEYSPACE, "tbl"); + Assert.assertSame(FastPathStrategy.simple(), tbm.params.fastPath); + } +} diff --git a/test/unit/org/apache/cassandra/service/accord/AccordCommandStoreTest.java b/test/unit/org/apache/cassandra/service/accord/AccordCommandStoreTest.java index 5131689845..c47f61987d 100644 --- a/test/unit/org/apache/cassandra/service/accord/AccordCommandStoreTest.java +++ b/test/unit/org/apache/cassandra/service/accord/AccordCommandStoreTest.java @@ -61,7 +61,9 @@ import org.apache.cassandra.cql3.QueryProcessor; import org.apache.cassandra.db.ColumnFamilyStore; import org.apache.cassandra.db.Keyspace; import org.apache.cassandra.schema.KeyspaceParams; +import org.apache.cassandra.schema.Schema; import org.apache.cassandra.schema.SchemaConstants; +import org.apache.cassandra.schema.TableId; import org.apache.cassandra.service.StorageService; import org.apache.cassandra.service.accord.AccordCachingState.Modified; import org.apache.cassandra.service.accord.api.PartitionKey; @@ -108,6 +110,7 @@ public class AccordCommandStoreTest AccordCommandStore commandStore = createAccordCommandStore(clock::incrementAndGet, "ks", "tbl"); QueryProcessor.executeInternal("INSERT INTO ks.tbl (k, c, v) VALUES (0, 0, 1)"); + TableId tableId = Schema.instance.getTableMetadata("ks", "tbl").id; TxnId oldTxnId1 = txnId(1, clock.incrementAndGet(), 1); TxnId oldTxnId2 = txnId(1, clock.incrementAndGet(), 1); TxnId oldTimestamp = txnId(1, clock.incrementAndGet(), 1); @@ -147,7 +150,7 @@ public class AccordCommandStoreTest Apply apply = Apply.SerializationSupport.create(txnId, - route.slice(Ranges.of(TokenRange.fullRange("ks"))), + route.slice(Ranges.of(TokenRange.fullRange(tableId))), 1L, Apply.Kind.Minimal, depTxn.keys(), diff --git a/test/unit/org/apache/cassandra/service/accord/AccordCommandTest.java b/test/unit/org/apache/cassandra/service/accord/AccordCommandTest.java index 516a89345a..0bd628903a 100644 --- a/test/unit/org/apache/cassandra/service/accord/AccordCommandTest.java +++ b/test/unit/org/apache/cassandra/service/accord/AccordCommandTest.java @@ -81,7 +81,7 @@ public class AccordCommandTest private static PartitionKey key(int k) { TableMetadata metadata = Schema.instance.getTableMetadata("ks", "tbl"); - return new PartitionKey(metadata.keyspace, metadata.id, metadata.partitioner.decorateKey(ByteBufferUtil.bytes(k))); + return new PartitionKey(metadata.id, metadata.partitioner.decorateKey(ByteBufferUtil.bytes(k))); } /** diff --git a/test/unit/org/apache/cassandra/service/accord/AccordConfigurationServiceTest.java b/test/unit/org/apache/cassandra/service/accord/AccordConfigurationServiceTest.java index 3cf9da57c1..3a0e0c7cb7 100644 --- a/test/unit/org/apache/cassandra/service/accord/AccordConfigurationServiceTest.java +++ b/test/unit/org/apache/cassandra/service/accord/AccordConfigurationServiceTest.java @@ -182,7 +182,7 @@ public class AccordConfigurationServiceTest Assert.assertEquals(null, AccordKeyspace.loadEpochDiskState()); Assert.assertTrue(executeInternal(format("SELECT * FROM %s.%s WHERE epoch=1", ACCORD_KEYSPACE_NAME, TOPOLOGIES)).isEmpty()); - Topology topology1 = new Topology(1, new Shard(AccordTopologyUtils.fullRange("ks"), ID_LIST, ID_SET)); + Topology topology1 = new Topology(1, new Shard(AccordTopology.fullRange(TBL1), ID_LIST, ID_SET)); service.reportTopology(topology1); loadEpoch(1, (epoch, topology, syncStatus, pendingSync, remoteSync, closed, redundant) -> { Assert.assertEquals(topology1, topology); @@ -204,7 +204,7 @@ public class AccordConfigurationServiceTest AccordConfigurationService service = new AccordConfigurationService(ID1, new Messaging(), new MockFailureDetector()); service.start(); - Topology topology1 = new Topology(1, new Shard(AccordTopologyUtils.fullRange("ks"), ID_LIST, ID_SET)); + Topology topology1 = new Topology(1, new Shard(AccordTopology.fullRange(TBL1), ID_LIST, ID_SET)); service.updateMapping(mappingForEpoch(ClusterMetadata.current().epoch.getEpoch() + 1)); service.reportTopology(topology1); service.acknowledgeEpoch(EpochReady.done(1), true); @@ -212,12 +212,12 @@ public class AccordConfigurationServiceTest service.receiveRemoteSyncComplete(ID2, 1); service.receiveRemoteSyncComplete(ID3, 1); - Topology topology2 = new Topology(2, new Shard(AccordTopologyUtils.fullRange("ks"), ID_LIST, of(ID1, ID2))); + Topology topology2 = new Topology(2, new Shard(AccordTopology.fullRange(TBL1), ID_LIST, of(ID1, ID2))); service.reportTopology(topology2); service.acknowledgeEpoch(EpochReady.done(2), true); service.receiveRemoteSyncComplete(ID1, 2); - Topology topology3 = new Topology(3, new Shard(AccordTopologyUtils.fullRange("ks"), ID_LIST, of(ID1, ID2))); + Topology topology3 = new Topology(3, new Shard(AccordTopology.fullRange(TBL1), ID_LIST, of(ID1, ID2))); service.reportTopology(topology3); service.acknowledgeEpoch(EpochReady.done(3), true); @@ -245,14 +245,14 @@ public class AccordConfigurationServiceTest service.registerListener(serviceListener); service.start(); - Topology topology1 = new Topology(1, new Shard(AccordTopologyUtils.fullRange("ks"), ID_LIST, ID_SET)); + Topology topology1 = new Topology(1, new Shard(AccordTopology.fullRange(TBL1), ID_LIST, ID_SET)); service.updateMapping(mappingForEpoch(ClusterMetadata.current().epoch.getEpoch() + 1)); service.reportTopology(topology1); - Topology topology2 = new Topology(2, new Shard(AccordTopologyUtils.fullRange("ks"), ID_LIST, of(ID1, ID2))); + Topology topology2 = new Topology(2, new Shard(AccordTopology.fullRange(TBL1), ID_LIST, of(ID1, ID2))); service.reportTopology(topology2); - Topology topology3 = new Topology(3, new Shard(AccordTopologyUtils.fullRange("ks"), ID_LIST, of(ID1, ID2))); + Topology topology3 = new Topology(3, new Shard(AccordTopology.fullRange(TBL1), ID_LIST, of(ID1, ID2))); service.reportTopology(topology3); service.truncateTopologiesUntil(3); Assert.assertEquals(EpochDiskState.create(3), service.diskState()); diff --git a/test/unit/org/apache/cassandra/service/accord/AccordFastPathCoordinatorTest.java b/test/unit/org/apache/cassandra/service/accord/AccordFastPathCoordinatorTest.java new file mode 100644 index 0000000000..1630b3c7c3 --- /dev/null +++ b/test/unit/org/apache/cassandra/service/accord/AccordFastPathCoordinatorTest.java @@ -0,0 +1,253 @@ +/* + * 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.service.accord; + +import accord.local.Node; +import accord.topology.Shard; +import accord.topology.Topology; +import com.google.common.collect.Iterables; +import org.apache.cassandra.config.DatabaseDescriptor; +import org.apache.cassandra.dht.IPartitioner; +import org.apache.cassandra.dht.Murmur3Partitioner; +import org.apache.cassandra.schema.*; +import org.apache.cassandra.service.accord.AccordFastPath.Status; +import org.apache.cassandra.tcm.ClusterMetadata; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +import static org.apache.cassandra.service.accord.AccordTestUtils.*; +import static org.apache.cassandra.service.accord.AccordTopologyTest.token; + +public class AccordFastPathCoordinatorTest +{ + private static final IPartitioner partitioner = Murmur3Partitioner.instance; + private static ClusterMetadata EMPTY; + + + public static final TableId TABLE_1 = TableId.fromString("00000000-0000-0000-0000-000000000001"); + + @BeforeClass + public static void beforeClass() throws Exception + { + DatabaseDescriptor.daemonInitialization(); + DatabaseDescriptor.setPartitionerUnsafe(partitioner); + EMPTY = new ClusterMetadata(partitioner); + } + + private static class CapturedUpdate + { + final Node.Id node; + final Status status; + + public CapturedUpdate(Node.Id node, Status status) + { + this.node = node; + this.status = status; + } + + @Override + public boolean equals(Object o) + { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CapturedUpdate that = (CapturedUpdate) o; + return Objects.equals(node, that.node) && status == that.status; + } + + @Override + public int hashCode() + { + return Objects.hash(node, status); + } + + @Override + public String toString() + { + return "CapturedUpdate{" + + "node=" + node + + ", status=" + status + + '}'; + } + } + + private static CapturedUpdate update(Node.Id node, Status status) + { + return new CapturedUpdate(node, status); + } + + private static class InstrumentedFastPathCoordinator extends AccordFastPathCoordinator + { + private ClusterMetadata currentMetadata = EMPTY; + private List capturedUpdates = new ArrayList<>(); + + public InstrumentedFastPathCoordinator(Node.Id localId) + { + super(localId); + } + + public InstrumentedFastPathCoordinator currentMetadata(ClusterMetadata currentMetadata) + { + this.currentMetadata = currentMetadata; + return this; + } + + @Override + ClusterMetadata currentMetadata() + { + return currentMetadata; + } + + @Override + void registerAsListener() + { + + } + + @Override + void updateFastPath(Node.Id node, Status status, long updateTimeMillis, long updateDelayMillis) + { + capturedUpdates.add(new CapturedUpdate(node, status)); + + } + + @Override + long getAccordFastPathUpdateDelayMillis() + { + return TimeUnit.SECONDS.toMillis(5); + } + } + + @Test + public void simpleAlive() + { + Topology topology = new Topology(1, + new Shard(AccordTopology.minRange(TABLE_1, token(0)), idList(0, 1, 2), idSet(0, 1, 2)), + new Shard(AccordTopology.maxRange(TABLE_1, token(0)), idList(3, 4, 5), idSet(3, 4, 5))); + + InstrumentedFastPathCoordinator coordinator = new InstrumentedFastPathCoordinator(id(0)); + coordinator.updatePeers(topology); + + // setup existing fast path state + coordinator.currentMetadata(EMPTY.transformer() + .withFastPathStatusSince(id(1), Status.UNAVAILABLE, 1, 1) + .withFastPathStatusSince(id(3), Status.UNAVAILABLE, 1, 1).build().metadata); + + Assert.assertTrue(coordinator.capturedUpdates.isEmpty()); + + + // peer isn't marked unavailable, shouldn't update + coordinator.onAlive(id(2)); + Assert.assertTrue(coordinator.capturedUpdates.isEmpty()); + + // node isn't a peer, shouldn't update + coordinator.onAlive(id(3)); + Assert.assertTrue(coordinator.capturedUpdates.isEmpty()); + + // node is a peer, should issue update + coordinator.onAlive(id(1)); + Assert.assertEquals(update(id(1), Status.NORMAL), Iterables.getOnlyElement(coordinator.capturedUpdates)); + } + + @Test + public void simpleDead() + { + Topology topology = new Topology(1, + new Shard(AccordTopology.minRange(TABLE_1, token(0)), idList(0, 1, 2), idSet(0, 1, 2)), + new Shard(AccordTopology.maxRange(TABLE_1, token(0)), idList(3, 4, 5), idSet(3, 4, 5))); + InstrumentedFastPathCoordinator coordinator = new InstrumentedFastPathCoordinator(id(0)); + coordinator.updatePeers(topology); + Assert.assertTrue(coordinator.capturedUpdates.isEmpty()); + + // not a peer, shouldn't update + coordinator.onDead(id(3)); + Assert.assertTrue(coordinator.capturedUpdates.isEmpty()); + + // is a peer, should update + coordinator.onDead(id(1)); + Assert.assertEquals(update(id(1), Status.UNAVAILABLE), Iterables.getOnlyElement(coordinator.capturedUpdates)); + } + + /** + * We shouldn't be scheduling updates if there aren't any accord tables + */ + @Test + public void noTableTest() + { + InstrumentedFastPathCoordinator coordinator = new InstrumentedFastPathCoordinator(id(0)); + coordinator.start(); + Assert.assertTrue(coordinator.capturedUpdates.isEmpty()); + + coordinator.onDead(id(1)); + Assert.assertTrue(coordinator.capturedUpdates.isEmpty()); + } + + /** + * node should mark itself as shutdown on shutdown + */ + @Test + public void selfShutdownTest() + { + InstrumentedFastPathCoordinator coordinator = new InstrumentedFastPathCoordinator(id(0)); + Assert.assertTrue(coordinator.capturedUpdates.isEmpty()); + + coordinator.onShutdown(); + Assert.assertEquals(update(id(0), Status.SHUTDOWN), Iterables.getOnlyElement(coordinator.capturedUpdates)); + } + + /** + * If a node finds itself marked shutdown on startup, it should mark itself normal + */ + @Test + public void startupTest() + { + InstrumentedFastPathCoordinator coordinator = new InstrumentedFastPathCoordinator(id(0)); + coordinator.currentMetadata(EMPTY.transformer().withFastPathStatusSince(id(0), Status.SHUTDOWN, 1, 1).build().metadata); + Assert.assertTrue(coordinator.capturedUpdates.isEmpty()); + coordinator.start(); + Assert.assertEquals(update(id(0), Status.NORMAL), Iterables.getOnlyElement(coordinator.capturedUpdates)); + } + + /** + * if a peer is marked as shutdown, other nodes should ignore FD signals until it marks itself alive again + */ + @Test + public void peerShutdownTest() + { + Topology topology = new Topology(1, + new Shard(AccordTopology.minRange(TABLE_1, token(0)), idList(0, 1, 2), idSet(0, 1, 2)), + new Shard(AccordTopology.maxRange(TABLE_1, token(0)), idList(3, 4, 5), idSet(3, 4, 5))); + InstrumentedFastPathCoordinator coordinator = new InstrumentedFastPathCoordinator(id(0)); + coordinator.currentMetadata(EMPTY.transformer().withFastPathStatusSince(id(1), Status.SHUTDOWN, 1, 1).build().metadata); + coordinator.updatePeers(topology); + Assert.assertTrue(coordinator.capturedUpdates.isEmpty()); + coordinator.start(); + + Assert.assertTrue(coordinator.isPeer(id(1))); + coordinator.onAlive(id(1)); + Assert.assertTrue(coordinator.capturedUpdates.isEmpty()); + coordinator.onDead(id(1)); + Assert.assertTrue(coordinator.capturedUpdates.isEmpty()); + } +} diff --git a/test/unit/org/apache/cassandra/service/accord/AccordKeyspaceTest.java b/test/unit/org/apache/cassandra/service/accord/AccordKeyspaceTest.java index 1cf6a6e680..52aff302e3 100644 --- a/test/unit/org/apache/cassandra/service/accord/AccordKeyspaceTest.java +++ b/test/unit/org/apache/cassandra/service/accord/AccordKeyspaceTest.java @@ -45,6 +45,8 @@ import accord.primitives.Txn; import accord.primitives.TxnId; import org.apache.cassandra.cql3.CQLTester; import org.apache.cassandra.db.Mutation; +import org.apache.cassandra.schema.Schema; +import org.apache.cassandra.schema.TableId; import org.apache.cassandra.service.accord.api.AccordRoutingKey; import org.assertj.core.api.Assertions; @@ -53,14 +55,14 @@ import static org.apache.cassandra.service.accord.AccordTestUtils.wrapInTxn; public class AccordKeyspaceTest extends CQLTester.InMemory { - private static final Ranges GLOBAL_SCOPE = Ranges.of(new TokenRange(AccordRoutingKey.SentinelKey.min(KEYSPACE), AccordRoutingKey.SentinelKey.max(KEYSPACE))); - @Test public void serde() { AtomicLong now = new AtomicLong(); String tableName = createTable("CREATE TABLE %s (k int, c int, v int, PRIMARY KEY (k, c))"); + TableId tableId = Schema.instance.getTableMetadata(KEYSPACE, tableName).id; + Ranges scope = Ranges.of(new TokenRange(AccordRoutingKey.SentinelKey.min(tableId), AccordRoutingKey.SentinelKey.max(tableId))); AccordCommandStore store = AccordTestUtils.createAccordCommandStore(now::incrementAndGet, KEYSPACE, tableName); @@ -68,25 +70,25 @@ public class AccordKeyspaceTest extends CQLTester.InMemory Txn txn = createTxn(wrapInTxn(String.format("SELECT * FROM %s.%s WHERE k=? LIMIT 1", KEYSPACE, tableName)), Collections.singletonList(42)); - PartialTxn partialTxn = txn.slice(GLOBAL_SCOPE, true); + PartialTxn partialTxn = txn.slice(scope, true); RoutingKey routingKey = partialTxn.keys().get(0).asKey().toUnseekable(); FullRoute route = partialTxn.keys().toRoute(routingKey); Deps deps = new Deps(KeyDeps.none((Keys) txn.keys()), RangeDeps.NONE); - PartialDeps partialDeps = deps.slice(GLOBAL_SCOPE); + PartialDeps partialDeps = deps.slice(scope); CommonAttributes.Mutable common = new CommonAttributes.Mutable(id); common.partialTxn(partialTxn); common.route(route); - common.partialDeps(partialDeps); + common.partialDeps(deps.slice(scope)); common.durability(Status.Durability.NotDurable); - Command.WaitingOn waitingOn = Command.WaitingOn.none(partialDeps); + Command.WaitingOn waitingOn = Command.WaitingOn.none(deps.slice(scope)); Command.Committed committed = Command.SerializerSupport.committed(common, SaveStatus.Committed, id, Ballot.ZERO, Ballot.ZERO, waitingOn); AccordSafeCommand safeCommand = new AccordSafeCommand(AccordTestUtils.loaded(id, null)); safeCommand.set(committed); - Commit commit = Commit.SerializerSupport.create(id, route.slice(GLOBAL_SCOPE), 1, Commit.Kind.Maximal, id, partialTxn, partialDeps, route, null); + Commit commit = Commit.SerializerSupport.create(id, route.slice(scope), 1, Commit.Kind.Maximal, id, partialTxn, partialDeps, route, null); store.appendToJournal(commit); Mutation mutation = AccordKeyspace.getCommandMutation(store, safeCommand, 42); diff --git a/test/unit/org/apache/cassandra/service/accord/AccordReadRepairTest.java b/test/unit/org/apache/cassandra/service/accord/AccordReadRepairTest.java index 8d8fb0fc46..d62ab52946 100644 --- a/test/unit/org/apache/cassandra/service/accord/AccordReadRepairTest.java +++ b/test/unit/org/apache/cassandra/service/accord/AccordReadRepairTest.java @@ -51,7 +51,6 @@ public class AccordReadRepairTest extends AccordTestBase { AccordTestBase.setupCluster(builder -> builder.appendConfig(config -> config.set("lwt_strategy", "accord").set("non_serial_write_strategy", "mixed")), 2); SHARED_CLUSTER.schemaChange("CREATE TYPE " + KEYSPACE + ".person (height int, age int)"); - SHARED_CLUSTER.get(1).runOnInstance(() -> AccordService.instance().ensureKeyspaceIsAccordManaged(KEYSPACE)); } /* @@ -61,7 +60,7 @@ public class AccordReadRepairTest extends AccordTestBase @Test public void testSerialReadRepair() throws Exception { - testReadRepair(cluster -> cluster.coordinator(1).execute("SELECT * FROM " + currentTable + " WHERE k = 1 AND c = 1;", ConsistencyLevel.SERIAL), + testReadRepair(cluster -> cluster.coordinator(1).execute("SELECT * FROM " + qualifiedTableName + " WHERE k = 1 AND c = 1;", ConsistencyLevel.SERIAL), new Object[][] {{1, 1, 1, 1}}); } @@ -69,7 +68,7 @@ public class AccordReadRepairTest extends AccordTestBase public void testCASFailedConditionReadRepair() throws Exception { // Even if the condition fails to apply the data checked when applying the condition should be repaired - testReadRepair(cluster -> cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, c, v1) VALUES (1, 1, 99) IF NOT EXISTS;", ConsistencyLevel.SERIAL), + testReadRepair(cluster -> cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, c, v1) VALUES (1, 1, 99) IF NOT EXISTS;", ConsistencyLevel.SERIAL), new Object[][] {{false, 1, 1, 1, 1}}); } @@ -77,7 +76,7 @@ public class AccordReadRepairTest extends AccordTestBase public void testCASReadRepair() throws Exception { // If the condition applies the read repair should preserve the existing timestamp - testReadRepair(cluster -> cluster.coordinator(1).execute("UPDATE " + currentTable + " SET v2 = 99 WHERE k = 1 and c = 1 IF EXISTS;", ConsistencyLevel.SERIAL), + testReadRepair(cluster -> cluster.coordinator(1).execute("UPDATE " + qualifiedTableName + " SET v2 = 99 WHERE k = 1 and c = 1 IF EXISTS;", ConsistencyLevel.SERIAL), new Object[][] {{Boolean.TRUE}}); } @@ -89,20 +88,20 @@ public class AccordReadRepairTest extends AccordTestBase public void testNonSerialReadRepair() throws Exception { for (ConsistencyLevel cl : ImmutableList.of(ConsistencyLevel.QUORUM)) - testReadRepair(cluster -> cluster.coordinator(1).execute("SELECT * FROM " + currentTable + " WHERE k = 1 AND c = 1;", cl), + testReadRepair(cluster -> cluster.coordinator(1).execute("SELECT * FROM " + qualifiedTableName + " WHERE k = 1 AND c = 1;", cl), new Object[][] {{1, 1, 1, 1}}); } void testReadRepair(Function accordTxn, Object[][] expected) throws Exception { - test("CREATE TABLE " + currentTable + " (k int, c int, v1 int, v2 int, PRIMARY KEY ((k), c));", + test("CREATE TABLE " + qualifiedTableName + " (k int, c int, v1 int, v2 int, PRIMARY KEY ((k), c));", cluster -> { Filter mutationFilter = cluster.filters().verbs(Verb.MUTATION_REQ.id).drop().on(); cluster.filters().verbs(Verb.HINT_REQ.id, Verb.HINT_RSP.id).drop().on(); - cluster.coordinator(1).execute("INSERT INTO " + currentTable + " (k, c, v1, v2) VALUES (1, 1, 1, 1) USING TIMESTAMP 42;", ConsistencyLevel.ONE); + cluster.coordinator(1).execute("INSERT INTO " + qualifiedTableName + " (k, c, v1, v2) VALUES (1, 1, 1, 1) USING TIMESTAMP 42;", ConsistencyLevel.ONE); mutationFilter.off(); Filter blockNodeOneReads = cluster.filters().verbs(Verb.READ_REQ.id).to(1).drop().on(); - assertThat(cluster.coordinator(2).executeWithResult("SELECT * FROM " + currentTable + " WHERE k = 1 AND c = 1;", ConsistencyLevel.ONE)) + assertThat(cluster.coordinator(2).executeWithResult("SELECT * FROM " + qualifiedTableName + " WHERE k = 1 AND c = 1;", ConsistencyLevel.ONE)) .isEmpty(); blockNodeOneReads.off(); // Should perform read repair @@ -110,7 +109,7 @@ public class AccordReadRepairTest extends AccordTestBase assertRows(result, expected); blockNodeOneReads.on(); // Side effect of the read repair should be visible now - assertThat(cluster.coordinator(2).executeWithResult("SELECT k, c, v1, WRITETIME(v1) FROM " + currentTable + " WHERE k = 1 AND c = 1;", ConsistencyLevel.ONE)) + assertThat(cluster.coordinator(2).executeWithResult("SELECT k, c, v1, WRITETIME(v1) FROM " + qualifiedTableName + " WHERE k = 1 AND c = 1;", ConsistencyLevel.ONE)) .isEqualTo(1, 1, 1, 42L); }); } diff --git a/test/unit/org/apache/cassandra/service/accord/AccordSyncPropagatorTest.java b/test/unit/org/apache/cassandra/service/accord/AccordSyncPropagatorTest.java index 919600e779..f57a3c1238 100644 --- a/test/unit/org/apache/cassandra/service/accord/AccordSyncPropagatorTest.java +++ b/test/unit/org/apache/cassandra/service/accord/AccordSyncPropagatorTest.java @@ -247,16 +247,13 @@ public class AccordSyncPropagatorTest } @Override - public Node.Id mappedId(InetAddressAndPort endpoint) + public Node.Id mappedIdOrNull(InetAddressAndPort endpoint) { - Node.Id id = nodeToAddress.inverse().get(endpoint); - if (id == null) - throw new NullPointerException("Unable to map endpoint: " + endpoint); - return id; + return nodeToAddress.inverse().get(endpoint); } @Override - public InetAddressAndPort mappedEndpoint(Node.Id id) + public InetAddressAndPort mappedEndpointOrNull(Node.Id id) { return nodeToAddress.get(id); } diff --git a/test/unit/org/apache/cassandra/service/accord/AccordTestUtils.java b/test/unit/org/apache/cassandra/service/accord/AccordTestUtils.java index 33255a0f0f..e30ddbb558 100644 --- a/test/unit/org/apache/cassandra/service/accord/AccordTestUtils.java +++ b/test/unit/org/apache/cassandra/service/accord/AccordTestUtils.java @@ -18,8 +18,10 @@ package org.apache.cassandra.service.accord; +import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; @@ -80,6 +82,7 @@ import org.apache.cassandra.db.DecoratedKey; import org.apache.cassandra.db.marshal.Int32Type; import org.apache.cassandra.metrics.AccordStateCacheMetrics; import org.apache.cassandra.schema.Schema; +import org.apache.cassandra.schema.TableId; import org.apache.cassandra.schema.TableMetadata; import org.apache.cassandra.service.ClientState; import org.apache.cassandra.service.accord.api.AccordAgent; @@ -96,6 +99,8 @@ import static java.lang.String.format; public class AccordTestUtils { + public static final TableId TABLE_ID1 = TableId.fromString("00000000-0000-0000-0000-000000000001"); + public static class Commands { public static Command notDefined(TxnId txnId, PartialTxn txn) @@ -308,7 +313,7 @@ public class AccordTestUtils public static Ranges fullRange(Seekables keys) { PartitionKey key = (PartitionKey) keys.get(0); - return Ranges.of(TokenRange.fullRange(key.keyspace())); + return Ranges.of(TokenRange.fullRange(key.table())); } public static PartialTxn createPartialTxn(int key) @@ -336,7 +341,7 @@ public class AccordTestUtils public static InMemoryCommandStore.Synchronized createInMemoryCommandStore(LongSupplier now, String keyspace, String table) { TableMetadata metadata = Schema.instance.getTableMetadata(keyspace, table); - TokenRange range = TokenRange.fullRange(metadata.keyspace); + TokenRange range = TokenRange.fullRange(metadata.id); Node.Id node = new Id(1); Topology topology = new Topology(1, new Shard(range, Lists.newArrayList(node), Sets.newHashSet(node), Collections.emptySet())); NodeTimeService time = new NodeTimeService() @@ -400,7 +405,7 @@ public class AccordTestUtils LongSupplier now, String keyspace, String table, ExecutorPlus loadExecutor, ExecutorPlus saveExecutor) { TableMetadata metadata = Schema.instance.getTableMetadata(keyspace, table); - TokenRange range = TokenRange.fullRange(metadata.keyspace); + TokenRange range = TokenRange.fullRange(metadata.id); Node.Id node = new Id(1); Topology topology = new Topology(1, new Shard(range, Lists.newArrayList(node), Sets.newHashSet(node), Collections.emptySet())); AccordCommandStore store = createAccordCommandStore(node, now, topology, loadExecutor, saveExecutor); @@ -432,11 +437,26 @@ public class AccordTestUtils public static PartitionKey key(TableMetadata table, int key) { DecoratedKey dk = table.partitioner.decorateKey(Int32Type.instance.decompose(key)); - return new PartitionKey(table.keyspace, table.id, dk); + return new PartitionKey(table.id, dk); } public static Keys keys(TableMetadata table, int... keys) { return Keys.of(IntStream.of(keys).mapToObj(key -> key(table, key)).collect(Collectors.toList())); } + + public static Node.Id id(int id) + { + return new Node.Id(id); + } + + public static List idList(int... ids) + { + return Arrays.stream(ids).mapToObj(AccordTestUtils::id).collect(Collectors.toList()); + } + + public static Set idSet(int... ids) + { + return Arrays.stream(ids).mapToObj(AccordTestUtils::id).collect(Collectors.toSet()); + } } diff --git a/test/unit/org/apache/cassandra/service/accord/AccordTopologyTest.java b/test/unit/org/apache/cassandra/service/accord/AccordTopologyTest.java index 0185957139..56675e6cf2 100644 --- a/test/unit/org/apache/cassandra/service/accord/AccordTopologyTest.java +++ b/test/unit/org/apache/cassandra/service/accord/AccordTopologyTest.java @@ -21,6 +21,7 @@ package org.apache.cassandra.service.accord; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Set; @@ -30,6 +31,7 @@ import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; +import accord.local.Node; import accord.local.Node.Id; import accord.topology.Shard; import accord.topology.Topology; @@ -45,6 +47,8 @@ import org.apache.cassandra.schema.KeyspaceMetadata; import org.apache.cassandra.schema.KeyspaceParams; import org.apache.cassandra.schema.Keyspaces; import org.apache.cassandra.schema.ReplicationParams; +import org.apache.cassandra.schema.TableId; +import org.apache.cassandra.schema.TableMetadata; import org.apache.cassandra.schema.Tables; import org.apache.cassandra.tcm.ClusterMetadata; import org.apache.cassandra.tcm.membership.Location; @@ -70,7 +74,7 @@ public class AccordTopologyTest private static final InetAddressAndPort EP3 = ep(3); private static final IPartitioner partitioner = Murmur3Partitioner.instance; - private static Tables tables = null; + private static TableId tableId = null; private static KeyspaceMetadata keyspace = null; private static final Location LOCATION = new Location("DC1", "RACK1"); @@ -79,8 +83,9 @@ public class AccordTopologyTest { DatabaseDescriptor.daemonInitialization(); DatabaseDescriptor.setPartitionerUnsafe(Murmur3Partitioner.instance); - tables = Tables.of(parse("CREATE TABLE tbl (k int, c int, v int, primary key (k, c))", "ks").build()); - keyspace = KeyspaceMetadata.create("ks", KeyspaceParams.simple(3), tables); + TableMetadata table = parse("CREATE TABLE tbl (k int, c int, v int, primary key (k, c))", "ks").build(); + tableId = table.id; + keyspace = KeyspaceMetadata.create("ks", KeyspaceParams.simple(3), Tables.of(table)); } private static InetAddressAndPort ep(int i) @@ -100,7 +105,7 @@ public class AccordTopologyTest return new NodeId(id); } - private static void addNode(ClusterMetadata.Transformer transformer, int node, Token token) + static void addNode(ClusterMetadata.Transformer transformer, int node, Token token) { NodeId nodeId = nodeId(node); InetAddressAndPort ep = ep(node); @@ -108,6 +113,7 @@ public class AccordTopologyTest transformer.register(nodeId, addresses, LOCATION, NodeVersion.CURRENT); transformer.withNodeState(nodeId, NodeState.JOINED); transformer.proposeToken(nodeId, Collections.singleton(token)); + transformer.addToRackAndDC(nodeId); } private static ClusterMetadata configureCluster(List> ranges, Keyspaces keyspaces) @@ -136,17 +142,17 @@ public class AccordTopologyTest return metadata; } - private static Token token(long t) + static Token token(long t) { return new Murmur3Partitioner.LongToken(t); } - private static Range range(Token left, Token right) + static Range range(Token left, Token right) { return new Range<>(left, right); } - private static Range range(long left, long right) + static Range range(long left, long right) { return range(token(left), token(right)); } @@ -164,12 +170,12 @@ public class AccordTopologyTest Assert.assertEquals(partitioner.getMaximumToken(), ranges.get(2).right); ClusterMetadata metadata = configureCluster(ranges, Keyspaces.of(keyspace)); - Topology topology = AccordTopologyUtils.createAccordTopology(metadata, ks -> true); + Topology topology = AccordTopology.createAccordTopology(metadata, ks -> true); Topology expected = new Topology(1, - new Shard(AccordTopologyUtils.minRange("ks", ranges.get(0).right), NODE_LIST, NODE_SET), - new Shard(AccordTopologyUtils.range("ks", ranges.get(1)), NODE_LIST, NODE_SET), - new Shard(AccordTopologyUtils.range("ks", ranges.get(2)), NODE_LIST, NODE_SET), - new Shard(AccordTopologyUtils.maxRange("ks", ranges.get(2).right), NODE_LIST, NODE_SET)); + new Shard(AccordTopology.minRange(tableId, ranges.get(0).right), NODE_LIST, NODE_SET), + new Shard(AccordTopology.range(tableId, ranges.get(1)), NODE_LIST, NODE_SET), + new Shard(AccordTopology.range(tableId, ranges.get(2)), NODE_LIST, NODE_SET), + new Shard(AccordTopology.maxRange(tableId, ranges.get(2).right), NODE_LIST, NODE_SET)); Assert.assertEquals(expected, topology); } @@ -182,13 +188,76 @@ public class AccordTopologyTest range(100, -100)); ClusterMetadata metadata = configureCluster(ranges, Keyspaces.of(keyspace)); - Topology topology = AccordTopologyUtils.createAccordTopology(metadata, ks -> true); + Topology topology = AccordTopology.createAccordTopology(metadata, ks -> true); Topology expected = new Topology(1, - new Shard(AccordTopologyUtils.minRange("ks", ranges.get(0).left), NODE_LIST, NODE_SET), - new Shard(AccordTopologyUtils.range("ks", ranges.get(0)), NODE_LIST, NODE_SET), - new Shard(AccordTopologyUtils.range("ks", ranges.get(1)), NODE_LIST, NODE_SET), - new Shard(AccordTopologyUtils.maxRange("ks", ranges.get(2).left), NODE_LIST, NODE_SET)); + new Shard(AccordTopology.minRange(tableId, ranges.get(0).left), NODE_LIST, NODE_SET), + new Shard(AccordTopology.range(tableId, ranges.get(0)), NODE_LIST, NODE_SET), + new Shard(AccordTopology.range(tableId, ranges.get(1)), NODE_LIST, NODE_SET), + new Shard(AccordTopology.maxRange(tableId, ranges.get(2).left), NODE_LIST, NODE_SET)); Assert.assertEquals(expected, topology); } + + @Test + public void fastPath() + { + List> ranges = ImmutableList.of(range(partitioner.getMinimumToken(), token(-100)), + range(-100, 100), + range(token(100), partitioner.getMaximumToken())); + ClusterMetadata metadata = configureCluster(ranges, Keyspaces.of(keyspace)); + Topology topology = AccordTopology.createAccordTopology(metadata, ks -> true); + Topology expected = new Topology(1, + new Shard(AccordTopology.minRange(tableId, ranges.get(0).right), NODE_LIST, NODE_SET), + new Shard(AccordTopology.range(tableId, ranges.get(1)), NODE_LIST, NODE_SET), + new Shard(AccordTopology.range(tableId, ranges.get(2)), NODE_LIST, NODE_SET), + new Shard(AccordTopology.maxRange(tableId, ranges.get(2).right), NODE_LIST, NODE_SET)); + Assert.assertEquals(expected, topology); + + topology = AccordTopology.createAccordTopology(metadata.transformer().withFastPathStatusSince(new Id(1), AccordFastPath.Status.UNAVAILABLE, 1, 1).build().metadata, ks -> true); + + Set fastPath = new HashSet<>(NODE_SET); + fastPath.remove(new Node.Id(1)); + + expected = new Topology(2, + new Shard(AccordTopology.minRange(tableId, ranges.get(0).right), NODE_LIST, fastPath), + new Shard(AccordTopology.range(tableId, ranges.get(1)), NODE_LIST, fastPath), + new Shard(AccordTopology.range(tableId, ranges.get(2)), NODE_LIST, fastPath), + new Shard(AccordTopology.maxRange(tableId, ranges.get(2).right), NODE_LIST, fastPath)); + Assert.assertEquals(expected, topology); + } + + /** + * Even if there are too many failures to reach quorum, fast path size shouldn't go below quorum size + */ + @Test + public void fastPathWithMoreThanMinimumFailedNodes() + { + List> ranges = ImmutableList.of(range(partitioner.getMinimumToken(), token(-100)), + range(-100, 100), + range(token(100), partitioner.getMaximumToken())); + ClusterMetadata metadata = configureCluster(ranges, Keyspaces.of(keyspace)); + Topology topology = AccordTopology.createAccordTopology(metadata, ks -> true); + Topology expected = new Topology(1, + new Shard(AccordTopology.minRange(tableId, ranges.get(0).right), NODE_LIST, NODE_SET), + new Shard(AccordTopology.range(tableId, ranges.get(1)), NODE_LIST, NODE_SET), + new Shard(AccordTopology.range(tableId, ranges.get(2)), NODE_LIST, NODE_SET), + new Shard(AccordTopology.maxRange(tableId, ranges.get(2).right), NODE_LIST, NODE_SET)); + Assert.assertEquals(expected, topology); + + metadata = metadata.transformer() + .withFastPathStatusSince(new Id(1), AccordFastPath.Status.UNAVAILABLE, 1, 1) + .withFastPathStatusSince(new Id(2), AccordFastPath.Status.UNAVAILABLE, 1, 1) + .build().metadata; + topology = AccordTopology.createAccordTopology(metadata, ks -> true); + + Set fastPath = new HashSet<>(NODE_SET); + fastPath.remove(new Node.Id(1)); + + expected = new Topology(2, + new Shard(AccordTopology.minRange(tableId, ranges.get(0).right), NODE_LIST, fastPath), + new Shard(AccordTopology.range(tableId, ranges.get(1)), NODE_LIST, fastPath), + new Shard(AccordTopology.range(tableId, ranges.get(2)), NODE_LIST, fastPath), + new Shard(AccordTopology.maxRange(tableId, ranges.get(2).right), NODE_LIST, fastPath)); + Assert.assertEquals(expected, topology); + } } diff --git a/test/unit/org/apache/cassandra/service/accord/CommandsForRangesTest.java b/test/unit/org/apache/cassandra/service/accord/CommandsForRangesTest.java index c86e0a769f..e3c3ba4346 100644 --- a/test/unit/org/apache/cassandra/service/accord/CommandsForRangesTest.java +++ b/test/unit/org/apache/cassandra/service/accord/CommandsForRangesTest.java @@ -46,11 +46,12 @@ import org.apache.cassandra.utils.IntervalTree; import static accord.utils.Property.qt; import static org.apache.cassandra.simulator.RandomSource.Choices.choose; +import static org.apache.cassandra.service.accord.AccordTestUtils.TABLE_ID1; import static org.assertj.core.api.Assertions.assertThat; public class CommandsForRangesTest { - private static Ranges FULL_RANGE = Ranges.of(new TokenRange(AccordRoutingKey.SentinelKey.min("test"), AccordRoutingKey.SentinelKey.max("test"))); + private static Ranges FULL_RANGE = Ranges.of(new TokenRange(AccordRoutingKey.SentinelKey.min(TABLE_ID1), AccordRoutingKey.SentinelKey.max(TABLE_ID1))); @BeforeClass public static void setup() throws NoSuchFieldException, IllegalAccessException @@ -98,7 +99,7 @@ public class CommandsForRangesTest IPartitioner partitioner = partitionerGen.next(rs); // some code reaches to the DD for partitioner... DatabaseDescriptor.setPartitionerUnsafe(partitioner); - Gen rangesGen = AccordGenerators.ranges(ignore -> Collections.singleton("test"), ignore -> partitioner); + Gen rangesGen = AccordGenerators.ranges(ignore -> Collections.singleton(TABLE_ID1), ignore -> partitioner); CommandsForRanges.Builder builder = new CommandsForRanges.Builder(); int numTxn = rs.nextInt(1, 10); Set uniq = new HashSet<>(); diff --git a/test/unit/org/apache/cassandra/service/accord/SimpleAccordEndpointMapper.java b/test/unit/org/apache/cassandra/service/accord/SimpleAccordEndpointMapper.java index 425169c34e..acca53d5fc 100644 --- a/test/unit/org/apache/cassandra/service/accord/SimpleAccordEndpointMapper.java +++ b/test/unit/org/apache/cassandra/service/accord/SimpleAccordEndpointMapper.java @@ -31,7 +31,7 @@ public enum SimpleAccordEndpointMapper implements AccordEndpointMapper INSTANCE; @Override - public Node.Id mappedId(InetAddressAndPort endpoint) + public Node.Id mappedIdOrNull(InetAddressAndPort endpoint) { if (endpoint.addressBytes.length != 4) throw new IllegalArgumentException("Only IPV4 is allowed: given " + endpoint.toString(true)); @@ -39,7 +39,7 @@ public enum SimpleAccordEndpointMapper implements AccordEndpointMapper } @Override - public InetAddressAndPort mappedEndpoint(Node.Id id) + public InetAddressAndPort mappedEndpointOrNull(Node.Id id) { byte[] array = ByteBufferUtil.bytes(id.id).array(); try diff --git a/test/unit/org/apache/cassandra/service/accord/api/AccordKeyTest.java b/test/unit/org/apache/cassandra/service/accord/api/AccordKeyTest.java index 95b4ed0078..0c74fac768 100644 --- a/test/unit/org/apache/cassandra/service/accord/api/AccordKeyTest.java +++ b/test/unit/org/apache/cassandra/service/accord/api/AccordKeyTest.java @@ -59,7 +59,7 @@ public class AccordKeyTest public void partitionKeyTest() { DecoratedKey dk = partitioner(TABLE1).decorateKey(ByteBufferUtil.bytes(5)); - PartitionKey pk = new PartitionKey("ks", TABLE1, dk); + PartitionKey pk = new PartitionKey(TABLE1, dk); SerializerTestUtils.assertSerializerIOEquality(pk, PartitionKey.serializer); } @@ -67,7 +67,7 @@ public class AccordKeyTest public void tokenKeyTest() { DecoratedKey dk = partitioner(TABLE1).decorateKey(ByteBufferUtil.bytes(5)); - TokenKey pk = new TokenKey("", dk.getToken()); + TokenKey pk = new TokenKey(TABLE1, dk.getToken()); SerializerTestUtils.assertSerializerIOEquality(pk, TokenKey.serializer); } @@ -75,10 +75,10 @@ public class AccordKeyTest public void comparisonTest() { DecoratedKey dk = partitioner(TABLE1).decorateKey(ByteBufferUtil.bytes(5)); - PartitionKey pk = new PartitionKey("", TABLE1, dk); - TokenKey tk = new TokenKey("", dk.getToken()); - TokenKey tkLow = new TokenKey("", dk.getToken().decreaseSlightly()); - TokenKey tkHigh = new TokenKey("", dk.getToken().nextValidToken()); + PartitionKey pk = new PartitionKey(TABLE1, dk); + TokenKey tk = new TokenKey(TABLE1, dk.getToken()); + TokenKey tkLow = new TokenKey(TABLE1, dk.getToken().decreaseSlightly()); + TokenKey tkHigh = new TokenKey(TABLE1, dk.getToken().nextValidToken()); Assert.assertTrue(tk.compareTo(pk) > 0); Assert.assertTrue(tkLow.compareTo(pk) < 0); @@ -91,22 +91,10 @@ public class AccordKeyTest Assert.assertTrue(TABLE1.compareTo(TABLE2) < 0); DecoratedKey dk1 = partitioner(TABLE1).decorateKey(ByteBufferUtil.bytes(5)); - PartitionKey pk1 = new PartitionKey("", TABLE1, dk1); + PartitionKey pk1 = new PartitionKey(TABLE1, dk1); DecoratedKey dk2 = partitioner(TABLE2).decorateKey(ByteBufferUtil.bytes(5)); - PartitionKey pk2 = new PartitionKey("", TABLE2, dk2); - - Assert.assertTrue(pk1.compareTo(pk2) < 0); - } - - @Test - public void keyspaceComparisonTest() - { - DecoratedKey dk1 = partitioner(TABLE1).decorateKey(ByteBufferUtil.bytes(5)); - PartitionKey pk1 = new PartitionKey("a", TABLE1, dk1); - - DecoratedKey dk2 = partitioner(TABLE1).decorateKey(ByteBufferUtil.bytes(5)); - PartitionKey pk2 = new PartitionKey("b", TABLE1, dk2); + PartitionKey pk2 = new PartitionKey(TABLE2, dk2); Assert.assertTrue(pk1.compareTo(pk2) < 0); } @@ -116,13 +104,13 @@ public class AccordKeyTest { Assert.assertTrue(TABLE1.compareTo(TABLE2) < 0); DecoratedKey dk1 = partitioner(TABLE1).decorateKey(ByteBufferUtil.bytes(5)); - PartitionKey pk1 = new PartitionKey("a", TABLE1, dk1); + PartitionKey pk1 = new PartitionKey(TABLE1, dk1); DecoratedKey dk2 = partitioner(TABLE2).decorateKey(ByteBufferUtil.bytes(5)); - PartitionKey pk2 = new PartitionKey("b", TABLE2, dk2); + PartitionKey pk2 = new PartitionKey(TABLE2, dk2); - SentinelKey loSentinel = SentinelKey.min("a"); - SentinelKey hiSentinel = SentinelKey.max("a"); + SentinelKey loSentinel = SentinelKey.min(TABLE1); + SentinelKey hiSentinel = SentinelKey.max(TABLE1); Assert.assertTrue(loSentinel.compareTo(hiSentinel) < 0); Assert.assertTrue(pk1.compareTo(loSentinel) > 0); Assert.assertTrue(loSentinel.compareTo(pk1) < 0); diff --git a/test/unit/org/apache/cassandra/service/accord/fastpath/FastPathParsingTest.java b/test/unit/org/apache/cassandra/service/accord/fastpath/FastPathParsingTest.java new file mode 100644 index 0000000000..96b9e87435 --- /dev/null +++ b/test/unit/org/apache/cassandra/service/accord/fastpath/FastPathParsingTest.java @@ -0,0 +1,109 @@ +/* + * 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.service.accord.fastpath; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.StringJoiner; + +import com.google.common.collect.ImmutableMap; +import org.junit.Assert; +import org.junit.Test; + +import org.apache.cassandra.exceptions.ConfigurationException; + +import static java.lang.String.format; + +public class FastPathParsingTest +{ + private static void assertThrows(Runnable runnable, Class exception) + { + try + { + runnable.run(); + } + catch (Throwable e) + { + if (!exception.isAssignableFrom(e.getClass())) + { + throw new AssertionError(format("Expected %s to be thrown, got %s: %s", exception.getName(), e.getClass().getName(), e.getMessage())); + } + return; + } + Assert.fail(format("Expected %s to be thrown", exception.getName())); + } + + private static Map options(String... opts) + { + Assert.assertTrue("Need even numbered array for key value pairs, got " + Arrays.toString(opts), opts.length % 2 == 0); + ImmutableMap.Builder builder = ImmutableMap.builder(); + for (int i=0; i options = new HashMap<>(); + options.put(ParameterizedFastPathStrategy.SIZE, Integer.toString(size)); + if (dcs.length > 0) + { + StringJoiner joiner = new StringJoiner(","); + for (String dc : dcs) + joiner.add(dc); + options.put(ParameterizedFastPathStrategy.DCS, joiner.toString()); + } + + return ParameterizedFastPathStrategy.fromMap(options); + } + + @Test + public void fromString() + { + Assert.assertSame(SimpleFastPathStrategy.instance, FastPathStrategy.tableStrategyFromString("simple")); + } + + @Test + public void fromStringFailures() + { + assertThrows(() -> FastPathStrategy.tableStrategyFromString("something"), ConfigurationException.class); + } + + @Test + public void fromMap() + { + Assert.assertEquals(pfs(3), FastPathStrategy.fromMap(options("size", "3"))); + Assert.assertEquals(SimpleFastPathStrategy.instance, FastPathStrategy.fromMap(options())); + Assert.assertEquals(pfs(1, "dc1"), FastPathStrategy.fromMap(options("size", "1", "dcs", "dc1"))); + Assert.assertEquals(pfs(3, "dc1", "dc2"), FastPathStrategy.fromMap(options("size", "3", "dcs", "dc1,dc2"))); + Assert.assertEquals(pfs(5, "dc2", "dc1"), FastPathStrategy.fromMap(options("size", "5", "dcs", "dc2,dc1"))); + } + + @Test + public void fromMapFailures() + { + assertThrows(() -> FastPathStrategy.fromMap(options("dcs", "dc1")), ConfigurationException.class); + assertThrows(() -> FastPathStrategy.fromMap(options("size", "abc")), ConfigurationException.class); + assertThrows(() -> FastPathStrategy.fromMap(options("size", "0")), ConfigurationException.class); + assertThrows(() -> FastPathStrategy.fromMap(options("size", "-1")), ConfigurationException.class); + assertThrows(() -> FastPathStrategy.fromMap(options("size", "2", "dcs", " ")), ConfigurationException.class); + assertThrows(() -> FastPathStrategy.fromMap(options("size", "5", "dcs", "dc2,dc1", "happypath", "5")), ConfigurationException.class); + } +} diff --git a/test/unit/org/apache/cassandra/service/accord/fastpath/ParameterizedFastPathStrategyTest.java b/test/unit/org/apache/cassandra/service/accord/fastpath/ParameterizedFastPathStrategyTest.java new file mode 100644 index 0000000000..65650274fa --- /dev/null +++ b/test/unit/org/apache/cassandra/service/accord/fastpath/ParameterizedFastPathStrategyTest.java @@ -0,0 +1,153 @@ +/* + * 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.service.accord.fastpath; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.google.common.collect.ImmutableMap; +import org.junit.Assert; +import org.junit.Test; + +import accord.local.Node; +import org.apache.cassandra.exceptions.ConfigurationException; +import org.apache.cassandra.service.accord.fastpath.ParameterizedFastPathStrategy.WeightedDc; + +import static java.util.Collections.emptySet; +import static org.apache.cassandra.service.accord.AccordTestUtils.id; +import static org.apache.cassandra.service.accord.AccordTestUtils.idList; +import static org.apache.cassandra.service.accord.AccordTestUtils.idSet; +import static org.apache.cassandra.service.accord.fastpath.FastPathParsingTest.pfs; +import static org.junit.Assert.assertEquals; + +public class ParameterizedFastPathStrategyTest +{ + private static final List NODES = idList(1, 2, 3, 4, 5, 6); + private static final Map DCS_2; + private static final Map DCS_3; + + static + { + ImmutableMap.Builder builder = ImmutableMap.builder(); + builder.put(id(1), "DC1"); + builder.put(id(2), "DC1"); + builder.put(id(3), "DC1"); + builder.put(id(4), "DC2"); + builder.put(id(5), "DC2"); + builder.put(id(6), "DC2"); + DCS_2 = builder.build(); + + builder = ImmutableMap.builder(); + builder.put(id(1), "DC1"); + builder.put(id(2), "DC1"); + builder.put(id(3), "DC2"); + builder.put(id(4), "DC2"); + builder.put(id(5), "DC3"); + builder.put(id(6), "DC3"); + DCS_3 = builder.build(); + } + + @Test + public void noDCPreference() + { + assertEquals(idSet(1, 2, 3, 4, 5, 6), pfs(6).calculateFastPath(NODES, emptySet(), DCS_2)); + assertEquals(idSet(1, 2, 3, 4, 5), pfs(5).calculateFastPath(NODES, emptySet(), DCS_2)); + assertEquals(idSet(1, 2, 3, 4), pfs(4).calculateFastPath(NODES, emptySet(), DCS_2)); + assertEquals(idSet(1, 2, 3, 4), pfs(3).calculateFastPath(NODES, emptySet(), DCS_2)); + } + + @Test + public void noDCPreferenceUnavailables() + { + assertEquals(idSet(1, 2, 3, 4, 5, 6), pfs(6).calculateFastPath(NODES, idSet(4), DCS_2)); + assertEquals(idSet(1, 2, 3, 4, 5), pfs(5).calculateFastPath(NODES, idSet(1, 6), DCS_2)); + assertEquals(idSet(2, 3, 4, 5), pfs(4).calculateFastPath(NODES, idSet(1, 6), DCS_2)); + } + + + @Test + public void dcPreference() + { + assertEquals(idSet(1, 2, 3, 4, 5, 6), pfs(6, "DC1", "DC2").calculateFastPath(NODES, idSet(), DCS_3)); + assertEquals(idSet(1, 2, 3, 4), pfs(4, "DC1", "DC2").calculateFastPath(NODES, idSet(), DCS_3)); + assertEquals(idSet(1, 2, 5, 6), pfs(4, "DC1", "DC3").calculateFastPath(NODES, idSet(), DCS_3)); + } + + @Test + public void dcPreferenceUnavailables() + { + assertEquals(idSet(1, 2, 3, 4, 5), pfs(5, "DC1", "DC2").calculateFastPath(NODES, idSet(2, 4, 6), DCS_3)); + assertEquals(idSet(1, 2, 3, 5, 6), pfs(5, "DC1", "DC3").calculateFastPath(NODES, idSet(2, 4, 6), DCS_3)); + assertEquals(idSet(1, 3, 4, 5, 6), pfs(5, "DC2", "DC3").calculateFastPath(NODES, idSet(2, 4, 6), DCS_3)); + } + + private static WeightedDc wdc(String dc, int weight, boolean auto) + { + return new WeightedDc(dc, weight, auto); + } + + private static void assertCFE(int size, String... dcs) + { + try + { + pfs(size, dcs); + Assert.fail("expected ConfigurationException"); + } + catch (ConfigurationException ex) + { + // expected + } + } + + private static void assertPFS(ParameterizedFastPathStrategy actual, int size, WeightedDc... dcs) + { + Map dcMap = new HashMap<>(); + for (WeightedDc dc : dcs) + { + Assert.assertFalse(dcMap.containsKey(dc.name)); + dcMap.put(dc.name, dc); + } + ParameterizedFastPathStrategy expected = new ParameterizedFastPathStrategy(size, ImmutableMap.copyOf(dcMap)); + Assert.assertEquals(expected, actual); + } + + + @Test + public void dcParsingTest() + { + assertCFE(5, "DC1", "DC2:1"); + assertCFE(5, "DC1:-1", "DC2:1"); + assertCFE(5, "DC1", "DC1"); + } + + @Test + public void listParsingTest() + { + assertPFS(pfs(4, "DC1", "DC2", "DC3"), 4, wdc("DC1", 0, true), wdc("DC2", 1, true), wdc("DC3", 2, true)); + assertPFS(pfs(4, "DC2", "DC3", "DC1"), 4, wdc("DC2", 0, true), wdc("DC3", 1, true), wdc("DC1", 2, true)); + } + + @Test + public void weightParsingTest() + { + assertPFS(pfs(4, "DC1:0", "DC2:0", "DC3:1"), 4, wdc("DC1", 0, false), wdc("DC2", 0, false), wdc("DC3", 1, false)); + assertPFS(pfs(4, "DC2:100", "DC3:200", "DC1:300"), 4, wdc("DC2", 100, false), wdc("DC3", 200, false), wdc("DC1", 300, false)); + } +} diff --git a/test/unit/org/apache/cassandra/service/accord/fastpath/SimpleFastPathStrategyTest.java b/test/unit/org/apache/cassandra/service/accord/fastpath/SimpleFastPathStrategyTest.java new file mode 100644 index 0000000000..f19cac90ee --- /dev/null +++ b/test/unit/org/apache/cassandra/service/accord/fastpath/SimpleFastPathStrategyTest.java @@ -0,0 +1,43 @@ +/* + * 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.service.accord.fastpath; + +import java.util.Collections; +import java.util.Map; + +import org.junit.Assert; +import org.junit.Test; + +import accord.local.Node; + +import static org.apache.cassandra.service.accord.AccordTestUtils.idList; +import static org.apache.cassandra.service.accord.AccordTestUtils.idSet; + +public class SimpleFastPathStrategyTest +{ + private static final Map DCMAP = Collections.emptyMap(); + + @Test + public void testCalculation() + { + FastPathStrategy strategy = SimpleFastPathStrategy.instance; + Assert.assertEquals(idSet(1, 2, 3, 4, 5), strategy.calculateFastPath(idList(1, 2, 3, 4, 5), idSet(), DCMAP)); + Assert.assertEquals(idSet(3, 4, 5), strategy.calculateFastPath(idList(1, 2, 3, 4, 5), idSet(1, 2, 3), DCMAP)); + } +} diff --git a/test/unit/org/apache/cassandra/service/accord/serializers/CommandSerializersTest.java b/test/unit/org/apache/cassandra/service/accord/serializers/CommandSerializersTest.java index 34fda94017..9d04137587 100644 --- a/test/unit/org/apache/cassandra/service/accord/serializers/CommandSerializersTest.java +++ b/test/unit/org/apache/cassandra/service/accord/serializers/CommandSerializersTest.java @@ -55,7 +55,7 @@ public class CommandSerializersTest " END IF\n" + "COMMIT TRANSACTION"); PartitionKey key = (PartitionKey) txn.keys().get(0); - PartialTxn expected = txn.slice(Ranges.of(TokenRange.fullRange(key.keyspace())), true); + PartialTxn expected = txn.slice(Ranges.of(TokenRange.fullRange(key.table())), true); SerializerTestUtils.assertSerializerIOEquality(expected, CommandSerializers.partialTxn); } } diff --git a/test/unit/org/apache/cassandra/service/accord/txn/AbstractKeySortedTest.java b/test/unit/org/apache/cassandra/service/accord/txn/AbstractKeySortedTest.java index 890c760b0d..001206d858 100644 --- a/test/unit/org/apache/cassandra/service/accord/txn/AbstractKeySortedTest.java +++ b/test/unit/org/apache/cassandra/service/accord/txn/AbstractKeySortedTest.java @@ -114,7 +114,7 @@ public class AbstractKeySortedTest private static PartitionKey key(int k) { DecoratedKey dk = ByteOrderedPartitioner.instance.decorateKey(ByteBufferUtil.bytes(k)); - return new PartitionKey("", TABLE1, dk); + return new PartitionKey(TABLE1, dk); } private static Item item(int k, int v) diff --git a/test/unit/org/apache/cassandra/service/reads/DataResolverTest.java b/test/unit/org/apache/cassandra/service/reads/DataResolverTest.java index 19e7724807..062cda0b96 100644 --- a/test/unit/org/apache/cassandra/service/reads/DataResolverTest.java +++ b/test/unit/org/apache/cassandra/service/reads/DataResolverTest.java @@ -1325,7 +1325,7 @@ public class DataResolverTest extends AbstractReadResponseTest private ReplicaPlan.SharedForRangeRead plan(EndpointsForRange replicas, ConsistencyLevel consistencyLevel) { - BiFunction, Token, ReplicaPlan.ForWrite> repairPlan = (self, t) -> ReplicaPlans.forReadRepair(self, ClusterMetadata.current(), ks, consistencyLevel, t, (i) -> true, ReadCoordinator.DEFAULT); + BiFunction, Token, ReplicaPlan.ForWrite> repairPlan = (self, t) -> ReplicaPlans.forReadRepair(self, ClusterMetadata.current(), ks, null, consistencyLevel, t, (i) -> true, ReadCoordinator.DEFAULT); return ReplicaPlan.shared(new ReplicaPlan.ForRangeRead(ks, ks.getReplicationStrategy(), consistencyLevel, diff --git a/test/unit/org/apache/cassandra/service/reads/range/RangeCommandIteratorTest.java b/test/unit/org/apache/cassandra/service/reads/range/RangeCommandIteratorTest.java index dfd1f7f88d..b13c45bfbc 100644 --- a/test/unit/org/apache/cassandra/service/reads/range/RangeCommandIteratorTest.java +++ b/test/unit/org/apache/cassandra/service/reads/range/RangeCommandIteratorTest.java @@ -22,6 +22,7 @@ import java.util.ArrayList; import java.util.List; import com.google.common.collect.Iterators; +import org.apache.cassandra.schema.TableId; import org.junit.BeforeClass; import org.junit.Test; @@ -49,6 +50,7 @@ public class RangeCommandIteratorTest { private static final String KEYSPACE1 = "RangeCommandIteratorTest"; private static final String CF_STANDARD1 = "Standard1"; + private static final TableId TABLE_ID = TableId.generate(); @BeforeClass public static void defineSchema() throws ConfigurationException @@ -70,11 +72,11 @@ public class RangeCommandIteratorTest for (int i = 0; i + 1 < tokens.size(); i++) { Range range = Range.makeRowRange(tokens.get(i), tokens.get(i + 1)); - ranges.add(ReplicaPlans.forRangeRead(keyspace, null, ConsistencyLevel.ONE, range, 1)); + ranges.add(ReplicaPlans.forRangeRead(keyspace, TABLE_ID, null, ConsistencyLevel.ONE, range, 1)); vnodeCount++; } - ReplicaPlanMerger merge = new ReplicaPlanMerger(ranges.iterator(), keyspace, ConsistencyLevel.ONE); + ReplicaPlanMerger merge = new ReplicaPlanMerger(ranges.iterator(), keyspace, TABLE_ID, ConsistencyLevel.ONE); ReplicaPlan.ForRangeRead mergedRange = Iterators.getOnlyElement(merge); // all ranges are merged as test has only one node. assertEquals(vnodeCount, mergedRange.vnodeCount()); @@ -164,9 +166,9 @@ public class RangeCommandIteratorTest Keyspace keyspace, boolean withRangeMerger) { - CloseableIterator replicaPlans = new ReplicaPlanIterator(keyRange, null, keyspace, ConsistencyLevel.ONE); + CloseableIterator replicaPlans = new ReplicaPlanIterator(keyRange, null, keyspace, null, ConsistencyLevel.ONE); if (withRangeMerger) - replicaPlans = new ReplicaPlanMerger(replicaPlans, keyspace, ConsistencyLevel.ONE); + replicaPlans = new ReplicaPlanMerger(replicaPlans, keyspace, null, ConsistencyLevel.ONE); return replicaPlans; } diff --git a/test/unit/org/apache/cassandra/service/reads/range/RangeCommandsTest.java b/test/unit/org/apache/cassandra/service/reads/range/RangeCommandsTest.java index ce04d5deab..466309fcb2 100644 --- a/test/unit/org/apache/cassandra/service/reads/range/RangeCommandsTest.java +++ b/test/unit/org/apache/cassandra/service/reads/range/RangeCommandsTest.java @@ -79,7 +79,7 @@ public class RangeCommandsTest extends CQLTester // verify that a low concurrency factor is not capped by the max concurrency factor PartitionRangeReadCommand command = command(cfs, 50, 50); try (RangeCommandIterator partitions = RangeCommands.rangeCommandIterator(command, ONE, Dispatcher.RequestTime.forImmediateExecution()); - ReplicaPlanIterator ranges = new ReplicaPlanIterator(command.dataRange().keyRange(), command.indexQueryPlan(), keyspace, ONE)) + ReplicaPlanIterator ranges = new ReplicaPlanIterator(command.dataRange().keyRange(), command.indexQueryPlan(), keyspace, command.metadata().id, ONE)) { assertEquals(2, partitions.concurrencyFactor()); assertEquals(MAX_CONCURRENCY_FACTOR, partitions.maxConcurrencyFactor()); @@ -89,7 +89,7 @@ public class RangeCommandsTest extends CQLTester // verify that a high concurrency factor is capped by the max concurrency factor command = command(cfs, 1000, 50); try (RangeCommandIterator partitions = RangeCommands.rangeCommandIterator(command, ONE, Dispatcher.RequestTime.forImmediateExecution()); - ReplicaPlanIterator ranges = new ReplicaPlanIterator(command.dataRange().keyRange(), command.indexQueryPlan(), keyspace, ONE)) + ReplicaPlanIterator ranges = new ReplicaPlanIterator(command.dataRange().keyRange(), command.indexQueryPlan(), keyspace, command.metadata().id, ONE)) { assertEquals(MAX_CONCURRENCY_FACTOR, partitions.concurrencyFactor()); assertEquals(MAX_CONCURRENCY_FACTOR, partitions.maxConcurrencyFactor()); @@ -99,7 +99,7 @@ public class RangeCommandsTest extends CQLTester // with 0 estimated results per range the concurrency factor should be 1 command = command(cfs, 1000, 0); try (RangeCommandIterator partitions = RangeCommands.rangeCommandIterator(command, ONE, Dispatcher.RequestTime.forImmediateExecution()); - ReplicaPlanIterator ranges = new ReplicaPlanIterator(command.dataRange().keyRange(), command.indexQueryPlan(), keyspace, ONE)) + ReplicaPlanIterator ranges = new ReplicaPlanIterator(command.dataRange().keyRange(), command.indexQueryPlan(), keyspace, command.metadata().id, ONE)) { assertEquals(1, partitions.concurrencyFactor()); assertEquals(MAX_CONCURRENCY_FACTOR, partitions.maxConcurrencyFactor()); diff --git a/test/unit/org/apache/cassandra/service/reads/range/ReplicaPlanIteratorTest.java b/test/unit/org/apache/cassandra/service/reads/range/ReplicaPlanIteratorTest.java index 84f3a5e2e7..829211f8e8 100644 --- a/test/unit/org/apache/cassandra/service/reads/range/ReplicaPlanIteratorTest.java +++ b/test/unit/org/apache/cassandra/service/reads/range/ReplicaPlanIteratorTest.java @@ -21,6 +21,7 @@ package org.apache.cassandra.service.reads.range; import java.util.ArrayList; import java.util.List; +import org.apache.cassandra.schema.TableId; import org.junit.BeforeClass; import org.junit.Test; @@ -44,6 +45,7 @@ import static org.junit.Assert.assertEquals; public class ReplicaPlanIteratorTest { private static final String KEYSPACE = "ReplicaPlanIteratorTest"; + private static final TableId TABLE_ID = TableId.generate(); private static Keyspace keyspace; @BeforeClass @@ -163,7 +165,7 @@ public class ReplicaPlanIteratorTest @SafeVarargs private final void testRanges(Keyspace keyspace, AbstractBounds queryRange, AbstractBounds... expected) { - try (ReplicaPlanIterator iterator = new ReplicaPlanIterator(queryRange, null, keyspace, ConsistencyLevel.ANY)) + try (ReplicaPlanIterator iterator = new ReplicaPlanIterator(queryRange, null, keyspace, TABLE_ID, ConsistencyLevel.ANY)) { List> restrictedRanges = new ArrayList<>(expected.length); while (iterator.hasNext()) diff --git a/test/unit/org/apache/cassandra/service/reads/range/ReplicaPlanMergerTest.java b/test/unit/org/apache/cassandra/service/reads/range/ReplicaPlanMergerTest.java index aaa88c938d..46b71d532e 100644 --- a/test/unit/org/apache/cassandra/service/reads/range/ReplicaPlanMergerTest.java +++ b/test/unit/org/apache/cassandra/service/reads/range/ReplicaPlanMergerTest.java @@ -416,8 +416,8 @@ public class ReplicaPlanMergerTest AbstractBounds queryRange, AbstractBounds... expected) { - try (ReplicaPlanIterator originals = new ReplicaPlanIterator(queryRange, null, keyspace, ANY); // ANY avoids endpoint erros - ReplicaPlanMerger merger = new ReplicaPlanMerger(originals, keyspace, consistencyLevel)) + try (ReplicaPlanIterator originals = new ReplicaPlanIterator(queryRange, null, keyspace, null, ANY); // ANY avoids endpoint erros + ReplicaPlanMerger merger = new ReplicaPlanMerger(originals, keyspace, null, consistencyLevel)) { // collect the merged ranges List> mergedRanges = new ArrayList<>(expected.length); diff --git a/test/unit/org/apache/cassandra/service/reads/repair/AbstractReadRepairTest.java b/test/unit/org/apache/cassandra/service/reads/repair/AbstractReadRepairTest.java index d4a5b7a05f..4a6d31447c 100644 --- a/test/unit/org/apache/cassandra/service/reads/repair/AbstractReadRepairTest.java +++ b/test/unit/org/apache/cassandra/service/reads/repair/AbstractReadRepairTest.java @@ -361,7 +361,7 @@ public abstract class AbstractReadRepairTest replicas, 1, null, - (self, token) -> forReadRepair(self, ClusterMetadata.current(), keyspace, consistencyLevel, token, (r) -> true, ReadCoordinator.DEFAULT), + (self, token) -> forReadRepair(self, ClusterMetadata.current(), keyspace, null, consistencyLevel, token, (r) -> true, ReadCoordinator.DEFAULT), Epoch.EMPTY); } diff --git a/test/unit/org/apache/cassandra/tcm/ClusterMetadataTransformationTest.java b/test/unit/org/apache/cassandra/tcm/ClusterMetadataTransformationTest.java index b9df8471a2..37b3815c1c 100644 --- a/test/unit/org/apache/cassandra/tcm/ClusterMetadataTransformationTest.java +++ b/test/unit/org/apache/cassandra/tcm/ClusterMetadataTransformationTest.java @@ -50,14 +50,7 @@ import org.apache.cassandra.tcm.sequences.InProgressSequences; import org.apache.cassandra.tcm.sequences.LockedRanges; import org.mockito.Mockito; -import static org.apache.cassandra.tcm.MetadataKeys.ACCORD_KEYSPACES; -import static org.apache.cassandra.tcm.MetadataKeys.CONSENSUS_MIGRATION_STATE; -import static org.apache.cassandra.tcm.MetadataKeys.DATA_PLACEMENTS; -import static org.apache.cassandra.tcm.MetadataKeys.IN_PROGRESS_SEQUENCES; -import static org.apache.cassandra.tcm.MetadataKeys.LOCKED_RANGES; -import static org.apache.cassandra.tcm.MetadataKeys.NODE_DIRECTORY; -import static org.apache.cassandra.tcm.MetadataKeys.SCHEMA; -import static org.apache.cassandra.tcm.MetadataKeys.TOKEN_MAP; +import static org.apache.cassandra.tcm.MetadataKeys.*; import static org.apache.cassandra.tcm.ownership.OwnershipUtils.randomPlacements; import static org.apache.cassandra.tcm.ownership.OwnershipUtils.token; import static org.apache.cassandra.tcm.sequences.SequencesUtils.affectedRanges; @@ -304,8 +297,10 @@ public class ClusterMetadataTransformationTest return metadata.lockedRanges; else if (key == IN_PROGRESS_SEQUENCES) return metadata.inProgressSequences; - else if (key == ACCORD_KEYSPACES) - return metadata.accordKeyspaces; + else if (key == ACCORD_TABLES) + return metadata.accordTables; + else if (key == ACCORD_FAST_PATH) + return metadata.accordFastPath; else if (key == CONSENSUS_MIGRATION_STATE) return metadata.consensusMigrationState; diff --git a/test/unit/org/apache/cassandra/utils/AccordGenerators.java b/test/unit/org/apache/cassandra/utils/AccordGenerators.java index 7017e98664..fdd20b0739 100644 --- a/test/unit/org/apache/cassandra/utils/AccordGenerators.java +++ b/test/unit/org/apache/cassandra/utils/AccordGenerators.java @@ -49,6 +49,7 @@ import org.apache.cassandra.service.accord.api.PartitionKey; import org.quicktheories.impl.JavaRandom; import static accord.utils.AccordGens.txnIds; +import static org.apache.cassandra.service.accord.AccordTestUtils.TABLE_ID1; import static org.apache.cassandra.service.accord.AccordTestUtils.createPartialTxn; public class AccordGenerators @@ -99,47 +100,44 @@ public class AccordGenerators public static Gen keys() { - return keys(fromQT(Generators.IDENTIFIER_GEN), - fromQT(CassandraGenerators.TABLE_ID_GEN), + return keys(fromQT(CassandraGenerators.TABLE_ID_GEN), fromQT(CassandraGenerators.decoratedKeys())); } public static Gen keys(IPartitioner partitioner) { - return keys(fromQT(Generators.IDENTIFIER_GEN), - fromQT(CassandraGenerators.TABLE_ID_GEN), + return keys(fromQT(CassandraGenerators.TABLE_ID_GEN), fromQT(CassandraGenerators.decoratedKeys(ignore -> partitioner))); } - public static Gen keys(Gen keyspace, Gen tableId, Gen key) + public static Gen keys(Gen tableIdGen, Gen key) { - return rs -> new PartitionKey(keyspace.next(rs), tableId.next(rs), key.next(rs)); + return rs -> new PartitionKey(tableIdGen.next(rs), key.next(rs)); } - public static Gen routingKeyGen(Gen keyspace, Gen tokenGen) + public static Gen routingKeyGen(Gen tableIdGen, Gen tokenGen) { return rs -> { - String ks = keyspace.next(rs); - if (rs.nextBoolean()) return new AccordRoutingKey.TokenKey(ks, tokenGen.next(rs)); - else return rs.nextBoolean() ? AccordRoutingKey.SentinelKey.min(ks) : AccordRoutingKey.SentinelKey.max(ks); + TableId tableId = tableIdGen.next(rs); + if (rs.nextBoolean()) return new AccordRoutingKey.TokenKey(tableId, tokenGen.next(rs)); + else return rs.nextBoolean() ? AccordRoutingKey.SentinelKey.min(tableId) : AccordRoutingKey.SentinelKey.max(tableId); }; } public static Gen range() { - return PARTITIONER_GEN.flatMap(partitioner -> range(fromQT(Generators.IDENTIFIER_GEN), fromQT(CassandraGenerators.token(partitioner)))); + return PARTITIONER_GEN.flatMap(partitioner -> range(fromQT(CassandraGenerators.TABLE_ID_GEN), fromQT(CassandraGenerators.token(partitioner)))); } public static Gen range(IPartitioner partitioner) { - return range(fromQT(Generators.IDENTIFIER_GEN), fromQT(CassandraGenerators.token(partitioner))); + return range(fromQT(CassandraGenerators.TABLE_ID_GEN), fromQT(CassandraGenerators.token(partitioner))); } - public static Gen range(Gen keyspace, Gen tokenGen) + public static Gen range(Gen tables, Gen tokenGen) { return rs -> { - String ks = keyspace.next(rs); - Gen gen = routingKeyGen(Gens.constant(ks), tokenGen); + Gen gen = routingKeyGen(Gens.constant(tables.next(rs)), tokenGen); AccordRoutingKey a = gen.next(rs); AccordRoutingKey b = gen.next(rs); while (a.equals(b)) @@ -152,17 +150,17 @@ public class AccordGenerators public static Gen ranges() { // javac couldn't pick the right constructor with HashSet::new, so had to create new lambda... - return ranges(Gens.lists(fromQT(Generators.IDENTIFIER_GEN)).unique().ofSizeBetween(1, 10).map(l -> new HashSet<>(l)), PARTITIONER_GEN); + return ranges(Gens.lists(fromQT(CassandraGenerators.TABLE_ID_GEN)).unique().ofSizeBetween(1, 10).map(l -> new HashSet<>(l)), PARTITIONER_GEN); } - public static Gen ranges(Gen> keyspaceGen, Gen partitionerGen) + public static Gen ranges(Gen> tableIdGen, Gen partitionerGen) { return rs -> { - Set keyspaces = keyspaceGen.next(rs); + Set tables = tableIdGen.next(rs); IPartitioner partitioner = partitionerGen.next(rs); List ranges = new ArrayList<>(); int numSplits = rs.nextInt(10, 100); - TokenRange range = new TokenRange(AccordRoutingKey.SentinelKey.min(""), AccordRoutingKey.SentinelKey.max("")); + TokenRange range = new TokenRange(AccordRoutingKey.SentinelKey.min(TABLE_ID1), AccordRoutingKey.SentinelKey.max(TABLE_ID1)); AccordSplitter splitter = partitioner.accordSplitter().apply(Ranges.of(range)); BigInteger size = splitter.sizeOf(range); BigInteger update = splitter.divide(size, numSplits); @@ -171,9 +169,9 @@ public class AccordGenerators { BigInteger end = offset.add(update); TokenRange r = (TokenRange) splitter.subRange(range, offset, end); - for (String ks : keyspaces) + for (TableId id : tables) { - ranges.add(r.withKeyspace(ks)); + ranges.add(r.withTable(id)); } offset = end; } @@ -183,7 +181,7 @@ public class AccordGenerators public static Gen ranges(IPartitioner partitioner) { - return ranges(Gens.lists(fromQT(Generators.IDENTIFIER_GEN)).unique().ofSizeBetween(1, 10).map(l -> new HashSet<>(l)), ignore -> partitioner); + return ranges(Gens.lists(fromQT(CassandraGenerators.TABLE_ID_GEN)).unique().ofSizeBetween(1, 10).map(l -> new HashSet<>(l)), ignore -> partitioner); } public static Gen keyDepsGen() diff --git a/test/unit/org/apache/cassandra/utils/CassandraGenerators.java b/test/unit/org/apache/cassandra/utils/CassandraGenerators.java index 8867d6141e..1fc46ff209 100644 --- a/test/unit/org/apache/cassandra/utils/CassandraGenerators.java +++ b/test/unit/org/apache/cassandra/utils/CassandraGenerators.java @@ -119,6 +119,7 @@ import org.apache.cassandra.schema.Tables; import org.apache.cassandra.schema.Types; import org.apache.cassandra.schema.UserFunctions; import org.apache.cassandra.schema.Views; +import org.apache.cassandra.service.accord.fastpath.FastPathStrategy; import org.apache.cassandra.tcm.ClusterMetadata; import org.apache.cassandra.tcm.Epoch; import org.apache.cassandra.utils.AbstractTypeGenerators.TypeGenBuilder; @@ -481,7 +482,7 @@ public final class CassandraGenerators AbstractReplicationStrategy replication = replicationGen.generate(rs).withKeyspace(nameGen).build().generate(rs); ReplicationParams replicationParams = ReplicationParams.fromStrategy(replication); boolean durableWrites = durableWritesGen.generate(rs); - KeyspaceParams params = new KeyspaceParams(durableWrites, replicationParams); + KeyspaceParams params = new KeyspaceParams(durableWrites, replicationParams, FastPathStrategy.simple()); Tables tables = Tables.none(); Views views = Views.none(); Types types = Types.none();