Skip to content

Commit 683b148

Browse files
committed
SSTable-version-based bridge determination (squashed from bridged)
Determines the Cassandra bridge version from the highest SSTable version found on the cluster, making analytics independent of the Cassandra server version. Applied to both bulk writer and reader paths.
1 parent c877942 commit 683b148

47 files changed

Lines changed: 3112 additions & 350 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

analytics-sidecar-client/src/main/java/org/apache/cassandra/sidecar/client/SidecarClient.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,19 @@ public CompletableFuture<GossipInfoResponse> gossipInfo()
244244
return executor.executeRequestAsync(requestBuilder().gossipInfoRequest().build());
245245
}
246246

247+
/**
248+
* Executes the gossip info request using the default retry policy and configured selection policy
249+
*
250+
* @param instance the instance where the request will be executed
251+
* @return a completable future of the gossip info
252+
*/
253+
public CompletableFuture<GossipInfoResponse> gossipInfo(SidecarInstance instance)
254+
{
255+
return executor.executeRequestAsync(requestBuilder().singleInstanceSelectionPolicy(instance)
256+
.gossipInfoRequest()
257+
.build());
258+
}
259+
247260

248261
/**
249262
* Executes the GET gossip health request using the default retry policy and configured selection policy

cassandra-analytics-common/src/main/java/org/apache/cassandra/bridge/BridgeInitializationParameters.java

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,20 @@
2424
*/
2525
public class BridgeInitializationParameters
2626
{
27-
private final String sstableFormat;
27+
private final String configuredSSTableFormat;
2828

29-
public BridgeInitializationParameters(String sstableFormat)
29+
public BridgeInitializationParameters(String configuredSSTableFormat)
3030
{
31-
this.sstableFormat = sstableFormat;
31+
this.configuredSSTableFormat = configuredSSTableFormat;
3232
}
3333

3434
public static BridgeInitializationParameters fromEnvironment()
3535
{
36-
String sstableFormat = CassandraVersion.sstableFormat();
37-
return new BridgeInitializationParameters(sstableFormat);
36+
return new BridgeInitializationParameters(CassandraVersion.configuredSSTableFormat());
3837
}
3938

40-
public String getSstableFormat()
39+
public String getConfiguredSSTableFormat()
4140
{
42-
return sstableFormat;
41+
return configuredSSTableFormat;
4342
}
4443
}

cassandra-analytics-common/src/main/java/org/apache/cassandra/bridge/CassandraVersion.java

Lines changed: 145 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
package org.apache.cassandra.bridge;
2121

2222
import java.util.Arrays;
23+
import java.util.Collections;
2324
import java.util.HashSet;
25+
import java.util.List;
2426
import java.util.Optional;
2527
import java.util.Set;
2628

@@ -45,22 +47,47 @@
4547
*/
4648
public enum CassandraVersion
4749
{
48-
THREEZERO(30, "3.0", "three-zero", "big"),
49-
FOURZERO(40, "4.0", "four-zero", "big"),
50-
FOURONE(41, "4.1", "four-zero", "big"),
51-
FIVEZERO(50, "5.0", "five-zero", "big", "bti");
50+
THREEZERO(30, "3.0", "three-zero", new String[]{"big"},
51+
new String[]{
52+
// Cassandra 3.x native sstable versions
53+
"big-ma",
54+
"big-mb",
55+
"big-mc",
56+
"big-md",
57+
"big-me",
58+
"big-mf"
59+
}),
60+
FOURZERO(40, "4.0", "four-zero", new String[]{"big"},
61+
new String[]{
62+
// Cassandra 4.0 native sstable versions
63+
"big-na",
64+
"big-nb",
65+
}),
66+
FOURONE(41, "4.1", "four-zero", new String[]{"big"},
67+
new String[]{
68+
// Cassandra 4.1 did not introduce new native SSTable versions
69+
}),
70+
FIVEZERO(50, "5.0", "five-zero", new String[]{"big", "bti"},
71+
new String[]{
72+
// Cassandra 5.0 native sstable versions
73+
"big-oa",
74+
"bti-da",
75+
});
5276

5377
private final int number;
5478
private final String name;
5579
private final String jarBaseName; // Must match shadowJar.archiveFileName from Gradle configuration (without extension)
5680
private final Set<String> sstableFormats;
81+
private final List<String> nativeSStableVersions;
5782

58-
CassandraVersion(int number, String name, String jarBaseName, String... sstableFormats)
83+
84+
CassandraVersion(int number, String name, String jarBaseName, String[] sstableFormats, String[] nativeSStableVersions)
5985
{
6086
this.number = number;
6187
this.name = name;
6288
this.jarBaseName = jarBaseName;
6389
this.sstableFormats = new HashSet<>(Arrays.asList(sstableFormats));
90+
this.nativeSStableVersions = List.of(nativeSStableVersions);
6491
}
6592

6693
public int versionNumber()
@@ -78,13 +105,89 @@ public String jarBaseName()
78105
return jarBaseName;
79106
}
80107

