Skip to content

Conversation

@razdoburdin
Copy link
Contributor

@razdoburdin razdoburdin commented Dec 16, 2025

This PR adds ability to set custom index blocksize
Reopening of #235

The new parameter structure for build method of DynamicVamanaIndex and DynamicVamanaIndexLeanVec is introduced.
Example of building a LeanVec index with block_size = 2^12

svs::runtime::v0::DynamicVamanaIndex* index = nullptr;
svs::runtime::v0::VamanaIndex::BuildParams build_params{64};
svs::runtime::v0::VamanaIndex::DynamicIndexParams dynamic_index_params{12};
svs::runtime::v0::Status status = svs::runtime::v0::DynamicVamanaIndexLeanVec::build(
    &index,
    test_d,
    svs::runtime::v0::MetricType::L2,
    svs::runtime::v0::StorageKind::LeanVec4x4,
    32,
    build_params,
    {},
    dynamic_index_params
);

@rfsaliev
Copy link
Member

Hi!
Thank you for the PR.
Looks good but I see some issues:

  • Extra dependencies on SVS internal headers (svs/lib/...) added to the runtime API in index_blocksize.h - I would avoid such dependencies by replacing:
    • usage svs::lib::PowerOfTwo with just a size_t BlockSizeExponent(); and size_t BlockSizeBytes() const { return 1 << blocksize_exp_; }
    • replace IndexBlockSize .ctor with a static factory method e.g. static Status IndexBlockSize::make(size_t blocksize_exp) noexcept; - as it was made to other runtime API classes.
  • The DynamicVamanaIndex::add(..., IndexBlockSize); method has unclear semantic, because blocksize argument can be applied at the first call only, but not at subsequential calls.

Instead I would propose to setup block size in a build() method:

  • One of solutions can be blocksize field in VamanaIndex::BuildParams - but it seems block size makes no sense in non-dynamic indices.
  • Another option: define a dedicated structure with parameters for dynamic indices: e.g. blocksize, reuse_empty_slots, etc.

Copy link
Member

@rfsaliev rfsaliev left a comment

Choose a reason for hiding this comment

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

Please also read my standalone comment to the PR as well.

@razdoburdin
Copy link
Contributor Author

Thanks for comments.

I have modified the PR, according to your request:

  1. I have added a new structure VamanaIndex::DynamicIndexParams, being passed to build() constructor. It contains the only field blocksize_exp now, but it can be expanded.
  2. In this case the dedicated IndexBlockSize is no longer needed, so I have removed it. The DynamicVamanaIndex class is no responsible for checking the validity of input parameters by calling check_params method.

Copy link
Member

@rfsaliev rfsaliev left a comment

Choose a reason for hiding this comment

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

LGFM
just few comments/suggestions

@ahuber21
Copy link
Contributor

ahuber21 commented Jan 7, 2026

@razdoburdin could you give an example how this is used in a comment or the PR description?

@razdoburdin
Copy link
Contributor Author

@razdoburdin could you give an example how this is used in a comment or the PR description?

I have updated the PR description

@razdoburdin
Copy link
Contributor Author

@rfsaliev @ahuber21 , faiss_tests linking is failed with this PR, due to changes of DynamicVamanaIndex::build arguments. What to you think would be proper fix for this issue ?

@ahuber21
Copy link
Contributor

@razdoburdin it makes sense, the missing symbol is

svs::runtime::v0::DynamicVamanaIndex::build(svs::runtime::v0::DynamicVamanaIndex**, unsigned long, svs::runtime::v0::MetricType, svs::runtime::v0::StorageKind, svs::runtime::v0::VamanaIndex::BuildParams const&, svs::runtime::v0::VamanaIndex::SearchParams const&)

This is the function you modified and added a new parameter. It has a default value, but I guess for ABI compatibility it is required to do this instead

    static Status build(
        DynamicVamanaIndex** index,
        size_t dim,
        MetricType metric,
        StorageKind storage_kind,
        const VamanaIndex::BuildParams& params = {},
        const VamanaIndex::SearchParams& default_search_params = {},
        const VamanaIndex::DynamicIndexParams& dynamic_index_params = {}
    ) noexcept;

    static Status build(
        DynamicVamanaIndex** index,
        size_t dim,
        MetricType metric,
        StorageKind storage_kind,
        const VamanaIndex::BuildParams& params = {},
        const VamanaIndex::SearchParams& default_search_params = {}
    ) noexcept {
        build(index, dim, metric, storage_kind, params, default_search_params, {});
    }

