mirror of https://github.com/apache/cassandra
perf improvements
This commit is contained in:
parent
599cd59736
commit
7dadc080cb
|
|
@ -1 +1 @@
|
||||||
Subproject commit ef36616441bd4ff4fec5379d986c75ad5a62ff7d
|
Subproject commit 3562bb3c9ce4e9eecdf65e236e968ef3ee9e0a86
|
||||||
|
|
@ -47,9 +47,9 @@ public class AccordSpec
|
||||||
|
|
||||||
public volatile DurationSpec fast_path_update_delay = new DurationSpec.IntSecondsBound(5);
|
public volatile DurationSpec fast_path_update_delay = new DurationSpec.IntSecondsBound(5);
|
||||||
|
|
||||||
public volatile DurationSpec schedule_durability_frequency = new DurationSpec.IntSecondsBound(15);
|
public volatile DurationSpec schedule_durability_frequency = new DurationSpec.IntSecondsBound(5);
|
||||||
public volatile DurationSpec durability_txnid_lag = new DurationSpec.IntSecondsBound(5);
|
public volatile DurationSpec durability_txnid_lag = new DurationSpec.IntSecondsBound(5);
|
||||||
public volatile DurationSpec shard_durability_cycle = new DurationSpec.IntMinutesBound(2);
|
public volatile DurationSpec shard_durability_cycle = new DurationSpec.IntMinutesBound(1);
|
||||||
public volatile DurationSpec global_durability_cycle = new DurationSpec.IntMinutesBound(10);
|
public volatile DurationSpec global_durability_cycle = new DurationSpec.IntMinutesBound(10);
|
||||||
|
|
||||||
public enum TransactionalRangeMigration
|
public enum TransactionalRangeMigration
|
||||||
|
|
|
||||||
|
|
@ -500,6 +500,7 @@ public class Config
|
||||||
public volatile int counter_cache_keys_to_save = Integer.MAX_VALUE;
|
public volatile int counter_cache_keys_to_save = Integer.MAX_VALUE;
|
||||||
|
|
||||||
public DataStorageSpec.LongMebibytesBound paxos_cache_size = null;
|
public DataStorageSpec.LongMebibytesBound paxos_cache_size = null;
|
||||||
|
public DataStorageSpec.LongMebibytesBound accord_cache_size = null;
|
||||||
|
|
||||||
public DataStorageSpec.LongMebibytesBound consensus_migration_cache_size = null;
|
public DataStorageSpec.LongMebibytesBound consensus_migration_cache_size = null;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -227,6 +227,7 @@ public class DatabaseDescriptor
|
||||||
|
|
||||||
private static long keyCacheSizeInMiB;
|
private static long keyCacheSizeInMiB;
|
||||||
private static long paxosCacheSizeInMiB;
|
private static long paxosCacheSizeInMiB;
|
||||||
|
private static long accordCacheSizeInMiB;
|
||||||
private static long consensusMigrationCacheSizeInMiB;
|
private static long consensusMigrationCacheSizeInMiB;
|
||||||
private static long counterCacheSizeInMiB;
|
private static long counterCacheSizeInMiB;
|
||||||
private static long indexSummaryCapacityInMiB;
|
private static long indexSummaryCapacityInMiB;
|
||||||
|
|
@ -963,6 +964,22 @@ public class DatabaseDescriptor
|
||||||
+ conf.paxos_cache_size + "', supported values are <integer> >= 0.", false);
|
+ conf.paxos_cache_size + "', supported values are <integer> >= 0.", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// if paxosCacheSizeInMiB option was set to "auto" then size of the cache should be "max(10% of Heap (in MB), 1MB)
|
||||||
|
accordCacheSizeInMiB = (conf.accord_cache_size == null)
|
||||||
|
? Math.max(1, (int) ((Runtime.getRuntime().totalMemory() * 0.10) / 1024 / 1024))
|
||||||
|
: conf.accord_cache_size.toMebibytes();
|
||||||
|
|
||||||
|
if (accordCacheSizeInMiB < 0)
|
||||||
|
throw new NumberFormatException(); // to escape duplicating error message
|
||||||
|
}
|
||||||
|
catch (NumberFormatException e)
|
||||||
|
{
|
||||||
|
throw new ConfigurationException("paxos_cache_size option was set incorrectly to '"
|
||||||
|
+ conf.paxos_cache_size + "', supported values are <integer> >= 0.", false);
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// if consensusMigrationCacheSizeInMiB option was set to "auto" then size of the cache should be "min(1% of Heap (in MB), 50MB)
|
// if consensusMigrationCacheSizeInMiB option was set to "auto" then size of the cache should be "min(1% of Heap (in MB), 50MB)
|
||||||
|
|
@ -4266,6 +4283,11 @@ public class DatabaseDescriptor
|
||||||
return paxosCacheSizeInMiB;
|
return paxosCacheSizeInMiB;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static long getAccordCacheSizeInMiB()
|
||||||
|
{
|
||||||
|
return accordCacheSizeInMiB;
|
||||||
|
}
|
||||||
|
|
||||||
public static long getConsensusMigrationCacheSizeInMiB()
|
public static long getConsensusMigrationCacheSizeInMiB()
|
||||||
{
|
{
|
||||||
return consensusMigrationCacheSizeInMiB;
|
return consensusMigrationCacheSizeInMiB;
|
||||||
|
|
|
||||||
|
|
@ -978,11 +978,7 @@ public class CompactionIterator extends CompactionInfo.Holder implements Unfilte
|
||||||
if (redundantBeforeEntry == null)
|
if (redundantBeforeEntry == null)
|
||||||
return row;
|
return row;
|
||||||
|
|
||||||
TxnId redundantBeforeTxnId = redundantBeforeEntry.shardRedundantBefore();
|
return CommandsForKeysAccessor.withoutRedundantCommands(partitionKey, row, redundantBeforeEntry);
|
||||||
if (redundantBeforeTxnId.equals(TxnId.NONE))
|
|
||||||
return row;
|
|
||||||
|
|
||||||
return CommandsForKeysAccessor.withoutRedundantCommands(partitionKey, row, redundantBeforeTxnId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -268,7 +268,7 @@ public enum Verb
|
||||||
PAXOS2_PREPARE_REQ (40, P2, writeTimeout, MUTATION, () -> PaxosPrepare.requestSerializer, () -> PaxosPrepare.requestHandler, PAXOS2_PREPARE_RSP ),
|
PAXOS2_PREPARE_REQ (40, P2, writeTimeout, MUTATION, () -> PaxosPrepare.requestSerializer, () -> PaxosPrepare.requestHandler, PAXOS2_PREPARE_RSP ),
|
||||||
PAXOS2_PREPARE_REFRESH_RSP (51, P2, writeTimeout, REQUEST_RESPONSE, () -> PaxosPrepareRefresh.responseSerializer, RESPONSE_HANDLER ),
|
PAXOS2_PREPARE_REFRESH_RSP (51, P2, writeTimeout, REQUEST_RESPONSE, () -> PaxosPrepareRefresh.responseSerializer, RESPONSE_HANDLER ),
|
||||||
PAXOS2_PREPARE_REFRESH_REQ (41, P2, writeTimeout, MUTATION, () -> PaxosPrepareRefresh.requestSerializer, () -> PaxosPrepareRefresh.requestHandler, PAXOS2_PREPARE_REFRESH_RSP ),
|
PAXOS2_PREPARE_REFRESH_REQ (41, P2, writeTimeout, MUTATION, () -> PaxosPrepareRefresh.requestSerializer, () -> PaxosPrepareRefresh.requestHandler, PAXOS2_PREPARE_REFRESH_RSP ),
|
||||||
PAXOS2_PROPOSE_RSP (52, P2, writeTimeout, REQUEST_RESPONSE, () -> PaxosPropose.ACCEPT_RESULT_SERIALIZER, RESPONSE_HANDLER ),
|
PAXOS2_PROPOSE_RSP (52, P2, writeTimeout, REQUEST_RESPONSE, () -> PaxosPropose.ACCEPT_RESULT_SERIALIZER, RESPONSE_HANDLER ),
|
||||||
PAXOS2_PROPOSE_REQ (42, P2, writeTimeout, MUTATION, () -> PaxosPropose.requestSerializer, () -> PaxosPropose.requestHandler, PAXOS2_PROPOSE_RSP ),
|
PAXOS2_PROPOSE_REQ (42, P2, writeTimeout, MUTATION, () -> PaxosPropose.requestSerializer, () -> PaxosPropose.requestHandler, PAXOS2_PROPOSE_RSP ),
|
||||||
PAXOS2_COMMIT_AND_PREPARE_RSP (53, P2, writeTimeout, REQUEST_RESPONSE, () -> PaxosPrepare.responseSerializer, RESPONSE_HANDLER ),
|
PAXOS2_COMMIT_AND_PREPARE_RSP (53, P2, writeTimeout, REQUEST_RESPONSE, () -> PaxosPrepare.responseSerializer, RESPONSE_HANDLER ),
|
||||||
PAXOS2_COMMIT_AND_PREPARE_REQ (43, P2, writeTimeout, MUTATION, () -> PaxosCommitAndPrepare.requestSerializer, () -> PaxosCommitAndPrepare.requestHandler, PAXOS2_COMMIT_AND_PREPARE_RSP ),
|
PAXOS2_COMMIT_AND_PREPARE_REQ (43, P2, writeTimeout, MUTATION, () -> PaxosCommitAndPrepare.requestSerializer, () -> PaxosCommitAndPrepare.requestHandler, PAXOS2_COMMIT_AND_PREPARE_RSP ),
|
||||||
|
|
@ -307,41 +307,41 @@ public enum Verb
|
||||||
DATA_MOVEMENT_EXECUTED_REQ (817, P1, rpcTimeout, MISC, () -> DataMovement.Status.serializer, () -> DataMovements.instance, DATA_MOVEMENT_EXECUTED_RSP ),
|
DATA_MOVEMENT_EXECUTED_REQ (817, P1, rpcTimeout, MISC, () -> DataMovement.Status.serializer, () -> DataMovements.instance, DATA_MOVEMENT_EXECUTED_RSP ),
|
||||||
|
|
||||||
// accord
|
// accord
|
||||||
ACCORD_SIMPLE_RSP (119, P2, writeTimeout, REQUEST_RESPONSE, () -> EnumSerializer.simpleReply, RESPONSE_HANDLER ),
|
ACCORD_SIMPLE_RSP (119, P2, writeTimeout, IMMEDIATE, () -> EnumSerializer.simpleReply, RESPONSE_HANDLER ),
|
||||||
ACCORD_PRE_ACCEPT_RSP (120, P2, writeTimeout, REQUEST_RESPONSE, () -> PreacceptSerializers.reply, RESPONSE_HANDLER ),
|
ACCORD_PRE_ACCEPT_RSP (120, P2, writeTimeout, IMMEDIATE, () -> PreacceptSerializers.reply, RESPONSE_HANDLER ),
|
||||||
ACCORD_PRE_ACCEPT_REQ (121, P2, writeTimeout, IMMEDIATE, () -> PreacceptSerializers.request, AccordService::verbHandlerOrNoop, ACCORD_PRE_ACCEPT_RSP ),
|
ACCORD_PRE_ACCEPT_REQ (121, P2, writeTimeout, IMMEDIATE, () -> PreacceptSerializers.request, AccordService::verbHandlerOrNoop, ACCORD_PRE_ACCEPT_RSP ),
|
||||||
ACCORD_ACCEPT_RSP (122, P2, writeTimeout, REQUEST_RESPONSE, () -> AcceptSerializers.reply, RESPONSE_HANDLER ),
|
ACCORD_ACCEPT_RSP (122, P2, writeTimeout, IMMEDIATE, () -> AcceptSerializers.reply, RESPONSE_HANDLER ),
|
||||||
ACCORD_ACCEPT_REQ (123, P2, writeTimeout, IMMEDIATE, () -> AcceptSerializers.request, AccordService::verbHandlerOrNoop, ACCORD_ACCEPT_RSP ),
|
ACCORD_ACCEPT_REQ (123, P2, writeTimeout, IMMEDIATE, () -> AcceptSerializers.request, AccordService::verbHandlerOrNoop, ACCORD_ACCEPT_RSP ),
|
||||||
ACCORD_ACCEPT_INVALIDATE_REQ (124, P2, writeTimeout, IMMEDIATE, () -> AcceptSerializers.invalidate, AccordService::verbHandlerOrNoop, ACCORD_ACCEPT_RSP ),
|
ACCORD_ACCEPT_INVALIDATE_REQ (124, P2, writeTimeout, IMMEDIATE, () -> AcceptSerializers.invalidate, AccordService::verbHandlerOrNoop, ACCORD_ACCEPT_RSP ),
|
||||||
ACCORD_READ_RSP (125, P2, writeTimeout, REQUEST_RESPONSE, () -> ReadDataSerializers.reply, RESPONSE_HANDLER ),
|
ACCORD_READ_RSP (125, P2, writeTimeout, IMMEDIATE, () -> ReadDataSerializers.reply, RESPONSE_HANDLER ),
|
||||||
ACCORD_READ_REQ (126, P2, writeTimeout, IMMEDIATE, () -> ReadDataSerializers.readData, AccordService::verbHandlerOrNoop, ACCORD_READ_RSP ),
|
ACCORD_READ_REQ (126, P2, writeTimeout, IMMEDIATE, () -> ReadDataSerializers.readData, AccordService::verbHandlerOrNoop, ACCORD_READ_RSP ),
|
||||||
ACCORD_COMMIT_REQ (127, P2, writeTimeout, IMMEDIATE, () -> CommitSerializers.request, AccordService::verbHandlerOrNoop, ACCORD_READ_RSP ),
|
ACCORD_COMMIT_REQ (127, P2, writeTimeout, IMMEDIATE, () -> CommitSerializers.request, AccordService::verbHandlerOrNoop, ACCORD_READ_RSP ),
|
||||||
ACCORD_COMMIT_INVALIDATE_REQ (128, P2, writeTimeout, IMMEDIATE, () -> CommitSerializers.invalidate, AccordService::verbHandlerOrNoop ),
|
ACCORD_COMMIT_INVALIDATE_REQ (128, P2, writeTimeout, IMMEDIATE, () -> CommitSerializers.invalidate, AccordService::verbHandlerOrNoop ),
|
||||||
ACCORD_APPLY_RSP (129, P2, writeTimeout, REQUEST_RESPONSE, () -> ApplySerializers.reply, RESPONSE_HANDLER ),
|
ACCORD_APPLY_RSP (129, P2, writeTimeout, IMMEDIATE, () -> ApplySerializers.reply, RESPONSE_HANDLER ),
|
||||||
ACCORD_APPLY_REQ (130, P2, writeTimeout, IMMEDIATE, () -> ApplySerializers.request, AccordService::verbHandlerOrNoop, ACCORD_APPLY_RSP ),
|
ACCORD_APPLY_REQ (130, P2, writeTimeout, IMMEDIATE, () -> ApplySerializers.request, AccordService::verbHandlerOrNoop, ACCORD_APPLY_RSP ),
|
||||||
ACCORD_BEGIN_RECOVER_RSP (131, P2, writeTimeout, REQUEST_RESPONSE, () -> RecoverySerializers.reply, RESPONSE_HANDLER ),
|
ACCORD_BEGIN_RECOVER_RSP (131, P2, writeTimeout, IMMEDIATE, () -> RecoverySerializers.reply, RESPONSE_HANDLER ),
|
||||||
ACCORD_BEGIN_RECOVER_REQ (132, P2, writeTimeout, IMMEDIATE, () -> RecoverySerializers.request, AccordService::verbHandlerOrNoop, ACCORD_BEGIN_RECOVER_RSP ),
|
ACCORD_BEGIN_RECOVER_REQ (132, P2, writeTimeout, IMMEDIATE, () -> RecoverySerializers.request, AccordService::verbHandlerOrNoop, ACCORD_BEGIN_RECOVER_RSP ),
|
||||||
ACCORD_BEGIN_INVALIDATE_RSP (133, P2, writeTimeout, REQUEST_RESPONSE, () -> BeginInvalidationSerializers.reply, RESPONSE_HANDLER ),
|
ACCORD_BEGIN_INVALIDATE_RSP (133, P2, writeTimeout, IMMEDIATE, () -> BeginInvalidationSerializers.reply, RESPONSE_HANDLER ),
|
||||||
ACCORD_BEGIN_INVALIDATE_REQ (134, P2, writeTimeout, IMMEDIATE, () -> BeginInvalidationSerializers.request, AccordService::verbHandlerOrNoop, ACCORD_BEGIN_INVALIDATE_RSP ),
|
ACCORD_BEGIN_INVALIDATE_REQ (134, P2, writeTimeout, IMMEDIATE, () -> BeginInvalidationSerializers.request, AccordService::verbHandlerOrNoop, ACCORD_BEGIN_INVALIDATE_RSP ),
|
||||||
ACCORD_WAIT_ON_COMMIT_RSP (136, P2, writeTimeout, REQUEST_RESPONSE, () -> WaitOnCommitSerializer.reply, RESPONSE_HANDLER ),
|
ACCORD_WAIT_ON_COMMIT_RSP (136, P2, writeTimeout, IMMEDIATE, () -> WaitOnCommitSerializer.reply, RESPONSE_HANDLER ),
|
||||||
ACCORD_WAIT_ON_COMMIT_REQ (135, P2, writeTimeout, IMMEDIATE, () -> WaitOnCommitSerializer.request, AccordService::verbHandlerOrNoop, ACCORD_WAIT_ON_COMMIT_RSP ),
|
ACCORD_WAIT_ON_COMMIT_REQ (135, P2, writeTimeout, IMMEDIATE, () -> WaitOnCommitSerializer.request, AccordService::verbHandlerOrNoop, ACCORD_WAIT_ON_COMMIT_RSP ),
|
||||||
ACCORD_WAIT_UNTIL_APPLIED_REQ (137, P2, writeTimeout, IMMEDIATE, () -> ReadDataSerializers.waitUntilApplied, AccordService::verbHandlerOrNoop, ACCORD_READ_RSP ),
|
ACCORD_WAIT_UNTIL_APPLIED_REQ (137, P2, writeTimeout, IMMEDIATE, () -> ReadDataSerializers.waitUntilApplied, AccordService::verbHandlerOrNoop, ACCORD_READ_RSP ),
|
||||||
ACCORD_INFORM_OF_TXN_REQ (138, P2, writeTimeout, IMMEDIATE, () -> InformOfTxnIdSerializers.request, AccordService::verbHandlerOrNoop, ACCORD_SIMPLE_RSP ),
|
ACCORD_INFORM_OF_TXN_REQ (138, P2, writeTimeout, IMMEDIATE, () -> InformOfTxnIdSerializers.request, AccordService::verbHandlerOrNoop, ACCORD_SIMPLE_RSP ),
|
||||||
ACCORD_INFORM_HOME_DURABLE_REQ (139, P2, writeTimeout, IMMEDIATE, () -> InformHomeDurableSerializers.request, AccordService::verbHandlerOrNoop, ACCORD_SIMPLE_RSP ),
|
ACCORD_INFORM_HOME_DURABLE_REQ (139, P2, writeTimeout, IMMEDIATE, () -> InformHomeDurableSerializers.request, AccordService::verbHandlerOrNoop, ACCORD_SIMPLE_RSP ),
|
||||||
ACCORD_INFORM_DURABLE_REQ (140, P2, writeTimeout, IMMEDIATE, () -> InformDurableSerializers.request, AccordService::verbHandlerOrNoop, ACCORD_SIMPLE_RSP ),
|
ACCORD_INFORM_DURABLE_REQ (140, P2, writeTimeout, IMMEDIATE, () -> InformDurableSerializers.request, AccordService::verbHandlerOrNoop, ACCORD_SIMPLE_RSP ),
|
||||||
ACCORD_CHECK_STATUS_RSP (141, P2, writeTimeout, REQUEST_RESPONSE, () -> CheckStatusSerializers.reply, RESPONSE_HANDLER ),
|
ACCORD_CHECK_STATUS_RSP (141, P2, writeTimeout, IMMEDIATE, () -> CheckStatusSerializers.reply, RESPONSE_HANDLER ),
|
||||||
ACCORD_CHECK_STATUS_REQ (142, P2, writeTimeout, IMMEDIATE, () -> CheckStatusSerializers.request, AccordService::verbHandlerOrNoop, ACCORD_CHECK_STATUS_RSP ),
|
ACCORD_CHECK_STATUS_REQ (142, P2, writeTimeout, IMMEDIATE, () -> CheckStatusSerializers.request, AccordService::verbHandlerOrNoop, ACCORD_CHECK_STATUS_RSP ),
|
||||||
ACCORD_GET_DEPS_RSP (143, P2, writeTimeout, REQUEST_RESPONSE, () -> GetDepsSerializers.reply, RESPONSE_HANDLER ),
|
ACCORD_GET_DEPS_RSP (143, P2, writeTimeout, IMMEDIATE, () -> GetDepsSerializers.reply, RESPONSE_HANDLER ),
|
||||||
ACCORD_GET_DEPS_REQ (144, P2, writeTimeout, IMMEDIATE, () -> GetDepsSerializers.request, AccordService::verbHandlerOrNoop, ACCORD_GET_DEPS_RSP ),
|
ACCORD_GET_DEPS_REQ (144, P2, writeTimeout, IMMEDIATE, () -> GetDepsSerializers.request, AccordService::verbHandlerOrNoop, ACCORD_GET_DEPS_RSP ),
|
||||||
ACCORD_GET_EPHMRL_READ_DEPS_RSP (161, P2, writeTimeout, REQUEST_RESPONSE, () -> GetEphmrlReadDepsSerializers.reply, RESPONSE_HANDLER ),
|
ACCORD_GET_EPHMRL_READ_DEPS_RSP (161, P2, writeTimeout, IMMEDIATE, () -> GetEphmrlReadDepsSerializers.reply, RESPONSE_HANDLER ),
|
||||||
ACCORD_GET_EPHMRL_READ_DEPS_REQ (162, P2, writeTimeout, IMMEDIATE, () -> GetEphmrlReadDepsSerializers.request, AccordService::verbHandlerOrNoop, ACCORD_GET_EPHMRL_READ_DEPS_RSP),
|
ACCORD_GET_EPHMRL_READ_DEPS_REQ (162, P2, writeTimeout, IMMEDIATE, () -> GetEphmrlReadDepsSerializers.request, AccordService::verbHandlerOrNoop, ACCORD_GET_EPHMRL_READ_DEPS_RSP),
|
||||||
ACCORD_GET_MAX_CONFLICT_RSP (163, P2, writeTimeout, REQUEST_RESPONSE, () -> GetMaxConflictSerializers.reply, RESPONSE_HANDLER ),
|
ACCORD_GET_MAX_CONFLICT_RSP (163, P2, writeTimeout, IMMEDIATE, () -> GetMaxConflictSerializers.reply, RESPONSE_HANDLER ),
|
||||||
ACCORD_GET_MAX_CONFLICT_REQ (164, P2, writeTimeout, IMMEDIATE, () -> GetMaxConflictSerializers.request, AccordService::verbHandlerOrNoop, ACCORD_GET_MAX_CONFLICT_RSP),
|
ACCORD_GET_MAX_CONFLICT_REQ (164, P2, writeTimeout, IMMEDIATE, () -> GetMaxConflictSerializers.request, AccordService::verbHandlerOrNoop, ACCORD_GET_MAX_CONFLICT_RSP),
|
||||||
ACCORD_FETCH_DATA_RSP (145, P2, repairTimeout,REQUEST_RESPONSE, () -> FetchSerializers.reply, RESPONSE_HANDLER ),
|
ACCORD_FETCH_DATA_RSP (145, P2, repairTimeout,IMMEDIATE, () -> FetchSerializers.reply, RESPONSE_HANDLER ),
|
||||||
ACCORD_FETCH_DATA_REQ (146, P2, repairTimeout,IMMEDIATE, () -> FetchSerializers.request, AccordService::verbHandlerOrNoop, ACCORD_FETCH_DATA_RSP ),
|
ACCORD_FETCH_DATA_REQ (146, P2, repairTimeout,IMMEDIATE, () -> FetchSerializers.request, AccordService::verbHandlerOrNoop, ACCORD_FETCH_DATA_RSP ),
|
||||||
ACCORD_SET_SHARD_DURABLE_REQ (147, P2, writeTimeout, IMMEDIATE, () -> SetDurableSerializers.shardDurable, AccordService::verbHandlerOrNoop, ACCORD_SIMPLE_RSP ),
|
ACCORD_SET_SHARD_DURABLE_REQ (147, P2, writeTimeout, IMMEDIATE, () -> SetDurableSerializers.shardDurable, AccordService::verbHandlerOrNoop, ACCORD_SIMPLE_RSP ),
|
||||||
ACCORD_SET_GLOBALLY_DURABLE_REQ (148, P2, writeTimeout, IMMEDIATE, () -> SetDurableSerializers.globallyDurable,AccordService::verbHandlerOrNoop, ACCORD_SIMPLE_RSP ),
|
ACCORD_SET_GLOBALLY_DURABLE_REQ (148, P2, writeTimeout, IMMEDIATE, () -> SetDurableSerializers.globallyDurable,AccordService::verbHandlerOrNoop, ACCORD_SIMPLE_RSP ),
|
||||||
ACCORD_QUERY_DURABLE_BEFORE_RSP (149, P2, writeTimeout, REQUEST_RESPONSE, () -> QueryDurableBeforeSerializers.reply, RESPONSE_HANDLER ),
|
ACCORD_QUERY_DURABLE_BEFORE_RSP (149, P2, writeTimeout, IMMEDIATE, () -> QueryDurableBeforeSerializers.reply, RESPONSE_HANDLER ),
|
||||||
ACCORD_QUERY_DURABLE_BEFORE_REQ (150, P2, writeTimeout, IMMEDIATE, () -> QueryDurableBeforeSerializers.request,AccordService::verbHandlerOrNoop, ACCORD_QUERY_DURABLE_BEFORE_RSP ),
|
ACCORD_QUERY_DURABLE_BEFORE_REQ (150, P2, writeTimeout, IMMEDIATE, () -> QueryDurableBeforeSerializers.request,AccordService::verbHandlerOrNoop, ACCORD_QUERY_DURABLE_BEFORE_RSP ),
|
||||||
|
|
||||||
ACCORD_SYNC_NOTIFY_REQ (151, P2, writeTimeout, IMMEDIATE, () -> Notification.listSerializer, () -> AccordSyncPropagator.verbHandler, ACCORD_SIMPLE_RSP ),
|
ACCORD_SYNC_NOTIFY_REQ (151, P2, writeTimeout, IMMEDIATE, () -> Notification.listSerializer, () -> AccordSyncPropagator.verbHandler, ACCORD_SIMPLE_RSP ),
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,7 @@ public class AccordCachingState<K, V> extends IntrusiveLinkedListNode
|
||||||
|
|
||||||
int estimatedSizeOnHeap(ToLongFunction<V> estimator)
|
int estimatedSizeOnHeap(ToLongFunction<V> estimator)
|
||||||
{
|
{
|
||||||
shouldUpdateSize = false;
|
shouldUpdateSize = false; // TODO (expected): probably not the safest place to clear need to compute size
|
||||||
return lastQueriedEstimatedSizeOnHeap = Ints.checkedCast(EMPTY_SIZE + estimateStateOnHeapSize(estimator));
|
return lastQueriedEstimatedSizeOnHeap = Ints.checkedCast(EMPTY_SIZE + estimateStateOnHeapSize(estimator));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -204,7 +204,7 @@ public class AccordCachingState<K, V> extends IntrusiveLinkedListNode
|
||||||
protected State<K, V> state(State<K, V> next)
|
protected State<K, V> state(State<K, V> next)
|
||||||
{
|
{
|
||||||
State<K, V> prev = state;
|
State<K, V> prev = state;
|
||||||
if (prev != next)
|
if (prev != next) // TODO (expected): we change state to transition the cache state machine but often keep payload the same - so shouldn't recompute
|
||||||
shouldUpdateSize = true;
|
shouldUpdateSize = true;
|
||||||
return state = next;
|
return state = next;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ import accord.api.Agent;
|
||||||
import accord.api.DataStore;
|
import accord.api.DataStore;
|
||||||
import accord.api.Key;
|
import accord.api.Key;
|
||||||
import accord.api.ProgressLog;
|
import accord.api.ProgressLog;
|
||||||
import accord.impl.CommandsForKey;
|
import accord.local.CommandsForKey;
|
||||||
import accord.impl.CommandsSummary;
|
import accord.impl.CommandsSummary;
|
||||||
import accord.impl.TimestampsForKey;
|
import accord.impl.TimestampsForKey;
|
||||||
import accord.local.Command;
|
import accord.local.Command;
|
||||||
|
|
@ -114,8 +114,8 @@ public class AccordCommandStore extends CommandStore implements CacheSize
|
||||||
private final ExecutionOrder executionOrder;
|
private final ExecutionOrder executionOrder;
|
||||||
private final AccordStateCache stateCache;
|
private final AccordStateCache stateCache;
|
||||||
private final AccordStateCache.Instance<TxnId, Command, AccordSafeCommand> commandCache;
|
private final AccordStateCache.Instance<TxnId, Command, AccordSafeCommand> commandCache;
|
||||||
private final AccordStateCache.Instance<RoutableKey, TimestampsForKey, AccordSafeTimestampsForKey> timestampsForKeyCache;
|
private final AccordStateCache.Instance<Key, TimestampsForKey, AccordSafeTimestampsForKey> timestampsForKeyCache;
|
||||||
private final AccordStateCache.Instance<RoutableKey, CommandsForKey, AccordSafeCommandsForKey> commandsForKeyCache;
|
private final AccordStateCache.Instance<Key, CommandsForKey, AccordSafeCommandsForKey> commandsForKeyCache;
|
||||||
private AsyncOperation<?> currentOperation = null;
|
private AsyncOperation<?> currentOperation = null;
|
||||||
private AccordSafeCommandStore current = null;
|
private AccordSafeCommandStore current = null;
|
||||||
private long lastSystemTimestampMicros = Long.MIN_VALUE;
|
private long lastSystemTimestampMicros = Long.MIN_VALUE;
|
||||||
|
|
@ -161,7 +161,7 @@ public class AccordCommandStore extends CommandStore implements CacheSize
|
||||||
this::validateCommand,
|
this::validateCommand,
|
||||||
AccordObjectSizes::command);
|
AccordObjectSizes::command);
|
||||||
timestampsForKeyCache =
|
timestampsForKeyCache =
|
||||||
stateCache.instance(RoutableKey.class,
|
stateCache.instance(Key.class,
|
||||||
AccordSafeTimestampsForKey.class,
|
AccordSafeTimestampsForKey.class,
|
||||||
AccordSafeTimestampsForKey::new,
|
AccordSafeTimestampsForKey::new,
|
||||||
this::loadTimestampsForKey,
|
this::loadTimestampsForKey,
|
||||||
|
|
@ -169,7 +169,7 @@ public class AccordCommandStore extends CommandStore implements CacheSize
|
||||||
this::validateTimestampsForKey,
|
this::validateTimestampsForKey,
|
||||||
AccordObjectSizes::timestampsForKey);
|
AccordObjectSizes::timestampsForKey);
|
||||||
commandsForKeyCache =
|
commandsForKeyCache =
|
||||||
stateCache.instance(RoutableKey.class,
|
stateCache.instance(Key.class,
|
||||||
AccordSafeCommandsForKey.class,
|
AccordSafeCommandsForKey.class,
|
||||||
AccordSafeCommandsForKey::new,
|
AccordSafeCommandsForKey::new,
|
||||||
this::loadCommandsForKey,
|
this::loadCommandsForKey,
|
||||||
|
|
@ -220,7 +220,7 @@ public class AccordCommandStore extends CommandStore implements CacheSize
|
||||||
|
|
||||||
MessageProvider messageProvider = journal.makeMessageProvider(txnId);
|
MessageProvider messageProvider = journal.makeMessageProvider(txnId);
|
||||||
|
|
||||||
SerializerSupport.TxnAndDeps txnAndDeps = SerializerSupport.extractTxnAndDeps(status, accepted, messageProvider);
|
SerializerSupport.TxnAndDeps txnAndDeps = SerializerSupport.extractTxnAndDeps(unsafeRangesForEpoch(), status, accepted, messageProvider);
|
||||||
Seekables<?, ?> keys = txnAndDeps.txn.keys();
|
Seekables<?, ?> keys = txnAndDeps.txn.keys();
|
||||||
if (keys.domain() != Routable.Domain.Range)
|
if (keys.domain() != Routable.Domain.Range)
|
||||||
throw new AssertionError(String.format("Txn keys are not range for %s", txnAndDeps.txn));
|
throw new AssertionError(String.format("Txn keys are not range for %s", txnAndDeps.txn));
|
||||||
|
|
@ -311,12 +311,12 @@ public class AccordCommandStore extends CommandStore implements CacheSize
|
||||||
return commandCache;
|
return commandCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AccordStateCache.Instance<RoutableKey, TimestampsForKey, AccordSafeTimestampsForKey> timestampsForKeyCache()
|
public AccordStateCache.Instance<Key, TimestampsForKey, AccordSafeTimestampsForKey> timestampsForKeyCache()
|
||||||
{
|
{
|
||||||
return timestampsForKeyCache;
|
return timestampsForKeyCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AccordStateCache.Instance<RoutableKey, CommandsForKey, AccordSafeCommandsForKey> commandsForKeyCache()
|
public AccordStateCache.Instance<Key, CommandsForKey, AccordSafeCommandsForKey> commandsForKeyCache()
|
||||||
{
|
{
|
||||||
return commandsForKeyCache;
|
return commandsForKeyCache;
|
||||||
}
|
}
|
||||||
|
|
@ -466,8 +466,8 @@ public class AccordCommandStore extends CommandStore implements CacheSize
|
||||||
|
|
||||||
public AccordSafeCommandStore beginOperation(PreLoadContext preLoadContext,
|
public AccordSafeCommandStore beginOperation(PreLoadContext preLoadContext,
|
||||||
Map<TxnId, AccordSafeCommand> commands,
|
Map<TxnId, AccordSafeCommand> commands,
|
||||||
NavigableMap<RoutableKey, AccordSafeTimestampsForKey> timestampsForKeys,
|
NavigableMap<Key, AccordSafeTimestampsForKey> timestampsForKeys,
|
||||||
NavigableMap<RoutableKey, AccordSafeCommandsForKey> commandsForKeys)
|
NavigableMap<Key, AccordSafeCommandsForKey> commandsForKeys)
|
||||||
{
|
{
|
||||||
Invariants.checkState(current == null);
|
Invariants.checkState(current == null);
|
||||||
commands.values().forEach(AccordSafeState::preExecute);
|
commands.values().forEach(AccordSafeState::preExecute);
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ import accord.primitives.Range;
|
||||||
import accord.topology.Topology;
|
import accord.topology.Topology;
|
||||||
import accord.utils.RandomSource;
|
import accord.utils.RandomSource;
|
||||||
import org.apache.cassandra.cache.CacheSize;
|
import org.apache.cassandra.cache.CacheSize;
|
||||||
|
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||||
import org.apache.cassandra.metrics.AccordStateCacheMetrics;
|
import org.apache.cassandra.metrics.AccordStateCacheMetrics;
|
||||||
import org.apache.cassandra.metrics.CacheSizeMetrics;
|
import org.apache.cassandra.metrics.CacheSizeMetrics;
|
||||||
import org.apache.cassandra.schema.TableId;
|
import org.apache.cassandra.schema.TableId;
|
||||||
|
|
@ -47,7 +48,7 @@ public class AccordCommandStores extends CommandStores implements CacheSize
|
||||||
ShardDistributor shardDistributor, ProgressLog.Factory progressLogFactory, AccordJournal journal)
|
ShardDistributor shardDistributor, ProgressLog.Factory progressLogFactory, AccordJournal journal)
|
||||||
{
|
{
|
||||||
super(time, agent, store, random, shardDistributor, progressLogFactory, AccordCommandStore.factory(journal, new AccordStateCacheMetrics(ACCORD_STATE_CACHE)));
|
super(time, agent, store, random, shardDistributor, progressLogFactory, AccordCommandStore.factory(journal, new AccordStateCacheMetrics(ACCORD_STATE_CACHE)));
|
||||||
setCapacity(maxCacheSize());
|
setCapacity(DatabaseDescriptor.getAccordCacheSizeInMiB() << 20);
|
||||||
this.cacheSizeMetrics = new CacheSizeMetrics(ACCORD_STATE_CACHE, this);
|
this.cacheSizeMetrics = new CacheSizeMetrics(ACCORD_STATE_CACHE, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -110,11 +111,6 @@ public class AccordCommandStores extends CommandStores implements CacheSize
|
||||||
forEach(commandStore -> ((AccordSafeCommandStore) commandStore).commandStore().setCapacity(perStore));
|
forEach(commandStore -> ((AccordSafeCommandStore) commandStore).commandStore().setCapacity(perStore));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long maxCacheSize()
|
|
||||||
{
|
|
||||||
return 5 << 20; // TODO (required): make configurable
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized Supplier<EpochReady> updateTopology(Node node, Topology newTopology, boolean startSync)
|
public synchronized Supplier<EpochReady> updateTopology(Node node, Topology newTopology, boolean startSync)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import java.time.Duration;
|
||||||
import accord.config.LocalConfig;
|
import accord.config.LocalConfig;
|
||||||
import org.apache.cassandra.config.Config;
|
import org.apache.cassandra.config.Config;
|
||||||
|
|
||||||
|
// TODO (expected): should this be merged with AccordSpec?
|
||||||
public class AccordConfiguration implements LocalConfig
|
public class AccordConfiguration implements LocalConfig
|
||||||
{
|
{
|
||||||
private final Config config;
|
private final Config config;
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
@ -570,6 +571,7 @@ public class AccordJournal implements Shutdownable
|
||||||
|
|
||||||
Key(Timestamp timestamp, Type type)
|
Key(Timestamp timestamp, Type type)
|
||||||
{
|
{
|
||||||
|
if (timestamp == null) throw new NullPointerException("Null timestamp for type " + type);
|
||||||
this.timestamp = timestamp;
|
this.timestamp = timestamp;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
@ -1361,6 +1363,19 @@ public class AccordJournal implements Shutdownable
|
||||||
return presentMessages;
|
return presentMessages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<MessageType> all()
|
||||||
|
{
|
||||||
|
Set<Type> types = EnumSet.allOf(Type.class);
|
||||||
|
Set<Key> keys = new ObjectHashSet<>(types.size() + 1, 0.9f);
|
||||||
|
for (Type type : types)
|
||||||
|
keys.add(new Key(txnId, type));
|
||||||
|
Set<Key> presentKeys = journal.test(keys);
|
||||||
|
Set<MessageType> presentMessages = new ObjectHashSet<>(presentKeys.size() + 1, 0.9f);
|
||||||
|
for (Key key : presentKeys)
|
||||||
|
presentMessages.add(key.type.outgoingType);
|
||||||
|
return presentMessages;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PreAccept preAccept()
|
public PreAccept preAccept()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import accord.api.Key;
|
import accord.api.Key;
|
||||||
import accord.impl.CommandsForKey;
|
import accord.local.CommandsForKey;
|
||||||
import accord.impl.TimestampsForKey;
|
import accord.impl.TimestampsForKey;
|
||||||
import accord.local.Command;
|
import accord.local.Command;
|
||||||
import accord.local.Command.WaitingOn;
|
import accord.local.Command.WaitingOn;
|
||||||
|
|
@ -593,7 +593,7 @@ public class AccordKeyspace
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO (expected): garbage-free filtering, reusing encoding
|
// TODO (expected): garbage-free filtering, reusing encoding
|
||||||
public Row withoutRedundantCommands(PartitionKey key, Row row, TxnId redundantBefore)
|
public Row withoutRedundantCommands(PartitionKey key, Row row, RedundantBefore.Entry redundantBefore)
|
||||||
{
|
{
|
||||||
Invariants.checkState(row.columnCount() == 1);
|
Invariants.checkState(row.columnCount() == 1);
|
||||||
Cell<?> cell = row.getCell(data);
|
Cell<?> cell = row.getCell(data);
|
||||||
|
|
@ -601,7 +601,10 @@ public class AccordKeyspace
|
||||||
return row;
|
return row;
|
||||||
|
|
||||||
CommandsForKey current = CommandsForKeySerializer.fromBytes(key, cell.buffer());
|
CommandsForKey current = CommandsForKeySerializer.fromBytes(key, cell.buffer());
|
||||||
CommandsForKey updated = current.withoutRedundant(redundantBefore);
|
if (current == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
CommandsForKey updated = current.withRedundantBefore(redundantBefore);
|
||||||
if (current == updated)
|
if (current == updated)
|
||||||
return row;
|
return row;
|
||||||
|
|
||||||
|
|
@ -823,7 +826,7 @@ public class AccordKeyspace
|
||||||
Command.Committed committed = command.asCommitted();
|
Command.Committed committed = command.asCommitted();
|
||||||
Command.Committed originalCommitted = original != null && original.isCommitted() ? original.asCommitted() : null;
|
Command.Committed originalCommitted = original != null && original.isCommitted() ? original.asCommitted() : null;
|
||||||
if (originalCommitted == null || committed.waitingOn != originalCommitted.waitingOn)
|
if (originalCommitted == null || committed.waitingOn != originalCommitted.waitingOn)
|
||||||
builder.addCell(live(CommandsColumns.waiting_on, timestampMicros, WaitingOnSerializer.serialize(committed.waitingOn)));
|
builder.addCell(live(CommandsColumns.waiting_on, timestampMicros, WaitingOnSerializer.serialize(committed.txnId(), committed.waitingOn)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Row row = builder.build();
|
Row row = builder.build();
|
||||||
|
|
@ -1190,10 +1193,10 @@ public class AccordKeyspace
|
||||||
Ballot promised = deserializePromisedOrNull(row);
|
Ballot promised = deserializePromisedOrNull(row);
|
||||||
Ballot accepted = deserializeAcceptedOrNull(row);
|
Ballot accepted = deserializeAcceptedOrNull(row);
|
||||||
|
|
||||||
WaitingOnProvider waitingOn = deserializeWaitingOn(row);
|
WaitingOnProvider waitingOn = deserializeWaitingOn(txnId, row);
|
||||||
MessageProvider messages = commandStore.makeMessageProvider(txnId);
|
MessageProvider messages = commandStore.makeMessageProvider(txnId);
|
||||||
|
|
||||||
return SerializerSupport.reconstruct(attrs, status, executeAt, promised, accepted, waitingOn, messages);
|
return SerializerSupport.reconstruct(commandStore.unsafeRangesForEpoch(), attrs, status, executeAt, promised, accepted, waitingOn, messages);
|
||||||
}
|
}
|
||||||
catch (Throwable t)
|
catch (Throwable t)
|
||||||
{
|
{
|
||||||
|
|
@ -1271,7 +1274,7 @@ public class AccordKeyspace
|
||||||
return deserializeTimestampOrNull(row.getBlob("accepted_ballot"), Ballot::fromBits);
|
return deserializeTimestampOrNull(row.getBlob("accepted_ballot"), Ballot::fromBits);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static WaitingOnProvider deserializeWaitingOn(UntypedResultSet.Row row)
|
private static WaitingOnProvider deserializeWaitingOn(TxnId txnId, UntypedResultSet.Row row)
|
||||||
{
|
{
|
||||||
ByteBuffer bytes = row.getBlob("waiting_on");
|
ByteBuffer bytes = row.getBlob("waiting_on");
|
||||||
|
|
||||||
|
|
@ -1285,7 +1288,7 @@ public class AccordKeyspace
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return WaitingOnSerializer.deserialize(deps, bytes);
|
return WaitingOnSerializer.deserialize(txnId, deps.keyDeps.keys(), deps.rangeDeps.txnIds(), bytes);
|
||||||
}
|
}
|
||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -24,11 +24,12 @@ import java.util.function.ToLongFunction;
|
||||||
import accord.api.Key;
|
import accord.api.Key;
|
||||||
import accord.api.Result;
|
import accord.api.Result;
|
||||||
import accord.api.RoutingKey;
|
import accord.api.RoutingKey;
|
||||||
import accord.impl.CommandsForKey;
|
import accord.local.CommandsForKey;
|
||||||
import accord.impl.CommandsForKey.Info;
|
import accord.local.CommandsForKey.TxnInfo;
|
||||||
import accord.impl.TimestampsForKey;
|
import accord.impl.TimestampsForKey;
|
||||||
import accord.local.Command;
|
import accord.local.Command;
|
||||||
import accord.local.Command.WaitingOn;
|
import accord.local.Command.WaitingOn;
|
||||||
|
import accord.local.CommandsForKey.TxnInfoWithMissing;
|
||||||
import accord.local.CommonAttributes;
|
import accord.local.CommonAttributes;
|
||||||
import accord.local.Node;
|
import accord.local.Node;
|
||||||
import accord.local.SaveStatus;
|
import accord.local.SaveStatus;
|
||||||
|
|
@ -305,7 +306,6 @@ public class AccordObjectSizes
|
||||||
return ACCEPTED;
|
return ACCEPTED;
|
||||||
case Committed:
|
case Committed:
|
||||||
case Stable:
|
case Stable:
|
||||||
case ReadyToExecute:
|
|
||||||
return COMMITTED;
|
return COMMITTED;
|
||||||
case PreApplied:
|
case PreApplied:
|
||||||
case Applied:
|
case Applied:
|
||||||
|
|
@ -363,22 +363,25 @@ public class AccordObjectSizes
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long EMPTY_CFK_SIZE = measure(new CommandsForKey(null));
|
private static long EMPTY_CFK_SIZE = measure(new CommandsForKey(null));
|
||||||
private static long EMPTY_INFO_SIZE = measure(CommandsForKey.Info.createMock(null, null, null));
|
private static long EMPTY_INFO_SIZE = measure(TxnInfo.createMock(TxnId.NONE, null, null, null));
|
||||||
|
private static long EMPTY_INFO_WITH_MISSING_ADDITIONAL_SIZE = measure(TxnInfo.createMock(TxnId.NONE, null, null, null)) - EMPTY_INFO_SIZE;
|
||||||
public static long commandsForKey(CommandsForKey cfk)
|
public static long commandsForKey(CommandsForKey cfk)
|
||||||
{
|
{
|
||||||
long size = EMPTY_CFK_SIZE;
|
long size = EMPTY_CFK_SIZE;
|
||||||
size += key(cfk.key());
|
size += key(cfk.key());
|
||||||
size += 2 * ObjectSizes.sizeOfReferenceArray(cfk.size());
|
size += ObjectSizes.sizeOfReferenceArray(cfk.size());
|
||||||
size += cfk.size() * TIMESTAMP_SIZE;
|
size += cfk.size() * EMPTY_INFO_SIZE;
|
||||||
for (int i = 0 ; i < cfk.size() ; ++i)
|
for (int i = 0 ; i < cfk.size() ; ++i)
|
||||||
{
|
{
|
||||||
Info info = cfk.info(i);
|
TxnInfo info = cfk.get(i);
|
||||||
if (info.getClass() == CommandsForKey.NoInfo.class)
|
if (info.getClass() != TxnInfoWithMissing.class) continue;
|
||||||
continue;
|
TxnInfoWithMissing infoWithMissing = (TxnInfoWithMissing) info;
|
||||||
|
if (infoWithMissing.missing.length > 0)
|
||||||
size += EMPTY_INFO_SIZE;
|
{
|
||||||
if (info.missing.length > 0)
|
size += EMPTY_INFO_WITH_MISSING_ADDITIONAL_SIZE;
|
||||||
size += ObjectSizes.sizeOfReferenceArray(info.missing.length);
|
size += ObjectSizes.sizeOfReferenceArray(infoWithMissing.missing.length);
|
||||||
|
size += infoWithMissing.missing.length * TIMESTAMP_SIZE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,7 @@ import accord.api.DataStore;
|
||||||
import accord.api.Key;
|
import accord.api.Key;
|
||||||
import accord.api.ProgressLog;
|
import accord.api.ProgressLog;
|
||||||
import accord.impl.AbstractSafeCommandStore;
|
import accord.impl.AbstractSafeCommandStore;
|
||||||
import accord.impl.CommandsForKey;
|
import accord.local.CommandsForKey;
|
||||||
import accord.impl.CommandsForKeys;
|
|
||||||
import accord.impl.CommandsSummary;
|
import accord.impl.CommandsSummary;
|
||||||
import accord.local.Command;
|
import accord.local.Command;
|
||||||
import accord.local.CommandStores.RangesForEpoch;
|
import accord.local.CommandStores.RangesForEpoch;
|
||||||
|
|
@ -41,7 +40,6 @@ import accord.local.PreLoadContext;
|
||||||
import accord.primitives.AbstractKeys;
|
import accord.primitives.AbstractKeys;
|
||||||
import accord.primitives.Deps;
|
import accord.primitives.Deps;
|
||||||
import accord.primitives.Ranges;
|
import accord.primitives.Ranges;
|
||||||
import accord.primitives.RoutableKey;
|
|
||||||
import accord.primitives.Routables;
|
import accord.primitives.Routables;
|
||||||
import accord.primitives.Seekables;
|
import accord.primitives.Seekables;
|
||||||
import accord.primitives.Timestamp;
|
import accord.primitives.Timestamp;
|
||||||
|
|
@ -53,16 +51,16 @@ import static accord.primitives.Routable.Domain.Range;
|
||||||
public class AccordSafeCommandStore extends AbstractSafeCommandStore<AccordSafeCommand, AccordSafeTimestampsForKey, AccordSafeCommandsForKey>
|
public class AccordSafeCommandStore extends AbstractSafeCommandStore<AccordSafeCommand, AccordSafeTimestampsForKey, AccordSafeCommandsForKey>
|
||||||
{
|
{
|
||||||
private final Map<TxnId, AccordSafeCommand> commands;
|
private final Map<TxnId, AccordSafeCommand> commands;
|
||||||
private final NavigableMap<RoutableKey, AccordSafeCommandsForKey> commandsForKeys;
|
private final NavigableMap<Key, AccordSafeCommandsForKey> commandsForKeys;
|
||||||
private final NavigableMap<RoutableKey, AccordSafeTimestampsForKey> timestampsForKeys;
|
private final NavigableMap<Key, AccordSafeTimestampsForKey> timestampsForKeys;
|
||||||
private final AccordCommandStore commandStore;
|
private final AccordCommandStore commandStore;
|
||||||
private final RangesForEpoch ranges;
|
private final RangesForEpoch ranges;
|
||||||
CommandsForRanges.Updater rangeUpdates = null;
|
CommandsForRanges.Updater rangeUpdates = null;
|
||||||
|
|
||||||
public AccordSafeCommandStore(PreLoadContext context,
|
public AccordSafeCommandStore(PreLoadContext context,
|
||||||
Map<TxnId, AccordSafeCommand> commands,
|
Map<TxnId, AccordSafeCommand> commands,
|
||||||
NavigableMap<RoutableKey, AccordSafeTimestampsForKey> timestampsForKey,
|
NavigableMap<Key, AccordSafeTimestampsForKey> timestampsForKey,
|
||||||
NavigableMap<RoutableKey, AccordSafeCommandsForKey> commandsForKey,
|
NavigableMap<Key, AccordSafeCommandsForKey> commandsForKey,
|
||||||
AccordCommandStore commandStore)
|
AccordCommandStore commandStore)
|
||||||
{
|
{
|
||||||
super(context);
|
super(context);
|
||||||
|
|
@ -94,7 +92,7 @@ public class AccordSafeCommandStore extends AbstractSafeCommandStore<AccordSafeC
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AccordSafeCommandsForKey getCommandsForKeyInternal(RoutableKey key)
|
protected AccordSafeCommandsForKey getCommandsForKeyInternal(Key key)
|
||||||
{
|
{
|
||||||
return commandsForKeys.get(key);
|
return commandsForKeys.get(key);
|
||||||
}
|
}
|
||||||
|
|
@ -106,7 +104,7 @@ public class AccordSafeCommandStore extends AbstractSafeCommandStore<AccordSafeC
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AccordSafeCommandsForKey getCommandsForKeyIfLoaded(RoutableKey key)
|
protected AccordSafeCommandsForKey getCommandsForKeyIfLoaded(Key key)
|
||||||
{
|
{
|
||||||
AccordSafeCommandsForKey cfk = commandStore.commandsForKeyCache().acquireIfLoaded(key);
|
AccordSafeCommandsForKey cfk = commandStore.commandsForKeyCache().acquireIfLoaded(key);
|
||||||
if (cfk != null) cfk.preExecute();
|
if (cfk != null) cfk.preExecute();
|
||||||
|
|
@ -114,7 +112,7 @@ public class AccordSafeCommandStore extends AbstractSafeCommandStore<AccordSafeC
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AccordSafeTimestampsForKey getTimestampsForKeyInternal(RoutableKey key)
|
protected AccordSafeTimestampsForKey getTimestampsForKeyInternal(Key key)
|
||||||
{
|
{
|
||||||
return timestampsForKeys.get(key);
|
return timestampsForKeys.get(key);
|
||||||
}
|
}
|
||||||
|
|
@ -126,7 +124,7 @@ public class AccordSafeCommandStore extends AbstractSafeCommandStore<AccordSafeC
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AccordSafeTimestampsForKey getTimestampsForKeyIfLoaded(RoutableKey key)
|
protected AccordSafeTimestampsForKey getTimestampsForKeyIfLoaded(Key key)
|
||||||
{
|
{
|
||||||
AccordSafeTimestampsForKey cfk = commandStore.timestampsForKeyCache().acquireIfLoaded(key);
|
AccordSafeTimestampsForKey cfk = commandStore.timestampsForKeyCache().acquireIfLoaded(key);
|
||||||
if (cfk != null) cfk.preExecute();
|
if (cfk != null) cfk.preExecute();
|
||||||
|
|
@ -177,14 +175,14 @@ public class AccordSafeCommandStore extends AbstractSafeCommandStore<AccordSafeC
|
||||||
Ranges allRanges = ranges.all();
|
Ranges allRanges = ranges.all();
|
||||||
deps.keyDeps.keys().forEach(allRanges, key -> {
|
deps.keyDeps.keys().forEach(allRanges, key -> {
|
||||||
// TODO (now): batch register to minimise GC
|
// TODO (now): batch register to minimise GC
|
||||||
deps.keyDeps.forEach(key, txnId -> {
|
deps.keyDeps.forEach(key, (txnId, txnIdx) -> {
|
||||||
// TODO (desired, efficiency): this can be made more efficient by batching by epoch
|
// TODO (desired, efficiency): this can be made more efficient by batching by epoch
|
||||||
if (ranges.coordinates(txnId).contains(key))
|
if (ranges.coordinates(txnId).contains(key))
|
||||||
return; // already coordinates, no need to replicate
|
return; // already coordinates, no need to replicate
|
||||||
if (!ranges.allBefore(txnId.epoch()).contains(key))
|
if (!ranges.allBefore(txnId.epoch()).contains(key))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
CommandsForKeys.registerNotWitnessed(this, key, txnId);
|
get(key).registerHistorical(this, txnId);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
CommandsForRanges commandsForRanges = commandStore.commandsForRanges();
|
CommandsForRanges commandsForRanges = commandStore.commandsForRanges();
|
||||||
|
|
@ -221,7 +219,7 @@ public class AccordSafeCommandStore extends AbstractSafeCommandStore<AccordSafeC
|
||||||
for (Key key : keys)
|
for (Key key : keys)
|
||||||
{
|
{
|
||||||
if (!slice.contains(key)) continue;
|
if (!slice.contains(key)) continue;
|
||||||
CommandsForKey commands = commandsForKey(key).current();
|
CommandsForKey commands = get(key).current();
|
||||||
accumulate = map.apply(commands, accumulate);
|
accumulate = map.apply(commands, accumulate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -233,11 +231,11 @@ public class AccordSafeCommandStore extends AbstractSafeCommandStore<AccordSafeC
|
||||||
Routables<?> sliced = keysOrRanges.slice(slice, Routables.Slice.Minimal);
|
Routables<?> sliced = keysOrRanges.slice(slice, Routables.Slice.Minimal);
|
||||||
if (!context.keys().slice(slice, Routables.Slice.Minimal).containsAll(sliced))
|
if (!context.keys().slice(slice, Routables.Slice.Minimal).containsAll(sliced))
|
||||||
throw new AssertionError("Range(s) detected not present in the PreLoadContext: expected " + context.keys() + " but given " + keysOrRanges);
|
throw new AssertionError("Range(s) detected not present in the PreLoadContext: expected " + context.keys() + " but given " + keysOrRanges);
|
||||||
for (RoutableKey key : timestampsForKeys.keySet())
|
for (Key key : commandsForKeys.keySet())
|
||||||
{
|
{
|
||||||
//TODO (duplicate code): this is a repeat of Key... only change is checking contains in range
|
//TODO (duplicate code): this is a repeat of Key... only change is checking contains in range
|
||||||
if (!sliced.contains(key)) continue;
|
if (!sliced.contains(key)) continue;
|
||||||
CommandsForKey commands = commandsForKey(key).current();
|
CommandsForKey commands = get(key).current();
|
||||||
accumulate = map.apply(commands, accumulate);
|
accumulate = map.apply(commands, accumulate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -263,22 +261,20 @@ public class AccordSafeCommandStore extends AbstractSafeCommandStore<AccordSafeC
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void update(Command prev, Command updated, @Nullable Seekables<?, ?> keysOrRanges)
|
protected void update(Command prev, Command updated)
|
||||||
{
|
{
|
||||||
super.update(prev, updated, keysOrRanges);
|
super.update(prev, updated);
|
||||||
|
|
||||||
if (updated.txnId().domain() == Range && CommandsForKey.needsUpdate(prev, updated))
|
if (updated.txnId().domain() == Range && CommandsForKey.needsUpdate(prev, updated))
|
||||||
{
|
{
|
||||||
|
Seekables<?, ?> keysOrRanges = updated.keysOrRanges();
|
||||||
|
if (keysOrRanges == null) keysOrRanges = prev.keysOrRanges();
|
||||||
if (keysOrRanges == null)
|
if (keysOrRanges == null)
|
||||||
{
|
return;
|
||||||
if (updated.known().isDefinitionKnown()) keysOrRanges = updated.partialTxn().keys();
|
|
||||||
else if (prev.known().isDefinitionKnown()) keysOrRanges = prev.partialTxn().keys();
|
|
||||||
else return;
|
|
||||||
}
|
|
||||||
List<TxnId> waitingOn;
|
|
||||||
|
|
||||||
if (updated.partialDeps() == null) waitingOn = Collections.emptyList();
|
List<TxnId> waitingOn;
|
||||||
// TODO (required): this is faulty: we cannot simply save the raw transaction ids, as they may be for other ranges
|
// TODO (required): this is faulty: we cannot simply save the raw transaction ids, as they may be for other ranges
|
||||||
|
if (updated.partialDeps() == null) waitingOn = Collections.emptyList();
|
||||||
else waitingOn = updated.partialDeps().txnIds();
|
else waitingOn = updated.partialDeps().txnIds();
|
||||||
updateRanges().put(updated.txnId(), (Ranges)keysOrRanges, updated.saveStatus(), updated.executeAt(), waitingOn);
|
updateRanges().put(updated.txnId(), (Ranges)keysOrRanges, updated.saveStatus(), updated.executeAt(), waitingOn);
|
||||||
}
|
}
|
||||||
|
|
@ -300,8 +296,8 @@ public class AccordSafeCommandStore extends AbstractSafeCommandStore<AccordSafeC
|
||||||
}
|
}
|
||||||
|
|
||||||
public void postExecute(Map<TxnId, AccordSafeCommand> commands,
|
public void postExecute(Map<TxnId, AccordSafeCommand> commands,
|
||||||
Map<RoutableKey, AccordSafeTimestampsForKey> timestampsForKey,
|
Map<Key, AccordSafeTimestampsForKey> timestampsForKey,
|
||||||
Map<RoutableKey, AccordSafeCommandsForKey> commandsForKeys
|
Map<Key, AccordSafeCommandsForKey> commandsForKeys
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
postExecute();
|
postExecute();
|
||||||
|
|
|
||||||
|
|
@ -23,18 +23,17 @@ import java.util.Objects;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
|
||||||
import accord.api.Key;
|
import accord.api.Key;
|
||||||
import accord.impl.CommandsForKey;
|
import accord.local.CommandsForKey;
|
||||||
import accord.impl.SafeCommandsForKey;
|
import accord.local.SafeCommandsForKey;
|
||||||
import accord.primitives.RoutableKey;
|
|
||||||
|
|
||||||
public class AccordSafeCommandsForKey extends SafeCommandsForKey implements AccordSafeState<RoutableKey, CommandsForKey>
|
public class AccordSafeCommandsForKey extends SafeCommandsForKey implements AccordSafeState<Key, CommandsForKey>
|
||||||
{
|
{
|
||||||
private boolean invalidated;
|
private boolean invalidated;
|
||||||
private final AccordCachingState<RoutableKey, CommandsForKey> global;
|
private final AccordCachingState<Key, CommandsForKey> global;
|
||||||
private CommandsForKey original;
|
private CommandsForKey original;
|
||||||
private CommandsForKey current;
|
private CommandsForKey current;
|
||||||
|
|
||||||
public AccordSafeCommandsForKey(AccordCachingState<RoutableKey, CommandsForKey> global)
|
public AccordSafeCommandsForKey(AccordCachingState<Key, CommandsForKey> global)
|
||||||
{
|
{
|
||||||
super((Key) global.key());
|
super((Key) global.key());
|
||||||
this.global = global;
|
this.global = global;
|
||||||
|
|
@ -83,7 +82,7 @@ public class AccordSafeCommandsForKey extends SafeCommandsForKey implements Acco
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AccordCachingState<RoutableKey, CommandsForKey> global()
|
public AccordCachingState<Key, CommandsForKey> global()
|
||||||
{
|
{
|
||||||
checkNotInvalidated();
|
checkNotInvalidated();
|
||||||
return global;
|
return global;
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@ public interface AccordSafeState<K, V> extends SafeState<V>
|
||||||
{
|
{
|
||||||
void set(V update);
|
void set(V update);
|
||||||
V original();
|
V original();
|
||||||
|
void invalidate();
|
||||||
|
boolean invalidated();
|
||||||
void preExecute();
|
void preExecute();
|
||||||
void postExecute();
|
void postExecute();
|
||||||
AccordCachingState<K, V> global();
|
AccordCachingState<K, V> global();
|
||||||
|
|
|
||||||
|
|
@ -26,17 +26,16 @@ import com.google.common.annotations.VisibleForTesting;
|
||||||
import accord.api.Key;
|
import accord.api.Key;
|
||||||
import accord.impl.SafeTimestampsForKey;
|
import accord.impl.SafeTimestampsForKey;
|
||||||
import accord.impl.TimestampsForKey;
|
import accord.impl.TimestampsForKey;
|
||||||
import accord.primitives.RoutableKey;
|
|
||||||
import accord.primitives.Timestamp;
|
import accord.primitives.Timestamp;
|
||||||
|
|
||||||
public class AccordSafeTimestampsForKey extends SafeTimestampsForKey implements AccordSafeState<RoutableKey, TimestampsForKey>
|
public class AccordSafeTimestampsForKey extends SafeTimestampsForKey implements AccordSafeState<Key, TimestampsForKey>
|
||||||
{
|
{
|
||||||
private boolean invalidated;
|
private boolean invalidated;
|
||||||
private final AccordCachingState<RoutableKey, TimestampsForKey> global;
|
private final AccordCachingState<Key, TimestampsForKey> global;
|
||||||
private TimestampsForKey original;
|
private TimestampsForKey original;
|
||||||
private TimestampsForKey current;
|
private TimestampsForKey current;
|
||||||
|
|
||||||
public AccordSafeTimestampsForKey(AccordCachingState<RoutableKey, TimestampsForKey> global)
|
public AccordSafeTimestampsForKey(AccordCachingState<Key, TimestampsForKey> global)
|
||||||
{
|
{
|
||||||
super((Key) global.key());
|
super((Key) global.key());
|
||||||
this.global = global;
|
this.global = global;
|
||||||
|
|
@ -71,7 +70,7 @@ public class AccordSafeTimestampsForKey extends SafeTimestampsForKey implements
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AccordCachingState<RoutableKey, TimestampsForKey> global()
|
public AccordCachingState<Key, TimestampsForKey> global()
|
||||||
{
|
{
|
||||||
checkNotInvalidated();
|
checkNotInvalidated();
|
||||||
return global;
|
return global;
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ public class AccordService implements IAccordService, Shutdownable
|
||||||
private final AccordDataStore dataStore;
|
private final AccordDataStore dataStore;
|
||||||
private final AccordJournal journal;
|
private final AccordJournal journal;
|
||||||
private final CoordinateDurabilityScheduling durabilityScheduling;
|
private final CoordinateDurabilityScheduling durabilityScheduling;
|
||||||
private final AccordVerbHandler<? extends Request> verbHandler;
|
private final AccordVerbHandler<? extends Request> requestHandler;
|
||||||
private final LocalConfig configuration;
|
private final LocalConfig configuration;
|
||||||
@GuardedBy("this")
|
@GuardedBy("this")
|
||||||
private State state = State.INIT;
|
private State state = State.INIT;
|
||||||
|
|
@ -296,7 +296,7 @@ public class AccordService implements IAccordService, Shutdownable
|
||||||
configuration);
|
configuration);
|
||||||
this.nodeShutdown = toShutdownable(node);
|
this.nodeShutdown = toShutdownable(node);
|
||||||
this.durabilityScheduling = new CoordinateDurabilityScheduling(node);
|
this.durabilityScheduling = new CoordinateDurabilityScheduling(node);
|
||||||
this.verbHandler = new AccordVerbHandler<>(node, configService, journal);
|
this.requestHandler = new AccordVerbHandler<>(node, configService, journal);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -313,14 +313,14 @@ public class AccordService implements IAccordService, Shutdownable
|
||||||
durabilityScheduling.setShardCycleTime(Ints.checkedCast(DatabaseDescriptor.getAccordShardDurabilityCycle(SECONDS)), SECONDS);
|
durabilityScheduling.setShardCycleTime(Ints.checkedCast(DatabaseDescriptor.getAccordShardDurabilityCycle(SECONDS)), SECONDS);
|
||||||
durabilityScheduling.setTxnIdLag(Ints.checkedCast(DatabaseDescriptor.getAccordScheduleDurabilityTxnIdLag(SECONDS)), TimeUnit.SECONDS);
|
durabilityScheduling.setTxnIdLag(Ints.checkedCast(DatabaseDescriptor.getAccordScheduleDurabilityTxnIdLag(SECONDS)), TimeUnit.SECONDS);
|
||||||
durabilityScheduling.setFrequency(Ints.checkedCast(DatabaseDescriptor.getAccordScheduleDurabilityFrequency(SECONDS)), SECONDS);
|
durabilityScheduling.setFrequency(Ints.checkedCast(DatabaseDescriptor.getAccordScheduleDurabilityFrequency(SECONDS)), SECONDS);
|
||||||
durabilityScheduling.start();
|
// durabilityScheduling.start();
|
||||||
state = State.STARTED;
|
state = State.STARTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IVerbHandler<? extends Request> verbHandler()
|
public IVerbHandler<? extends Request> verbHandler()
|
||||||
{
|
{
|
||||||
return verbHandler;
|
return requestHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ import com.google.common.collect.ImmutableSortedMap;
|
||||||
|
|
||||||
import accord.api.Key;
|
import accord.api.Key;
|
||||||
import accord.api.RoutingKey;
|
import accord.api.RoutingKey;
|
||||||
import accord.impl.CommandsForKey;
|
import accord.local.CommandsForKey;
|
||||||
import accord.impl.CommandsSummary;
|
import accord.impl.CommandsSummary;
|
||||||
import accord.local.Command;
|
import accord.local.Command;
|
||||||
import accord.local.SaveStatus;
|
import accord.local.SaveStatus;
|
||||||
|
|
@ -64,7 +64,6 @@ import org.apache.cassandra.utils.IntervalTree;
|
||||||
import static accord.local.SafeCommandStore.*;
|
import static accord.local.SafeCommandStore.*;
|
||||||
import static accord.local.SafeCommandStore.TestDep.ANY_DEPS;
|
import static accord.local.SafeCommandStore.TestDep.ANY_DEPS;
|
||||||
import static accord.local.SafeCommandStore.TestDep.WITH;
|
import static accord.local.SafeCommandStore.TestDep.WITH;
|
||||||
import static accord.local.SafeCommandStore.TestStartedAt.ANY;
|
|
||||||
import static accord.local.SafeCommandStore.TestStartedAt.STARTED_BEFORE;
|
import static accord.local.SafeCommandStore.TestStartedAt.STARTED_BEFORE;
|
||||||
import static accord.local.SafeCommandStore.TestStatus.ANY_STATUS;
|
import static accord.local.SafeCommandStore.TestStatus.ANY_STATUS;
|
||||||
import static accord.local.Status.Stable;
|
import static accord.local.Status.Stable;
|
||||||
|
|
@ -379,11 +378,13 @@ public class CommandsForRanges
|
||||||
|
|
||||||
private static Range toRange(Interval<RoutableKey, RangeCommandSummary> interval)
|
private static Range toRange(Interval<RoutableKey, RangeCommandSummary> interval)
|
||||||
{
|
{
|
||||||
TokenKey start = (TokenKey) interval.min;
|
AccordRoutingKey start = (AccordRoutingKey) interval.min;
|
||||||
TokenKey end = (TokenKey) interval.max;
|
if (!(start instanceof AccordRoutingKey.SentinelKey))
|
||||||
|
start = new TokenKey(start.table(), start.token().decreaseSlightly());
|
||||||
|
AccordRoutingKey end = (AccordRoutingKey) interval.max;
|
||||||
// TODO (required, correctness) : accord doesn't support wrap around, so decreaseSlightly may fail in some cases
|
// TODO (required, correctness) : accord doesn't support wrap around, so decreaseSlightly may fail in some cases
|
||||||
// TODO (required, correctness) : this logic is mostly used for testing, so is it actually safe for all partitioners?
|
// TODO (required, correctness) : this logic is mostly used for testing, so is it actually safe for all partitioners?
|
||||||
return new TokenRange(start.withToken(start.token().decreaseSlightly()), end);
|
return new TokenRange(start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|
|
||||||
|
|
@ -117,6 +117,9 @@ public class AccordAgent implements Agent
|
||||||
public boolean isExpired(TxnId initiated, long now)
|
public boolean isExpired(TxnId initiated, long now)
|
||||||
{
|
{
|
||||||
// TODO: should distinguish between reads and writes
|
// TODO: should distinguish between reads and writes
|
||||||
|
if (initiated.kind().isSyncPoint())
|
||||||
|
return false;
|
||||||
|
|
||||||
return now - initiated.hlc() > getReadRpcTimeout(MICROSECONDS);
|
return now - initiated.hlc() > getReadRpcTimeout(MICROSECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,12 +33,12 @@ import com.google.common.collect.ImmutableSet;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import accord.api.Key;
|
||||||
import accord.api.RoutingKey;
|
import accord.api.RoutingKey;
|
||||||
import accord.local.KeyHistory;
|
import accord.local.KeyHistory;
|
||||||
import accord.local.PreLoadContext;
|
import accord.local.PreLoadContext;
|
||||||
import accord.primitives.Range;
|
import accord.primitives.Range;
|
||||||
import accord.primitives.Ranges;
|
import accord.primitives.Ranges;
|
||||||
import accord.primitives.RoutableKey;
|
|
||||||
import accord.primitives.Seekables;
|
import accord.primitives.Seekables;
|
||||||
import accord.primitives.TxnId;
|
import accord.primitives.TxnId;
|
||||||
import accord.utils.Invariants;
|
import accord.utils.Invariants;
|
||||||
|
|
@ -121,7 +121,7 @@ public class AsyncLoader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void referenceAndAssembleReadsForKey(RoutableKey key,
|
private void referenceAndAssembleReadsForKey(Key key,
|
||||||
AsyncOperation.Context context,
|
AsyncOperation.Context context,
|
||||||
List<AsyncChain<?>> listenChains)
|
List<AsyncChain<?>> listenChains)
|
||||||
{
|
{
|
||||||
|
|
@ -157,7 +157,7 @@ public class AsyncLoader
|
||||||
{
|
{
|
||||||
case Key:
|
case Key:
|
||||||
// cast to Keys fails...
|
// cast to Keys fails...
|
||||||
Iterable<RoutableKey> keys = (Iterable<RoutableKey>) keysOrRanges;
|
Iterable<Key> keys = (Iterable<Key>) keysOrRanges;
|
||||||
keys.forEach(key -> referenceAndAssembleReadsForKey(key, context, chains));
|
keys.forEach(key -> referenceAndAssembleReadsForKey(key, context, chains));
|
||||||
break;
|
break;
|
||||||
case Range:
|
case Range:
|
||||||
|
|
@ -172,7 +172,7 @@ public class AsyncLoader
|
||||||
|
|
||||||
private AsyncChain<?> referenceAndDispatchReadsForRange(AsyncOperation.Context context)
|
private AsyncChain<?> referenceAndDispatchReadsForRange(AsyncOperation.Context context)
|
||||||
{
|
{
|
||||||
AsyncChain<Set<? extends RoutableKey>> overlappingKeys = findOverlappingKeys((Ranges) keysOrRanges);
|
AsyncChain<Set<? extends Key>> overlappingKeys = findOverlappingKeys((Ranges) keysOrRanges);
|
||||||
|
|
||||||
return overlappingKeys.flatMap(keys -> {
|
return overlappingKeys.flatMap(keys -> {
|
||||||
if (keys.isEmpty())
|
if (keys.isEmpty())
|
||||||
|
|
@ -183,14 +183,14 @@ public class AsyncLoader
|
||||||
}, commandStore);
|
}, commandStore);
|
||||||
}
|
}
|
||||||
|
|
||||||
private AsyncChain<Set<? extends RoutableKey>> findOverlappingKeys(Ranges ranges)
|
private AsyncChain<Set<? extends Key>> findOverlappingKeys(Ranges ranges)
|
||||||
{
|
{
|
||||||
Invariants.checkArgument(!ranges.isEmpty());
|
Invariants.checkArgument(!ranges.isEmpty());
|
||||||
|
|
||||||
List<AsyncChain<Set<PartitionKey>>> chains = new ArrayList<>(ranges.size());
|
List<AsyncChain<Set<PartitionKey>>> chains = new ArrayList<>(ranges.size());
|
||||||
for (Range range : ranges)
|
for (Range range : ranges)
|
||||||
chains.add(findOverlappingKeys(range));
|
chains.add(findOverlappingKeys(range));
|
||||||
return AsyncChains.reduce(chains, (a, b) -> ImmutableSet.<RoutableKey>builder().addAll(a).addAll(b).build());
|
return AsyncChains.reduce(chains, (a, b) -> ImmutableSet.<Key>builder().addAll(a).addAll(b).build());
|
||||||
}
|
}
|
||||||
|
|
||||||
private AsyncChain<Set<PartitionKey>> findOverlappingKeys(Range range)
|
private AsyncChain<Set<PartitionKey>> findOverlappingKeys(Range range)
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.slf4j.MDC;
|
import org.slf4j.MDC;
|
||||||
|
|
||||||
|
import accord.api.Key;
|
||||||
import accord.local.CommandStore;
|
import accord.local.CommandStore;
|
||||||
import accord.local.PreLoadContext;
|
import accord.local.PreLoadContext;
|
||||||
import accord.local.SafeCommandStore;
|
import accord.local.SafeCommandStore;
|
||||||
|
|
@ -67,8 +68,8 @@ public abstract class AsyncOperation<R> extends AsyncChains.Head<R> implements R
|
||||||
static class Context
|
static class Context
|
||||||
{
|
{
|
||||||
final HashMap<TxnId, AccordSafeCommand> commands = new HashMap<>();
|
final HashMap<TxnId, AccordSafeCommand> commands = new HashMap<>();
|
||||||
final TreeMap<RoutableKey, AccordSafeTimestampsForKey> timestampsForKey = new TreeMap<>();
|
final TreeMap<Key, AccordSafeTimestampsForKey> timestampsForKey = new TreeMap<>();
|
||||||
final TreeMap<RoutableKey, AccordSafeCommandsForKey> commandsForKey = new TreeMap<>();
|
final TreeMap<Key, AccordSafeCommandsForKey> commandsForKey = new TreeMap<>();
|
||||||
|
|
||||||
void releaseResources(AccordCommandStore commandStore)
|
void releaseResources(AccordCommandStore commandStore)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,6 @@ public class AccordInteropApply extends Apply implements Command.TransientListen
|
||||||
case PreCommitted:
|
case PreCommitted:
|
||||||
case Committed:
|
case Committed:
|
||||||
case PreApplied:
|
case PreApplied:
|
||||||
case ReadyToExecute:
|
|
||||||
synchronized (this)
|
synchronized (this)
|
||||||
{
|
{
|
||||||
waitingOn.set(safeStore.commandStore().id());
|
waitingOn.set(safeStore.commandStore().id());
|
||||||
|
|
@ -249,7 +248,6 @@ public class AccordInteropApply extends Apply implements Command.TransientListen
|
||||||
case PreCommitted:
|
case PreCommitted:
|
||||||
case Committed:
|
case Committed:
|
||||||
case PreApplied:
|
case PreApplied:
|
||||||
case ReadyToExecute:
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case Applied:
|
case Applied:
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,10 @@ import java.util.Arrays;
|
||||||
import com.google.common.primitives.Ints;
|
import com.google.common.primitives.Ints;
|
||||||
|
|
||||||
import accord.api.Key;
|
import accord.api.Key;
|
||||||
import accord.impl.CommandsForKey;
|
import accord.local.CommandsForKey;
|
||||||
import accord.impl.CommandsForKey.Info;
|
import accord.local.CommandsForKey.TxnInfo;
|
||||||
import accord.impl.CommandsForKey.InternalStatus;
|
import accord.local.CommandsForKey.InternalStatus;
|
||||||
import accord.impl.CommandsForKey.NoInfo;
|
import accord.local.CommandsForKey.Unmanaged;
|
||||||
import accord.local.Node;
|
import accord.local.Node;
|
||||||
import accord.primitives.Routable.Domain;
|
import accord.primitives.Routable.Domain;
|
||||||
import accord.primitives.Timestamp;
|
import accord.primitives.Timestamp;
|
||||||
|
|
@ -35,8 +35,10 @@ import accord.primitives.Txn;
|
||||||
import accord.primitives.TxnId;
|
import accord.primitives.TxnId;
|
||||||
import accord.utils.Invariants;
|
import accord.utils.Invariants;
|
||||||
import org.apache.cassandra.db.TypeSizes;
|
import org.apache.cassandra.db.TypeSizes;
|
||||||
|
import org.apache.cassandra.db.marshal.ByteBufferAccessor;
|
||||||
import org.apache.cassandra.utils.vint.VIntCoding;
|
import org.apache.cassandra.utils.vint.VIntCoding;
|
||||||
|
|
||||||
|
import static accord.local.CommandsForKey.NO_PENDING_UNMANAGED;
|
||||||
import static accord.primitives.Txn.Kind.ExclusiveSyncPoint;
|
import static accord.primitives.Txn.Kind.ExclusiveSyncPoint;
|
||||||
import static accord.primitives.Txn.Kind.Read;
|
import static accord.primitives.Txn.Kind.Read;
|
||||||
import static accord.primitives.Txn.Kind.Write;
|
import static accord.primitives.Txn.Kind.Write;
|
||||||
|
|
@ -104,23 +106,7 @@ public class CommandsForKeySerializer
|
||||||
{
|
{
|
||||||
int commandCount = cfk.size();
|
int commandCount = cfk.size();
|
||||||
if (commandCount == 0)
|
if (commandCount == 0)
|
||||||
{
|
return ByteBuffer.allocate(1);
|
||||||
// TODO (expected): we should not need to special-case, but best solution here is not to store redundantBefore;
|
|
||||||
// but this requires some modest deeper changes, so for now special-case serialization when empty
|
|
||||||
Timestamp redundantBefore = cfk.redundantBefore();
|
|
||||||
ByteBuffer out = ByteBuffer.allocate(TypeSizes.sizeofUnsignedVInt(0) +
|
|
||||||
TypeSizes.sizeofUnsignedVInt(redundantBefore.epoch()) +
|
|
||||||
TypeSizes.sizeofUnsignedVInt(redundantBefore.hlc()) +
|
|
||||||
TypeSizes.sizeofUnsignedVInt(redundantBefore.flags()) +
|
|
||||||
TypeSizes.sizeofUnsignedVInt(redundantBefore.node.id));
|
|
||||||
VIntCoding.writeUnsignedVInt32(0, out);
|
|
||||||
VIntCoding.writeUnsignedVInt(redundantBefore.epoch(), out);
|
|
||||||
VIntCoding.writeUnsignedVInt(redundantBefore.hlc(), out);
|
|
||||||
VIntCoding.writeUnsignedVInt32(redundantBefore.flags(), out);
|
|
||||||
VIntCoding.writeUnsignedVInt32(redundantBefore.node.id, out);
|
|
||||||
out.flip();
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
int[] nodeIds = cachedInts().getInts(Math.min(64, commandCount));
|
int[] nodeIds = cachedInts().getInts(Math.min(64, commandCount));
|
||||||
try
|
try
|
||||||
|
|
@ -129,11 +115,9 @@ public class CommandsForKeySerializer
|
||||||
// whether we have any missing transactions to encode, any executeAt that are not equal to their TxnId
|
// whether we have any missing transactions to encode, any executeAt that are not equal to their TxnId
|
||||||
// and whether there are any non-standard flag bits to encode
|
// and whether there are any non-standard flag bits to encode
|
||||||
boolean hasNonStandardFlags = false;
|
boolean hasNonStandardFlags = false;
|
||||||
int nodeIdCount, missingIdCount = 0, executeAtCount = 0, bitsPerExecuteAtFlags = 0;
|
int nodeIdCount = 0, missingIdCount = 0, executeAtCount = 0, bitsPerExecuteAtFlags = 0;
|
||||||
int bitsPerExecuteAtEpochDelta = 0, bitsPerExecuteAtHlcDelta = 1; // to permit us to use full 64 bits and encode in 5 bits we force at least one hlc bit
|
int bitsPerExecuteAtEpochDelta = 0, bitsPerExecuteAtHlcDelta = 1; // to permit us to use full 64 bits and encode in 5 bits we force at least one hlc bit
|
||||||
{
|
{
|
||||||
nodeIdCount = 1;
|
|
||||||
nodeIds[0] = cfk.redundantBefore().node.id;
|
|
||||||
for (int i = 0 ; i < commandCount ; ++i)
|
for (int i = 0 ; i < commandCount ; ++i)
|
||||||
{
|
{
|
||||||
if (nodeIdCount + 1 >= nodeIds.length)
|
if (nodeIdCount + 1 >= nodeIds.length)
|
||||||
|
|
@ -143,24 +127,19 @@ public class CommandsForKeySerializer
|
||||||
nodeIds = cachedInts().resize(nodeIds, nodeIds.length, nodeIds.length * 2);
|
nodeIds = cachedInts().resize(nodeIds, nodeIds.length, nodeIds.length * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
TxnId txnId = cfk.txnId(i);
|
TxnInfo txn = cfk.get(i);
|
||||||
Info info = cfk.info(i);
|
|
||||||
|
|
||||||
hasNonStandardFlags |= txnIdFlags(txnId) != STANDARD;
|
hasNonStandardFlags |= txnIdFlags(txn) != STANDARD;
|
||||||
nodeIds[nodeIdCount++] = txnId.node.id;
|
nodeIds[nodeIdCount++] = txn.node.id;
|
||||||
|
|
||||||
if (info.getClass() == NoInfo.class)
|
missingIdCount += txn.missing().length;
|
||||||
|
if (txn.executeAt == txn)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
missingIdCount += info.missing.length;
|
nodeIds[nodeIdCount++] = txn.executeAt.node.id;
|
||||||
|
bitsPerExecuteAtEpochDelta = Math.max(bitsPerExecuteAtEpochDelta, numberOfBitsToRepresent(txn.executeAt.epoch() - txn.epoch()));
|
||||||
if (info.executeAt == txnId)
|
bitsPerExecuteAtHlcDelta = Math.max(bitsPerExecuteAtHlcDelta, numberOfBitsToRepresent(txn.executeAt.hlc() - txn.hlc()));
|
||||||
continue;
|
bitsPerExecuteAtFlags = Math.max(bitsPerExecuteAtFlags, numberOfBitsToRepresent(txn.executeAt.flags()));
|
||||||
|
|
||||||
nodeIds[nodeIdCount++] = info.executeAt.node.id;
|
|
||||||
bitsPerExecuteAtEpochDelta = Math.max(bitsPerExecuteAtEpochDelta, numberOfBitsToRepresent(info.executeAt.epoch() - txnId.epoch()));
|
|
||||||
bitsPerExecuteAtHlcDelta = Math.max(bitsPerExecuteAtHlcDelta, numberOfBitsToRepresent(info.executeAt.hlc() - txnId.hlc()));
|
|
||||||
bitsPerExecuteAtFlags = Math.max(bitsPerExecuteAtFlags, numberOfBitsToRepresent(info.executeAt.flags()));
|
|
||||||
executeAtCount += 1;
|
executeAtCount += 1;
|
||||||
}
|
}
|
||||||
nodeIdCount = compact(nodeIds);
|
nodeIdCount = compact(nodeIds);
|
||||||
|
|
@ -175,8 +154,8 @@ public class CommandsForKeySerializer
|
||||||
int maxHeaderBits = minHeaderBits;
|
int maxHeaderBits = minHeaderBits;
|
||||||
int totalBytes = 0;
|
int totalBytes = 0;
|
||||||
|
|
||||||
long prevEpoch = cfk.redundantBefore().epoch();
|
long prevEpoch = cfk.get(0).epoch();
|
||||||
long prevHlc = cfk.redundantBefore().hlc();
|
long prevHlc = cfk.get(0).hlc();
|
||||||
int[] bytesHistogram = cachedInts().getInts(12);
|
int[] bytesHistogram = cachedInts().getInts(12);
|
||||||
Arrays.fill(bytesHistogram, 0);
|
Arrays.fill(bytesHistogram, 0);
|
||||||
for (int i = 0 ; i < commandCount ; ++i)
|
for (int i = 0 ; i < commandCount ; ++i)
|
||||||
|
|
@ -214,7 +193,7 @@ public class CommandsForKeySerializer
|
||||||
if (hasNonStandardFlags && txnIdFlags(txnId) == RAW)
|
if (hasNonStandardFlags && txnIdFlags(txnId) == RAW)
|
||||||
totalBytes += 2;
|
totalBytes += 2;
|
||||||
|
|
||||||
Info info = cfk.info(i);
|
TxnInfo info = cfk.get(i);
|
||||||
if (info.status.hasInfo)
|
if (info.status.hasInfo)
|
||||||
headerBits += infoHeaderBits;
|
headerBits += infoHeaderBits;
|
||||||
maxHeaderBits = Math.max(headerBits, maxHeaderBits);
|
maxHeaderBits = Math.max(headerBits, maxHeaderBits);
|
||||||
|
|
@ -247,9 +226,11 @@ public class CommandsForKeySerializer
|
||||||
// then pick third number as 75th %ile, but at least 1 less than highest, and one more than second
|
// then pick third number as 75th %ile, but at least 1 less than highest, and one more than second
|
||||||
// finally, ensure third then second are distributed so that there is no more than a gap of 4 between them and the next
|
// finally, ensure third then second are distributed so that there is no more than a gap of 4 between them and the next
|
||||||
int l0 = Math.max(0, Math.min(3, minBasicBytes - headerBytes));
|
int l0 = Math.max(0, Math.min(3, minBasicBytes - headerBytes));
|
||||||
int l1 = Math.max(l0+1, Math.min(l0+4,Arrays.binarySearch(bytesHistogram, commandCount/4) - headerBytes));
|
int l1 = Arrays.binarySearch(bytesHistogram, minBasicBytes, maxBasicBytes, commandCount/4);
|
||||||
|
l1 = Math.max(l0+1, Math.min(l0+4, (l1 < 0 ? -1 - l1 : l1) - headerBytes));
|
||||||
int l3 = Math.max(l1+2, maxBasicBytes - headerBytes);
|
int l3 = Math.max(l1+2, maxBasicBytes - headerBytes);
|
||||||
int l2 = Math.max(l1+1, Math.min(l3-1, Arrays.binarySearch(bytesHistogram, (3*commandCount)/4) - headerBytes));
|
int l2 = Arrays.binarySearch(bytesHistogram, minBasicBytes, maxBasicBytes,(3*commandCount)/4);
|
||||||
|
l2 = Math.max(l1+1, Math.min(l3-1, (l2 < 0 ? -1 -l2 : l2) - headerBytes));
|
||||||
while (l3-l2 > 4) ++l2;
|
while (l3-l2 > 4) ++l2;
|
||||||
while (l2-l1 > 4) ++l1;
|
while (l2-l1 > 4) ++l1;
|
||||||
hlcBytesLookup = setHlcBytes(l0, l1, l2, l3);
|
hlcBytesLookup = setHlcBytes(l0, l1, l2, l3);
|
||||||
|
|
@ -267,16 +248,13 @@ public class CommandsForKeySerializer
|
||||||
totalBytes += TypeSizes.sizeofUnsignedVInt(nodeIds[i] - nodeIds[i-1]);
|
totalBytes += TypeSizes.sizeofUnsignedVInt(nodeIds[i] - nodeIds[i-1]);
|
||||||
totalBytes += 2;
|
totalBytes += 2;
|
||||||
|
|
||||||
Arrays.fill(bytesHistogram, minBasicBytes, maxBasicBytes + 1, 0);
|
|
||||||
cachedInts().forceDiscard(bytesHistogram);
|
cachedInts().forceDiscard(bytesHistogram);
|
||||||
|
|
||||||
prevEpoch = cfk.redundantBefore().epoch();
|
prevEpoch = cfk.get(0).epoch();
|
||||||
prevHlc = cfk.redundantBefore().hlc();
|
prevHlc = cfk.get(0).hlc();
|
||||||
// account for encoding redundantBefore
|
// account for encoding redundantBefore
|
||||||
totalBytes += TypeSizes.sizeofUnsignedVInt(prevEpoch);
|
totalBytes += TypeSizes.sizeofUnsignedVInt(prevEpoch);
|
||||||
totalBytes += TypeSizes.sizeofUnsignedVInt(prevHlc);
|
totalBytes += TypeSizes.sizeofUnsignedVInt(prevHlc);
|
||||||
totalBytes += 2; // flags TODO (expected): pack this along with uniqueIdBits, as usually zero bits should be needed
|
|
||||||
totalBytes += (bitsPerNodeId+7)/8;
|
|
||||||
|
|
||||||
if (missingIdCount + executeAtCount > 0)
|
if (missingIdCount + executeAtCount > 0)
|
||||||
{
|
{
|
||||||
|
|
@ -291,6 +269,20 @@ public class CommandsForKeySerializer
|
||||||
totalBytes += 2;
|
totalBytes += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// count unmanaged bytes
|
||||||
|
int unmanagedPendingCommitCount = 0;
|
||||||
|
for (int i = 0 ; i < cfk.unmanagedCount() ; ++i)
|
||||||
|
{
|
||||||
|
Unmanaged unmanaged = cfk.getUnmanaged(i);
|
||||||
|
if (unmanaged.pending == Unmanaged.Pending.COMMIT)
|
||||||
|
++unmanagedPendingCommitCount;
|
||||||
|
totalBytes += CommandSerializers.txnId.serializedSize();
|
||||||
|
// TODO (desired): this could be more efficient, e.g. referencing one of the TxnInfo indexes for timestamp
|
||||||
|
totalBytes += CommandSerializers.timestamp.serializedSize();
|
||||||
|
}
|
||||||
|
totalBytes += TypeSizes.sizeofUnsignedVInt(unmanagedPendingCommitCount);
|
||||||
|
totalBytes += TypeSizes.sizeofUnsignedVInt(cfk.unmanagedCount() - unmanagedPendingCommitCount);
|
||||||
|
|
||||||
ByteBuffer out = ByteBuffer.allocate(totalBytes);
|
ByteBuffer out = ByteBuffer.allocate(totalBytes);
|
||||||
VIntCoding.writeUnsignedVInt32(commandCount, out);
|
VIntCoding.writeUnsignedVInt32(commandCount, out);
|
||||||
VIntCoding.writeUnsignedVInt32(nodeIdCount, out);
|
VIntCoding.writeUnsignedVInt32(nodeIdCount, out);
|
||||||
|
|
@ -301,8 +293,6 @@ public class CommandsForKeySerializer
|
||||||
|
|
||||||
VIntCoding.writeUnsignedVInt(prevEpoch, out);
|
VIntCoding.writeUnsignedVInt(prevEpoch, out);
|
||||||
VIntCoding.writeUnsignedVInt(prevHlc, out);
|
VIntCoding.writeUnsignedVInt(prevHlc, out);
|
||||||
out.putShort((short) cfk.redundantBefore().flags());
|
|
||||||
writeLeastSignificantBytes(Arrays.binarySearch(nodeIds, 0, nodeIdCount, cfk.redundantBefore().node.id), (bitsPerNodeId+7)/8, out);
|
|
||||||
|
|
||||||
int executeAtMask = executeAtCount > 0 ? 1 : 0;
|
int executeAtMask = executeAtCount > 0 ? 1 : 0;
|
||||||
int missingDepsMask = missingIdCount > 0 ? 1 : 0;
|
int missingDepsMask = missingIdCount > 0 ? 1 : 0;
|
||||||
|
|
@ -311,7 +301,7 @@ public class CommandsForKeySerializer
|
||||||
for (int i = 0 ; i < commandCount ; ++i)
|
for (int i = 0 ; i < commandCount ; ++i)
|
||||||
{
|
{
|
||||||
TxnId txnId = cfk.txnId(i);
|
TxnId txnId = cfk.txnId(i);
|
||||||
Info info = cfk.info(i);
|
TxnInfo info = cfk.get(i);
|
||||||
InternalStatus status = info.status;
|
InternalStatus status = info.status;
|
||||||
|
|
||||||
long bits = status.ordinal();
|
long bits = status.ordinal();
|
||||||
|
|
@ -322,7 +312,7 @@ public class CommandsForKeySerializer
|
||||||
bits |= hasExecuteAt << bitIndex;
|
bits |= hasExecuteAt << bitIndex;
|
||||||
bitIndex += statusHasInfo & executeAtMask;
|
bitIndex += statusHasInfo & executeAtMask;
|
||||||
|
|
||||||
long hasMissingIds = info.missing != CommandsForKey.NO_TXNIDS ? 1 : 0;
|
long hasMissingIds = info.missing() != CommandsForKey.NO_TXNIDS ? 1 : 0;
|
||||||
bits |= hasMissingIds << bitIndex;
|
bits |= hasMissingIds << bitIndex;
|
||||||
bitIndex += statusHasInfo & missingDepsMask;
|
bitIndex += statusHasInfo & missingDepsMask;
|
||||||
|
|
||||||
|
|
@ -392,6 +382,20 @@ public class CommandsForKeySerializer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VIntCoding.writeUnsignedVInt32(unmanagedPendingCommitCount, out);
|
||||||
|
VIntCoding.writeUnsignedVInt32(cfk.unmanagedCount() - unmanagedPendingCommitCount, out);
|
||||||
|
Unmanaged.Pending pending = unmanagedPendingCommitCount == 0 ? Unmanaged.Pending.APPLY : Unmanaged.Pending.COMMIT;
|
||||||
|
for (int i = 0 ; i < cfk.unmanagedCount() ; ++i)
|
||||||
|
{
|
||||||
|
Unmanaged unmanaged = cfk.getUnmanaged(i);
|
||||||
|
Invariants.checkState(unmanaged.pending == pending);
|
||||||
|
CommandSerializers.txnId.serialize(unmanaged.txnId, out, ByteBufferAccessor.instance, out.position());
|
||||||
|
out.position(out.position() + CommandSerializers.txnId.serializedSize());
|
||||||
|
CommandSerializers.timestamp.serialize(unmanaged.waitingUntil, out, ByteBufferAccessor.instance, out.position());
|
||||||
|
out.position(out.position() + CommandSerializers.timestamp.serializedSize());
|
||||||
|
if (--unmanagedPendingCommitCount == 0) pending = Unmanaged.Pending.APPLY;
|
||||||
|
}
|
||||||
|
|
||||||
if ((executeAtCount | missingIdCount) > 0)
|
if ((executeAtCount | missingIdCount) > 0)
|
||||||
{
|
{
|
||||||
int bitsPerCommandId = numberOfBitsToRepresent(commandCount);
|
int bitsPerCommandId = numberOfBitsToRepresent(commandCount);
|
||||||
|
|
@ -407,21 +411,17 @@ public class CommandsForKeySerializer
|
||||||
|
|
||||||
for (int i = 0 ; i < commandCount ; ++i)
|
for (int i = 0 ; i < commandCount ; ++i)
|
||||||
{
|
{
|
||||||
Info info = cfk.info(i);
|
TxnInfo txn = cfk.get(i);
|
||||||
if (info.getClass() == NoInfo.class)
|
if (txn.executeAt != txn)
|
||||||
continue;
|
|
||||||
|
|
||||||
TxnId txnId = cfk.txnId(i);
|
|
||||||
if (info.executeAt != txnId)
|
|
||||||
{
|
{
|
||||||
Timestamp executeAt = info.executeAt;
|
Timestamp executeAt = txn.executeAt;
|
||||||
int nodeIdx = Arrays.binarySearch(nodeIds, 0, nodeIdCount, executeAt.node.id);
|
int nodeIdx = Arrays.binarySearch(nodeIds, 0, nodeIdCount, executeAt.node.id);
|
||||||
if (bitsPerExecuteAt <= 64)
|
if (bitsPerExecuteAt <= 64)
|
||||||
{
|
{
|
||||||
Invariants.checkState(executeAt.epoch() >= txnId.epoch());
|
Invariants.checkState(executeAt.epoch() >= txn.epoch());
|
||||||
long executeAtBits = executeAt.epoch() - txnId.epoch();
|
long executeAtBits = executeAt.epoch() - txn.epoch();
|
||||||
int offset = bitsPerExecuteAtEpochDelta;
|
int offset = bitsPerExecuteAtEpochDelta;
|
||||||
executeAtBits |= (executeAt.hlc() - txnId.hlc()) << offset ;
|
executeAtBits |= (executeAt.hlc() - txn.hlc()) << offset ;
|
||||||
offset += bitsPerExecuteAtHlcDelta;
|
offset += bitsPerExecuteAtHlcDelta;
|
||||||
executeAtBits |= ((long)executeAt.flags()) << offset;
|
executeAtBits |= ((long)executeAt.flags()) << offset;
|
||||||
offset += bitsPerExecuteAtFlags;
|
offset += bitsPerExecuteAtFlags;
|
||||||
|
|
@ -431,9 +431,9 @@ public class CommandsForKeySerializer
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
buffer = flushBits(buffer, bufferCount, executeAt.epoch() - txnId.epoch(), bitsPerExecuteAtEpochDelta, out);
|
buffer = flushBits(buffer, bufferCount, executeAt.epoch() - txn.epoch(), bitsPerExecuteAtEpochDelta, out);
|
||||||
bufferCount = (bufferCount + bitsPerExecuteAtEpochDelta) & 63;
|
bufferCount = (bufferCount + bitsPerExecuteAtEpochDelta) & 63;
|
||||||
buffer = flushBits(buffer, bufferCount, executeAt.hlc() - txnId.hlc(), bitsPerExecuteAtHlcDelta, out);
|
buffer = flushBits(buffer, bufferCount, executeAt.hlc() - txn.hlc(), bitsPerExecuteAtHlcDelta, out);
|
||||||
bufferCount = (bufferCount + bitsPerExecuteAtHlcDelta) & 63;
|
bufferCount = (bufferCount + bitsPerExecuteAtHlcDelta) & 63;
|
||||||
buffer = flushBits(buffer, bufferCount, executeAt.flags(), bitsPerExecuteAtFlags, out);
|
buffer = flushBits(buffer, bufferCount, executeAt.flags(), bitsPerExecuteAtFlags, out);
|
||||||
bufferCount = (bufferCount + bitsPerExecuteAtFlags) & 63;
|
bufferCount = (bufferCount + bitsPerExecuteAtFlags) & 63;
|
||||||
|
|
@ -442,16 +442,17 @@ public class CommandsForKeySerializer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.missing.length > 0)
|
TxnId[] missing = txn.missing();
|
||||||
|
if (missing.length > 0)
|
||||||
{
|
{
|
||||||
int j = 0;
|
int j = 0;
|
||||||
while (j < info.missing.length - 1)
|
while (j < missing.length - 1)
|
||||||
{
|
{
|
||||||
int missingId = cfk.indexOf(info.missing[j++]);
|
int missingId = cfk.indexOf(missing[j++]);
|
||||||
buffer = flushBits(buffer, bufferCount, missingId, bitsPerMissingId, out);
|
buffer = flushBits(buffer, bufferCount, missingId, bitsPerMissingId, out);
|
||||||
bufferCount = (bufferCount + bitsPerMissingId) & 63;
|
bufferCount = (bufferCount + bitsPerMissingId) & 63;
|
||||||
}
|
}
|
||||||
int missingId = cfk.indexOf(info.missing[info.missing.length - 1]);
|
int missingId = cfk.indexOf(missing[missing.length - 1]);
|
||||||
missingId |= 1L << bitsPerCommandId;
|
missingId |= 1L << bitsPerCommandId;
|
||||||
buffer = flushBits(buffer, bufferCount, missingId, bitsPerMissingId, out);
|
buffer = flushBits(buffer, bufferCount, missingId, bitsPerMissingId, out);
|
||||||
bufferCount = (bufferCount + bitsPerMissingId) & 63;
|
bufferCount = (bufferCount + bitsPerMissingId) & 63;
|
||||||
|
|
@ -461,6 +462,7 @@ public class CommandsForKeySerializer
|
||||||
writeMostSignificantBytes(buffer, (bufferCount + 7)/8, out);
|
writeMostSignificantBytes(buffer, (bufferCount + 7)/8, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Invariants.checkState(!out.hasRemaining());
|
||||||
out.flip();
|
out.flip();
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
@ -494,16 +496,10 @@ public class CommandsForKeySerializer
|
||||||
in = in.duplicate();
|
in = in.duplicate();
|
||||||
int commandCount = VIntCoding.readUnsignedVInt32(in);
|
int commandCount = VIntCoding.readUnsignedVInt32(in);
|
||||||
if (commandCount == 0)
|
if (commandCount == 0)
|
||||||
{
|
return new CommandsForKey(key);
|
||||||
long epoch = VIntCoding.readUnsignedVInt(in);
|
|
||||||
long hlc = VIntCoding.readUnsignedVInt(in);
|
|
||||||
int flags = VIntCoding.readUnsignedVInt32(in);
|
|
||||||
Node.Id id = new Node.Id(VIntCoding.readUnsignedVInt32(in));
|
|
||||||
return new CommandsForKey(key).withoutRedundant(TxnId.fromValues(epoch, hlc, flags, id));
|
|
||||||
}
|
|
||||||
|
|
||||||
TxnId[] txnIds = new TxnId[commandCount];
|
TxnId[] txnIds = cachedTxnIds().get(commandCount);
|
||||||
Info[] infos = new Info[commandCount];
|
TxnInfo[] txns = new TxnInfo[commandCount];
|
||||||
int nodeIdCount = VIntCoding.readUnsignedVInt32(in);
|
int nodeIdCount = VIntCoding.readUnsignedVInt32(in);
|
||||||
int bitsPerNodeId = numberOfBitsToRepresent(nodeIdCount);
|
int bitsPerNodeId = numberOfBitsToRepresent(nodeIdCount);
|
||||||
long nodeIdMask = (1L << bitsPerNodeId) - 1;
|
long nodeIdMask = (1L << bitsPerNodeId) - 1;
|
||||||
|
|
@ -526,12 +522,8 @@ public class CommandsForKeySerializer
|
||||||
hlcBytesLookup = setHlcByteDeltas((flags >>> 5) & 0x3, (flags >>> 7) & 0x3, (flags >>> 9) & 0x3, (flags >>> 11) & 0x3);
|
hlcBytesLookup = setHlcByteDeltas((flags >>> 5) & 0x3, (flags >>> 7) & 0x3, (flags >>> 9) & 0x3, (flags >>> 11) & 0x3);
|
||||||
}
|
}
|
||||||
|
|
||||||
long prevEpoch = VIntCoding.readUnsignedVInt32(in);
|
long prevEpoch = VIntCoding.readUnsignedVInt(in);
|
||||||
long prevHlc = VIntCoding.readUnsignedVInt32(in);
|
long prevHlc = VIntCoding.readUnsignedVInt(in);
|
||||||
TxnId redundantBefore = TxnId.fromValues(prevEpoch, prevHlc, in.getShort(),
|
|
||||||
nodeIds[(int)readLeastSignificantBytes((bitsPerNodeId+7)/8, in)]);
|
|
||||||
|
|
||||||
|
|
||||||
for (int i = 0 ; i < commandCount ; ++i)
|
for (int i = 0 ; i < commandCount ; ++i)
|
||||||
{
|
{
|
||||||
long header = readLeastSignificantBytes(headerByteCount, in);
|
long header = readLeastSignificantBytes(headerByteCount, in);
|
||||||
|
|
@ -601,12 +593,34 @@ public class CommandsForKeySerializer
|
||||||
: TxnId.fromValues(epoch, hlc, flags, node);
|
: TxnId.fromValues(epoch, hlc, flags, node);
|
||||||
|
|
||||||
txnIds[i] = txnId;
|
txnIds[i] = txnId;
|
||||||
infos[i] = DECODE_INFOS[(executeAtInfoOffset | missingDepsInfoOffset)*STATUS_COUNT + status.ordinal()];
|
txns[i] = DECODE_INFOS[(executeAtInfoOffset | missingDepsInfoOffset)*STATUS_COUNT + status.ordinal()];
|
||||||
|
|
||||||
prevEpoch = epoch;
|
prevEpoch = epoch;
|
||||||
prevHlc = hlc;
|
prevHlc = hlc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int unmanagedPendingCommitCount = VIntCoding.readUnsignedVInt32(in);
|
||||||
|
int unmanagedCount = unmanagedPendingCommitCount + VIntCoding.readUnsignedVInt32(in);
|
||||||
|
Unmanaged[] unmanageds;
|
||||||
|
if (unmanagedCount == 0)
|
||||||
|
{
|
||||||
|
unmanageds = NO_PENDING_UNMANAGED;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unmanageds = new Unmanaged[unmanagedCount];
|
||||||
|
Unmanaged.Pending pending = unmanagedPendingCommitCount == 0 ? Unmanaged.Pending.APPLY : Unmanaged.Pending.COMMIT;
|
||||||
|
for (int i = 0 ; i < unmanagedCount ; ++i)
|
||||||
|
{
|
||||||
|
TxnId txnId = CommandSerializers.txnId.deserialize(in, ByteBufferAccessor.instance, in.position());
|
||||||
|
in.position(in.position() + CommandSerializers.txnId.serializedSize());
|
||||||
|
Timestamp waitingUntil = CommandSerializers.timestamp.deserialize(in, ByteBufferAccessor.instance, in.position());
|
||||||
|
in.position(in.position() + CommandSerializers.timestamp.serializedSize());
|
||||||
|
unmanageds[i] = new Unmanaged(pending, txnId, waitingUntil);
|
||||||
|
if (--unmanagedPendingCommitCount == 0) pending = Unmanaged.Pending.APPLY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (executeAtMasks + missingDepsMasks > 0)
|
if (executeAtMasks + missingDepsMasks > 0)
|
||||||
{
|
{
|
||||||
TxnId[] missingIdBuffer = cachedTxnIds().get(8);
|
TxnId[] missingIdBuffer = cachedTxnIds().get(8);
|
||||||
|
|
@ -630,13 +644,10 @@ public class CommandsForKeySerializer
|
||||||
|
|
||||||
for (int i = 0 ; i < commandCount ; ++i)
|
for (int i = 0 ; i < commandCount ; ++i)
|
||||||
{
|
{
|
||||||
Info info = infos[i];
|
|
||||||
if (info.getClass() == NoInfo.class)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
TxnId txnId = txnIds[i];
|
TxnId txnId = txnIds[i];
|
||||||
Timestamp executeAt = txnId;
|
TxnInfo placeholder = txns[i];
|
||||||
if (info.executeAt == null)
|
Timestamp executeAt;
|
||||||
|
if (placeholder.executeAt == null)
|
||||||
{
|
{
|
||||||
long epoch, hlc;
|
long epoch, hlc;
|
||||||
int flags;
|
int flags;
|
||||||
|
|
@ -661,8 +672,12 @@ public class CommandsForKeySerializer
|
||||||
}
|
}
|
||||||
executeAt = Timestamp.fromValues(epoch, hlc, flags, id);
|
executeAt = Timestamp.fromValues(epoch, hlc, flags, id);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
executeAt = txnId;
|
||||||
|
}
|
||||||
|
|
||||||
TxnId[] missing = info.missing;
|
TxnId[] missing = placeholder.missing();
|
||||||
if (missing == null)
|
if (missing == null)
|
||||||
{
|
{
|
||||||
int prev = -1;
|
int prev = -1;
|
||||||
|
|
@ -684,13 +699,19 @@ public class CommandsForKeySerializer
|
||||||
missingIdCount = 0;
|
missingIdCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
infos[i] = Info.create(txnId, info.status, executeAt, missing);
|
txns[i] = TxnInfo.create(txnId, placeholder.status, executeAt, missing);
|
||||||
}
|
}
|
||||||
|
|
||||||
cachedTxnIds().forceDiscard(missingIdBuffer, maxIdBufferCount);
|
cachedTxnIds().forceDiscard(missingIdBuffer, maxIdBufferCount);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = 0 ; i < commandCount ; ++i)
|
||||||
|
txns[i] = TxnInfo.create(txnIds[i], txns[i].status, txnIds[i]);
|
||||||
|
}
|
||||||
|
cachedTxnIds().forceDiscard(txnIds, commandCount);
|
||||||
|
|
||||||
return CommandsForKey.SerializerSupport.create(key, redundantBefore, txnIds, infos);
|
return CommandsForKey.SerializerSupport.create(key, txns, unmanageds);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getHlcBytes(int lookup, int index)
|
private static int getHlcBytes(int lookup, int index)
|
||||||
|
|
@ -833,16 +854,16 @@ public class CommandsForKeySerializer
|
||||||
|
|
||||||
private static final Txn.Kind[] TXN_ID_FLAG_BITS_KIND_LOOKUP = new Txn.Kind[] { Read, Write, ExclusiveSyncPoint, null };
|
private static final Txn.Kind[] TXN_ID_FLAG_BITS_KIND_LOOKUP = new Txn.Kind[] { Read, Write, ExclusiveSyncPoint, null };
|
||||||
private static final int STATUS_COUNT = InternalStatus.values().length;
|
private static final int STATUS_COUNT = InternalStatus.values().length;
|
||||||
private static final Info[] DECODE_INFOS = new Info[4 * STATUS_COUNT];
|
private static final TxnInfo[] DECODE_INFOS = new TxnInfo[4 * STATUS_COUNT];
|
||||||
static
|
static
|
||||||
{
|
{
|
||||||
for (InternalStatus status : InternalStatus.values())
|
for (InternalStatus status : InternalStatus.values())
|
||||||
{
|
{
|
||||||
int ordinal = status.ordinal();
|
int ordinal = status.ordinal();
|
||||||
DECODE_INFOS[ordinal] = status.asNoInfo;
|
DECODE_INFOS[ordinal] = TxnInfo.createMock(TxnId.NONE, status, TxnId.NONE, CommandsForKey.NO_TXNIDS);
|
||||||
DECODE_INFOS[STATUS_COUNT+ordinal] = Info.createMock(status, Timestamp.NONE, null);
|
DECODE_INFOS[STATUS_COUNT+ordinal] = TxnInfo.createMock(TxnId.NONE, status, TxnId.NONE, null);
|
||||||
DECODE_INFOS[2*STATUS_COUNT+ordinal] = Info.createMock(status, null, CommandsForKey.NO_TXNIDS);
|
DECODE_INFOS[2*STATUS_COUNT+ordinal] = TxnInfo.createMock(TxnId.NONE, status, null, CommandsForKey.NO_TXNIDS);
|
||||||
DECODE_INFOS[3*STATUS_COUNT+ordinal] = Info.createMock(status, null, null);
|
DECODE_INFOS[3*STATUS_COUNT+ordinal] = TxnInfo.createMock(TxnId.NONE, status, null, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,40 +22,63 @@ import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import accord.local.Command.WaitingOn;
|
import accord.local.Command.WaitingOn;
|
||||||
import accord.primitives.Deps;
|
import accord.primitives.Keys;
|
||||||
|
import accord.primitives.Routable;
|
||||||
|
import accord.primitives.TxnId;
|
||||||
import accord.utils.ImmutableBitSet;
|
import accord.utils.ImmutableBitSet;
|
||||||
import accord.utils.Invariants;
|
import accord.utils.Invariants;
|
||||||
import accord.utils.SimpleBitSet;
|
import accord.utils.SimpleBitSet;
|
||||||
|
import accord.utils.SortedArrays.SortedArrayList;
|
||||||
import org.apache.cassandra.db.TypeSizes;
|
import org.apache.cassandra.db.TypeSizes;
|
||||||
import org.apache.cassandra.io.util.DataInputPlus;
|
import org.apache.cassandra.io.util.DataInputPlus;
|
||||||
import org.apache.cassandra.io.util.DataOutputPlus;
|
import org.apache.cassandra.io.util.DataOutputPlus;
|
||||||
|
import org.apache.cassandra.utils.vint.VIntCoding;
|
||||||
|
|
||||||
public class WaitingOnSerializer
|
public class WaitingOnSerializer
|
||||||
{
|
{
|
||||||
public static void serialize(WaitingOn waitingOn, DataOutputPlus out) throws IOException
|
public static void serialize(TxnId txnId, WaitingOn waitingOn, DataOutputPlus out) throws IOException
|
||||||
{
|
{
|
||||||
// TODO (expected): use run length encoding; we know that at most 1/3rd of bits will be set between the three bitsets
|
out.writeUnsignedVInt32(waitingOn.keys.size());
|
||||||
int length = (waitingOn.deps.txnIdCount() + 63) / 64;
|
out.writeUnsignedVInt32(waitingOn.txnIds.size());
|
||||||
serialize(length, waitingOn.waitingOnCommit, out);
|
int keyCount = waitingOn.keys.size();
|
||||||
serialize(length, waitingOn.waitingOnApply, out);
|
int txnIdCount = waitingOn.txnIds.size();
|
||||||
serialize(length, waitingOn.appliedOrInvalidated, out);
|
int waitingOnLength = (txnIdCount + keyCount + 63) / 64;
|
||||||
|
serialize(waitingOnLength, waitingOn.waitingOn, out);
|
||||||
|
if (txnId.domain() == Routable.Domain.Range)
|
||||||
|
{
|
||||||
|
int appliedOrInvalidatedLength = (txnIdCount + 63) / 64;
|
||||||
|
serialize(appliedOrInvalidatedLength, waitingOn.appliedOrInvalidated, out);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static WaitingOn deserialize(Deps deps, DataInputPlus in) throws IOException
|
public static WaitingOn deserialize(TxnId txnId, Keys keys, SortedArrayList<TxnId> txnIds, DataInputPlus in) throws IOException
|
||||||
{
|
{
|
||||||
int length = (deps.txnIdCount() + 63) / 64;
|
int a = in.readUnsignedVInt32();
|
||||||
ImmutableBitSet waitingOnCommit = deserialize(length, in);
|
int b = in.readUnsignedVInt32();
|
||||||
ImmutableBitSet waitingOnApply = deserialize(length, in);
|
int waitingOnLength = (txnIds.size() + keys.size() + 63) / 64;
|
||||||
ImmutableBitSet appliedOrInvalidated = deserialize(length, in);
|
ImmutableBitSet waitingOn = deserialize(waitingOnLength, in);
|
||||||
return new WaitingOn(deps, waitingOnCommit, waitingOnApply, appliedOrInvalidated);
|
ImmutableBitSet appliedOrInvalidated = null;
|
||||||
|
if (txnId.domain() == Routable.Domain.Range)
|
||||||
|
{
|
||||||
|
int appliedOrInvalidatedLength = (txnIds.size() + 63) / 64;
|
||||||
|
appliedOrInvalidated = deserialize(appliedOrInvalidatedLength, in);
|
||||||
|
}
|
||||||
|
return new WaitingOn(keys, txnIds, waitingOn, appliedOrInvalidated);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long serializedSize(WaitingOn waitingOn)
|
public static long serializedSize(WaitingOn waitingOn)
|
||||||
{
|
{
|
||||||
int length = (waitingOn.deps.txnIdCount() + 63) / 64;
|
int keyCount = waitingOn.keys.size();
|
||||||
return serializedSize(length, waitingOn.waitingOnCommit)
|
int txnIdCount = waitingOn.txnIds.size();
|
||||||
+ serializedSize(length, waitingOn.waitingOnApply)
|
int waitingOnLength = (txnIdCount + keyCount + 63) / 64;
|
||||||
+ serializedSize(length, waitingOn.appliedOrInvalidated);
|
long size = serializedSize(waitingOnLength, waitingOn.waitingOn);
|
||||||
|
size += TypeSizes.sizeofUnsignedVInt(keyCount);
|
||||||
|
size += TypeSizes.sizeofUnsignedVInt(txnIdCount);
|
||||||
|
if (waitingOn.appliedOrInvalidated == null)
|
||||||
|
return size;
|
||||||
|
|
||||||
|
int appliedOrInvalidatedLength = (txnIdCount + 63) / 64;
|
||||||
|
return size + serializedSize(appliedOrInvalidatedLength, waitingOn.appliedOrInvalidated);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void serialize(int length, SimpleBitSet write, DataOutputPlus out) throws IOException
|
private static void serialize(int length, SimpleBitSet write, DataOutputPlus out) throws IOException
|
||||||
|
|
@ -81,14 +104,23 @@ public class WaitingOnSerializer
|
||||||
return (long) TypeSizes.LONG_SIZE * length;
|
return (long) TypeSizes.LONG_SIZE * length;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ByteBuffer serialize(WaitingOn waitingOn) throws IOException
|
public static ByteBuffer serialize(TxnId txnId, WaitingOn waitingOn) throws IOException
|
||||||
{
|
{
|
||||||
int length = (waitingOn.deps.txnIdCount() + 63) / 64;
|
int keyCount = waitingOn.keys.size();
|
||||||
ByteBuffer out = ByteBuffer.allocate(TypeSizes.LONG_SIZE * length * 3);
|
int txnIdCount = waitingOn.txnIds.size();
|
||||||
serialize(length, waitingOn.waitingOnCommit, out);
|
int waitingOnLength = (txnIdCount + keyCount + 63) / 64;
|
||||||
serialize(length, waitingOn.waitingOnApply, out);
|
int appliedOrInvalidatedLength = 0;
|
||||||
serialize(length, waitingOn.appliedOrInvalidated, out);
|
if (txnId.domain() == Routable.Domain.Range)
|
||||||
return (ByteBuffer) out.flip();
|
appliedOrInvalidatedLength = (txnIdCount + 63) / 64;
|
||||||
|
|
||||||
|
ByteBuffer out = ByteBuffer.allocate(TypeSizes.sizeofUnsignedVInt(keyCount) + TypeSizes.sizeofUnsignedVInt(txnIdCount)
|
||||||
|
+ TypeSizes.LONG_SIZE * (waitingOnLength + appliedOrInvalidatedLength));
|
||||||
|
VIntCoding.writeUnsignedVInt32(keyCount, out);
|
||||||
|
VIntCoding.writeUnsignedVInt32(txnIdCount, out);
|
||||||
|
serialize(waitingOnLength, waitingOn.waitingOn, out);
|
||||||
|
if (appliedOrInvalidatedLength > 0)
|
||||||
|
serialize(appliedOrInvalidatedLength, waitingOn.appliedOrInvalidated, out);
|
||||||
|
return out.flip();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void serialize(int length, SimpleBitSet write, ByteBuffer out)
|
private static void serialize(int length, SimpleBitSet write, ByteBuffer out)
|
||||||
|
|
@ -99,16 +131,23 @@ public class WaitingOnSerializer
|
||||||
out.putLong(bits[i]);
|
out.putLong(bits[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static WaitingOn deserialize(Deps deps, ByteBuffer in) throws IOException
|
public static WaitingOn deserialize(TxnId txnId, Keys keys, SortedArrayList<TxnId> txnIds, ByteBuffer in) throws IOException
|
||||||
{
|
{
|
||||||
int length = (deps.txnIdCount() + 63) / 64;
|
int waitingOnLength = (txnIds.size() + keys.size() + 63) / 64;
|
||||||
int position = in.position();
|
int position = in.position();
|
||||||
ImmutableBitSet waitingOnCommit = deserialize(position, length, in);
|
int a = VIntCoding.readUnsignedVInt32(in, position);
|
||||||
position += length*8;
|
position += TypeSizes.sizeofUnsignedVInt(a);
|
||||||
ImmutableBitSet waitingOnApply = deserialize(position, length, in);
|
int b = VIntCoding.readUnsignedVInt32(in, position);
|
||||||
position += length*8;
|
position += TypeSizes.sizeofUnsignedVInt(a);
|
||||||
ImmutableBitSet appliedOrInvalidated = deserialize(position, length, in);
|
ImmutableBitSet waitingOn = deserialize(position, waitingOnLength, in);
|
||||||
return new WaitingOn(deps, waitingOnCommit, waitingOnApply, appliedOrInvalidated);
|
ImmutableBitSet appliedOrInvalidated = null;
|
||||||
|
if (txnId.domain() == Routable.Domain.Range)
|
||||||
|
{
|
||||||
|
position += waitingOnLength*8;
|
||||||
|
int appliedOrInvalidatedLength = (txnIds.size() + 63) / 64;
|
||||||
|
appliedOrInvalidated = deserialize(position, appliedOrInvalidatedLength, in);
|
||||||
|
}
|
||||||
|
return new WaitingOn(keys, txnIds, waitingOn, appliedOrInvalidated);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ImmutableBitSet deserialize(int position, int length, ByteBuffer in)
|
private static ImmutableBitSet deserialize(int position, int length, ByteBuffer in)
|
||||||
|
|
|
||||||
|
|
@ -35,9 +35,10 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import accord.api.DataStore;
|
import accord.api.DataStore;
|
||||||
|
import accord.api.Key;
|
||||||
import accord.api.Write;
|
import accord.api.Write;
|
||||||
import accord.impl.AbstractSafeCommandStore;
|
import accord.impl.AbstractSafeCommandStore;
|
||||||
import accord.impl.CommandsForKeys;
|
import accord.impl.TimestampsForKeys;
|
||||||
import accord.impl.TimestampsForKey;
|
import accord.impl.TimestampsForKey;
|
||||||
import accord.local.SafeCommandStore;
|
import accord.local.SafeCommandStore;
|
||||||
import accord.primitives.PartialTxn;
|
import accord.primitives.PartialTxn;
|
||||||
|
|
@ -375,7 +376,7 @@ public class TxnWrite extends AbstractKeySorted<TxnWrite.Update> implements Writ
|
||||||
// TODO (expected, efficiency): 99.9999% of the time we can just use executeAt.hlc(), so can avoid bringing
|
// TODO (expected, efficiency): 99.9999% of the time we can just use executeAt.hlc(), so can avoid bringing
|
||||||
// cfk into memory by retaining at all times in memory key ranges that are dirty and must use this logic;
|
// cfk into memory by retaining at all times in memory key ranges that are dirty and must use this logic;
|
||||||
// any that aren't can just use executeAt.hlc
|
// any that aren't can just use executeAt.hlc
|
||||||
TimestampsForKey cfk = CommandsForKeys.updateLastExecutionTimestamps((AbstractSafeCommandStore<?,?,?>) safeStore, (RoutableKey) key, executeAt, true);
|
TimestampsForKey cfk = TimestampsForKeys.updateLastExecutionTimestamps((AbstractSafeCommandStore<?,?,?>) safeStore, (Key) key, executeAt, true);
|
||||||
long timestamp = AccordSafeTimestampsForKey.timestampMicrosFor(cfk, executeAt, true);
|
long timestamp = AccordSafeTimestampsForKey.timestampMicrosFor(cfk, executeAt, true);
|
||||||
// TODO (low priority - do we need to compute nowInSeconds, or can we just use executeAt?)
|
// TODO (low priority - do we need to compute nowInSeconds, or can we just use executeAt?)
|
||||||
int nowInSeconds = AccordSafeTimestampsForKey.nowInSecondsFor(cfk, executeAt, true);
|
int nowInSeconds = AccordSafeTimestampsForKey.nowInSecondsFor(cfk, executeAt, true);
|
||||||
|
|
|
||||||
|
|
@ -126,13 +126,27 @@ public class VIntCoding
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@DontInline
|
||||||
|
private static long readUnsignedVIntSlow(ByteBuffer in, int position, byte firstByte)
|
||||||
|
{
|
||||||
|
int size = numberOfExtraBytesToRead(firstByte);
|
||||||
|
long retval = firstByte & firstByteValueMask(size);
|
||||||
|
for (int ii = 0; ii < size; ii++)
|
||||||
|
{
|
||||||
|
byte b = in.get(position++);
|
||||||
|
retval <<= 8;
|
||||||
|
retval |= b & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
public static long readUnsignedVInt(ByteBuffer in)
|
public static long readUnsignedVInt(ByteBuffer in)
|
||||||
{
|
{
|
||||||
byte firstByte = in.get();
|
byte firstByte = in.get();
|
||||||
if (firstByte >= 0)
|
if (firstByte >= 0)
|
||||||
return firstByte;
|
return firstByte;
|
||||||
|
|
||||||
|
|
||||||
int position = in.position();
|
int position = in.position();
|
||||||
int limit = in.limit();
|
int limit = in.limit();
|
||||||
if (limit - position < 8)
|
if (limit - position < 8)
|
||||||
|
|
@ -155,6 +169,32 @@ public class VIntCoding
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static long readUnsignedVInt(ByteBuffer in, int position)
|
||||||
|
{
|
||||||
|
byte firstByte = in.get(position++);
|
||||||
|
if (firstByte >= 0)
|
||||||
|
return firstByte;
|
||||||
|
|
||||||
|
int limit = in.limit();
|
||||||
|
if (limit - position < 8)
|
||||||
|
return readUnsignedVIntSlow(in, position, firstByte);
|
||||||
|
|
||||||
|
int extraBytes = VIntCoding.numberOfExtraBytesToRead(firstByte);
|
||||||
|
int extraBits = extraBytes * 8;
|
||||||
|
|
||||||
|
long retval = in.getLong(position);
|
||||||
|
if (in.order() == ByteOrder.LITTLE_ENDIAN)
|
||||||
|
retval = Long.reverseBytes(retval);
|
||||||
|
|
||||||
|
// truncate the bytes we read in excess of those we needed
|
||||||
|
retval >>>= 64 - extraBits;
|
||||||
|
// remove the non-value bits from the first byte
|
||||||
|
firstByte &= VIntCoding.firstByteValueMask(extraBytes);
|
||||||
|
// shift the first byte up to its correct position
|
||||||
|
retval |= (long) firstByte << extraBits;
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
public static void skipUnsignedVInt(DataInputPlus input) throws IOException
|
public static void skipUnsignedVInt(DataInputPlus input) throws IOException
|
||||||
{
|
{
|
||||||
int firstByte = input.readByte();
|
int firstByte = input.readByte();
|
||||||
|
|
@ -330,6 +370,11 @@ public class VIntCoding
|
||||||
return checkedCast(readUnsignedVInt(input));
|
return checkedCast(readUnsignedVInt(input));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int readUnsignedVInt32(ByteBuffer input, int position)
|
||||||
|
{
|
||||||
|
return checkedCast(readUnsignedVInt(input, position));
|
||||||
|
}
|
||||||
|
|
||||||
// & this with the first byte to give the value part for a given extraBytesToRead encoded in the byte
|
// & this with the first byte to give the value part for a given extraBytesToRead encoded in the byte
|
||||||
public static int firstByteValueMask(int extraBytesToRead)
|
public static int firstByteValueMask(int extraBytesToRead)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
<!--
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<configuration debug="false" scan="true" scanPeriod="60 seconds">
|
||||||
|
<define name="cluster_id" class="org.apache.cassandra.distributed.impl.ClusterIDDefiner" />
|
||||||
|
<define name="instance_id" class="org.apache.cassandra.distributed.impl.InstanceIDDefiner" />
|
||||||
|
|
||||||
|
<!-- Shutdown hook ensures that async appender flushes -->
|
||||||
|
<shutdownHook class="ch.qos.logback.core.hook.DelayingShutdownHook"/>
|
||||||
|
|
||||||
|
<appender name="INSTANCEFILE" class="ch.qos.logback.core.FileAppender">
|
||||||
|
<file>./build/test/logs/${cassandra.testtag}/${suitename}/${cluster_id}/${instance_id}/system.log</file>
|
||||||
|
<encoder>
|
||||||
|
<pattern>%-5level [%thread] ${instance_id} %date{ISO8601} %F:%L - %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||||
|
<level>INFO</level>
|
||||||
|
</filter>
|
||||||
|
<immediateFlush>true</immediateFlush>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<appender name="INSTANCESTDERR" target="System.err" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>%-5level %date{HH:mm:ss,SSS} %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||||
|
<level>ERROR</level>
|
||||||
|
</filter>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<!-- Un-comment to enable TRACE logging for Accord transactions.
|
||||||
|
<logger name="accord" level="TRACE" />
|
||||||
|
<logger name="org.apache.cassandra.service.accord" level="TRACE" />
|
||||||
|
-->
|
||||||
|
|
||||||
|
<root level="DEBUG">
|
||||||
|
<appender-ref ref="INSTANCEFILE" /> <!-- use blocking to avoid race conditions with appending and searching -->
|
||||||
|
<appender-ref ref="INSTANCESTDERR" />
|
||||||
|
</root>
|
||||||
|
</configuration>
|
||||||
|
|
@ -21,6 +21,7 @@ package org.apache.cassandra.distributed.api;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
import org.apache.cassandra.distributed.shared.FutureUtils;
|
import org.apache.cassandra.distributed.shared.FutureUtils;
|
||||||
|
|
||||||
|
|
@ -60,6 +61,8 @@ public interface ICoordinator
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleQueryResult executeWithResult(String query, ConsistencyLevel consistencyLevel, Object... boundValues);
|
SimpleQueryResult executeWithResult(String query, ConsistencyLevel consistencyLevel, Object... boundValues);
|
||||||
|
Future<?> executeWithResult(BiConsumer<SimpleQueryResult, Throwable> callback, String query, ConsistencyLevel consistencyLevel, Object... boundValues);
|
||||||
|
Future<?> executeWithResult(BiConsumer<SimpleQueryResult, Throwable> callback, String query, ConsistencyLevel serialConsistencyLevel, ConsistencyLevel commitConsistencyLevel, Object... boundValues);
|
||||||
|
|
||||||
default SimpleQueryResult executeWithResult(String query, ConsistencyLevel serialConsistencyLevel, ConsistencyLevel commitConsistencyLevel, Object... boundValues)
|
default SimpleQueryResult executeWithResult(String query, ConsistencyLevel serialConsistencyLevel, ConsistencyLevel commitConsistencyLevel, Object... boundValues)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
import com.google.common.collect.Iterators;
|
import com.google.common.collect.Iterators;
|
||||||
|
|
||||||
|
|
@ -62,6 +63,30 @@ public class Coordinator implements ICoordinator
|
||||||
return instance().sync(() -> unsafeExecuteInternal(query, consistencyLevel, boundValues)).call();
|
return instance().sync(() -> unsafeExecuteInternal(query, consistencyLevel, boundValues)).call();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Future<?> executeWithResult(BiConsumer<SimpleQueryResult, Throwable> callback, String query, ConsistencyLevel consistencyLevel, Object... boundValues)
|
||||||
|
{
|
||||||
|
return executeWithResult(callback, query, null, consistencyLevel, boundValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Future<?> executeWithResult(BiConsumer<SimpleQueryResult, Throwable> callback, String query, ConsistencyLevel serialConsistencyLevel, ConsistencyLevel commitConsistencyLevel, Object... boundValues)
|
||||||
|
{
|
||||||
|
return instance().async(cb -> {
|
||||||
|
SimpleQueryResult result;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = CoordinatorHelper.unsafeExecuteInternal(query, serialConsistencyLevel, commitConsistencyLevel, boundValues);
|
||||||
|
}
|
||||||
|
catch (Throwable t)
|
||||||
|
{
|
||||||
|
callback.accept(null, t);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
callback.accept(result, null);
|
||||||
|
}).apply(callback);
|
||||||
|
}
|
||||||
|
|
||||||
public Future<SimpleQueryResult> asyncExecuteWithTracingWithResult(UUID sessionId, String query, ConsistencyLevel consistencyLevelOrigin, Object... boundValues)
|
public Future<SimpleQueryResult> asyncExecuteWithTracingWithResult(UUID sessionId, String query, ConsistencyLevel consistencyLevelOrigin, Object... boundValues)
|
||||||
{
|
{
|
||||||
return instance.async(() -> {
|
return instance.async(() -> {
|
||||||
|
|
|
||||||
|
|
@ -507,6 +507,7 @@ public class Instance extends IsolatedExecutor implements IInvokableInstance
|
||||||
public void receiveMessage(IMessage message)
|
public void receiveMessage(IMessage message)
|
||||||
{
|
{
|
||||||
sync(receiveMessageRunnable(message)).accept(false);
|
sync(receiveMessageRunnable(message)).accept(false);
|
||||||
|
// async(receiveMessageRunnable(message)).apply(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
/*
|
||||||
|
* 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.io.IOException;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.concurrent.Semaphore;
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.RateLimiter;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import org.apache.cassandra.distributed.api.ConsistencyLevel;
|
||||||
|
import org.apache.cassandra.distributed.api.ICoordinator;
|
||||||
|
import org.apache.cassandra.utils.EstimatedHistogram;
|
||||||
|
|
||||||
|
import static java.util.concurrent.TimeUnit.NANOSECONDS;
|
||||||
|
|
||||||
|
public class AccordLoadTest extends AccordTestBase
|
||||||
|
{
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(AccordLoadTest.class);
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setUp() throws IOException
|
||||||
|
{
|
||||||
|
AccordTestBase.setupCluster(builder -> builder.withConfig(config -> config.set("lwt_strategy", "accord").set("non_serial_write_strategy", "accord")), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore
|
||||||
|
@Test
|
||||||
|
public void testLoad() throws Exception
|
||||||
|
{
|
||||||
|
test("CREATE TABLE " + qualifiedTableName + " (k int, v int, PRIMARY KEY(k))",
|
||||||
|
cluster -> {
|
||||||
|
ICoordinator coordinator = cluster.coordinator(1);
|
||||||
|
final int batchSize = 1000;
|
||||||
|
final int concurrency = 100;
|
||||||
|
final int ratePerSecond = 1000;
|
||||||
|
final int keyCount = 10;
|
||||||
|
for (int i = 1; i <= keyCount; i++)
|
||||||
|
coordinator.execute("INSERT INTO " + qualifiedTableName + " (k, v) VALUES (0, 0) USING TIMESTAMP 0;", ConsistencyLevel.ALL, i);
|
||||||
|
|
||||||
|
Random random = new Random();
|
||||||
|
// CopyOnWriteArrayList<Throwable> exceptions = new CopyOnWriteArrayList<>();
|
||||||
|
final Semaphore inFlight = new Semaphore(concurrency);
|
||||||
|
final RateLimiter rateLimiter = RateLimiter.create(ratePerSecond);
|
||||||
|
long testStart = System.nanoTime();
|
||||||
|
// while (NANOSECONDS.toMinutes(System.nanoTime() - testStart) < 10 && exceptions.size() < 10000)
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
final EstimatedHistogram histogram = new EstimatedHistogram(200);
|
||||||
|
long batchStart = System.nanoTime();
|
||||||
|
for (int i = 0 ; i < batchSize ; ++i)
|
||||||
|
{
|
||||||
|
inFlight.acquire();
|
||||||
|
rateLimiter.acquire();
|
||||||
|
long commandStart = System.nanoTime();
|
||||||
|
coordinator.executeWithResult((success, fail) -> {
|
||||||
|
inFlight.release();
|
||||||
|
if (fail == null) histogram.add(NANOSECONDS.toMicros(System.nanoTime() - commandStart));
|
||||||
|
// else exceptions.add(fail);
|
||||||
|
}, "UPDATE " + qualifiedTableName + " SET v += 1 WHERE k = ? IF EXISTS;", ConsistencyLevel.SERIAL, ConsistencyLevel.QUORUM, random.nextInt(keyCount));
|
||||||
|
}
|
||||||
|
System.out.printf("%tT rate: %.2f/s\n", new Date(), (((float)batchSize * 1000) / NANOSECONDS.toMillis(System.nanoTime() - batchStart)));
|
||||||
|
System.out.printf("%tT percentiles: %d %d %d %d\n", new Date(), histogram.percentile(.25)/1000, histogram.percentile(.5)/1000, histogram.percentile(.75)/1000, histogram.percentile(1)/1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Logger logger()
|
||||||
|
{
|
||||||
|
return logger;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -38,7 +38,7 @@ import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import accord.api.Key;
|
import accord.api.Key;
|
||||||
import accord.api.Result;
|
import accord.api.Result;
|
||||||
import accord.impl.CommandsForKey;
|
import accord.local.CommandsForKey;
|
||||||
import accord.local.CheckedCommands;
|
import accord.local.CheckedCommands;
|
||||||
import accord.local.Command;
|
import accord.local.Command;
|
||||||
import accord.local.CommandStore;
|
import accord.local.CommandStore;
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,8 @@ import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import accord.api.Key;
|
import accord.api.Key;
|
||||||
import accord.api.Result;
|
import accord.api.Result;
|
||||||
import accord.impl.CommandsForKey;
|
import accord.local.CommandsForKey;
|
||||||
import accord.impl.CommandsForKeys;
|
import accord.impl.TimestampsForKeys;
|
||||||
import accord.impl.TimestampsForKey;
|
import accord.impl.TimestampsForKey;
|
||||||
import accord.local.Command;
|
import accord.local.Command;
|
||||||
import accord.local.CommonAttributes;
|
import accord.local.CommonAttributes;
|
||||||
|
|
@ -41,10 +41,13 @@ import accord.messages.Apply;
|
||||||
import accord.primitives.Ballot;
|
import accord.primitives.Ballot;
|
||||||
import accord.primitives.PartialDeps;
|
import accord.primitives.PartialDeps;
|
||||||
import accord.primitives.PartialTxn;
|
import accord.primitives.PartialTxn;
|
||||||
|
import accord.primitives.Range;
|
||||||
import accord.primitives.Ranges;
|
import accord.primitives.Ranges;
|
||||||
|
import accord.primitives.Routable;
|
||||||
import accord.primitives.Route;
|
import accord.primitives.Route;
|
||||||
import accord.primitives.RoutingKeys;
|
import accord.primitives.RoutingKeys;
|
||||||
import accord.primitives.Timestamp;
|
import accord.primitives.Timestamp;
|
||||||
|
import accord.primitives.Txn;
|
||||||
import accord.primitives.TxnId;
|
import accord.primitives.TxnId;
|
||||||
import accord.primitives.Writes;
|
import accord.primitives.Writes;
|
||||||
import accord.utils.ImmutableBitSet;
|
import accord.utils.ImmutableBitSet;
|
||||||
|
|
@ -102,20 +105,20 @@ public class AccordCommandStoreTest
|
||||||
AtomicLong clock = new AtomicLong(0);
|
AtomicLong clock = new AtomicLong(0);
|
||||||
PartialTxn depTxn = createPartialTxn(0);
|
PartialTxn depTxn = createPartialTxn(0);
|
||||||
Key key = (Key)depTxn.keys().get(0);
|
Key key = (Key)depTxn.keys().get(0);
|
||||||
|
Range range = key.toUnseekable().asRange();
|
||||||
AccordCommandStore commandStore = createAccordCommandStore(clock::incrementAndGet, "ks", "tbl");
|
AccordCommandStore commandStore = createAccordCommandStore(clock::incrementAndGet, "ks", "tbl");
|
||||||
|
|
||||||
QueryProcessor.executeInternal("INSERT INTO ks.tbl (k, c, v) VALUES (0, 0, 1)");
|
QueryProcessor.executeInternal("INSERT INTO ks.tbl (k, c, v) VALUES (0, 0, 1)");
|
||||||
TableId tableId = Schema.instance.getTableMetadata("ks", "tbl").id;
|
TableId tableId = Schema.instance.getTableMetadata("ks", "tbl").id;
|
||||||
TxnId oldTxnId1 = txnId(1, clock.incrementAndGet(), 1);
|
TxnId oldTxnId1 = txnId(1, clock.incrementAndGet(), 1, Txn.Kind.Write, Routable.Domain.Range);
|
||||||
TxnId oldTxnId2 = txnId(1, clock.incrementAndGet(), 1);
|
TxnId oldTxnId2 = txnId(1, clock.incrementAndGet(), 1, Txn.Kind.Write, Routable.Domain.Range);
|
||||||
TxnId oldTimestamp = txnId(1, clock.incrementAndGet(), 1);
|
TxnId txnId = txnId(1, clock.incrementAndGet(), 1, Txn.Kind.Write, Routable.Domain.Range);
|
||||||
TxnId txnId = txnId(1, clock.incrementAndGet(), 1);
|
|
||||||
|
|
||||||
PartialDeps dependencies;
|
PartialDeps dependencies;
|
||||||
try (PartialDeps.Builder builder = PartialDeps.builder(depTxn.covering()))
|
try (PartialDeps.Builder builder = PartialDeps.builder(depTxn.covering()))
|
||||||
{
|
{
|
||||||
builder.add(key, oldTxnId1);
|
builder.add(range, oldTxnId1);
|
||||||
builder.add(key, oldTxnId2);
|
builder.add(range, oldTxnId2);
|
||||||
dependencies = builder.build();
|
dependencies = builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -130,11 +133,9 @@ public class AccordCommandStoreTest
|
||||||
Ballot accepted = ballot(1, clock.incrementAndGet(), 1);
|
Ballot accepted = ballot(1, clock.incrementAndGet(), 1);
|
||||||
Timestamp executeAt = timestamp(1, clock.incrementAndGet(), 1);
|
Timestamp executeAt = timestamp(1, clock.incrementAndGet(), 1);
|
||||||
attrs.partialDeps(dependencies);
|
attrs.partialDeps(dependencies);
|
||||||
SimpleBitSet waitingOnCommit = new SimpleBitSet(2);
|
SimpleBitSet waitingOnApply = new SimpleBitSet(3);
|
||||||
waitingOnCommit.set(0);
|
|
||||||
SimpleBitSet waitingOnApply = new SimpleBitSet(2);
|
|
||||||
waitingOnApply.set(1);
|
waitingOnApply.set(1);
|
||||||
Command.WaitingOn waitingOn = new Command.WaitingOn(dependencies, new ImmutableBitSet(waitingOnCommit), new ImmutableBitSet(waitingOnApply), new ImmutableBitSet(2));
|
Command.WaitingOn waitingOn = new Command.WaitingOn(dependencies.keyDeps.keys(), dependencies.rangeDeps.txnIds(), new ImmutableBitSet(waitingOnApply), new ImmutableBitSet(2));
|
||||||
attrs.addListener(new Command.ProxyListener(oldTxnId1));
|
attrs.addListener(new Command.ProxyListener(oldTxnId1));
|
||||||
Pair<Writes, Result> result = AccordTestUtils.processTxnResult(commandStore, txnId, txn, executeAt);
|
Pair<Writes, Result> result = AccordTestUtils.processTxnResult(commandStore, txnId, txn, executeAt);
|
||||||
|
|
||||||
|
|
@ -183,10 +184,10 @@ public class AccordCommandStoreTest
|
||||||
AccordSafeTimestampsForKey tfk = new AccordSafeTimestampsForKey(loaded(key, null));
|
AccordSafeTimestampsForKey tfk = new AccordSafeTimestampsForKey(loaded(key, null));
|
||||||
tfk.initialize();
|
tfk.initialize();
|
||||||
|
|
||||||
CommandsForKeys.updateLastExecutionTimestamps(commandStore, tfk, txnId1, true);
|
TimestampsForKeys.updateLastExecutionTimestamps(commandStore, tfk, txnId1, true);
|
||||||
Assert.assertEquals(txnId1.hlc(), AccordSafeTimestampsForKey.timestampMicrosFor(tfk.current(), txnId1, true));
|
Assert.assertEquals(txnId1.hlc(), AccordSafeTimestampsForKey.timestampMicrosFor(tfk.current(), txnId1, true));
|
||||||
|
|
||||||
CommandsForKeys.updateLastExecutionTimestamps(commandStore, tfk, txnId2, true);
|
TimestampsForKeys.updateLastExecutionTimestamps(commandStore, tfk, txnId2, true);
|
||||||
Assert.assertEquals(txnId2.hlc(), AccordSafeTimestampsForKey.timestampMicrosFor(tfk.current(), txnId2, true));
|
Assert.assertEquals(txnId2.hlc(), AccordSafeTimestampsForKey.timestampMicrosFor(tfk.current(), txnId2, true));
|
||||||
|
|
||||||
Assert.assertEquals(txnId2, tfk.current().lastExecutedTimestamp());
|
Assert.assertEquals(txnId2, tfk.current().lastExecutedTimestamp());
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ import org.junit.Test;
|
||||||
|
|
||||||
import accord.api.Key;
|
import accord.api.Key;
|
||||||
import accord.api.RoutingKey;
|
import accord.api.RoutingKey;
|
||||||
import accord.impl.CommandsForKey;
|
import accord.local.CommandsForKey;
|
||||||
import accord.local.Command;
|
import accord.local.Command;
|
||||||
import accord.local.KeyHistory;
|
import accord.local.KeyHistory;
|
||||||
import accord.local.Node;
|
import accord.local.Node;
|
||||||
|
|
@ -117,7 +117,7 @@ public class AccordCommandTest
|
||||||
Assert.assertEquals(Status.PreAccepted, command.status());
|
Assert.assertEquals(Status.PreAccepted, command.status());
|
||||||
Assert.assertTrue(command.partialDeps() == null || command.partialDeps().isEmpty());
|
Assert.assertTrue(command.partialDeps() == null || command.partialDeps().isEmpty());
|
||||||
|
|
||||||
CommandsForKey cfk = ((AccordSafeCommandStore) instance).commandsForKey(key(1)).current();
|
CommandsForKey cfk = ((AccordSafeCommandStore) instance).get(key(1)).current();
|
||||||
Assert.assertTrue(cfk.indexOf(txnId) >= 0);
|
Assert.assertTrue(cfk.indexOf(txnId) >= 0);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
@ -145,7 +145,7 @@ public class AccordCommandTest
|
||||||
Assert.assertEquals(Status.Accepted, command.status());
|
Assert.assertEquals(Status.Accepted, command.status());
|
||||||
Assert.assertEquals(deps, command.partialDeps());
|
Assert.assertEquals(deps, command.partialDeps());
|
||||||
|
|
||||||
CommandsForKey cfk = ((AccordSafeCommandStore) instance).commandsForKey(key(1)).current();
|
CommandsForKey cfk = ((AccordSafeCommandStore) instance).get(key(1)).current();
|
||||||
Assert.assertTrue(cfk.indexOf(txnId) >= 0);
|
Assert.assertTrue(cfk.indexOf(txnId) >= 0);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
@ -160,7 +160,7 @@ public class AccordCommandTest
|
||||||
Assert.assertTrue(command.hasBeen(Status.Committed));
|
Assert.assertTrue(command.hasBeen(Status.Committed));
|
||||||
Assert.assertEquals(commit.partialDeps, command.partialDeps());
|
Assert.assertEquals(commit.partialDeps, command.partialDeps());
|
||||||
|
|
||||||
CommandsForKey cfk = ((AccordSafeCommandStore) instance).commandsForKey(key(1)).current();
|
CommandsForKey cfk = ((AccordSafeCommandStore) instance).get(key(1)).current();
|
||||||
Assert.assertTrue(cfk.indexOf(txnId) >= 0);
|
Assert.assertTrue(cfk.indexOf(txnId) >= 0);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,8 @@ import java.util.function.LongSupplier;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
|
@ -59,6 +61,7 @@ import accord.primitives.PartialDeps;
|
||||||
import accord.primitives.PartialTxn;
|
import accord.primitives.PartialTxn;
|
||||||
import accord.primitives.Participants;
|
import accord.primitives.Participants;
|
||||||
import accord.primitives.Ranges;
|
import accord.primitives.Ranges;
|
||||||
|
import accord.primitives.Routable;
|
||||||
import accord.primitives.Route;
|
import accord.primitives.Route;
|
||||||
import accord.primitives.Seekable;
|
import accord.primitives.Seekable;
|
||||||
import accord.primitives.Seekables;
|
import accord.primitives.Seekables;
|
||||||
|
|
@ -199,8 +202,8 @@ public class AccordTestUtils
|
||||||
@Override public void executed(Command command, ProgressShard progressShard) {}
|
@Override public void executed(Command command, ProgressShard progressShard) {}
|
||||||
@Override public void clear(TxnId txnId) {}
|
@Override public void clear(TxnId txnId) {}
|
||||||
@Override public void durable(Command command) {}
|
@Override public void durable(Command command) {}
|
||||||
@Override
|
@Override public void waiting(SafeCommand blockedBy, LocalExecution blockedUntil, Route<?> blockedOnRoute, Participants<?> blockedOnParticipants) {}
|
||||||
public void waiting(SafeCommand blockedBy, LocalExecution blockedUntil, Route<?> blockedOnRoute, Participants<?> blockedOnParticipants) {}
|
@Override public void waiting(TxnId blockedBy, LocalExecution blockedUntil, @Nullable Route<?> blockedOnRoute, @Nullable Participants<?> blockedOnParticipants) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static TxnId txnId(long epoch, long hlc, int node)
|
public static TxnId txnId(long epoch, long hlc, int node)
|
||||||
|
|
@ -213,6 +216,11 @@ public class AccordTestUtils
|
||||||
return new TxnId(epoch, hlc, kind, Key, new Node.Id(node));
|
return new TxnId(epoch, hlc, kind, Key, new Node.Id(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static TxnId txnId(long epoch, long hlc, int node, Txn.Kind kind, Routable.Domain domain)
|
||||||
|
{
|
||||||
|
return new TxnId(epoch, hlc, kind, domain, new Node.Id(node));
|
||||||
|
}
|
||||||
|
|
||||||
public static Timestamp timestamp(long epoch, long hlc, int node)
|
public static Timestamp timestamp(long epoch, long hlc, int node)
|
||||||
{
|
{
|
||||||
return Timestamp.fromValues(epoch, hlc, new Node.Id(node));
|
return Timestamp.fromValues(epoch, hlc, new Node.Id(node));
|
||||||
|
|
|
||||||
|
|
@ -32,13 +32,12 @@ import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import accord.api.Key;
|
import accord.api.Key;
|
||||||
import accord.impl.CommandsForKey;
|
import accord.local.CommandsForKey;
|
||||||
import accord.impl.TimestampsForKey;
|
import accord.impl.TimestampsForKey;
|
||||||
import accord.local.Command;
|
import accord.local.Command;
|
||||||
import accord.local.KeyHistory;
|
import accord.local.KeyHistory;
|
||||||
import accord.primitives.Keys;
|
import accord.primitives.Keys;
|
||||||
import accord.primitives.PartialTxn;
|
import accord.primitives.PartialTxn;
|
||||||
import accord.primitives.RoutableKey;
|
|
||||||
import accord.primitives.TxnId;
|
import accord.primitives.TxnId;
|
||||||
import accord.utils.async.AsyncChains;
|
import accord.utils.async.AsyncChains;
|
||||||
import accord.utils.async.AsyncResult;
|
import accord.utils.async.AsyncResult;
|
||||||
|
|
@ -96,7 +95,7 @@ public class AsyncLoaderTest
|
||||||
AccordStateCache.Instance<TxnId, Command, AccordSafeCommand> commandCache = commandStore.commandCache();
|
AccordStateCache.Instance<TxnId, Command, AccordSafeCommand> commandCache = commandStore.commandCache();
|
||||||
commandStore.executeBlocking(() -> commandStore.setCapacity(1024));
|
commandStore.executeBlocking(() -> commandStore.setCapacity(1024));
|
||||||
|
|
||||||
AccordStateCache.Instance<RoutableKey, TimestampsForKey, AccordSafeTimestampsForKey> timestampsCache = commandStore.timestampsForKeyCache();
|
AccordStateCache.Instance<Key, TimestampsForKey, AccordSafeTimestampsForKey> timestampsCache = commandStore.timestampsForKeyCache();
|
||||||
TxnId txnId = txnId(1, clock.incrementAndGet(), 1);
|
TxnId txnId = txnId(1, clock.incrementAndGet(), 1);
|
||||||
PartialTxn txn = createPartialTxn(0);
|
PartialTxn txn = createPartialTxn(0);
|
||||||
PartitionKey key = (PartitionKey) Iterables.getOnlyElement(txn.keys());
|
PartitionKey key = (PartitionKey) Iterables.getOnlyElement(txn.keys());
|
||||||
|
|
@ -375,7 +374,7 @@ public class AsyncLoaderTest
|
||||||
@Test
|
@Test
|
||||||
public void inProgressCFKSaveTest()
|
public void inProgressCFKSaveTest()
|
||||||
{
|
{
|
||||||
inProgressCFKSaveTest(COMMANDS, AccordCommandStore::commandsForKeyCache, context -> context.commandsForKey, CommandsForKey::new, (cfk, u) -> cfk.update(null, u));
|
this.inProgressCFKSaveTest(COMMANDS, AccordCommandStore::commandsForKeyCache, context -> context.commandsForKey, CommandsForKey::new, (cfk, u) -> cfk.update(null, u));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -384,7 +383,7 @@ public class AsyncLoaderTest
|
||||||
inProgressCFKSaveTest(TIMESTAMPS, AccordCommandStore::timestampsForKeyCache, context -> context.timestampsForKey, TimestampsForKey::new, (tfk, c) -> new TimestampsForKey(tfk.key(), c.executeAt(), c.executeAt().hlc(), c.executeAt()));
|
inProgressCFKSaveTest(TIMESTAMPS, AccordCommandStore::timestampsForKeyCache, context -> context.timestampsForKey, TimestampsForKey::new, (tfk, c) -> new TimestampsForKey(tfk.key(), c.executeAt(), c.executeAt().hlc(), c.executeAt()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T1, T2 extends AccordSafeState<RoutableKey, T1>, C extends AccordStateCache.Instance<RoutableKey, T1, T2>> void inProgressCFKSaveTest(KeyHistory history, Function<AccordCommandStore, C> getter, Function<Context, TreeMap<?, ?>> inContext, Function<Key, T1> initialiser, BiFunction<T1, Command, T1> update)
|
private <T1, T2 extends AccordSafeState<Key, T1>, C extends AccordStateCache.Instance<Key, T1, T2>> void inProgressCFKSaveTest(KeyHistory history, Function<AccordCommandStore, C> getter, Function<Context, TreeMap<?, ?>> inContext, Function<Key, T1> initialiser, BiFunction<T1, Command, T1> update)
|
||||||
{
|
{
|
||||||
AtomicLong clock = new AtomicLong(0);
|
AtomicLong clock = new AtomicLong(0);
|
||||||
ManualExecutor executor = new ManualExecutor();
|
ManualExecutor executor = new ManualExecutor();
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import accord.api.RoutingKey;
|
import accord.api.RoutingKey;
|
||||||
import accord.impl.SafeCommandsForKey;
|
import accord.local.SafeCommandsForKey;
|
||||||
import accord.local.CheckedCommands;
|
import accord.local.CheckedCommands;
|
||||||
import accord.local.Command;
|
import accord.local.Command;
|
||||||
import accord.local.PreLoadContext;
|
import accord.local.PreLoadContext;
|
||||||
|
|
@ -53,7 +53,6 @@ import accord.primitives.PartialDeps;
|
||||||
import accord.primitives.PartialRoute;
|
import accord.primitives.PartialRoute;
|
||||||
import accord.primitives.PartialTxn;
|
import accord.primitives.PartialTxn;
|
||||||
import accord.primitives.Ranges;
|
import accord.primitives.Ranges;
|
||||||
import accord.primitives.RoutableKey;
|
|
||||||
import accord.primitives.Route;
|
import accord.primitives.Route;
|
||||||
import accord.primitives.Timestamp;
|
import accord.primitives.Timestamp;
|
||||||
import accord.primitives.Txn;
|
import accord.primitives.Txn;
|
||||||
|
|
@ -259,7 +258,7 @@ public class AsyncOperationTest
|
||||||
Accept accept =
|
Accept accept =
|
||||||
Accept.SerializerSupport.create(txnId, partialRoute, txnId.epoch(), txnId.epoch(), false, Ballot.ZERO, executeAt, partialTxn.keys(), deps);
|
Accept.SerializerSupport.create(txnId, partialRoute, txnId.epoch(), txnId.epoch(), false, Ballot.ZERO, executeAt, partialTxn.keys(), deps);
|
||||||
Commit commit =
|
Commit commit =
|
||||||
Commit.SerializerSupport.create(txnId, partialRoute, txnId.epoch(), Commit.Kind.Commit, Ballot.ZERO, executeAt, partialTxn.keys(), partialTxn, deps, route, null);
|
Commit.SerializerSupport.create(txnId, partialRoute, txnId.epoch(), Commit.Kind.CommitSlowPath, Ballot.ZERO, executeAt, partialTxn.keys(), partialTxn, deps, route, null);
|
||||||
Commit stable =
|
Commit stable =
|
||||||
Commit.SerializerSupport.create(txnId, partialRoute, txnId.epoch(), Commit.Kind.StableSlowPath, Ballot.ZERO, executeAt, partialTxn.keys(), partialTxn, deps, route, null);
|
Commit.SerializerSupport.create(txnId, partialRoute, txnId.epoch(), Commit.Kind.StableSlowPath, Ballot.ZERO, executeAt, partialTxn.keys(), partialTxn, deps, route, null);
|
||||||
|
|
||||||
|
|
@ -482,8 +481,7 @@ public class AsyncOperationTest
|
||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//TODO this is due to bad typing for Instance, it doesn't use ? extends RoutableKey
|
assertNoReferences(commandStore.commandsForKeyCache(), keys);
|
||||||
assertNoReferences(commandStore.commandsForKeyCache(), (Iterable<RoutableKey>) (Iterable<?>) keys);
|
|
||||||
}
|
}
|
||||||
catch (AssertionError e)
|
catch (AssertionError e)
|
||||||
{
|
{
|
||||||
|
|
@ -524,8 +522,7 @@ public class AsyncOperationTest
|
||||||
private static void awaitDone(AccordCommandStore commandStore, List<TxnId> ids, Keys keys)
|
private static void awaitDone(AccordCommandStore commandStore, List<TxnId> ids, Keys keys)
|
||||||
{
|
{
|
||||||
awaitDone(commandStore.commandCache(), ids);
|
awaitDone(commandStore.commandCache(), ids);
|
||||||
//TODO this is due to bad typing for Instance, it doesn't use ? extends RoutableKey
|
awaitDone(commandStore.commandsForKeyCache(), keys);
|
||||||
awaitDone(commandStore.commandsForKeyCache(), (Iterable<RoutableKey>) (Iterable<?>) keys);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T> void awaitDone(AccordStateCache.Instance<T, ?, ?> cache, Iterable<T> keys)
|
private static <T> void awaitDone(AccordStateCache.Instance<T, ?, ?> cache, Iterable<T> keys)
|
||||||
|
|
|
||||||
|
|
@ -38,9 +38,10 @@ import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import accord.api.Key;
|
import accord.api.Key;
|
||||||
import accord.impl.CommandsForKey;
|
import accord.local.CommandsForKey;
|
||||||
import accord.impl.CommandsForKey.InternalStatus;
|
import accord.local.CommandsForKey.InternalStatus;
|
||||||
import accord.local.Command;
|
import accord.local.Command;
|
||||||
|
import accord.local.CommandsForKey.TxnInfo;
|
||||||
import accord.local.CommonAttributes;
|
import accord.local.CommonAttributes;
|
||||||
import accord.local.CommonAttributes.Mutable;
|
import accord.local.CommonAttributes.Mutable;
|
||||||
import accord.local.Listeners;
|
import accord.local.Listeners;
|
||||||
|
|
@ -241,9 +242,12 @@ public class CommandsForKeySerializerTest
|
||||||
List<TxnId> deps = cmds[i].deps;
|
List<TxnId> deps = cmds[i].deps;
|
||||||
List<TxnId> missing = cmds[i].missing;
|
List<TxnId> missing = cmds[i].missing;
|
||||||
for (int j = 0 ; j < limit ; ++j)
|
for (int j = 0 ; j < limit ; ++j)
|
||||||
if (i != j) deps.add(cmds[j].txnId);
|
{
|
||||||
|
if (i != j && cmds[i].txnId.kind().witnesses(cmds[j].txnId))
|
||||||
|
deps.add(cmds[j].txnId);
|
||||||
|
}
|
||||||
|
|
||||||
int missingCount = Math.min(limit - (limit > i ? 1 : 0), missingCountSupplier.getAsInt());
|
int missingCount = Math.min(deps.size(), missingCountSupplier.getAsInt());
|
||||||
while (missingCount > 0)
|
while (missingCount > 0)
|
||||||
{
|
{
|
||||||
int remove = source.nextInt(deps.size());
|
int remove = source.nextInt(deps.size());
|
||||||
|
|
@ -267,14 +271,14 @@ public class CommandsForKeySerializerTest
|
||||||
{
|
{
|
||||||
InternalStatus status = InternalStatus.from(cmds[j].saveStatus);
|
InternalStatus status = InternalStatus.from(cmds[j].saveStatus);
|
||||||
if (status == null || !status.hasInfo) continue;
|
if (status == null || !status.hasInfo) continue;
|
||||||
if (status.depsKnownBefore(cmds[j].txnId, cmds[j].executeAt).compareTo(cmds[i].txnId) > 0 && Collections.binarySearch(cmds[j].missing, cmds[i].txnId) < 0)
|
if (cmds[j].txnId.kind().witnesses(cmds[i].txnId) && status.depsKnownBefore(cmds[j].txnId, cmds[j].executeAt).compareTo(cmds[i].txnId) > 0 && Collections.binarySearch(cmds[j].missing, cmds[i].txnId) < 0)
|
||||||
continue outer;
|
continue outer;
|
||||||
}
|
}
|
||||||
for (int j = i + 1 ; j < cmds.length ; ++j)
|
for (int j = i + 1 ; j < cmds.length ; ++j)
|
||||||
{
|
{
|
||||||
InternalStatus status = InternalStatus.from(cmds[j].saveStatus);
|
InternalStatus status = InternalStatus.from(cmds[j].saveStatus);
|
||||||
if (status == null || !status.hasInfo) continue;
|
if (status == null || !status.hasInfo) continue;
|
||||||
if (Collections.binarySearch(cmds[j].missing, cmds[i].txnId) < 0)
|
if (cmds[j].txnId.kind().witnesses(cmds[i].txnId) && Collections.binarySearch(cmds[j].missing, cmds[i].txnId) < 0)
|
||||||
continue outer;
|
continue outer;
|
||||||
}
|
}
|
||||||
cmds[i].invisible = true;
|
cmds[i].invisible = true;
|
||||||
|
|
@ -322,7 +326,7 @@ public class CommandsForKeySerializerTest
|
||||||
@Test
|
@Test
|
||||||
public void serde()
|
public void serde()
|
||||||
{
|
{
|
||||||
// testOne(1821931462020409370L);
|
testOne(-6946067792202944553L);
|
||||||
Random random = new Random();
|
Random random = new Random();
|
||||||
for (int i = 0 ; i < 10000 ; ++i)
|
for (int i = 0 ; i < 10000 ; ++i)
|
||||||
{
|
{
|
||||||
|
|
@ -426,13 +430,13 @@ public class CommandsForKeySerializerTest
|
||||||
Assert.assertTrue(cmd.invisible);
|
Assert.assertTrue(cmd.invisible);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
CommandsForKey.Info info = cfk.info(i);
|
TxnInfo info = cfk.get(i);
|
||||||
InternalStatus expectStatus = InternalStatus.from(cmd.saveStatus);
|
InternalStatus expectStatus = InternalStatus.from(cmd.saveStatus);
|
||||||
if (expectStatus == null) expectStatus = InternalStatus.TRANSITIVELY_KNOWN;
|
if (expectStatus == null) expectStatus = InternalStatus.TRANSITIVELY_KNOWN;
|
||||||
if (expectStatus.hasInfo)
|
if (expectStatus.hasInfo)
|
||||||
Assert.assertEquals(cmd.executeAt, info.executeAt(cfk.txnId(i)));
|
Assert.assertEquals(cmd.executeAt, info.executeAt);
|
||||||
Assert.assertEquals(expectStatus, info.status);
|
Assert.assertEquals(expectStatus, info.status);
|
||||||
Assert.assertArrayEquals(cmd.missing.toArray(TxnId[]::new), info.missing);
|
Assert.assertArrayEquals(cmd.missing.toArray(TxnId[]::new), info.missing());
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -461,11 +465,12 @@ public class CommandsForKeySerializerTest
|
||||||
next = txnIdGen.next(rs0);
|
next = txnIdGen.next(rs0);
|
||||||
return next;
|
return next;
|
||||||
}).unique().ofSizeBetween(0, 10).next(rs);
|
}).unique().ofSizeBetween(0, 10).next(rs);
|
||||||
CommandsForKey.Info[] info = new CommandsForKey.Info[ids.length];
|
TxnInfo[] info = new TxnInfo[ids.length];
|
||||||
for (int i = 0; i < info.length; i++)
|
for (int i = 0; i < info.length; i++)
|
||||||
info[i] = rs.pick(InternalStatus.values()).asNoInfo;
|
info[i] = TxnInfo.create(ids[i], rs.pick(InternalStatus.values()), ids[i], CommandsForKey.NO_TXNIDS);
|
||||||
Arrays.sort(ids, Comparator.naturalOrder());
|
Arrays.sort(info, Comparator.naturalOrder());
|
||||||
CommandsForKey expected = CommandsForKey.SerializerSupport.create(pk, redudentBefore, ids, info);
|
|
||||||
|
CommandsForKey expected = CommandsForKey.SerializerSupport.create(pk, info, CommandsForKey.NO_PENDING_UNMANAGED);
|
||||||
|
|
||||||
ByteBuffer buffer = CommandsForKeySerializer.toBytesWithoutKey(expected);
|
ByteBuffer buffer = CommandsForKeySerializer.toBytesWithoutKey(expected);
|
||||||
CommandsForKey roundTrip = CommandsForKeySerializer.fromBytes(pk, buffer);
|
CommandsForKey roundTrip = CommandsForKeySerializer.fromBytes(pk, buffer);
|
||||||
|
|
@ -479,10 +484,10 @@ public class CommandsForKeySerializerTest
|
||||||
long tokenValue = -2311778975040348869L;
|
long tokenValue = -2311778975040348869L;
|
||||||
DecoratedKey key = Murmur3Partitioner.instance.decorateKey(Murmur3Partitioner.LongToken.keyForToken(tokenValue));
|
DecoratedKey key = Murmur3Partitioner.instance.decorateKey(Murmur3Partitioner.LongToken.keyForToken(tokenValue));
|
||||||
PartitionKey pk = new PartitionKey(TableId.fromString("1b255f4d-ef25-40a6-0000-000000000009"), key);
|
PartitionKey pk = new PartitionKey(TableId.fromString("1b255f4d-ef25-40a6-0000-000000000009"), key);
|
||||||
|
TxnId txnId = TxnId.fromValues(11,34052499,2,1);
|
||||||
CommandsForKey expected = CommandsForKey.SerializerSupport.create(pk,
|
CommandsForKey expected = CommandsForKey.SerializerSupport.create(pk,
|
||||||
TxnId.fromValues(0,0,0,0),
|
new TxnInfo[] { TxnInfo.create(txnId, InternalStatus.PREACCEPTED, txnId, CommandsForKey.NO_TXNIDS) },
|
||||||
new TxnId[] {TxnId.fromValues(11,34052499,2,1)},
|
CommandsForKey.NO_PENDING_UNMANAGED);
|
||||||
new CommandsForKey.Info[] { InternalStatus.PREACCEPTED.asNoInfo});
|
|
||||||
|
|
||||||
ByteBuffer buffer = CommandsForKeySerializer.toBytesWithoutKey(expected);
|
ByteBuffer buffer = CommandsForKeySerializer.toBytesWithoutKey(expected);
|
||||||
CommandsForKey roundTrip = CommandsForKeySerializer.fromBytes(pk, buffer);
|
CommandsForKey roundTrip = CommandsForKeySerializer.fromBytes(pk, buffer);
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,8 @@ import org.junit.Test;
|
||||||
|
|
||||||
import accord.local.Command;
|
import accord.local.Command;
|
||||||
import accord.primitives.Deps;
|
import accord.primitives.Deps;
|
||||||
|
import accord.primitives.Routable;
|
||||||
|
import accord.primitives.TxnId;
|
||||||
import accord.utils.Gen;
|
import accord.utils.Gen;
|
||||||
import accord.utils.Gens;
|
import accord.utils.Gens;
|
||||||
import accord.utils.SimpleBitSet;
|
import accord.utils.SimpleBitSet;
|
||||||
|
|
@ -51,19 +53,20 @@ public class WaitingOnSerializerTest
|
||||||
{
|
{
|
||||||
DataOutputBuffer buffer = new DataOutputBuffer();
|
DataOutputBuffer buffer = new DataOutputBuffer();
|
||||||
qt().forAll(waitingOnGen()).check(waitingOn -> {
|
qt().forAll(waitingOnGen()).check(waitingOn -> {
|
||||||
|
TxnId txnId = TxnId.NONE;
|
||||||
|
if (waitingOn.appliedOrInvalidated != null) txnId = new TxnId(txnId.epoch(), txnId.hlc(), txnId.kind(), Routable.Domain.Range, txnId.node);
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
long expectedSize = WaitingOnSerializer.serializedSize(waitingOn);
|
long expectedSize = WaitingOnSerializer.serializedSize(waitingOn);
|
||||||
WaitingOnSerializer.serialize(waitingOn, buffer);
|
WaitingOnSerializer.serialize(txnId, waitingOn, buffer);
|
||||||
Assertions.assertThat(buffer.getLength()).isEqualTo(expectedSize);
|
Assertions.assertThat(buffer.getLength()).isEqualTo(expectedSize);
|
||||||
Command.WaitingOn read = WaitingOnSerializer.deserialize(waitingOn.deps, new DataInputBuffer(buffer.unsafeGetBufferAndFlip(), false));
|
Command.WaitingOn read = WaitingOnSerializer.deserialize(txnId, waitingOn.keys, waitingOn.txnIds, new DataInputBuffer(buffer.unsafeGetBufferAndFlip(), false));
|
||||||
Assertions.assertThat(read)
|
Assertions.assertThat(read)
|
||||||
.isEqualTo(waitingOn)
|
.isEqualTo(waitingOn)
|
||||||
.isEqualTo(WaitingOnSerializer.deserialize(waitingOn.deps, WaitingOnSerializer.serialize(waitingOn)));
|
.isEqualTo(WaitingOnSerializer.deserialize(txnId, waitingOn.keys, waitingOn.txnIds, WaitingOnSerializer.serialize(txnId, waitingOn)));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum WaitingOnSets
|
private enum WaitingOnSets { APPLY, APPLIED_OR_INVALIDATED }
|
||||||
{COMMIT, APPLY, APPLYED_OR_INVALIDATED}
|
|
||||||
|
|
||||||
private static Gen<Command.WaitingOn> waitingOnGen()
|
private static Gen<Command.WaitingOn> waitingOnGen()
|
||||||
{
|
{
|
||||||
|
|
@ -73,22 +76,20 @@ public class WaitingOnSerializerTest
|
||||||
return rs -> {
|
return rs -> {
|
||||||
Deps deps = depsGen.next(rs);
|
Deps deps = depsGen.next(rs);
|
||||||
if (deps.isEmpty()) return Command.WaitingOn.EMPTY;
|
if (deps.isEmpty()) return Command.WaitingOn.EMPTY;
|
||||||
int[] selected = Gens.arrays(Gens.ints().between(0, deps.txnIdCount() - 1)).unique().ofSizeBetween(0, deps.txnIdCount() - 1).next(rs);
|
int txnIdCount = deps.rangeDeps.txnIdCount();
|
||||||
SimpleBitSet waitingOnCommit = new SimpleBitSet(deps.txnIdCount(), false);
|
int keyCount = deps.keyDeps.keys().size();
|
||||||
SimpleBitSet waitingOnApply = new SimpleBitSet(deps.txnIdCount(), false);
|
int[] selected = Gens.arrays(Gens.ints().between(0, txnIdCount + keyCount - 1)).unique().ofSizeBetween(0, txnIdCount + keyCount).next(rs);
|
||||||
SimpleBitSet appliedOrInvalidated = new SimpleBitSet(deps.txnIdCount(), false);
|
SimpleBitSet waitingOn = new SimpleBitSet(txnIdCount + keyCount, false);
|
||||||
|
SimpleBitSet appliedOrInvalidated = rs.nextBoolean() ? null : new SimpleBitSet(txnIdCount, false);
|
||||||
for (int i : selected)
|
for (int i : selected)
|
||||||
{
|
{
|
||||||
WaitingOnSets set = sets.next(rs);
|
WaitingOnSets set = appliedOrInvalidated == null || i >= txnIdCount ? WaitingOnSets.APPLY : sets.next(rs);
|
||||||
switch (set)
|
switch (set)
|
||||||
{
|
{
|
||||||
case COMMIT:
|
|
||||||
waitingOnCommit.set(i);
|
|
||||||
break;
|
|
||||||
case APPLY:
|
case APPLY:
|
||||||
waitingOnApply.set(i);
|
waitingOn.set(i);
|
||||||
break;
|
break;
|
||||||
case APPLYED_OR_INVALIDATED:
|
case APPLIED_OR_INVALIDATED:
|
||||||
appliedOrInvalidated.set(i);
|
appliedOrInvalidated.set(i);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
@ -96,7 +97,7 @@ public class WaitingOnSerializerTest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Command.WaitingOn(deps, Utils.ensureImmutable(waitingOnCommit), Utils.ensureImmutable(waitingOnApply), Utils.ensureImmutable(appliedOrInvalidated));
|
return new Command.WaitingOn(deps.keyDeps.keys(), deps.rangeDeps.txnIds(), Utils.ensureImmutable(waitingOn), Utils.ensureImmutable(appliedOrInvalidated));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue