-
Notifications
You must be signed in to change notification settings - Fork 14
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
Multiple back-ends #8
Comments
Actually, it'd need |
I believe @stjepang named the new repo Recently, after reading @ticki's blog on |
That's exactly how I got the idea.
There are many issues, but I think that it's possible, because as long as the trait is extensive enough, the unused interfaces for either backend can simply be empty methods. |
The trait could look like this: trait Backend {
fn try_gc() -> bool;
fn gc() {
while !Self::try_gc() {}
}
fn begin_epoch();
fn end_epoch();
fn begin_read() -> usize;
unsafe fn protect(ptr: *const u8, handle: usize);
unsafe fn unprotect(handle: usize);
fn add_garbage(ptr: *const u8);
} In the start of your manipulating function, you'd call It seems very messy like that, but imagine wrapping it in some convinient API:
|
Having a common API that encapsulates both EBR and HP is definitely a compelling idea. Last year I implemented exactly that in C++ (the code is not public, sorry!). In the end this common backend API worked ok with simple stuff like lock-free stacks and queues, but was more painful with skiplists. My general feeling was that the idea seems nice in theory, but in practice isn't worth it. However, that's just my 2 cents based on one semi-successful attempt, and I encourage you to explore this idea further. |
@stjepang, could you elaborate on the cases where it fails? |
I think my main beef with it was that the API is the lowest common denominator of EBR and HP, so you have to deal with the pains of both. With very complex data structures the backend API gets kinda messy, because you have to mark the critical section (the EBR part) as well as protect each pointer read (the HP part). And then if you want to get into optimizations, it becomes even more painful. What is compelling about this approach is that the user can choose the optimal garbage collection scheme for themselves. While that sounds nice, I actually tend to believe that the benefits of giving the choice to the user are very little. For concurrent data structures there usually already is the right choice. For example, skiplists with HP are around 3 times slower than skiplists with EBR, so why would anyone want HP? Or, hash tables should be almost equally fast with HP and EBR (depends on the hash table flavor), so why would anyone want EBR? The direction I'm more interested in exploring are hybrid approaches: combining EBR and HP so that you get the best of both worlds. For example, if you're searching for a key in a B+ tree, you probably want EBR because you're going to load multiple nodes while traversing the tree. However, if you're implementing an iterator over leaves of the tree, you want to protect nodes using HP (because they don't have those annoying critical sections). |
That's true.
Well, it means that complex structures such as hash tables won't have to be implemented twice. |
I was wondering if the API could be generalized to the extend that switching to non-epoch (e.g. conc) backends would be possible.
For example, there could be a
Backend
trait with an interface something like this:gc
for forcing garbage collection.add_garbage
for - well - adding new garbage.start_block_dtor
for blocking an object's destructionend_block_dtor
for ending the block.Under epochs, 3. and 4. would corresponds to
pin
andGuard::drop
respectively. Under hazards, 3. and 4. would correspond to creating hazards and freeing them respectively.cc. @stjepang.
The text was updated successfully, but these errors were encountered: