-
Notifications
You must be signed in to change notification settings - Fork 122
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
Proposal for overhaul of buffer representation #251
Comments
Something which does strike me with this design is the similarity to the existing registries. I strongly suspect these could be unified too, probably by parameterising a Rawbuffer over the held state. type Buffer = Rawbuffer<BufferState>;
type Registry = Rawbuffer<RegistryState>; |
If this works, this is a great idea. If you didn't provide a straw man proposal for a FixedBuf, is that because you don't know yet or because it's obvious? I would want the BufX I have in my BufRing code to also use it of course. In the frequent case of there being a single allocation being the backing store, do you see the ref and the ref_mut being as efficient as before? Perhaps with the exception of a test added, to the accessor itself (ref or ref_mut), that the iovec length is 1? What would it do to the API if the buffer were made of multiple backing stores though. Doesn't it mean the ref and ref_mut can't be asked to return a &[u8] or &mut[u8]? Maybe an approach would be those would panic if used on a multiple-backing-stored buffer. And there would be test (aka try) functions that returned an Option<&[u8]>. But it would be up to the user of the library to either know they are only using single-backing-stored buffers so they can safely use ref and ref_mut, or they have to be safe and use something like try_ref and try_ref_mut? Kind of like users have to know if dividing by their variable is safe or they should be adding their own test for zero. Would it subsume the slice struct too or would that be a second concrete type? |
I don't follow. I thought you're thinking a concrete, non-parameterized type could do it all? |
Yes, badly phrased by me: I can unify the buffer types without parameterisation. It may be possible tounify both Buffer and BufferRegistries by parameterising the underlying state - given a buffer can now represent multiple memory regions, and a Registry holds multiple memory regions, this is perhaps unsurprising. |
I've not yet fleshed this out. It is certinaly possible, and highly desireable, the question is only do I need some additional meta data in the state to achieve it: i.e, on drop, is some additional info required. |
Looking at |
I would hope other meta data would not be needed. I've wondered why something like a buf id was needed in the first place. Couldn't we say our registries have to be built from a contiguous block of memory so the buffer address being returned in the destructor would be enough to identifier the portion of the region that was being returned to the registry? I know in my own case of using a buf id in the BufRing implementation, it felt wrong. But I was just following what had already been established in the crate. But if we're talking about a better implementation for all, I would heavily lean towards requiring the registry to be able to use the buffer address itself as the identifier - even if it means we can't use a vec of vecs as a registry any more. |
I don't love the idea that every buffer has two allocations before even talking about the backing store buffer. And why is the state vec containing various destructors. Do we lose flexibility by saying there is one destructor for the entire buffer, and it has to know how to deal with the iovec parts? I hesitate to mention this, but would it be a reason to bring a tinyvec into the discussion so the most normal case of a single backing store is handled with no extra allocations? |
Yes: you'll see I made mention to the case for SSO. I'd have thought this was a very good optimization. We have 16 bytes left on the cache line, so it doesn't even need to rely on nonnull optimizations, although it could. |
I'm curious if there are known use cases or concrete motivations for this (as well as just following bytes::Buf)? Is the use of iovec to support vectored IO? |
Yes - motivated by |
Hi @ollie-etl . Sorry for very late mentioning you, but I found this request is very reasonable. We're having somehow different motivation (sum type is required to abstract two different API signature: Did you make any try for this change? |
This follows on from #161 #216 at least, but lays out a concrete proposal and rational. This proposal would represent a major API change.
I am proposing unifying all buffers with a single, non-parameterized buffer type, similar to owned-buf. This proposed buffer has the following properties. For the sake of this Proposal, I'll refer to it as
Buffer
.Properties of
Buffer
Buffer
may be backed by multiple, non contiguos memory regions. This is inspired by the trait bytes::buf.Motivation
Many of the function in the API in
tokio-uring
either allocate, or require allocating aVec
externally when operating over vectored or multipart memory regions. Specificallyreadv
,writev
,recvmsg
andsendmsg
variants. This is a shame, because these calls tend to be called on when trying to optimise performance (in my experience). The allocation occurs because the underlying uring ops require a contiguous iovec to represent the operation.Candidate design
Notes
Impact on API
This is a bit hand-wavey, because I haven't given all aspects due consideration. However, it does seem that some rationalization becomes available. Want to write data?
Want to write vectored data?
Request for feedback
@Noah-Kennedy @carllerche @FrankReh @mzabaluev @redbaron @nrc @rrichardson
I'm prepared to flesh this out more into a PR, provided I can get an indication this is not dead in the water before I start. This would represent a significant time investment, which I'm unwilling to commit to without initial feedback.
The text was updated successfully, but these errors were encountered: