openraft icon indicating copy to clipboard operation
openraft copied to clipboard

Feature: Added sled store example based on rocks example

Open k-u-s opened this issue 2 years ago • 18 comments

Hey, this adds a sled db example based on rocks db example as mentioned in #418. New example are at-par functionality wise with current but achieve it in different ways showcasing a different set of libraries to achieve comparable results.

Checklist

  • [ ] Updated guide with pertinent info (may not always apply).
  • [x] Squash down commits to one or two logical commits which clearly describe the work you've done.
  • [x] Unittest is a friend:)

This change is Reviewable

k-u-s avatar Jul 07 '22 15:07 k-u-s

Thanks, man!

AFAIK, there is still a concern with multiple sled instances:

From the sled README: https://github.com/spacejam/sled

sled does not support multiple open instances for the time being. Please keep sled open for the duration of your process's lifespan. It's totally safe and often quite convenient to use a global lazy_static sled instance, modulo the normal global variable trade-offs. Every operation is threadsafe, and most are implemented under the hood with lock-free algorithms that avoid blocking in hot paths.

We had encountered problems with multiple sled instances in our project and have switched to a single-instance manner.

To use sled, there has to be a singleton sled instance, as it does: https://github.com/datafuselabs/databend/blob/ee1d5c023ddb526744650786dfc5f45668f78d22/common/meta/sled-store/src/db.rs#L74-L83


Since the example framework can be reused with different store engines, this example can be just a Raftstorage implementation, to reduce code duplication. The rocksdb store is going to be a standalone crate:

  • #440

drmingdrmer avatar Jul 08 '22 02:07 drmingdrmer

With standalone crate i think its good to wait for https://github.com/datafuselabs/openraft/pull/440 to be merged.

As for the singleton from what i understand only place where db instance is created is in new function that should be called once per raft instance. Created db like that is owned by storage and it lives as long as storage lives which practically will be for the duration of program. It was done to reduce exposed types from sled crate.

Would you prefer that new function accepts sled::Db as parameter instead of directory path?

k-u-s avatar Jul 08 '22 06:07 k-u-s

LGTM

lichuang avatar Jul 08 '22 07:07 lichuang

This is cool :D, we used sled in the past it's a super interesting project!

Licenser avatar Jul 08 '22 09:07 Licenser

With standalone crate i think its good to wait for #440 to be merged.

Right:D

As for the singleton from what i understand only place where db instance is created is in new function that should be called once per raft instance. Created db like that is owned by storage and it lives as long as storage lives which practically will be for the duration of program. It was done to reduce exposed types from sled crate.

I mean, sled does not allow to create multi instances in a process. The concurrency control in it is process-wise. In the example, it creates multiple instances in threads, which may lead to some concurrency issues, according to the doc.

Would you prefer that new function accepts sled::Db as parameter instead of directory path?

Yes:D

drmingdrmer avatar Jul 09 '22 04:07 drmingdrmer

Changed signature of new to accept Arcsled::Db instead of directory path. So now its up to user to ensure correct lifetime.

k-u-s avatar Jul 11 '22 08:07 k-u-s

@k-u-s If this PR is meant to introduce an example of a sled store, it does not need to be a complete application. Other parts, such as the network, are repeated codes and will be a maintenance burden.

drmingdrmer avatar Jul 27 '22 12:07 drmingdrmer

This example is based on one early versions of rocksdb sample (which looks quite similar to mem) both of them have those parts. And to keep them similar as much as possible I only replace store.rs and added test_store.rs, rest should be pretty much without change.

I think its better to have example projects to follow same convention. if you prefer I could modify it but right now I am not sure how would you like it to look. One think that came to my mind is to merge mem/rocksdb/sled examples (if they in fact only differs in store.rs impl) into one where you can change underling store by passing cmd flag or setting some env variable.

k-u-s avatar Jul 27 '22 12:07 k-u-s

