-
Notifications
You must be signed in to change notification settings - Fork 52
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
Conversation
|
||
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>; |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 :)
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this 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.
D'oh! I ran I fixed the problem in 18599e4. Interestingly, Clippy's suggestion was suboptimal, as it suggested:
When in fact we can do better than removing the |
@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 timesResult<_, lmdb::Error>
.In the process, I also added testing of
MultiStore.get_first()
andMultiStore.delete_all()
to confirm that they work as expected.Let me know what you think.