@razdoburdin
Copy link
Contributor Author

@razdoburdin it makes sense, the missing symbol is

svs::runtime::v0::DynamicVamanaIndex::build(svs::runtime::v0::DynamicVamanaIndex**, unsigned long, svs::runtime::v0::MetricType, svs::runtime::v0::StorageKind, svs::runtime::v0::VamanaIndex::BuildParams const&, svs::runtime::v0::VamanaIndex::SearchParams const&)

This is the function you modified and added a new parameter. It has a default value, but I guess for ABI compatibility it is required to do this instead

    static Status build(
        DynamicVamanaIndex** index,
        size_t dim,
        MetricType metric,
        StorageKind storage_kind,
        const VamanaIndex::BuildParams& params = {},
        const VamanaIndex::SearchParams& default_search_params = {},
        const VamanaIndex::DynamicIndexParams& dynamic_index_params = {}
    ) noexcept;

    static Status build(
        DynamicVamanaIndex** index,
        size_t dim,
        MetricType metric,
        StorageKind storage_kind,
        const VamanaIndex::BuildParams& params = {},
        const VamanaIndex::SearchParams& default_search_params = {}
    ) noexcept {
        build(index, dim, metric, storage_kind, params, default_search_params, {});
    }

but the code with this overload wouldn't compile :(
if we have a call build(index, dim, metric, storage_kind) the compiler can't decide which overload to use.

@ahuber21
Copy link
Contributor

Right, we'd have to remove the default arguments and replicate the original ABI.
Actually, I think this wouldn't be a nice solution. Maybe we have to consider incrementing the API version ... @rfsaliev do you have an opinion?

@rfsaliev
Copy link
Member

rfsaliev commented Jan 19, 2026

Right, we'd have to remove the default arguments and replicate the original ABI. Actually, I think this wouldn't be a nice solution. Maybe we have to consider incrementing the API version ... @rfsaliev do you have an opinion?

As a workaround, for ABI compatibility I would declare:

    static Status build(
        DynamicVamanaIndex** index,
        size_t dim,
        MetricType metric,
        StorageKind storage_kind,
        const VamanaIndex::BuildParams& params = {},
        const VamanaIndex::SearchParams& default_search_params = {}
    ) noexcept;

    static Status build(
        DynamicVamanaIndex** index,
        size_t dim,
        MetricType metric,
        StorageKind storage_kind,
        const VamanaIndex::BuildParams& params,
        const VamanaIndex::SearchParams& default_search_params,
        const VamanaIndex::DynamicIndexParams& dynamic_index_params
    ) noexcept;

The first declaration is for ABI compatibility.
When the second is fully explicit for new functionality.

Implementation code should look like:

// ABI backward compatibility
static Status build(
    DynamicVamanaIndex** index,
    size_t dim,
    MetricType metric,
    StorageKind storage_kind,
    const VamanaIndex::BuildParams& params,
    const VamanaIndex::SearchParams& default_search_params
) noexcept {
    build(index, dim, metric, storage_kind, params, default_search_params, VamanaIndex::DynamicIndexParams{});
}

// Real implementation with new parameter
static Status build(
    DynamicVamanaIndex** index,
    size_t dim,
    MetricType metric,
    StorageKind storage_kind,
    const VamanaIndex::BuildParams& params,
    const VamanaIndex::SearchParams& default_search_params,
    const VamanaIndex::DynamicIndexParams& dynamic_index_params
) noexcept {
// Full implementation
}

Copy link
Member

@rfsaliev rfsaliev left a comment

Choose a reason for hiding this comment

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

LGFM

Dmitry Razdoburdin added 2 commits January 20, 2026 03:40
Copy link
Contributor

@ahuber21 ahuber21 left a comment

Choose a reason for hiding this comment

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

LGTM. Follow-up request: Could you please experiment with rss_increase in runtime_test.cpp? The function rss_threshold() accepts a parameter allocator_block_size. Could you add new test cases where you have a small blocksize value and see if the tests still pass? And then please add them in a new PR.

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.

3 participants