Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wrap lmdb-rs transactions in rkv abstraction #116

Merged
merged 3 commits into from
Feb 6, 2019

Conversation

mykmelez
Copy link
Contributor

@mykmelez mykmelez commented Feb 6, 2019

@ncloudioj @rrichardson This branch re-wraps LMDB transactions in a Reader/Writer abstraction to fix #115.

The names aren't important, and I'm happy to use something else (even the same names as LMDB). I just want to achieve consistency in the return values of rkv methods, so they don't return sometimes Result<_, StoreError> and other times Result<_, lmdb::Error>.

In the process, I also added testing of MultiStore.get_first() and MultiStore.delete_all() to confirm that they work as expected.

Let me know what you think.

@mykmelez mykmelez requested a review from ncloudioj February 6, 2019 00:32

pub trait Read {
fn get<K: AsRef<[u8]>>(&self, db: Database, k: &K) -> Result<Option<Value>, StoreError>;
fn open_ro_cursor(&self, db: Database) -> Result<RoCursor, StoreError>;
Copy link
Member

Choose a reason for hiding this comment

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

Shall we make this function as crate(pub)? Looks like RoCursor is only internally used by the rkv iterators. If this makes sense, let's remove the pub use lmdb::RoCursor in the lib.rs.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I haven't found a way to do this, as it seems like the visibility of the function depends on the visibility of the trait, and it isn't possible to hide the trait, since public methods like SingleStore.get() have parameters that are bound to the trait. Do you know of any way around that?

Copy link
Member

Choose a reason for hiding this comment

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

Ugh, right, it's a trait. Perhaps split this trait into two, and make the cursor one visible at the crate level?

My concern is that exposing RoCursor to the consumer is not very useful in rkv, and it might lead to lmdb:errors upon misuses.

Copy link
Member

Choose a reason for hiding this comment

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

I think we can polish this in a followup patch once we come up with the better solution.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think we can hide a trait that only declares an open_ro_cursor() function either, as we would still need to specify that trait in the public interfaces of SingleStore.iter_start(), SingleStore.iter_from(), and MultiStore.get() in order to call open_ro_cursor() on the Reader/Writer given to those functions.

Copy link
Member

Choose a reason for hiding this comment

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

Yea, looks like hiding traits alone is just a deadend, perhpas apply the good old delegation trick to those iter_* functions? Need to stop myself from concerning this prematurely :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hehe, I filed #117 so we don't forget about it! 😉

src/readwrite.rs Outdated
pub struct Reader<'env>(pub RoTransaction<'env>);
pub struct Writer<'env>(pub RwTransaction<'env>);

pub trait Read {
Copy link
Member

Choose a reason for hiding this comment

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

As you mentioned about the naming, I think Reader&Writer are reasonable names for read_only/write transactions. Though I find the Read trait a bit confusing here. At the first glance, I thought this is a reader specific trait. I believe that we wanted to express the fact that both read_only and write transactions can read the store.

Would it be better to name this trait as Readable, despite that it's not the preferred naming convention for traits in Rust?

Copy link
Contributor Author

@mykmelez mykmelez Feb 6, 2019

Choose a reason for hiding this comment

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

Yes, it's a good point, the trait name is too confusing. I've renamed it to Readable in 1c7a144.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For what it's worth, it isn't clear to me what the preferred naming convention is for traits in Rust. milesmcc/ieql#2 suggests that it's "imperatives over modified words," in which case Read would be preferred to Readable.

But rust-lang/api-guidelines#28 suggests that the matter is more complicated, and it isn't clear to me that the answer is as simple as to use imperatives. In any case, it's plenty reasonable for us to use Readable, especially for a trait that consumers usually won't interact with directly.

Copy link
Member

@ncloudioj ncloudioj left a comment

Choose a reason for hiding this comment

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

r=nanj Abstraction of raw LMDB transactions is indeed necessary for rkv!

Just two minor suggestions for your consideration. Also, looks like Clippy has found some nits in the code.

@mykmelez
Copy link
Contributor Author

mykmelez commented Feb 6, 2019

Also, looks like Clippy has found some nits in the code.

D'oh! I ran cargo clippy but not cargo clippy --all-targets --all-features -- -D warnings, which also checks the targets in examples/.

I fixed the problem in 18599e4. Interestingly, Clippy's suggestion was suboptimal, as it suggested:

error: identical conversion
  --> examples/iterator.rs:74:33
   |
74 |     writer.commit().map_err(|e| e.into())
   |                                 ^^^^^^^^ help: consider removing `.into()`: `e`
   |
   = note: `-D clippy::identity-conversion` implied by `-D warnings`
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#identity_conversion

When in fact we can do better than removing the .into() and remove the entire .map_err() call.

@mykmelez mykmelez merged commit 9b46134 into mozilla:master Feb 6, 2019
@mykmelez mykmelez deleted the wrap-transaction branch February 6, 2019 20:06
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.

committing transaction returns lmdb::Error instead of StoreError
2 participants