-
-
Notifications
You must be signed in to change notification settings - Fork 296
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: make implicit free-list more controllable
This is done by three new `Repository` methods: * `empty_reusable_buffer()` - hook into the free-list yourself. * `set_freelist()` - enable or initialize the free-list. * `without_freelist()` - a builder to disable the freelist from the start.
- Loading branch information
Showing
8 changed files
with
136 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
use std::cell::RefCell; | ||
use std::ops::{Deref, DerefMut}; | ||
|
||
/// A buffer that is returned to the free-list after usage. | ||
#[derive(Clone)] | ||
pub struct Buffer<'repo> { | ||
/// The buffer that would be returned to the freelist of `repo`. | ||
/// Note that buffers without capacity (i.e. without allocation) aren't returned. | ||
pub inner: Vec<u8>, | ||
/// The repository from whose free-list the `inner` buffer was taken, and to which it will be returned. | ||
pub repo: &'repo crate::Repository, | ||
} | ||
|
||
impl From<Buffer<'_>> for Vec<u8> { | ||
fn from(mut value: Buffer<'_>) -> Self { | ||
std::mem::take(&mut value.inner) | ||
} | ||
} | ||
|
||
impl Deref for Buffer<'_> { | ||
type Target = Vec<u8>; | ||
|
||
fn deref(&self) -> &Self::Target { | ||
&self.inner | ||
} | ||
} | ||
|
||
impl DerefMut for Buffer<'_> { | ||
fn deref_mut(&mut self) -> &mut Self::Target { | ||
&mut self.inner | ||
} | ||
} | ||
|
||
impl Drop for Buffer<'_> { | ||
fn drop(&mut self) { | ||
self.repo.reuse_buffer(&mut self.inner); | ||
} | ||
} | ||
|
||
/// Internal | ||
impl crate::Repository { | ||
/// Note that the returned buffer might still have data in it. | ||
#[inline] | ||
pub(crate) fn free_buf(&self) -> Vec<u8> { | ||
self.bufs | ||
.as_ref() | ||
.and_then(|bufs| bufs.borrow_mut().pop()) | ||
.unwrap_or_default() | ||
} | ||
|
||
/// This method is commonly called from the destructor of objects that previously claimed an entry | ||
/// in the free-list with [crate::Repository::free_buf]. | ||
/// They are welcome to take out the data themselves, for instance when the object is detached, to avoid | ||
/// it to be reclaimed. | ||
#[inline] | ||
pub(crate) fn reuse_buffer(&self, data: &mut Vec<u8>) { | ||
if data.capacity() > 0 { | ||
if let Some(bufs) = self.bufs.as_ref() { | ||
bufs.borrow_mut().push(std::mem::take(data)); | ||
} | ||
} | ||
} | ||
} | ||
|
||
/// Freelist configuration | ||
/// | ||
/// The free-list is an internal and 'transparent' mechanism for obtaining and re-using memory buffers when | ||
/// reading objects. That way, trashing is avoided as buffers are re-used and re-written. | ||
/// | ||
/// However, there are circumstances when releasing memory early is preferred, for instance on the server side. | ||
/// | ||
/// Also note that the free-list isn't cloned, so each clone of this instance starts with an empty one. | ||
impl crate::Repository { | ||
/// Return an empty buffer which is tied to this repository instance, and reuse its memory allocation by | ||
/// keeping it around even after it drops. | ||
pub fn empty_reusable_buffer(&self) -> Buffer<'_> { | ||
let mut inner = self.free_buf(); | ||
inner.clear(); | ||
Buffer { inner, repo: self } | ||
} | ||
|
||
/// Set the currently used freelist to `list`. If `None`, it will be disabled entirely. | ||
/// | ||
/// Return the currently previously allocated free-list, a list of reusable buffers typically used when reading objects. | ||
/// May be `None` if there was no free-list. | ||
pub fn set_freelist(&mut self, list: Option<Vec<Vec<u8>>>) -> Option<Vec<Vec<u8>>> { | ||
let previous = self.bufs.take(); | ||
self.bufs = list.map(RefCell::new); | ||
previous.map(RefCell::into_inner) | ||
} | ||
|
||
/// A builder method to disable the free-list on a newly created instance. | ||
pub fn without_freelist(mut self) -> Self { | ||
self.bufs.take(); | ||
self | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters