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

Future API changes to consider #677

Closed
7 tasks done
cberner opened this issue Sep 4, 2023 · 17 comments · Fixed by #766
Closed
7 tasks done

Future API changes to consider #677

cberner opened this issue Sep 4, 2023 · 17 comments · Fixed by #766

Comments

@cberner
Copy link
Owner

cberner commented Sep 4, 2023

  • replace drain and drain_filter with extract_if to match BtreeMap. Waiting on the std API to stabilize, so we can match it. Tracking Issue for {BTreeMap,BTreeSet}::extract_if rust-lang/rust#70530
  • constant time API to get the length of a MultimapValue
  • optimize Table::len() by storing the number of entries in a counter. See len is slow #710
  • Introduce a common trait for all tables, including untyped ones, that has the stats() and len() methods
  • Implement len() for untyped tables
  • Rename RedbKey to Key and RedbValue to Value
  • Remove lifetimes from as many public structs as possible
@Gawdl3y
Copy link

Gawdl3y commented Dec 26, 2023

I'm eager to see a lot of the lifetimes being removed from public structs, as I believe the lifetimes are making downstream use of vincent-herlemont/native_db kludgier than it could be. See vincent-herlemont/native_db#69 and vincent-herlemont/native_db#71. The main struct causing the troubles there is redb::TableDefinition.

@Ralith
Copy link

Ralith commented Jan 27, 2024

The lifetime relationships of ReadTransaction and ReadOnlyTable forced me to expose two layers of guard objects in https://github.com/Ralith/hypermine/blob/master/save/src/lib.rs, which is a mildly annoying wart in an otherwise ergonomic encapsulation of redb.

@cberner
Copy link
Owner Author

cberner commented Jan 28, 2024

@Ralith can you give master a try and see if the new 'static lifetimes resolves your issue?

@Ralith
Copy link

Ralith commented Jan 28, 2024

That avoids the double-guard for reads, but it looks like the problem still exists for writes. Not sure how solvable that is without making things more dynamic, though.

@cberner
Copy link
Owner Author

cberner commented Jan 29, 2024 via email

@eserilev
Copy link

eserilev commented Feb 3, 2024

Recently I was trying to do something like

 let iter = {
            let read_txn = self.db.begin_read().unwrap();
            let table = read_txn.open_table(table_definition).unwrap();
            table.range::<&[u8]>(from..).unwrap().map(|res| {
                let (k, v) = res.unwrap();
                Ok((
                    K::from_bytes(k.value()).unwrap(),
                    v.value().to_vec(),
                ))
            })
        }

because of lifetime issues I couldn't find a way to return iter cleanly. The static lifetime changes currently on master are a huge game changer for us. Really excited for this to land!

@cberner cberner changed the title 2.0 API changes to consider Future API changes to consider Feb 3, 2024
@cberner
Copy link
Owner Author

cberner commented Feb 3, 2024

master now has much friendlier lifetimes

@Evrey
Copy link

Evrey commented Mar 12, 2024

For future changes i’d like to also suggest this one:

  • Replace all occurrences of String with beef::Cow<'static, str> or core::borrow::Cow<'static, str> where possible.

This would obviously be a breaking change, hence »future change«.

I’m suggesting this, because currently there are a bunch of completely useless String allocations being performed in my code base. I only use const table definitions with &'static str table names, so all the error paths can take the name from my table definition directly, resulting in e.g. TableError::TableDoesNotExist(Cow<'static, str>). To make it worse, usually i throw these String names away immediately, because when i am handling errors, i know which table i just opened and don’t need a copy of the name.

@cberner
Copy link
Owner Author

cberner commented Mar 13, 2024

Unfortunately, I don't think that would work. The call site can have a non 'static lifetime:

.ok_or_else(|| TableError::TableDoesNotExist(definition.name().to_string()))?;

@Evrey
Copy link

Evrey commented Mar 15, 2024

Well, yes. I’m suggesting to borrow the name when it’s 'static, and only allocate it when it’s not. Alternatively, have TableErrors bound to the table definition’s lifetime (which i’d say makes sense to do), storing borrowed &'a strs, and have an impl<'a> Into<TableError<'static>> from TableError<'a> that allocates all Cow<'_, str> names, erasing the original lifetime.

@cberner
Copy link
Owner Author

cberner commented Mar 16, 2024

I’m suggesting to borrow the name when it’s 'static, and only allocate it when it’s not.

Do you have an example of the code for that? I'm not sure how to make it conditional on whether the lifetime is 'static or not

@Evrey
Copy link

Evrey commented Mar 20, 2024

Oh right. I’ve been surfing on too much nightly Rust and forgot you can’t specialise over lifetimes.

@Ralith
Copy link

Ralith commented Mar 29, 2024

I plan to remove [write transaction lifetimes] too. Just haven't gotten to it yet

It looks like a double-guard is still needed for write transactions: WriteTransaction::open_table borrows from the transaction, which means that an encapsulating API cannot store both the transaction and the tables in the same object.

@cberner
Copy link
Owner Author

cberner commented Mar 30, 2024

Yes, that's correct. If you need it to be lifetime-less, I would recommend opening the tables on-demand rather than retaining them.

@Ralith
Copy link

Ralith commented Mar 30, 2024

That would work, but I hesitated since the cost of open_table isn't clear. What's a good mental model here?

@cberner
Copy link
Owner Author

cberner commented Mar 31, 2024

It's log N in the number of tables in the database, and for repeat opens of the same table should end up being about as expensive as a few HashMap lookups

@Evrey
Copy link

Evrey commented Mar 31, 2024

Those are good numbers to document in APIs.

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 a pull request may close this issue.

5 participants