Skip to content

Commit 51fd033

Browse files
committed
Avoid zero-filling IPC reads with typed buffer handling
1 parent 1ffd202 commit 51fd033

2 files changed

Lines changed: 345 additions & 45 deletions

File tree

arrow-buffer/src/buffer/immutable.rs

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
// specific language governing permissions and limitations
1616
// under the License.
1717

18-
use std::alloc::Layout;
18+
use std::alloc::{Layout, handle_alloc_error};
1919
use std::fmt::Debug;
2020
use std::ptr::NonNull;
2121
use std::sync::Arc;
@@ -84,6 +84,81 @@ pub struct Buffer {
8484
length: usize,
8585
}
8686

87+
/// An aligned byte buffer that can be filled through `Read::read_exact` and
88+
/// converted into [`Buffer`] without copying.
89+
///
90+
/// This is used for IPC reads that need Arrow buffer alignment but should not
91+
/// zero-fill the allocation before reading into it.
92+
pub struct AlignedVec {
93+
ptr: NonNull<u8>,
94+
len: usize,
95+
layout: Layout,
96+
}
97+
98+
impl AlignedVec {
99+
/// Allocates `len` bytes with the requested alignment.
100+
pub fn new(len: usize, align: usize) -> Self {
101+
let layout =
102+
Layout::from_size_align(len, align).expect("failed to create layout for AlignedVec");
103+
104+
let ptr = match layout.size() {
105+
0 => crate::buffer::dangling_ptr(),
106+
_ => {
107+
// Safety: `layout` has non-zero size and was constructed above.
108+
let raw_ptr = unsafe { std::alloc::alloc(layout) };
109+
NonNull::new(raw_ptr).unwrap_or_else(|| handle_alloc_error(layout))
110+
}
111+
};
112+
113+
Self { ptr, len, layout }
114+
}
115+
}
116+
117+
impl std::ops::Deref for AlignedVec {
118+
type Target = [u8];
119+
120+
fn deref(&self) -> &[u8] {
121+
// Safety: `ptr` points to `len` bytes owned by this AlignedVec.
122+
unsafe { std::slice::from_raw_parts(self.ptr.as_ptr(), self.len) }
123+
}
124+
}
125+
126+
impl std::ops::DerefMut for AlignedVec {
127+
fn deref_mut(&mut self) -> &mut [u8] {
128+
// Safety: `ptr` points to `len` bytes owned by this AlignedVec.
129+
unsafe { std::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) }
130+
}
131+
}
132+
133+
impl From<AlignedVec> for Buffer {
134+
fn from(value: AlignedVec) -> Self {
135+
// Safety: `value.ptr` was allocated with `value.layout`, and the
136+
// resulting Bytes will deallocate it with the same layout.
137+
let bytes =
138+
unsafe { Bytes::new(value.ptr, value.len, Deallocation::Standard(value.layout)) };
139+
std::mem::forget(value);
140+
Buffer::from(bytes)
141+
}
142+
}
143+
144+
impl From<AlignedVec> for MutableBuffer {
145+
fn from(value: AlignedVec) -> Self {
146+
let buffer = Buffer::from(value);
147+
buffer
148+
.into_mutable()
149+
.expect("AlignedVec should be uniquely owned")
150+
}
151+
}
152+
153+
impl Drop for AlignedVec {
154+
fn drop(&mut self) {
155+
if self.layout.size() != 0 {
156+
// Safety: `ptr` was allocated with this exact layout in `new`.
157+
unsafe { std::alloc::dealloc(self.ptr.as_ptr(), self.layout) }
158+
}
159+
}
160+
}
161+
87162
impl Default for Buffer {
88163
#[inline]
89164
fn default() -> Self {

0 commit comments

Comments
 (0)