Skip to content

feat: Milestone 1 - added replication plumbing, tests and shared helpers#332

Open
jimezesinachi wants to merge 8 commits into
mainfrom
feat/replication-m1-foundation
Open

feat: Milestone 1 - added replication plumbing, tests and shared helpers#332
jimezesinachi wants to merge 8 commits into
mainfrom
feat/replication-m1-foundation

Conversation

@jimezesinachi
Copy link
Copy Markdown
Collaborator

No description provided.

Signed-off-by: Jim Ezesinachi <ezesinachijim@gmail.com>
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 8, 2026

Test Results

362 tests   362 ✅  19m 20s ⏱️
 42 suites    0 💤
  4 files      0 ❌

Results for commit 3029cb0.

♻️ This comment has been updated with latest results.

Signed-off-by: Jim Ezesinachi <ezesinachijim@gmail.com>
Signed-off-by: Jim Ezesinachi <ezesinachijim@gmail.com>
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 8, 2026

Benchmark Results

group                                                        main                                   pr
-----                                                        ----                                   --
predicate_query_with_index/size_100                          1.02      3.1±0.00µs        ? ?/sec    1.00      3.0±0.00µs        ? ?/sec
predicate_query_with_index/size_1000                         1.00     31.6±0.05µs        ? ?/sec    1.05     33.1±0.01µs        ? ?/sec
predicate_query_with_index/size_10000                        1.00    400.2±2.28µs        ? ?/sec    1.00    398.6±0.25µs        ? ?/sec
predicate_query_with_index/size_100000                       1.02      5.7±0.70ms        ? ?/sec    1.00      5.6±0.38ms        ? ?/sec
predicate_query_without_index/size_100                       1.02      7.2±0.00µs        ? ?/sec    1.00      7.0±0.01µs        ? ?/sec
predicate_query_without_index/size_1000                      1.05    106.3±0.15µs        ? ?/sec    1.00    101.7±0.06µs        ? ?/sec
predicate_query_without_index/size_10000                     1.02    772.0±1.36µs        ? ?/sec    1.00    755.8±2.77µs        ? ?/sec
predicate_query_without_index/size_100000                    1.00     12.7±0.86ms        ? ?/sec    1.07     13.6±1.30ms        ? ?/sec
store_batch_insertion_without_predicates/size_100            1.01    187.4±1.50µs        ? ?/sec    1.00    186.4±1.75µs        ? ?/sec
store_batch_insertion_without_predicates/size_1000           1.02   1256.7±8.17µs        ? ?/sec    1.00  1229.6±14.57µs        ? ?/sec
store_batch_insertion_without_predicates/size_10000          1.03     14.0±0.09ms        ? ?/sec    1.00     13.6±0.10ms        ? ?/sec
store_batch_insertion_without_predicates/size_100000         1.03    137.5±0.79ms        ? ?/sec    1.00    134.1±0.77ms        ? ?/sec
store_retrieval_linear_cosine_similarity/size_100            1.00     85.4±1.66µs        ? ?/sec    1.04     88.7±2.71µs        ? ?/sec
store_retrieval_linear_cosine_similarity/size_1000           1.00    719.1±2.75µs        ? ?/sec    1.00    717.8±3.01µs        ? ?/sec
store_retrieval_linear_cosine_similarity/size_10000          1.00      7.2±0.02ms        ? ?/sec    1.00      7.2±0.03ms        ? ?/sec
store_retrieval_linear_cosine_similarity/size_100000         1.00     75.6±0.35ms        ? ?/sec    1.00     75.4±0.42ms        ? ?/sec
store_retrieval_linear_dot_product/size_100                  1.00     84.9±1.87µs        ? ?/sec    1.01     85.6±3.50µs        ? ?/sec
store_retrieval_linear_dot_product/size_1000                 1.00    707.9±3.40µs        ? ?/sec    1.00    706.6±3.10µs        ? ?/sec
store_retrieval_linear_dot_product/size_10000                1.01      7.1±0.03ms        ? ?/sec    1.00      7.0±0.01ms        ? ?/sec
store_retrieval_linear_dot_product/size_100000               1.00     73.6±0.29ms        ? ?/sec    1.00     73.3±0.23ms        ? ?/sec
store_retrieval_linear_euclidean_distance/size_100           1.00     83.7±1.20µs        ? ?/sec    1.02     85.0±1.43µs        ? ?/sec
store_retrieval_linear_euclidean_distance/size_1000          1.00    700.4±2.93µs        ? ?/sec    1.01    708.0±4.13µs        ? ?/sec
store_retrieval_linear_euclidean_distance/size_10000         1.00      7.1±0.07ms        ? ?/sec    1.00      7.1±0.04ms        ? ?/sec
store_retrieval_linear_euclidean_distance/size_100000        1.00     72.9±0.43ms        ? ?/sec    1.02     74.2±0.24ms        ? ?/sec
store_retrieval_no_condition/size_100                        1.02     86.7±2.58µs        ? ?/sec    1.00     85.0±1.29µs        ? ?/sec
store_retrieval_no_condition/size_1000                       1.00    724.0±3.21µs        ? ?/sec    1.00    722.7±3.41µs        ? ?/sec
store_retrieval_no_condition/size_10000                      1.00      7.3±0.03ms        ? ?/sec    1.01      7.3±0.09ms        ? ?/sec
store_retrieval_no_condition/size_100000                     1.02     77.3±0.56ms        ? ?/sec    1.00     75.7±0.49ms        ? ?/sec
store_retrieval_non_linear_hnsw/size_100                     1.00    169.4±0.39µs        ? ?/sec    1.00    169.5±0.30µs        ? ?/sec
store_retrieval_non_linear_hnsw/size_1000                    1.00    485.2±2.18µs        ? ?/sec    1.02    493.4±0.84µs        ? ?/sec
store_retrieval_non_linear_hnsw/size_10000                   1.00      2.1±0.04ms        ? ?/sec    1.00      2.1±0.03ms        ? ?/sec
store_retrieval_non_linear_hnsw/size_100000                  1.07     12.4±0.16ms        ? ?/sec    1.00     11.6±0.10ms        ? ?/sec
store_retrieval_non_linear_kdtree/size_100                   1.00    179.8±0.54µs        ? ?/sec    1.00    180.2±0.16µs        ? ?/sec
store_retrieval_non_linear_kdtree/size_1000                  1.00   1155.5±2.17µs        ? ?/sec    1.00   1153.7±1.93µs        ? ?/sec
store_retrieval_non_linear_kdtree/size_10000                 1.01     12.4±0.07ms        ? ?/sec    1.00     12.3±0.10ms        ? ?/sec
store_retrieval_non_linear_kdtree/size_100000                1.01    149.5±0.90ms        ? ?/sec    1.00    148.6±1.02ms        ? ?/sec
store_sequential_insertion_without_predicates/size_100       1.00    260.8±0.24µs        ? ?/sec    1.01    262.5±0.17µs        ? ?/sec
store_sequential_insertion_without_predicates/size_1000      1.00      2.6±0.00ms        ? ?/sec    1.00      2.6±0.01ms        ? ?/sec
store_sequential_insertion_without_predicates/size_10000     1.00     25.6±0.05ms        ? ?/sec    1.00     25.7±0.02ms        ? ?/sec
store_sequential_insertion_without_predicates/size_100000    1.00    256.2±0.10ms        ? ?/sec    1.00    256.5±0.17ms        ? ?/sec