81-
private static final String sstableFormat;
108+
/**
109+
* Get the set of SSTable formats supported by this Cassandra version.
110+
*
111+
* @return Set of supported SSTable format strings
112+
*/
113+
public Set<String> sstableFormats()
114+
{
115+
return sstableFormats;
116+
}
117+
118+
/**
119+
* Get the list of native SSTable version strings for this Cassandra version.
120+
*
121+
* @return List of native SSTable version strings
122+
*/
123+
public List<String> getNativeSStableVersions()
124+
{
125+
return nativeSStableVersions;
126+
}
127+
128+
/**
129+
* Get the set of SSTable version strings that this Cassandra version can read.
130+
* This includes:
131+
* - Native versions for this Cassandra version
132+
* - All SSTable versions from the previous major version (including all minor versions)
133+
* For example, Cassandra 5.0 can read:
134+
* - 5.0 native versions (big-oa, bti-da)
135+
* - 4.0 versions (big-na, big-nb)
136+
* - 4.1 versions (if any)
137+
* But NOT 3.0 versions
138+
*
139+
* @return Set of full SSTable version strings that can be read
140+
*/
141+
public Set<String> getSupportedSStableVersionsForRead()
142+
{
143+
Set<String> readableVersions = new HashSet<>(this.nativeSStableVersions);
144+
145+
int previousMajor = getPreviousMajorVersion();
146+
147+
// Add all SSTable versions from the previous major version and its minors
148+
// E.g., C* 5.0 (version 50) can read C* 4.0 (40) and C* 4.1 (41) SSTables, but not C* 3.x (30)
149+
for (CassandraVersion version : CassandraVersion.values())
150+
{
151+
// Include versions from the previous major version family (e.g., 40-49 for C* 5.0)
152+
if (version.versionNumber() >= previousMajor && version.versionNumber() < this.number)
153+
{
154+
readableVersions.addAll(version.nativeSStableVersions);
155+
}
156+
}
157+
158+
return Collections.unmodifiableSet(readableVersions);
159+
}
160+
161+
/**
162+
* Get the previous major version number for this Cassandra version.
163+
* Calculates dynamically using: (majorVersion - 1) * 10
164+
* For example:
165+
* - C5.0 (50) returns 40 (C4.x)
166+
* - C4.1 (41) returns 30 (C3.x)
167+
* - C4.0 (40) returns 30 (C3.x)
168+
* - C3.0 (30) returns 20 (C2.x - which doesn't exist)
169+
* - C10.0 (100) returns 90 (C9.x)
170+
*
171+
* @return previous major version number
172+
*/
173+
@VisibleForTesting
174+
int getPreviousMajorVersion()
175+
{
176+
// Get major version: 50 -> 5, 41 -> 4, 40 -> 4, 30 -> 3
177+
int majorVersion = this.number / 10;
178+
179+
// Calculate previous major version: (majorVersion - 1) * 10
180+
// E.g., 5 -> 40, 4 -> 30, 3 -> 20
181+
return (majorVersion - 1) * 10;
182+
}
183+
184+
private static final String configuredSSTableFormat;
82185
private static final CassandraVersion[] implementedVersions;
83186
private static final String[] supportedVersions;
84187

