pub struct StringColumn { /* private fields */ }Expand description
A column of strings: the views, and the one arena the long ones live in.
The arena is append only, so an offset recorded in a view stays correct for the life of the
column even though the arena’s address does not. That is the property a Vec<u8> has and a raw
pointer into it does not, and it is the reason a view holds an offset.
This was a Vec<Vec<u8>> of fixed size blocks, which meant reading one long string was two
dependent loads, the outer vector’s element to find the block’s data pointer and then the bytes.
One arena makes it one, from a base the compiler can keep in a register across a row loop, and it
deletes the case where a string longer than a block needed a block of its own. On server3, over a
chunk of 1024 strings, comparing a column against a literal went from 14.9 nanoseconds a row to
13.2 at 40 bytes a string and from 14.2 to 12.9 at 120, gathering half the rows from 29.5 to 25.3
and from 36.9 to 29.1, and building the column from 12.0 to 8.9 at 40 bytes.
§The one number that got worse, and what it actually is
Building a column whose payload passes 128 KiB, which at 1024 rows means strings averaging more
than 128 bytes, went the other way: 14.6 nanoseconds a row to 41.0. That is not the copy and it
is not the doubling, it is glibc. An allocation that size comes from mmap rather than the heap,
so it is handed back to the kernel when the column is dropped and the next chunk faults every
page of it in again, while sixteen KiB blocks come back off a free list already faulted. Run the
same benchmark with MALLOC_MMAP_THRESHOLD_ raised and the arena builds that column in 9.6
nanoseconds a row against the blocks’ 16.2, so the design is not what is slow there.
The fix is that a chunk’s payload should come from a pool the engine owns rather than from
malloc per chunk, which is the buffer manager at layer three and is where this belongs.
Self::reserve_bytes is the part that is available now, and it recovers a quarter of it.
Implementations§
Source§impl StringColumn
impl StringColumn
Sourcepub fn with_capacity(capacity: usize) -> Self
pub fn with_capacity(capacity: usize) -> Self
An empty column with room for capacity strings.
Sourcepub fn views(&self) -> &[StringView]
pub fn views(&self) -> &[StringView]
The views, for a kernel that wants to compare prefixes without reading any payload.
Sourcepub fn bytes(&self, index: usize) -> Option<&[u8]>
pub fn bytes(&self, index: usize) -> Option<&[u8]>
The bytes at index, or None past the end.
This is what a comparison, a hash and an equality check all actually want, and it is worth
having separately from Self::get because that one validates UTF-8 and they do not need
it. Everything in a column arrived through Self::push, which takes a &str, so the
bytes are valid either way and the validation is a scan of the payload that changes no
answer. On a varchar filter it was measured at most of the per row cost.
Sourcepub fn heap_bytes(&self) -> usize
pub fn heap_bytes(&self) -> usize
Total bytes of payload held in the arena, which is what the memory accounting wants.
Sourcepub fn reserve_bytes(&mut self, bytes: usize)
pub fn reserve_bytes(&mut self, bytes: usize)
Room for bytes of payload, taken in one allocation rather than as the strings arrive.
A builder that knows the total byte count, which a scan reading a page and a gather copying a column both do, saves the doubling entirely. Nothing is wrong without it, which is why it is a hint and not a constructor argument.
Trait Implementations§
Source§impl Clone for StringColumn
impl Clone for StringColumn
Source§fn clone(&self) -> StringColumn
fn clone(&self) -> StringColumn
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for StringColumn
impl Debug for StringColumn
Source§impl Default for StringColumn
impl Default for StringColumn
Source§fn default() -> StringColumn
fn default() -> StringColumn
impl Eq for StringColumn
Source§impl<'a> Extend<&'a str> for StringColumn
impl<'a> Extend<&'a str> for StringColumn
Source§fn extend<T: IntoIterator<Item = &'a str>>(&mut self, iter: T)
fn extend<T: IntoIterator<Item = &'a str>>(&mut self, iter: T)
Source§fn extend_one(&mut self, item: T)
fn extend_one(&mut self, item: T)
extend_one)Source§fn extend_reserve(&mut self, additional: usize)
fn extend_reserve(&mut self, additional: usize)
extend_one)