|
53 | 53 | import accord.topology.TopologyException; |
54 | 54 |
|
55 | 55 | import org.apache.cassandra.config.Config.PaxosVariant; |
| 56 | +import org.apache.cassandra.config.DatabaseDescriptor; |
56 | 57 | import org.apache.cassandra.cql3.CQLTester; |
| 58 | +import org.apache.cassandra.cql3.QueryProcessor; |
| 59 | +import org.apache.cassandra.cql3.UntypedResultSet; |
57 | 60 | import org.apache.cassandra.cql3.ast.AssignmentOperator; |
58 | 61 | import org.apache.cassandra.cql3.ast.Literal; |
59 | 62 | import org.apache.cassandra.cql3.ast.Mutation; |
|
64 | 67 | import org.apache.cassandra.cql3.ast.Txn; |
65 | 68 | import org.apache.cassandra.cql3.functions.types.utils.Bytes; |
66 | 69 | import org.apache.cassandra.cql3.statements.TransactionStatement; |
| 70 | +import org.apache.cassandra.db.SystemKeyspace; |
| 71 | +import org.apache.cassandra.db.marshal.BytesType; |
67 | 72 | import org.apache.cassandra.db.marshal.Int32Type; |
68 | 73 | import org.apache.cassandra.db.marshal.ListType; |
69 | 74 | import org.apache.cassandra.db.marshal.MapType; |
|
79 | 84 | import org.apache.cassandra.distributed.test.sai.SAIUtil; |
80 | 85 | import org.apache.cassandra.distributed.util.QueryResultUtil; |
81 | 86 | import org.apache.cassandra.exceptions.InvalidRequestException; |
| 87 | +import org.apache.cassandra.exceptions.WriteTimeoutException; |
| 88 | +import org.apache.cassandra.io.util.DataInputBuffer; |
| 89 | +import org.apache.cassandra.schema.SchemaConstants; |
82 | 90 | import org.apache.cassandra.service.accord.AccordService; |
83 | 91 | import org.apache.cassandra.service.accord.AccordTestUtils; |
84 | 92 | import org.apache.cassandra.service.consensus.TransactionalMode; |
@@ -418,6 +426,81 @@ public void testPartitionMultiRowReturn() throws Exception |
418 | 426 | }); |
419 | 427 | } |
420 | 428 |
|
| 429 | + @Test |
| 430 | + public void testSinglePartitionKeyBatch() throws Throwable |
| 431 | + { |
| 432 | + String KEYSPACE = "ks" + System.currentTimeMillis(); |
| 433 | + List<String> ddls = Arrays.asList("DROP KEYSPACE IF EXISTS " + KEYSPACE + ';', |
| 434 | + "CREATE KEYSPACE " + KEYSPACE + " WITH REPLICATION={'class':'SimpleStrategy', 'replication_factor': 2}", |
| 435 | + "CREATE TABLE " + qualifiedAccordTableName + " (k int PRIMARY KEY, v int) WITH " + transactionalMode.asCqlParam(), |
| 436 | + "CREATE TABLE " + qualifiedRegularTableName + " (k int PRIMARY KEY, v int)"); |
| 437 | + |
| 438 | + test(ddls, cluster -> { |
| 439 | + cluster.coordinator(1).execute("BEGIN BATCH\n" + |
| 440 | + "INSERT INTO " + qualifiedAccordTableName + " (k, v) VALUES (1, 2);\n" + |
| 441 | + "INSERT INTO " + qualifiedRegularTableName + " (k, v) VALUES (1, 3);\n" + |
| 442 | + "APPLY BATCH;", ConsistencyLevel.ONE); |
| 443 | + |
| 444 | + SimpleQueryResult r1 = cluster.coordinator(1).executeWithResult("SELECT * FROM " + qualifiedAccordTableName + " WHERE k = 1", ConsistencyLevel.ONE); |
| 445 | + SimpleQueryResult r2 = cluster.coordinator(1).executeWithResult("SELECT * FROM " + qualifiedRegularTableName + " WHERE k = 1", ConsistencyLevel.ONE); |
| 446 | + |
| 447 | + assertEquals(1, r1.toObjectArrays().length); |
| 448 | + assertEquals(1, r2.toObjectArrays().length); |
| 449 | + }); |
| 450 | + } |
| 451 | + |
| 452 | + @Test |
| 453 | + public void testSinglePartitionKeyBatchWrittenToBatchLog() throws Throwable |
| 454 | + { |
| 455 | + String KEYSPACE = "ks" + System.currentTimeMillis(); |
| 456 | + DatabaseDescriptor.daemonInitialization(); |
| 457 | + List<String> ddls = Arrays.asList("DROP KEYSPACE IF EXISTS " + KEYSPACE + ';', |
| 458 | + "CREATE KEYSPACE " + KEYSPACE + " WITH REPLICATION={'class':'SimpleStrategy', 'replication_factor': 2}", |
| 459 | + "CREATE TABLE " + qualifiedAccordTableName + " (k int PRIMARY KEY, v int) WITH " + transactionalMode.asCqlParam(), |
| 460 | + "CREATE TABLE " + qualifiedRegularTableName + " (k int PRIMARY KEY, v int)"); |
| 461 | + |
| 462 | + test(ddls, cluster -> { |
| 463 | + pauseHints(); |
| 464 | + blockMutationAndPreAccept(cluster); |
| 465 | + try |
| 466 | + { |
| 467 | + cluster.coordinator(1).execute("BEGIN BATCH\n" + |
| 468 | + "INSERT INTO " + qualifiedAccordTableName + " (k, v) VALUES (1, 2);\n" + |
| 469 | + "INSERT INTO " + qualifiedRegularTableName + " (k, v) VALUES (1, 3);\n" + |
| 470 | + "APPLY BATCH;", ConsistencyLevel.ALL); |
| 471 | + fail("Should have thrown WTE"); |
| 472 | + } |
| 473 | + catch (Throwable t) |
| 474 | + { |
| 475 | + assertEquals(t.getClass().getName(), WriteTimeoutException.class.getName()); |
| 476 | + } |
| 477 | + |
| 478 | + if (transactionalMode.nonSerialWritesThroughAccord) |
| 479 | + cluster.get(1).runOnInstance(() -> { |
| 480 | + String query = String.format("SELECT id, mutations, version FROM %s.%s", |
| 481 | + SchemaConstants.SYSTEM_KEYSPACE_NAME, |
| 482 | + SystemKeyspace.BATCHES); |
| 483 | + |
| 484 | + Iterator<UntypedResultSet.Row> r = QueryProcessor.executeInternal(query).iterator(); |
| 485 | + assertTrue(r.hasNext()); |
| 486 | + UntypedResultSet.Row row = r.next(); |
| 487 | + |
| 488 | + int version = row.getInt("version"); |
| 489 | + List<ByteBuffer> serializedMutations = row.getList("mutations", BytesType.instance); |
| 490 | + assertEquals(1, serializedMutations.size()); |
| 491 | + |
| 492 | + try (DataInputBuffer in = new DataInputBuffer(serializedMutations.get(0), true)) |
| 493 | + { |
| 494 | + assertEquals(2, org.apache.cassandra.db.Mutation.serializer.deserialize(in, version).getPartitionUpdates().size()); |
| 495 | + } |
| 496 | + catch (Exception e) |
| 497 | + { |
| 498 | + fail("Deserialization failed"); |
| 499 | + } |
| 500 | + }); |
| 501 | + }); |
| 502 | + } |
| 503 | + |
421 | 504 | @Test |
422 | 505 | public void testSaiMultiRowReturn() throws Exception |
423 | 506 | { |
|
0 commit comments