Fix PartitionUpdate.isEmpty deserialization issue to avoid potential EOFException

Patch by marcuse; reviewed by Sam Tunnicliffe for CASSANDRA-20345
This commit is contained in:
Marcus Eriksson 2025-03-03 08:41:34 +01:00
parent 417bb21d2e
commit 369daf56bc
4 changed files with 38 additions and 3 deletions

View File

@ -1,4 +1,5 @@
5.1
* Fix PartitionUpdate.isEmpty deserialization issue to avoid potential EOFException (CASSANDRA-20345)
* Avoid adding LEFT nodes to tokenMap on upgrade from gossip (CASSANDRA-20344)
* Allow empty placements when deserializing cluster metadata (CASSANDRA-20343)
* Reduce heap pressure when initializing CMS (CASSANDRA-20267)

View File

@ -800,7 +800,7 @@ public class PartitionUpdate extends AbstractBTreePartition
if (version >= MessagingService.VERSION_51)
{
long epoch = VIntCoding.getUnsignedVInt(in, position);
position += VIntCoding.computeVIntSize(epoch);
position += VIntCoding.computeUnsignedVIntSize(epoch);
}
// DecoratedKey key = metadata.decorateKey(ByteBufferUtil.readWithVIntLength(in));

View File

@ -74,6 +74,7 @@ import org.apache.cassandra.tcm.ClusterMetadata;
import org.apache.cassandra.tcm.ClusterMetadataService;
import org.apache.cassandra.tcm.membership.Directory;
import org.apache.cassandra.tcm.membership.NodeVersion;
import org.apache.cassandra.tcm.transformations.CustomTransformation;
import org.apache.cassandra.tcm.transformations.ForceSnapshot;
import org.apache.cassandra.utils.*;
@ -271,6 +272,38 @@ public class PaxosRepairTest extends TestBaseImpl
}
}
@Test
public void epochBadDeserializationTest() throws Throwable
{
try (Cluster cluster = init(Cluster.build(3).withConfig(WITH_NETWORK).withoutVNodes().start()))
{
cluster.schemaChange("CREATE TABLE " + KEYSPACE + '.' + TABLE + " (pk text primary key, v int)");
cluster.get(1).runOnInstance(() -> {
// just execute transformations to get epoch bumped enough for the bug to occur
for (int i = 0; i < 75; i++)
ClusterMetadataService.instance().commit(CustomTransformation.make("x"+i));
});
// and bump the epoch in the tablemetadata:
cluster.schemaChange("ALTER TABLE " + KEYSPACE + '.' + TABLE + " WITH comment='abc'");
cluster.verbs(PAXOS_COMMIT_REQ).drop();
try
{
cluster.coordinator(1).execute("INSERT INTO " + KEYSPACE + '.' + TABLE + " (pk, v) VALUES ('xyzxyzxyzxyzxyzxyzxyzxyz', 1) IF NOT EXISTS", ConsistencyLevel.QUORUM);
Assert.fail("expected write timeout");
}
catch (RuntimeException e)
{
// exception expected
}
cluster.filters().reset();
cluster.get(1).shutdown().get();
cluster.get(1).startup();
}
}
@Ignore
@Test
public void topologyChangePaxosTest() throws Throwable

View File

@ -43,6 +43,7 @@ import org.apache.cassandra.schema.TableId;
import org.apache.cassandra.schema.TableMetadata;
import org.apache.cassandra.service.paxos.Ballot;
import org.apache.cassandra.service.paxos.Commit;
import org.apache.cassandra.tcm.Epoch;
import org.apache.cassandra.utils.ByteBufferUtil;
import org.apache.cassandra.utils.CloseableIterator;
import org.apache.cassandra.utils.FBUtilities;
@ -96,7 +97,7 @@ public class PaxosRowsTest
SchemaLoader.prepareServer();
ks = "coordinatorsessiontest";
metadata = CreateTableStatement.parse("CREATE TABLE tbl (k INT PRIMARY KEY, v INT)", ks).build();
metadata = CreateTableStatement.parse("CREATE TABLE tbl (k INT PRIMARY KEY, v INT)", ks).epoch(Epoch.create(100)).build();
tableId = metadata.id;
}
@ -109,7 +110,7 @@ public class PaxosRowsTest
@Test
public void testRowInterpretation()
{
DecoratedKey key = dk(5);
DecoratedKey key = dk(Integer.MAX_VALUE);
Ballot[] ballots = createBallots(3);
SystemKeyspace.savePaxosWritePromise(key, metadata, ballots[0]);