[ 
https://issues.apache.org/jira/browse/CASSANDRA-17103?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17573987#comment-17573987
 ] 

David Capwell edited comment on CASSANDRA-17103 at 8/2/22 1:44 AM:
-------------------------------------------------------------------

I think accord.topology.TopologyManager#forKeys(accord.txn.Keys, long) also 
produces the wrong results under some conditions; setup:

* RF=1 (this is 100% just to trick accord to touch multiple ranges/shards)
* use org.apache.cassandra.dht.Murmur3Partitioner.LongToken#keyForToken to 
generate a key that maps perfectly to the token for each instance
* touch each key

In the test above, we should have a min of 2 splits (possible 3rd to account 
for wrapped ranges), but it actually only has 1!  I see that the call to 
accord.topology.Topology#forKeys(accord.txn.Keys) returns a single shard even 
though there are 2 keys that map to 2 different shards!

The transaction doesn't fail I think because we don't block read/write to 
out-of-bound ranges

Test

{code}
@Test
    public void multipleShards() throws Throwable
    {
        String keyspace = "ks" + System.currentTimeMillis();

        try (Cluster cluster = init(Cluster.build(2).start()))
        {
            cluster.schemaChange("CREATE KEYSPACE " + keyspace + " WITH 
REPLICATION={'class':'SimpleStrategy', 'replication_factor': 1}");
            cluster.schemaChange("CREATE TABLE " + keyspace + ".tbl (k blob, c 
int, v int, primary key (k, c))");
            cluster.forEach(node -> node.runOnInstance(() -> 
AccordService.instance.createEpochFromConfigUnsafe()));

            cluster.forEach(node -> node.runOnInstance(() -> 
AccordService.instance.setCacheSize(0)));
            List<String> tokens = cluster.stream()
                                         .flatMap(i -> 
StreamSupport.stream(Splitter.on(",").split(i.config().getString("initial_token")).spliterator(),
 false))
                                         .collect(Collectors.toList());
            List<byte[]> keys = tokens.stream().map(t -> 
(Murmur3Partitioner.LongToken) 
Murmur3Partitioner.instance.getTokenFactory().fromString(t))
                                      
.map(Murmur3Partitioner.LongToken::keyForToken)
                                      .map(ByteBufferUtil::getArray)
                                      .collect(Collectors.toList());

            cluster.get(1).runOnInstance(() -> {
                AccordTxnBuilder txn = txn();
                for (byte[] data : keys)
                {
                    ByteBuffer key = ByteBuffer.wrap(data);
                    txn = txn.withRead("SELECT * FROM " + keyspace + ".tbl 
WHERE k=? and c=0", key)
                          .withWrite("INSERT INTO " + keyspace + ".tbl (k, c, 
v) VALUES (?, 0, 0)", key)
                          .withCondition(keyspace, "tbl", key, 0, NOT_EXISTS);
                }
                execute(txn);
            });
        }
    }
{code}


I wrote this test to hit a condition in 
accord.coordinate.tracking.ReadTracker#computeMinimalReadSetAndMarkInflight 
that I thought was odd.  

{code}
this.forEachTrackerForNode(node, (tracker, ignore) -> {
                    toRead.remove(tracker);
                });
{code}

If we do for-each tracker then won't this clear toRead?  I wanted to run 
through a debugger to confirm but got hit by the fact that the Topology only 
had a single Shard


was (Author: dcapwell):
I think accord.topology.TopologyManager#forKeys(accord.txn.Keys, long) also 
produces the wrong results under some conditions; setup:

* RF=1 (this is 100% just to trick accord to touch multiple ranges)
* use org.apache.cassandra.dht.Murmur3Partitioner.LongToken#keyForToken to 
generate a key that maps perfectly to the token for each instance
* touch each key

In the test above, we should have a min of 2 splits (possible 3rd to account 
for wrapped ranges), but it actually only has 1!  I see that the call to 
accord.topology.Topology#forKeys(accord.txn.Keys) returns a single shard even 
though there are 2 keys that map to 2 different shards!

The transaction doesn't fail I think because we don't block read/write to 
out-of-bound ranges

Test

{code}
@Test
    public void multipleShards() throws Throwable
    {
        String keyspace = "ks" + System.currentTimeMillis();

        try (Cluster cluster = init(Cluster.build(2).start()))
        {
            cluster.schemaChange("CREATE KEYSPACE " + keyspace + " WITH 
REPLICATION={'class':'SimpleStrategy', 'replication_factor': 1}");
            cluster.schemaChange("CREATE TABLE " + keyspace + ".tbl (k blob, c 
int, v int, primary key (k, c))");
            cluster.forEach(node -> node.runOnInstance(() -> 
AccordService.instance.createEpochFromConfigUnsafe()));

            cluster.forEach(node -> node.runOnInstance(() -> 
AccordService.instance.setCacheSize(0)));
            List<String> tokens = cluster.stream()
                                         .flatMap(i -> 
StreamSupport.stream(Splitter.on(",").split(i.config().getString("initial_token")).spliterator(),
 false))
                                         .collect(Collectors.toList());
            List<byte[]> keys = tokens.stream().map(t -> 
(Murmur3Partitioner.LongToken) 
Murmur3Partitioner.instance.getTokenFactory().fromString(t))
                                      
.map(Murmur3Partitioner.LongToken::keyForToken)
                                      .map(ByteBufferUtil::getArray)
                                      .collect(Collectors.toList());

            cluster.get(1).runOnInstance(() -> {
                AccordTxnBuilder txn = txn();
                for (byte[] data : keys)
                {
                    ByteBuffer key = ByteBuffer.wrap(data);
                    txn = txn.withRead("SELECT * FROM " + keyspace + ".tbl 
WHERE k=? and c=0", key)
                          .withWrite("INSERT INTO " + keyspace + ".tbl (k, c, 
v) VALUES (?, 0, 0)", key)
                          .withCondition(keyspace, "tbl", key, 0, NOT_EXISTS);
                }
                execute(txn);
            });
        }
    }
{code}


I wrote this test to hit a condition in 
accord.coordinate.tracking.ReadTracker#computeMinimalReadSetAndMarkInflight 
that I thought was odd.  

{code}
this.forEachTrackerForNode(node, (tracker, ignore) -> {
                    toRead.remove(tracker);
                });
{code}

If we do for-each tracker then won't this clear toRead?  I wanted to run 
through a debugger to confirm but got hit by the fact that the Topology only 
had a single Shard

> CEP-15 (C*): Messaging and storage engine integration
> -----------------------------------------------------
>
>                 Key: CASSANDRA-17103
>                 URL: https://issues.apache.org/jira/browse/CASSANDRA-17103
>             Project: Cassandra
>          Issue Type: New Feature
>          Components: Accord
>            Reporter: Benedict Elliott Smith
>            Priority: Normal
>
> This work encompasses implementing Accord’s storage and networking interfaces 
> within Cassandra, so that messages may be sent around the cluster and 
> exectuted



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org
For additional commands, e-mail: commits-h...@cassandra.apache.org

Reply via email to