From ac8f2b426ad678b6044e3db6ef6b2614dfed5a90 Mon Sep 17 00:00:00 2001 From: Sylwia Szunejko Date: Mon, 24 Mar 2025 11:38:28 +0100 Subject: [PATCH 1/5] Fix intendentions in SupportedOptionsInitializer.cs --- .../Connections/Control/SupportedOptionsInitializer.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Cassandra/Connections/Control/SupportedOptionsInitializer.cs b/src/Cassandra/Connections/Control/SupportedOptionsInitializer.cs index e857a93d7..b9a77d992 100644 --- a/src/Cassandra/Connections/Control/SupportedOptionsInitializer.cs +++ b/src/Cassandra/Connections/Control/SupportedOptionsInitializer.cs @@ -1,12 +1,12 @@ -// +// // Copyright (C) DataStax Inc. -// +// // Licensed 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. From b1ea452eca4d3b7d6f7bfaf4e304b22b11be1dd9 Mon Sep 17 00:00:00 2001 From: Sylwia Szunejko Date: Mon, 24 Mar 2025 11:38:01 +0100 Subject: [PATCH 2/5] Parse Scylla sharding info from supported message --- .../Control/SupportedOptionsInitializer.cs | 80 ++++++++++++++++++- src/Cassandra/ShardingInfo.cs | 45 +++++++++++ 2 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 src/Cassandra/ShardingInfo.cs diff --git a/src/Cassandra/Connections/Control/SupportedOptionsInitializer.cs b/src/Cassandra/Connections/Control/SupportedOptionsInitializer.cs index b9a77d992..642201b85 100644 --- a/src/Cassandra/Connections/Control/SupportedOptionsInitializer.cs +++ b/src/Cassandra/Connections/Control/SupportedOptionsInitializer.cs @@ -28,6 +28,16 @@ internal class SupportedOptionsInitializer : ISupportedOptionsInitializer private readonly Metadata _metadata; + private const string ScyllaShard = "SCYLLA_SHARD"; + private const string ScyllaNrShards = "SCYLLA_NR_SHARDS"; + private const string ScyllaPartitioner = "SCYLLA_PARTITIONER"; + private const string ScyllaShardingAlgorithm = "SCYLLA_SHARDING_ALGORITHM"; + private const string ScyllaShardingIgnoreMSB = "SCYLLA_SHARDING_IGNORE_MSB"; + private const string ScyllaShardAwarePort = "SCYLLA_SHARD_AWARE_PORT"; + private const string ScyllaShardAwarePortSSL = "SCYLLA_SHARD_AWARE_PORT_SSL"; + + private ShardingInfo _shardingInfo; + public SupportedOptionsInitializer(Metadata metadata) { _metadata = metadata; @@ -49,6 +59,7 @@ public async Task ApplySupportedOptionsAsync(IConnection connection) } ApplyProductTypeOption(supportedResponse.Output.Options); + ApplyScyllaShardingOption(supportedResponse.Output.Options); } private void ApplyProductTypeOption(IDictionary options) @@ -68,5 +79,72 @@ private void ApplyProductTypeOption(IDictionary options) _metadata.SetProductTypeAsDbaas(); } } + + private void ApplyScyllaShardingOption(IDictionary options) + { + if (!options.TryGetValue(SupportedOptionsInitializer.ScyllaShard, out var scyllaShard)) + { + return; + } + if (scyllaShard.Length <= 0) + { + return; + } + + if (!options.TryGetValue(SupportedOptionsInitializer.ScyllaNrShards, out var scyllaNrShards)) + { + return; + } + if (scyllaNrShards.Length <= 0) + { + return; + } + + if (!options.TryGetValue(SupportedOptionsInitializer.ScyllaPartitioner, out var scyllaPartitioner)) + { + return; + } + if (scyllaPartitioner.Length <= 0) + { + return; + } + + if (!options.TryGetValue(SupportedOptionsInitializer.ScyllaShardingAlgorithm, out var scyllaShardingAlgorithm)) + { + return; + } + if (scyllaShardingAlgorithm.Length <= 0) + { + return; + } + + if (!options.TryGetValue(SupportedOptionsInitializer.ScyllaShardingIgnoreMSB, out var scyllaShardingIgnoreMSB)) + { + return; + } + if (scyllaShardingIgnoreMSB.Length <= 0) + { + return; + } + + if (!options.TryGetValue(SupportedOptionsInitializer.ScyllaShardAwarePort, out var scyllaShardAwarePort)) + { + scyllaShardAwarePort = new string[] { "0" }; + } + + if (!options.TryGetValue(SupportedOptionsInitializer.ScyllaShardAwarePortSSL, out var scyllaShardAwarePortSSL)) + { + scyllaShardAwarePortSSL = new string[] { "0" }; + } + + _shardingInfo = ShardingInfo.Create( + scyllaShard[0], + scyllaNrShards[0], + scyllaPartitioner[0], + scyllaShardingAlgorithm[0], + scyllaShardingIgnoreMSB[0], + scyllaShardAwarePort[0], + scyllaShardAwarePortSSL[0]); + } } -} \ No newline at end of file +} diff --git a/src/Cassandra/ShardingInfo.cs b/src/Cassandra/ShardingInfo.cs new file mode 100644 index 000000000..646070b23 --- /dev/null +++ b/src/Cassandra/ShardingInfo.cs @@ -0,0 +1,45 @@ +namespace Cassandra +{ + /// + /// Represents Scylla connection options as sent in SUPPORTED + /// frame. + /// + public class ShardingInfo + { + public int ScyllaShard { get; } + public int ScyllaNrShards { get; } + public string ScyllaPartitioner { get; } + public string ScyllaShardingAlgorithm { get; } + public ulong ScyllaShardingIgnoreMSB { get; } + public ulong ScyllaShardAwarePort { get; } + public ulong ScyllaShardAwarePortSSL { get; } + + private ShardingInfo(int scyllaShard, int scyllaNrShards, string scyllaPartitioner, + string scyllaShardingAlgorithm, ulong scyllaShardingIgnoreMSB, + ulong scyllaShardAwarePort, ulong scyllaShardAwarePortSSL) + { + ScyllaShard = scyllaShard; + ScyllaNrShards = scyllaNrShards; + ScyllaPartitioner = scyllaPartitioner; + ScyllaShardingAlgorithm = scyllaShardingAlgorithm; + ScyllaShardingIgnoreMSB = scyllaShardingIgnoreMSB; + ScyllaShardAwarePort = scyllaShardAwarePort; + ScyllaShardAwarePortSSL = scyllaShardAwarePortSSL; + } + + public static ShardingInfo Create(string scyllaShard, string scyllaNrShards, string scyllaPartitioner, + string scyllaShardingAlgorithm, string scyllaShardingIgnoreMSB, + string scyllaShardAwarePort, string scyllaShardAwarePortSSL) + { + return new ShardingInfo( + int.Parse(scyllaShard), + int.Parse(scyllaNrShards), + scyllaPartitioner, + scyllaShardingAlgorithm, + ulong.Parse(scyllaShardingIgnoreMSB), + ulong.Parse(scyllaShardAwarePort), + ulong.Parse(scyllaShardAwarePortSSL) + ); + } + } +} \ No newline at end of file From 8592d730312d6ec5df3658a19d0689088607918c Mon Sep 17 00:00:00 2001 From: Sylwia Szunejko Date: Thu, 27 Mar 2025 09:04:07 +0100 Subject: [PATCH 3/5] Expose ShardingInfo in SupportedOptionsInitializer --- .../TestHelpers/FakeSupportedOptionsInitializer.cs | 13 +++++++++---- .../Control/ISupportedOptionsInitializer.cs | 9 +++++---- .../Control/SupportedOptionsInitializer.cs | 5 +++++ 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/Cassandra.Tests/Connections/TestHelpers/FakeSupportedOptionsInitializer.cs b/src/Cassandra.Tests/Connections/TestHelpers/FakeSupportedOptionsInitializer.cs index 981118fbc..041fea31f 100644 --- a/src/Cassandra.Tests/Connections/TestHelpers/FakeSupportedOptionsInitializer.cs +++ b/src/Cassandra.Tests/Connections/TestHelpers/FakeSupportedOptionsInitializer.cs @@ -1,12 +1,12 @@ -// +// // Copyright (C) DataStax Inc. -// +// // Licensed 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. @@ -33,5 +33,10 @@ public Task ApplySupportedOptionsAsync(IConnection connection) { return TaskHelper.Completed; } + + public ShardingInfo GetShardingInfo() + { + return null; + } } } \ No newline at end of file diff --git a/src/Cassandra/Connections/Control/ISupportedOptionsInitializer.cs b/src/Cassandra/Connections/Control/ISupportedOptionsInitializer.cs index e06b4533c..f745e80e6 100644 --- a/src/Cassandra/Connections/Control/ISupportedOptionsInitializer.cs +++ b/src/Cassandra/Connections/Control/ISupportedOptionsInitializer.cs @@ -1,12 +1,12 @@ -// +// // Copyright (C) DataStax Inc. -// +// // Licensed 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. @@ -20,5 +20,6 @@ namespace Cassandra.Connections.Control internal interface ISupportedOptionsInitializer { Task ApplySupportedOptionsAsync(IConnection connection); + ShardingInfo GetShardingInfo(); } } \ No newline at end of file diff --git a/src/Cassandra/Connections/Control/SupportedOptionsInitializer.cs b/src/Cassandra/Connections/Control/SupportedOptionsInitializer.cs index 642201b85..644b637b9 100644 --- a/src/Cassandra/Connections/Control/SupportedOptionsInitializer.cs +++ b/src/Cassandra/Connections/Control/SupportedOptionsInitializer.cs @@ -62,6 +62,11 @@ public async Task ApplySupportedOptionsAsync(IConnection connection) ApplyScyllaShardingOption(supportedResponse.Output.Options); } + public ShardingInfo GetShardingInfo() + { + return _shardingInfo; + } + private void ApplyProductTypeOption(IDictionary options) { if (!options.TryGetValue(SupportedOptionsInitializer.SupportedProductTypeKey, out var productTypeOptions)) From 5b2b3ffa1c15ba86d2ea8c50debf3e9969057ff9 Mon Sep 17 00:00:00 2001 From: Sylwia Szunejko Date: Thu, 27 Mar 2025 09:06:20 +0100 Subject: [PATCH 4/5] Add function to check if ControlConnection is shard aware --- src/Cassandra/Connections/Control/ControlConnection.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Cassandra/Connections/Control/ControlConnection.cs b/src/Cassandra/Connections/Control/ControlConnection.cs index 99a4fa86a..f61bc0519 100644 --- a/src/Cassandra/Connections/Control/ControlConnection.cs +++ b/src/Cassandra/Connections/Control/ControlConnection.cs @@ -897,5 +897,14 @@ public Task ScheduleAllKeyspacesRefreshAsync(bool processNow) ? _eventDebouncer.HandleEventAsync(@event, true) : _eventDebouncer.ScheduleEventAsync(@event, false); } + + public bool IsShardAware() + { + if (_supportedOptionsInitializer.GetShardingInfo() == null) + { + return false; + } + return _supportedOptionsInitializer.GetShardingInfo().ScyllaNrShards > 0; + } } } \ No newline at end of file From b9e800f2a09019af89cfd3c6995f9078f889d43d Mon Sep 17 00:00:00 2001 From: Sylwia Szunejko Date: Thu, 27 Mar 2025 09:07:46 +0100 Subject: [PATCH 5/5] Add test to check if cluster is shard aware --- .../ShardAwareOptionsTests.cs | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/Cassandra.IntegrationTests/ShardAwareOptionsTests.cs diff --git a/src/Cassandra.IntegrationTests/ShardAwareOptionsTests.cs b/src/Cassandra.IntegrationTests/ShardAwareOptionsTests.cs new file mode 100644 index 000000000..0d24217d6 --- /dev/null +++ b/src/Cassandra.IntegrationTests/ShardAwareOptionsTests.cs @@ -0,0 +1,35 @@ +using Cassandra.Connections.Control; +using Cassandra.IntegrationTests.TestBase; +using Cassandra.IntegrationTests.TestClusterManagement; +using Cassandra.SessionManagement; +using NUnit.Framework; + +namespace Cassandra.IntegrationTests +{ + [TestFixture] + public class ShardAwareOptionsTests : TestGlobals + { + private ITestCluster _realCluster; + + [TearDown] + public void TestTearDown() + { + TestClusterManager.TryRemove(); + _realCluster = null; + } + + [Test] + public void Should_Connect_To_Shard_Aware_Cluster() + { + _realCluster = TestClusterManager.CreateNew(); + var cluster = ClusterBuilder() + .WithSocketOptions(new SocketOptions().SetReadTimeoutMillis(22000).SetConnectTimeoutMillis(60000)) + .AddContactPoint(_realCluster.InitialContactPoint) + .Build(); + var session = cluster.Connect(); + IInternalCluster internalCluster = cluster; + var controlConnection = (ControlConnection)internalCluster.GetControlConnection(); + Assert.IsTrue(controlConnection.IsShardAware()); + } + } +} \ No newline at end of file