Skip to content

Conversation

eolivelli
Copy link

@eolivelli eolivelli commented Oct 8, 2025

What is the issue

See https://github.com/riptano/cndb/issues/15619

What does this PR fix and why was it fixed

  • Introduce an callback to get the SAI version to use for a specific keyspace (defaults to cassandra.sai.latest.versison)
  • Introduce a Optional parameter to Version.current() and call it everywhere apart from tests
  • The new code should be "faster" because in many places we used to call current() that in turn reads a volatile variable, now on some hot paths we are using a final field (in IndexContext or other places)

CNDB side implementation: https://github.com/riptano/cndb/issues/15619

Copy link

github-actions bot commented Oct 8, 2025

Checklist before you submit for review

  • This PR adheres to the Definition of Done
  • Make sure there is a PR in the CNDB project updating the Converged Cassandra version
  • Use NoSpamLogger for log lines that may appear frequently in the logs
  • Verify test results on Butler
  • Test coverage for new/modified code is > 80%
  • Proper code formatting
  • Proper title for each commit staring with the project-issue number, like CNDB-1234
  • Each commit has a meaningful description
  • Each commit is not very long and contains related changes
  • Renames, moves and reformatting are in distinct commits
  • All new files should contain the DataStax copyright header instead of the Apache License one

/** Cost to begin processing PKs into index ordinals for estimateAnnSortCost */
// DC introduced the one-to-many ordinal mapping optimization
public final static double ANN_SORT_OPEN_COST = Version.current().onOrAfter(Version.DC) ? 370 : 4200;
public final static double ANN_SORT_OPEN_COST = Version.current().onOrAfter(Version.DC) ? 370 : 4200; // it's okay to make this depending on the main SAI version

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eolivelli why is this ok?

Copy link
Author

@eolivelli eolivelli Oct 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is okay because in production we use 'EC' or 'AA' everywhere

where we use 'AA' there is no vector search
so ALL the production clusters that support vector search use 'EC' or later
we can remove this check and make it a fixed constant

Copy link
Member

@JeremiahDJordan JeremiahDJordan Oct 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can’t let keyspaces on AA use ORDER BY.
is this just Ann order by or also the generic one?
If this is just for ANN then it’s ok. The base will be EC and we won’t let people make a vector index to attempt ANN if their keyspace doesn’t support EC.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having a quick look, it seems that this and the following ANN_SORT_KEY_COST definitions are the only places (outside of tests) that use Version.current() (the version without a keyspace).

I strongly suggest we fix this, remove Version.current() and have the version selection take String instead of Optional<String>. IMO, the concept of a "main" SAI version is confusing and is dangerous (makes it way too easy to rely on the default with debatable justification), so we should eliminate if it's not strictly needed (and it doesn't seem it is).

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback. I have removed Version.current() and Version.CURRENT, so Version.current(String) is the only door. VersionSelector is moved to Version.Selector, which doesn't have an optional keyspace argument anymore.

@adelapena adelapena changed the title CNDB-15619: Allow to customize SAI format to write and to consider as current() depending on a keyspace [WIP] CNDB-15619: Allow to customize SAI format to write and to consider as current() depending on a keyspace Oct 10, 2025
@adelapena adelapena marked this pull request as ready for review October 10, 2025 12:36
@adelapena
Copy link

Setting as ready to review so CI runs on push, and added [WIP] (work in progress) to the title.

Preconditions.checkArgument(!sealed, "Should not add components for SSTable %s at this point; the completion marker has already been written", descriptor);
// When a sstable doesn't have any complete group, we use a marker empty one with a generation of -1:
Preconditions.checkArgument(buildId != EMPTY_GROUP_MARKER, "Should not be adding component to empty components");
// TODO....
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't find a good way to implement this assertion, maybe we can remove the commented code ?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added back the checks using a memoized instance of the empty group marker for the version.