This example is based on one early versions of rocksdb sample (which looks quite similar to mem) both of them have those parts. And to keep them similar as much as possible I only replace store.rs and added test_store.rs, rest should be pretty much without change.

I think its better to have example projects to follow same convention. if you prefer I could modify it but right now I am not sure how would you like it to look. One think that came to my mind is to merge mem/rocksdb/sled examples (if they in fact only differs in store.rs impl) into one where you can change underling store by passing cmd flag or setting some env variable.

It'd be better without repeated code. There should be only one application level example. In a previous discussion it's recommended to move the rocksdb store into a standalone crate: https://github.com/datafuselabs/openraft/pull/436#issuecomment-1176001831

After this is done, the example could have a feature to switch to a different storage implementation, e.g.: cargo test --features memstore|rocksdbstore|sledstore.

drmingdrmer avatar Jul 27 '22 14:07 drmingdrmer

I'll try to provide sample next week

k-u-s avatar Jul 29 '22 07:07 k-u-s

Took a little longer cause Im evaluating different options since sled seams to not be maintained anymore.

Anyway added sledstore crate similar to rockstore, is this what you had in mind?

k-u-s avatar Aug 12 '22 08:08 k-u-s

Took a little longer cause Im evaluating different options since sled seams to not be maintained anymore.

Anyway added sledstore crate similar to rockstore, is this what you had in mind?

Thank you man!

The overall implementation is ok, except there are some consistency issues. E.g.: updating to last_applied and applying a log to the state machine has to be in an atomic operation. Otherwise, there is a chance a log entry will be applied twice. In such a case, a sled::Tree::transaction() has to be used.

And it does not have to be a complete application, since the network and application framework is almost the same as the other two examples.

a sled-store can be just a crate that implements RaftStorage. Similar to the standalone rocksdb-based store: https://github.com/datafuselabs/openraft/tree/main/rocksstore

drmingdrmer avatar Aug 14 '22 06:08 drmingdrmer

@drmingdrmer removed raft-kv-sled example and used mentioned transaction inside apply_to_state_machine method.

Do you prefer for sled-store name for crate instead of sledstore? I initially chosen that name since rocksstore and memstore do not use -

k-u-s avatar Aug 16 '22 08:08 k-u-s

@drmingdrmer removed raft-kv-sled example and used mentioned transaction inside apply_to_state_machine method.

Do you prefer for sled-store name for crate instead of sledstore? I initially chosen that name since rocksstore and memstore do not use -

Either one is Ok to me:). To be consistent with names, without - would be good.

drmingdrmer avatar Aug 16 '22 09:08 drmingdrmer

So i leave the name as it is.

I see you started ci build but my branch was outdated so i merged current main and fixed errors.

Also I unchecked Squash down commits to one or two logical commits which clearly describe the work you've done. since it no longer true. Do you prefer them squashed?

k-u-s avatar Aug 16 '22 10:08 k-u-s

@k-u-s Some of the commit messages does not follow the style: <type>: blabla.

It's recommended to rebase commits into one before publishing a PR with git rebase, git rebase -i.

A simple command to rebase your branch onto main and squash them into one commit is: git update-ref refs/heads/my_branch $(echo "commit_message" | git commit-tree my_branch^{tree} -p main)

Replace my_branch and commit_message with actual values.

drmingdrmer avatar Aug 16 '22 10:08 drmingdrmer

I see you also use lint so updated with cargo fmt --all also changed test to use tempdir instead of current working directory

k-u-s avatar Aug 16 '22 13:08 k-u-s

~~Not sure why i did not get those errors when i invoked it locally.~~ Ok from what i can see its different tool.

I'll fixed them tomorrow

k-u-s avatar Aug 16 '22 13:08 k-u-s

Do you have some script or cargo command that verify locally all this checks that ci does?

k-u-s avatar Aug 17 '22 09:08 k-u-s

Do you have some script or cargo command that verify locally all this checks that ci does?

There are several commands in Makefile: make fmt, make fix etc.

drmingdrmer avatar Aug 17 '22 09:08 drmingdrmer