@jimezesinachi jimezesinachi requested review from Iamdavidonuh and deven96 and removed request for Iamdavidonuh May 9, 2026 07:50
DelPred(Vec<u8>),
DropPredIndex(Vec<u8>),
DropNonLinearAlgorithmIndex(Vec<u8>),
DropStore(Vec<u8>),
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

I thought we added PurgeStores recently to DB?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

A'firm, good catch

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Turns out, there appears to be no purge_stores handler for DB. There is one for AI, but none for DB. See here: https://github.com/deven96/ahnlich/blob/main/ahnlich/db/src/server/handler.rs

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Oh schade... we definitely don't have then
Skip for now

@@ -0,0 +1,425 @@
// `clippy::result_large_err` and `clippy::type_complexity` fire on signatures
Copy link
Copy Markdown
Owner

@deven96 deven96 May 12, 2026

Choose a reason for hiding this comment

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

Prefix mod with a definition of what the statemachine is and what it does

let mut inner = self.inner.lock().expect("state machine lock poisoned");
let mut responses = Vec::new();

for entry in entries {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

A bit skeptical about running the entries in a loop to inner.handler.apply. If there's an error with applying entry in the middle, we return error but have already applied some previous entries?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

A bit skeptical about running the entries in a loop to inner.handler.apply. If there's an error with applying entry in the middle, we return error but have already applied some previous entries?

Shey, I see what you're saying. I'm thinking of potential solutions: maybe rollback, or just try and check and fail early somehow?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Yeah maybe fail early for a start as I'm not sure we have some sure fire way to rollback yet

source: StorageIOError::read_state_machine(&e),
})?;

let mut inner = self.inner.lock().expect("state machine lock poisoned");
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Curious about panicking as a whole with respect to lock poisoning of the state machine

Shouldn't it be captured with StorageError instead?

Copy link
Copy Markdown
Collaborator Author

@jimezesinachi jimezesinachi May 15, 2026

Choose a reason for hiding this comment

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

Curious about panicking as a whole with respect to lock poisoning of the state machine

Shouldn't it be captured with StorageError instead?

I see what you're saying. I think my thinking here was that if lock is poisoned, the state machine is corrupt and in a way "unrecoverable until node restart". But user API wise, it does make sense to just bubble up as a StorageError, possibly with a message saying "the state machine lock is poisoned"

opts.create_if_missing(true);
opts.create_missing_column_families(true);
let cfs = vec![
ColumnFamilyDescriptor::new("logs", Options::default()),
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Would rather we have static strings referencing the column names and reuse across the rocksdb mod

Copy link
Copy Markdown
Collaborator Author

@jimezesinachi jimezesinachi May 15, 2026

Choose a reason for hiding this comment

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

Makes sense. I'll use constants

})
}

fn save_vote_sync(&mut self, vote: &Vote<C::NodeId>) -> Result<(), StorageError<C::NodeId>> {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Perhaps a stronger harness around setting&getting meta.... I'm largely wary about having to repeat strings as there's a huge chance that with an update things can be missed

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Makes sense. I'll use helper functions here

meta: &SnapshotMeta<C::NodeId, C::Node>,
snapshot: Box<C::SnapshotData>,
) -> Result<(), StorageError<C::NodeId>> {
let cursor: Cursor<Vec<u8>> = (*snapshot).clone().into();
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Do we have to clone the entire snapshot in order to deserialize it?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Looking again, I'm not sure. Will take a closer look and fix

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.

2 participants