@adelapena adelapena changed the title [WIP] CNDB-15619: Allow to customize SAI format to write and to consider as current() depending on a keyspace CNDB-15619: Allow to customize SAI format to write and to consider as current() depending on a keyspace Oct 14, 2025
Copy link

@pcmanus pcmanus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple of very minor nits, but lgtm otherwise.

IndexComponentsImpl components;
if (buildId == null)
{
Version version = context == null ? Version.current(descriptor.ksname) : context.version();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That line is dead code/unused.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed.

});
}

@Override
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the goal of adding that override? The default implementation in IndexComponents already returns buildId().version(), so it seems this override returns the same thing is isn't necessary. Obviously not a big deal even if unnecessary but ...

var indexWriter = new OnDiskGraphIndexWriter.Builder(builder.getGraph(), indexFile.toPath())
.withStartOffset(termsOffset)
.withVersion(Version.current().onDiskFormat().jvectorFileFormatVersion())
.withVersion(perIndexComponents.context().version().onDiskFormat().jvectorFileFormatVersion())
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: the .context() part can be removed (at least for consistency with other calls in this file :)).

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, removed.

CassandraOnHeapGraph.writePqHeader(pqOutput.asSequentialWriter(), unitVectors, VectorCompression.CompressionType.PRODUCT_QUANTIZATION);
compressedVectors.write(pqOutput.asSequentialWriter(), Version.current().onDiskFormat().jvectorFileFormatVersion());
CassandraOnHeapGraph.writePqHeader(pqOutput.asSequentialWriter(), unitVectors, VectorCompression.CompressionType.PRODUCT_QUANTIZATION, perIndexComponents.version());
compressedVectors.write(pqOutput.asSequentialWriter(), context.version().onDiskFormat().jvectorFileFormatVersion());
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: we use perIndexComponents.version() the line above, and context.version() here. It's obviously not a big deal since the value is always going to be the same, but that also feel a tad confusing for people not as familiar with the code, that on seeing it done differently may expect those 2 things aren't the same. Tl;dr, I think it's worth being consistent to facilitate future readers.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, I have put the context's version in a local var and used it on all the calls.

@adelapena
Copy link

Thanks for the review. I think I've addressed all the suggestions. Now I'll rebase and squash, and start working on a port to cndb-main-release-202505.

… current() depending on a keyspace

There is a new cassandra.sai.version.selector.class system property allowing
to provide an implementation of the o.a.c.index.sai.disk.format.Version.Selector
interface to specify that version of the SAI on-disk index format should be
used for each keyspace.
@adelapena adelapena force-pushed the cndb-15619-sai-per-tenant branch from be59b99 to 8eba026 Compare October 15, 2025 10:52
Copy link

@cassci-bot
Copy link

❌ Build ds-cassandra-pr-gate/PR-2041 rejected by Butler


1 regressions found
See build details here


Found 1 new test failures

Test Explanation Runs Upstream
o.a.c.index.sai.cql.VectorKeyRestrictedOnPartitionTest.partitionRestrictedWidePartitionBqCompressedTest[eb] (compression) REGRESSION 🔵🔴 0 / 10

No known test failures found

@adelapena
Copy link

The occasional failure of VectorKeyRestrictedOnPartitionTest.partitionRestrictedWidePartitionBqCompressedTest seems due to a recall slightly worse than the expected 10%, similar to https://github.com/riptano/cndb/issues/12778, so likely not caused by the changes. I haven't been able to reproduce it locally.

@adelapena adelapena merged commit 82064a0 into main Oct 16, 2025
497 of 498 checks passed
@adelapena adelapena deleted the cndb-15619-sai-per-tenant branch October 16, 2025 16:50
adelapena added a commit that referenced this pull request Oct 16, 2025
… current() depending on a keyspace (#2064)

There is a new cassandra.sai.version.selector.class system property allowing
to provide an implementation of the o.a.c.index.sai.disk.format.Version.Selector
interface to specify that version of the SAI on-disk index format should be
used for each keyspace.

This is a cherry-pick of #2041

Co-authored-by: Enrico Olivelli <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants