Skip to content

fix(vectordb): share single adapter across account backends to prevent RocksDB lock contention#777

Merged
zhoujh01 merged 1 commit intovolcengine:mainfrom
stakpak:fix/vectordb-lock-contention
Mar 19, 2026
Merged

fix(vectordb): share single adapter across account backends to prevent RocksDB lock contention#777
zhoujh01 merged 1 commit intovolcengine:mainfrom
stakpak:fix/vectordb-lock-contention

Conversation

@ahmedhesham6
Copy link
Contributor

Description

Fix RocksDB lock contention in the local vectordb backend when running in multi-tenant mode. Every call to _get_backend_for_account() or _get_root_backend() was creating a new _SingleAccountBackend with its own PersistStore instance, all pointing to the same on-disk RocksDB directory. Since RocksDB enforces single-process exclusive locking, only the first opener succeeds — all subsequent ones fail with RuntimeError: IO error: lock ... already held by process.

The fix creates the adapter once in VikingVectorIndexBackend.__init__() and passes it as a shared_adapter to every _SingleAccountBackend, eliminating lock contention entirely.

Related Issue

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Refactoring (no functional changes)
  • Performance improvement
  • Test update

Changes Made

  • Create the collection adapter once in VikingVectorIndexBackend.__init__() instead of per-account
  • Add optional shared_adapter parameter to _SingleAccountBackend constructor
  • Pass the shared adapter to every _SingleAccountBackend created by _get_backend_for_account() and _get_root_backend()
  • Preserve backward compatibility: when shared_adapter is not provided, fall back to create_collection_adapter(config)

Testing

  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • I have tested this on the following platforms:
    • Linux
    • macOS
    • Windows

Checklist

  • My code follows the project's coding style
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • Any dependent changes have been merged and published

Screenshots (if applicable)

N/A

Additional Notes

  • No behavioral change for single-account setups or non-local backends (e.g. Qdrant, Weaviate)
  • The shared adapter pattern only applies when VikingVectorIndexBackend manages multiple account backends; standalone _SingleAccountBackend usage is unaffected

…t RocksDB lock contention

## Problem

When using the `local` vectordb backend in multi-tenant mode, every call to
`_get_backend_for_account()` or `_get_root_backend()` creates a new
`_SingleAccountBackend`, which in turn calls `create_collection_adapter(config)`.

For the local backend, each adapter creates its own `PersistStore` instance via
`get_or_create_local_collection()` → `create_store_manager("local", path)` →
`engine.PersistStore(path)`. Since all account backends use the **same storage
path**, multiple `PersistStore` instances attempt to acquire an exclusive RocksDB
lock on the same `LOCK` file at `{path}/store/LOCK`.

The first instance succeeds, but all subsequent instances fail with:

    RuntimeError: IO error: lock /app/data/vectordb/context/store/LOCK:
    already held by process

This makes **all vector operations permanently broken** after the second account
backend is created — search returns zero results, upserts silently fail to
index, and the error floods the logs on every request.

The bug is triggered in any deployment with more than one account or when both
a regular account backend and the root backend are accessed (which happens on
almost every API request).

## Root cause

`VikingVectorIndexBackend` lazily creates per-account `_SingleAccountBackend`
instances. Each one independently calls `create_collection_adapter(config)`,
producing separate `LocalCollectionAdapter` → `PersistStore` instances that all
point to the same on-disk RocksDB directory. RocksDB enforces single-process
exclusive locking, so only the first opener succeeds.

## Fix

Create the adapter **once** in `VikingVectorIndexBackend.__init__()` and pass it
as a `shared_adapter` to every `_SingleAccountBackend`. The adapter (and its
underlying `PersistStore` / RocksDB handle) is reused across all account
backends, eliminating lock contention entirely.

The `_SingleAccountBackend` constructor now accepts an optional `shared_adapter`
parameter. When provided, it uses the shared instance instead of creating a new
one. When not provided (e.g. standalone usage), it falls back to the original
`create_collection_adapter(config)` behavior for backward compatibility.

## Impact

- Fixes permanent vectordb failure in multi-tenant local backend deployments
- Search (`ov find`, `ov search`) now returns results
- Vector upserts during session commit are properly indexed
- Memory extraction vectorization completes successfully
- No behavioral change for single-account setups or non-local backends
@ahmedhesham6 ahmedhesham6 force-pushed the fix/vectordb-lock-contention branch from 81d2101 to 3362766 Compare March 19, 2026 11:43
@CLAassistant
Copy link

CLAassistant commented Mar 19, 2026

CLA assistant check
All committers have signed the CLA.

@zhoujh01 zhoujh01 merged commit 337e51f into volcengine:main Mar 19, 2026
1 check passed
@github-project-automation github-project-automation bot moved this from Backlog to Done in OpenViking project Mar 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants