Skip to content

Commit d928457

Browse files
authored
perf: reuse inflight buf in lodc to reduce alloc and page fault (#871)
* chore: remove some unnecessary comments Signed-off-by: MrCroxx <mrcroxx@outlook.com> * perf: reuse inflight buffer in lodc wirte to reduce alloc and page fault Signed-off-by: MrCroxx <mrcroxx@outlook.com> --------- Signed-off-by: MrCroxx <mrcroxx@outlook.com>
1 parent 78fca8d commit d928457

File tree

2 files changed

+28
-11
lines changed

2 files changed

+28
-11
lines changed

foyer-storage/src/io/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,11 @@ impl SharedIoSlice {
343343
pub fn absolute(&self) -> Range<usize> {
344344
self.start..self.end
345345
}
346+
347+
/// Convert into [`IoBuffer`], if the [`SharedIoSlice`] has exactly one reference.
348+
pub fn try_into_io_buffer(self) -> Option<IoBuffer> {
349+
Arc::into_inner(self.buffer)
350+
}
346351
}
347352

348353
impl Deref for SharedIoSlice {

foyer-storage/src/large/flusher.rs

+23-11
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ use crate::{
5555
large::indexer::{EntryAddress, HashedEntryAddress},
5656
region::{GetCleanRegionHandle, RegionManager},
5757
runtime::Runtime,
58-
Compression, Dev, Statistics,
58+
Compression, Dev, SharedIoSlice, Statistics,
5959
};
6060

6161
pub enum Submission<K, V>
@@ -157,7 +157,11 @@ where
157157
let (tx, rx) = flume::unbounded();
158158

159159
let buffer_size = config.buffer_pool_size / config.flushers;
160-
let writer = create_writer(buffer_size, device.region_size(), device.region_size(), metrics.clone());
160+
161+
let buffer = IoBuffer::new(buffer_size);
162+
let rotate_buffer = Some(IoBuffer::new(buffer_size));
163+
164+
let writer = create_writer(buffer, device.region_size(), device.region_size(), metrics.clone());
161165
let writer = Some(writer);
162166

163167
let current_region_handle = region_manager.get_clean_region();
@@ -168,8 +172,8 @@ where
168172
writer,
169173
tombstone_infos: vec![],
170174
waiters: vec![],
175+
rotate_buffer,
171176
queue_init: None,
172-
buffer_size,
173177
submit_queue_size: submit_queue_size.clone(),
174178
region_manager,
175179
device,
@@ -220,13 +224,13 @@ where
220224
}
221225

222226
fn create_writer(
223-
capacity: usize,
227+
buffer: IoBuffer,
224228
region_size: usize,
225229
current_region_remain: usize,
226230
metrics: Arc<Metrics>,
227231
) -> BatchWriter {
228232
// TODO(MrCroxx): optimize buffer allocation.
229-
BatchWriter::new(IoBuffer::new(capacity), region_size, current_region_remain, metrics)
233+
BatchWriter::new(buffer, region_size, current_region_remain, metrics)
230234
}
231235

232236
#[derive(Debug)]
@@ -245,6 +249,7 @@ struct IoTaskCtx {
245249
handle: Option<GetCleanRegionHandle>,
246250
waiters: Vec<oneshot::Sender<()>>,
247251
init: Instant,
252+
io_slice: SharedIoSlice,
248253
}
249254

250255
struct Runner<K, V>
@@ -260,10 +265,14 @@ where
260265
waiters: Vec<oneshot::Sender<()>>,
261266
queue_init: Option<Instant>,
262267

268+
/// IoBuffer rotates between writer and inflight io task.
269+
///
270+
/// Use this field to avoid allocation.
271+
rotate_buffer: Option<IoBuffer>,
272+
263273
submit_queue_size: Arc<AtomicUsize>,
264274

265275
current_region_handle: GetCleanRegionHandle,
266-
buffer_size: usize,
267276

268277
region_manager: RegionManager,
269278
indexer: Indexer,
@@ -333,8 +342,9 @@ where
333342
let io_task = self.submit_io_task(buf, batch, tombstone_infos, waiters, init);
334343
self.io_tasks.push_back(io_task);
335344

345+
let buffer = self.rotate_buffer.take().unwrap();
336346
let writer = create_writer(
337-
self.buffer_size,
347+
buffer,
338348
self.device.region_size(),
339349
remain,
340350
// self.current_region_state.remain,
@@ -346,11 +356,13 @@ where
346356

347357
tokio::select! {
348358
biased;
349-
IoTaskCtx { handle, waiters, init } = self.next_io_task_finish() => {
359+
IoTaskCtx { handle, waiters, init, io_slice } = self.next_io_task_finish() => {
350360
if let Some(handle) = handle {
351361
self.current_region_handle = handle;
352362
}
353363
self.handle_io_complete(waiters, init);
364+
// `try_into_io_buffer` must return `Some(..)` here.
365+
self.rotate_buffer = io_slice.try_into_io_buffer();
354366
}
355367
Ok(submission) = rx.recv_async() => {
356368
self.recv(submission);
@@ -554,7 +566,6 @@ where
554566
}
555567
};
556568

557-
// let f: BoxFuture<'_, Result<Vec<CleanRegionState>>> = try_join_all(futures).boxed();
558569
let f: BoxFuture<'_, Result<(Vec<GetCleanRegionHandle>, ())>> = try_join(try_join_all(futures), future).boxed();
559570
let handle = self
560571
.runtime
@@ -565,13 +576,15 @@ where
565576
handle: states.pop(),
566577
waiters,
567578
init,
579+
io_slice: shared,
568580
},
569581
Ok(Err(e)) => {
570582
tracing::error!(?e, "[lodc flusher]: io task error");
571583
IoTaskCtx {
572584
handle: None,
573585
waiters,
574586
init,
587+
io_slice: shared,
575588
}
576589
}
577590
Err(e) => {
@@ -580,13 +593,12 @@ where
580593
handle: None,
581594
waiters,
582595
init,
596+
io_slice: shared,
583597
}
584598
}
585599
})
586600
.boxed();
587601

588-
// self.io_tasks.push_back(handle);
589-
590602
handle
591603
}
592604

0 commit comments

Comments
 (0)