85188
static
86189
{
87-
sstableFormat = System.getProperty("cassandra.analytics.bridges.sstable_format", "big");
190+
configuredSSTableFormat = System.getProperty("cassandra.analytics.bridges.sstable_format", "big");
88191

89192
// NOTE: These default enum names must stay in sync with cassandraVersionEnumMap in build.gradle.
90193
// FOURONE is intentionally excluded from local-dev defaults to keep iteration fast;
@@ -93,25 +196,25 @@ public String jarBaseName()
93196
String.join(",", FOURZERO.name(), FIVEZERO.name()));
94197
implementedVersions = Arrays.stream(providedVersionsOrDefault.split(","))
95198
.map(CassandraVersion::valueOf)
96-
.filter(v -> v.sstableFormats.contains(sstableFormat))
199+
.filter(v -> v.sstableFormats().contains(configuredSSTableFormat))
97200
.toArray(CassandraVersion[]::new);
98201

99202
// NOTE: These default versions must stay in sync with cassandraFullVersionMap in build.gradle.
100203
String providedSupportedVersionsOrDefault = System.getProperty("cassandra.analytics.bridges.supported_versions",
101204
"cassandra-4.0.17,cassandra-5.0.5");
102205
supportedVersions = Arrays.stream(providedSupportedVersionsOrDefault.split(","))
103206
.filter(version -> CassandraVersion.fromVersion(version)
104-
.filter(v -> v.sstableFormats.contains(sstableFormat))
207+
.filter(v -> v.sstableFormats().contains(configuredSSTableFormat))
105208
.isPresent())
106209
.toArray(String[]::new);
107210

108211
Preconditions.checkArgument(implementedVersions.length > 0 && supportedVersions.length > 0,
109212
"No versions available");
110213
}
111214

112-
public static String sstableFormat()
215+
public static String configuredSSTableFormat()
113216
{
114-
return sstableFormat;
217+
return configuredSSTableFormat;
115218
}
116219

117220
public static Optional<CassandraVersion> fromVersion(String cassandraVersion)
@@ -122,6 +225,37 @@ public static Optional<CassandraVersion> fromVersion(String cassandraVersion)
122225
.findAny();
123226
}
124227

228+
/**
229+
* Find the Cassandra version that originally writes SSTables with this version string.
230+
* Returns the native Cassandra version that introduced this SSTable version.
231+
*
232+
* @param sstableVersion full version string including format (e.g., "big-na", "bti-da")
233+
* @return Optional containing the CassandraVersion that natively writes this format,
234+
* or Optional.empty() if:
235+
* <ul>
236+
* <li>The version string is null</li>
237+
* <li>The version string is unrecognized (not in any enum's nativeSStableVersions)</li>
238+
* <li>The version format is invalid or doesn't match expected pattern</li>
239+
* </ul>
240+
*/
241+
public static Optional<CassandraVersion> fromSSTableVersion(String sstableVersion)
242+
{
243+
if (sstableVersion == null)
244+
{
245+
return Optional.empty();
246+
}
247+
248+
for (CassandraVersion version : CassandraVersion.values())
249+
{
250+
if (version.nativeSStableVersions.contains(sstableVersion))
251+
{
252+
return Optional.of(version);
253+
}
254+
}
255+
256+
return Optional.empty();
257+
}
258+
125259
public static CassandraVersion[] implementedVersions()
126260
{
127261
return implementedVersions;

0 commit comments

Comments
 (0)