Skip to content

CASSANDRA-18519: (CEP-15: (C*) Add notion of CommandsForRanges and make this durable in C*)#46

Closed
dcapwell wants to merge 38 commits intoapache:trunkfrom
dcapwell:CASSANDRA-18519
Closed

CASSANDRA-18519: (CEP-15: (C*) Add notion of CommandsForRanges and make this durable in C*)#46
dcapwell wants to merge 38 commits intoapache:trunkfrom
dcapwell:CASSANDRA-18519

Conversation

@dcapwell
Copy link
Contributor

No description provided.

import static accord.utils.Utils.ensureSortedImmutable;
import static accord.utils.Utils.ensureSortedMutable;

public class CommandTimeseries<D>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just moved this out of CommandsForKeys so that the range logic didn't have to duplicate anything... I just build this time series from the data on-demand

public enum TestTimestamp
{BEFORE, AFTER}

private final Seekable keyOrRange;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this type change is the only real change to this class


package accord.impl;

public interface CommandTimeseriesHolder
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not a fan of the name, so any recommendations welcome =)

}

private <P1> int[] subsetFor(Unseekables<?, ?> select, IndexedPredicate<P1> predicate, P1 param)
private enum OnUnknown { REJECT, IGNORE }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this was actually a hack to make progress...

What I saw was that the local epoch=1, but we saw epoch=2, we try to see if there is overlap and fail as epoch=1 doesn't have the new table range that is defined in epoch=2

I changed C* code to defer exec of messages and PreLoadContext until the epoch they depend on is ready... which may remove the need for this hack...

This likely hasn't been found in burn due to working with a single range, so only would impact new ranges being added and used right away (which happens in C* tests)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It kind of makes sense as a work around for the case you are describing, where is this code that tries to compare different epochs that fails?

It seems like this change is opting everything into the IGNORE behavior?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Went with ignore for all cases as I couldn’t find any caller that allowed the failure. At the dr office so can’t show, it changing default and running AccordCQLTest you hit this right away

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here is the exception

java.lang.IllegalArgumentException: Range not found for TokenKey{keyspace=demo_ks, key=-9079300900759362424}

	at accord.topology.Topology.subsetFor(Topology.java:266)
	at accord.topology.Topology.visitNodeForKeysOnceOrMore(Topology.java:337)
	at accord.topology.TopologyManager.withUnsyncedEpochs(TopologyManager.java:341)
	at accord.topology.TopologyManager.withUnsyncedEpochs(TopologyManager.java:310)
	at accord.coordinate.CoordinatePreAccept.<init>(CoordinatePreAccept.java:129)
	at accord.coordinate.CoordinateTransaction.<init>(CoordinateTransaction.java:49)
	at accord.coordinate.CoordinateTransaction.coordinate(CoordinateTransaction.java:54)
	at accord.local.Node.initiateCoordination(Node.java:447)
	at accord.local.Node.lambda$coordinate$9(Node.java:439)
	at accord.local.Node.withEpoch(Node.java:220)
	at accord.local.Node.coordinate(Node.java:439)

So, the use case is the following

  1. create a new Keyspace w/ table
  2. run a txn over that new table

The org.apache.cassandra.distributed.test.accord.NewSchemaTest test stresses this edge case to make sure the different epochs are supported

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh, interesting consequence of having the table id in the MSB of the key.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in this case, TokenKey is scoped to the keyspace, so a new table in an existing keyspace is fine, but adding a new keyspace and touching it causes this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah right, I was concerned about this because it causes false conflicts across tables in a key space. Discussed it with Benedict and we might want to scope it differently at some point.

import accord.primitives.Ranges;
import accord.primitives.TxnId;

public class RangeUnavailable extends Exhausted
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exhausted could be different things, so this makes it easier to see what happened; what table ranges could not be read?


for (D data : (testTimestamp == TestTimestamp.BEFORE ? commands.headMap(timestamp, false) : commands.tailMap(timestamp, false)).values())
{
TxnId txnId = loader.txnId(data);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed the ordering of this method due to cost to deserialize for CommandsForKeys, idea was to only deserialize what is needed and avoid touching deps until needed

@aweisberg aweisberg self-requested a review May 22, 2023 16:36
Copy link
Contributor

@aweisberg aweisberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing major, some questions. The Topology change is the main thing I need to understand better since it is always opting into IGNORE at the moment.

}

private <P1> int[] subsetFor(Unseekables<?, ?> select, IndexedPredicate<P1> predicate, P1 param)
private enum OnUnknown { REJECT, IGNORE }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It kind of makes sense as a work around for the case you are describing, where is this code that tries to compare different epochs that fails?

It seems like this change is opting everything into the IGNORE behavior?

return construct(cachedRanges.completeAndDiscard(result, count));
}

public Map<Boolean, Ranges> partitioningBy(Predicate<? super Range> test)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved away from the Partition class as this actually is better the more I looked at it... Partition class didn't properly handle this.isEmpty(), but with a map we have a few states

  1. map is empty
  2. map(true)
  3. map(false)
  4. map(true, false)

With this change, we at least have the same signature as Collectors.partitioningBy

Runner.run(nodeCount, new StandardQueue.Factory(randomSource), randomSource::fork, factory, commands);
try
{
Runner.run(nodeCount, new StandardQueue.Factory(randomSource), randomSource::fork, factory, commands);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these tests are not deterministic, so same seed doesn't actually get the same results =(

}

@Override
protected void registerHistoricalTransactions(Deps deps)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved this to safe command store... we can't handle this in CommandStore for C* unless we lazy load the dependencies (which requires #27)

Copy link
Contributor

@aweisberg aweisberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 TY

NodeTimeService time();
CommandStores.RangesForEpoch ranges();
Timestamp maxConflict(Seekables<?, ?> keys, Ranges slice);
void registerHistoricalTransactions(Deps deps);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had intended to keep this to CommandStore to isolate the APIs - SafeCommandStore is for working with Command and SafeCommand whereas CommandStore is for internal book-keeping operations.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry, just saw this after merge...

In order to make the outcome of this method durable, it has to be in the safe store for C*, so felt it was best to move it there as that's were we mutate state normally

case Invalidated:
return true;
default:
return false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer not to use default properties, as it makes it harder to safely modify the state machine in future.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this actually used?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it was, but then deleted in favor of something else; but forgot to purge this

@dcapwell dcapwell closed this May 25, 2023
@dcapwell dcapwell deleted the CASSANDRA-18519 branch May 25, 2023 23:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants