Skip to content

Commit 15df127

Browse files
authored
feat: support setting disk io throttle (#65)
Signed-off-by: MrCroxx <mrcroxx@outlook.com>
1 parent b2b0758 commit 15df127

File tree

7 files changed

+103
-17
lines changed

7 files changed

+103
-17
lines changed

Cargo.lock

Lines changed: 11 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ error-stack = { version = "0.5", default-features = false, features = [
6262
fastimer = { version = "0.9.0" }
6363
fastrace = { version = "0.7.9" }
6464
fastrace-opentelemetry = { version = "0.10.0" }
65-
foyer = { version = "0.17", features = ["nightly"] }
65+
foyer = { version = "0.17.1", features = ["nightly", "serde"] }
6666
futures-util = { version = "0.3.31" }
6767
gix-discover = { version = "0.40.1" }
6868
googletest = { version = "0.14.0" }

cmd/percas/src/start.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ async fn run_server(server_rt: &Runtime, gossip_rt: &Runtime, config: Config) ->
143143
&config.storage.data_dir,
144144
config.storage.memory_capacity,
145145
config.storage.disk_capacity,
146+
config.storage.disk_throttle,
146147
)
147148
.await
148149
.change_context_lazy(make_error)?;

crates/core/benches/benchmark.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ fn foyer_engine(c: &mut Criterion) {
3232
{
3333
let dir = tempdir_in("/tmp").unwrap();
3434
let engine = runtime.block_on(async {
35-
FoyerEngine::try_new(dir.path(), Some(0), 4 * 1024 * 1024 * 1024)
35+
FoyerEngine::try_new(dir.path(), Some(0), 4 * 1024 * 1024 * 1024, None)
3636
.await
3737
.unwrap()
3838
});
@@ -59,7 +59,7 @@ fn foyer_engine(c: &mut Criterion) {
5959
.for_each(|len| {
6060
let dir = tempdir_in("/tmp").unwrap();
6161
let engine = runtime.block_on(async {
62-
FoyerEngine::try_new(dir.path(), Some(0), 4 * 1024 * 1024 * 1024)
62+
FoyerEngine::try_new(dir.path(), Some(0), 4 * 1024 * 1024 * 1024, None)
6363
.await
6464
.unwrap()
6565
});

crates/core/src/config.rs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,54 @@ pub enum ServerConfig {
6262
},
6363
}
6464

65+
#[cfg(test)]
66+
pub(crate) mod defs {
67+
68+
use serde::Deserialize;
69+
use serde::Serialize;
70+
71+
#[derive(schemars::JsonSchema, Serialize, Deserialize)]
72+
#[serde(remote = "foyer::IopsCounter")]
73+
#[serde(deny_unknown_fields)]
74+
#[serde(tag = "mode")]
75+
pub enum IopsCounterDef {
76+
/// Count 1 iops for each read/write.
77+
#[serde(rename = "per_io")]
78+
PerIo,
79+
/// Count 1 iops for each read/write with the size of the i/o.
80+
#[serde(rename = "per_io_size")]
81+
PerIoSize(std::num::NonZeroUsize),
82+
}
83+
84+
#[derive(schemars::JsonSchema, Serialize, Deserialize)]
85+
#[serde(remote = "foyer::Throttle")]
86+
#[serde(deny_unknown_fields)]
87+
pub struct ThrottleDef {
88+
/// The maximum write iops for the device.
89+
pub write_iops: Option<std::num::NonZeroUsize>,
90+
/// The maximum read iops for the device.
91+
pub read_iops: Option<std::num::NonZeroUsize>,
92+
/// The maximum write throughput for the device.
93+
pub write_throughput: Option<std::num::NonZeroUsize>,
94+
/// The maximum read throughput for the device.
95+
pub read_throughput: Option<std::num::NonZeroUsize>,
96+
/// The iops counter for the device.
97+
#[serde(with = "IopsCounterDef")]
98+
pub iops_counter: foyer::IopsCounter,
99+
}
100+
}
101+
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
102+
#[cfg_attr(test, derive(schemars::JsonSchema))]
103+
#[serde(deny_unknown_fields)]
104+
#[repr(transparent)]
105+
pub struct DiskThrottle(#[cfg_attr(test, serde(with = "defs::ThrottleDef"))] foyer::Throttle);
106+
107+
impl From<DiskThrottle> for foyer::Throttle {
108+
fn from(value: DiskThrottle) -> Self {
109+
value.0
110+
}
111+
}
112+
65113
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
66114
#[cfg_attr(test, derive(schemars::JsonSchema))]
67115
#[serde(deny_unknown_fields)]
@@ -70,6 +118,8 @@ pub struct StorageConfig {
70118
pub data_dir: PathBuf,
71119
pub disk_capacity: u64,
72120
#[serde(skip_serializing_if = "Option::is_none")]
121+
pub disk_throttle: Option<DiskThrottle>,
122+
#[serde(skip_serializing_if = "Option::is_none")]
73123
pub memory_capacity: Option<u64>,
74124
}
75125

@@ -203,6 +253,7 @@ impl Default for Config {
203253
storage: StorageConfig {
204254
data_dir: default_data_dir(),
205255
disk_capacity: 512 * 1024 * 1024,
256+
disk_throttle: None,
206257
memory_capacity: None,
207258
},
208259
telemetry: TelemetryConfig {
@@ -299,6 +350,31 @@ pub const fn known_option_entries() -> &'static [OptionEntry] {
299350
ent_path: "storage.disk_capacity",
300351
ent_type: "integer",
301352
},
353+
OptionEntry {
354+
env_name: "PERCAS_CONFIG_STORAGE_DISK_THROTTLE_IOPS_COUNTER_MODE",
355+
ent_path: "storage.disk_throttle.iops_counter.mode",
356+
ent_type: "string",
357+
},
358+
OptionEntry {
359+
env_name: "PERCAS_CONFIG_STORAGE_DISK_THROTTLE_READ_IOPS",
360+
ent_path: "storage.disk_throttle.read_iops",
361+
ent_type: "integer",
362+
},
363+
OptionEntry {
364+
env_name: "PERCAS_CONFIG_STORAGE_DISK_THROTTLE_READ_THROUGHPUT",
365+
ent_path: "storage.disk_throttle.read_throughput",
366+
ent_type: "integer",
367+
},
368+
OptionEntry {
369+
env_name: "PERCAS_CONFIG_STORAGE_DISK_THROTTLE_WRITE_IOPS",
370+
ent_path: "storage.disk_throttle.write_iops",
371+
ent_type: "integer",
372+
},
373+
OptionEntry {
374+
env_name: "PERCAS_CONFIG_STORAGE_DISK_THROTTLE_WRITE_THROUGHPUT",
375+
ent_path: "storage.disk_throttle.write_throughput",
376+
ent_type: "integer",
377+
},
302378
OptionEntry {
303379
env_name: "PERCAS_CONFIG_STORAGE_MEMORY_CAPACITY",
304380
ent_path: "storage.memory_capacity",

crates/core/src/engine.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ use foyer::RuntimeOptions;
2828
use sysinfo::Pid;
2929
use thiserror::Error;
3030

31+
use crate::DiskThrottle;
3132
use crate::num_cpus;
3233

3334
const DEFAULT_MEMORY_CAPACITY_FACTOR: f64 = 0.8;
@@ -46,6 +47,7 @@ impl FoyerEngine {
4647
data_dir: &Path,
4748
memory_capacity: Option<u64>,
4849
disk_capacity: u64,
50+
disk_throttle: Option<DiskThrottle>,
4951
) -> Result<Self, EngineError> {
5052
let _ = std::fs::create_dir_all(data_dir);
5153
if !data_dir.exists() {
@@ -55,6 +57,13 @@ impl FoyerEngine {
5557
)));
5658
}
5759

60+
let mut dev = DirectFsDeviceOptions::new(data_dir)
61+
.with_capacity(disk_capacity as usize)
62+
.with_file_size(64 * 1024 * 1024);
63+
if let Some(throttle) = disk_throttle {
64+
dev = dev.with_throttle(throttle.into());
65+
}
66+
5867
let parallelism = num_cpus().get();
5968
let cache = HybridCacheBuilder::new()
6069
.with_policy(HybridCachePolicy::WriteOnInsertion)
@@ -78,11 +87,7 @@ impl FoyerEngine {
7887
.with_shards(parallelism)
7988
.with_eviction_config(FifoConfig::default())
8089
.storage(foyer::Engine::Large)
81-
.with_device_options(
82-
DirectFsDeviceOptions::new(data_dir)
83-
.with_capacity(disk_capacity as usize)
84-
.with_file_size(64 * 1024 * 1024),
85-
)
90+
.with_device_options(dev)
8691
.with_recover_mode(RecoverMode::Quiet)
8792
.with_runtime_options(RuntimeOptions::Unified(Default::default()))
8893
.build()
@@ -132,7 +137,7 @@ mod tests {
132137
async fn test_get() {
133138
let temp_dir = tempfile::tempdir().unwrap();
134139

135-
let engine = FoyerEngine::try_new(temp_dir.path(), Some(512 * 1024), 1024 * 1024)
140+
let engine = FoyerEngine::try_new(temp_dir.path(), Some(512 * 1024), 1024 * 1024, None)
136141
.await
137142
.unwrap();
138143
engine.put(b"foo".to_vec().as_ref(), b"bar".to_vec().as_ref());

tests/toolkit/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ pub fn start_test_server(_test_name: &str, rt: &Runtime) -> Option<TestServerSta
9999
&config.storage.data_dir,
100100
config.storage.memory_capacity,
101101
config.storage.disk_capacity,
102+
config.storage.disk_throttle,
102103
)
103104
.await
104105
.unwrap();

0 commit comments

Comments
 (0)