Skip to content

Commit 58da38d

Browse files
authored
feat: support persist cache task when scheduler replicates task (#953)
Signed-off-by: Gaius <[email protected]>
1 parent e787afe commit 58da38d

File tree

21 files changed

+296
-441
lines changed

21 files changed

+296
-441
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ members = [
1212
]
1313

1414
[workspace.package]
15-
version = "0.2.5"
15+
version = "0.2.6"
1616
authors = ["The Dragonfly Developers"]
1717
homepage = "https://d7y.io/"
1818
repository = "https://github.com/dragonflyoss/client.git"
@@ -22,15 +22,15 @@ readme = "README.md"
2222
edition = "2021"
2323

2424
[workspace.dependencies]
25-
dragonfly-client = { path = "dragonfly-client", version = "0.2.5" }
26-
dragonfly-client-core = { path = "dragonfly-client-core", version = "0.2.5" }
27-
dragonfly-client-config = { path = "dragonfly-client-config", version = "0.2.5" }
28-
dragonfly-client-storage = { path = "dragonfly-client-storage", version = "0.2.5" }
29-
dragonfly-client-backend = { path = "dragonfly-client-backend", version = "0.2.5" }
30-
dragonfly-client-util = { path = "dragonfly-client-util", version = "0.2.5" }
31-
dragonfly-client-init = { path = "dragonfly-client-init", version = "0.2.5" }
25+
dragonfly-client = { path = "dragonfly-client", version = "0.2.6" }
26+
dragonfly-client-core = { path = "dragonfly-client-core", version = "0.2.6" }
27+
dragonfly-client-config = { path = "dragonfly-client-config", version = "0.2.6" }
28+
dragonfly-client-storage = { path = "dragonfly-client-storage", version = "0.2.6" }
29+
dragonfly-client-backend = { path = "dragonfly-client-backend", version = "0.2.6" }
30+
dragonfly-client-util = { path = "dragonfly-client-util", version = "0.2.6" }
31+
dragonfly-client-init = { path = "dragonfly-client-init", version = "0.2.6" }
3232
thiserror = "1.0"
33-
dragonfly-api = "=2.1.16"
33+
dragonfly-api = "=2.1.23"
3434
reqwest = { version = "0.12.4", features = [
3535
"stream",
3636
"native-tls",
@@ -102,6 +102,7 @@ tempfile = "3.14.0"
102102
tokio-rustls = "0.25.0-alpha.4"
103103
serde_json = "1.0.137"
104104
lru = "0.12.5"
105+
fs2 = "0.4.3"
105106

106107
[profile.release]
107108
opt-level = "z"

dragonfly-client-config/src/dfdaemon.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ fn default_scheduler_announce_interval() -> Duration {
155155
/// default_scheduler_schedule_timeout is the default timeout for scheduling.
156156
#[inline]
157157
fn default_scheduler_schedule_timeout() -> Duration {
158-
Duration::from_secs(10)
158+
Duration::from_secs(180)
159159
}
160160

161161
/// default_dynconfig_refresh_interval is the default interval to refresh dynamic configuration from manager.

dragonfly-client-core/src/error/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ pub enum DFError {
4242
#[error{"hashring {0} is failed"}]
4343
HashRing(String),
4444

45+
/// NoSpace is the error when there is no space left on device.
46+
#[error("no space left on device: {0}")]
47+
NoSpace(String),
48+
4549
/// HostNotFound is the error when the host is not found.
4650
#[error{"host {0} not found"}]
4751
HostNotFound(String),

dragonfly-client-storage/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ tokio-util.workspace = true
2525
sha2.workspace = true
2626
crc.workspace = true
2727
base16ct.workspace = true
28+
fs2.workspace = true
2829
num_cpus = "1.0"
2930
bincode = "1.3.3"
3031
rayon = "1.10.0"

dragonfly-client-storage/src/content.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,33 @@ impl Content {
8484
Ok(Content { config, dir })
8585
}
8686

87+
/// available_space returns the available space of the disk.
88+
pub fn available_space(&self) -> Result<u64> {
89+
let stat = fs2::statvfs(&self.dir)?;
90+
Ok(stat.available_space())
91+
}
92+
93+
/// total_space returns the total space of the disk.
94+
pub fn total_space(&self) -> Result<u64> {
95+
let stat = fs2::statvfs(&self.dir)?;
96+
Ok(stat.total_space())
97+
}
98+
99+
/// has_enough_space checks if the storage has enough space to store the content.
100+
pub fn has_enough_space(&self, content_length: u64) -> Result<bool> {
101+
let available_space = self.available_space()?;
102+
if available_space < content_length {
103+
warn!(
104+
"not enough space to store the persistent cache task: available_space={}, content_length={}",
105+
available_space, content_length
106+
);
107+
108+
return Ok(false);
109+
}
110+
111+
Ok(true)
112+
}
113+
87114
/// hard_link_or_copy_task hard links or copies the task content to the destination.
88115
#[instrument(skip_all)]
89116
pub async fn hard_link_or_copy_task(

dragonfly-client-storage/src/lib.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use std::path::PathBuf;
2424
use std::sync::Arc;
2525
use std::time::Duration;
2626
use tokio::io::AsyncRead;
27-
use tracing::{debug, error, instrument};
27+
use tracing::{debug, error, instrument, warn};
2828

2929
pub mod content;
3030
pub mod metadata;
@@ -59,6 +59,21 @@ impl Storage {
5959
})
6060
}
6161

62+
/// total_space returns the total space of the disk.
63+
pub fn total_space(&self) -> Result<u64> {
64+
self.content.total_space()
65+
}
66+
67+
/// available_space returns the available space of the disk.
68+
pub fn available_space(&self) -> Result<u64> {
69+
self.content.available_space()
70+
}
71+
72+
/// has_enough_space checks if the storage has enough space to store the content.
73+
pub fn has_enough_space(&self, content_length: u64) -> Result<bool> {
74+
self.content.has_enough_space(content_length)
75+
}
76+
6277
/// hard_link_or_copy_task hard links or copies the task content to the destination.
6378
#[instrument(skip_all)]
6479
pub async fn hard_link_or_copy_task(
@@ -245,6 +260,12 @@ impl Storage {
245260
self.metadata.get_persistent_cache_task(id)
246261
}
247262

263+
/// persist_persistent_cache_task persists the persistent cache task metadata.
264+
#[instrument(skip_all)]
265+
pub fn persist_persistent_cache_task(&self, id: &str) -> Result<metadata::PersistentCacheTask> {
266+
self.metadata.persist_persistent_cache_task(id)
267+
}
268+
248269
/// is_persistent_cache_task_exists returns whether the persistent cache task exists.
249270
#[instrument(skip_all)]
250271
pub fn is_persistent_cache_task_exists(&self, id: &str) -> Result<bool> {

dragonfly-client-storage/src/metadata.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -700,6 +700,22 @@ impl<E: StorageEngineOwned> Metadata<E> {
700700
Ok(task)
701701
}
702702

703+
/// persist_persistent_cache_task persists the persistent cache task metadata.
704+
#[instrument(skip_all)]
705+
pub fn persist_persistent_cache_task(&self, id: &str) -> Result<PersistentCacheTask> {
706+
let task = match self.db.get::<PersistentCacheTask>(id.as_bytes())? {
707+
Some(mut task) => {
708+
task.persistent = true;
709+
task.updated_at = Utc::now().naive_utc();
710+
task
711+
}
712+
None => return Err(Error::TaskNotFound(id.to_string())),
713+
};
714+
715+
self.db.put(id.as_bytes(), &task)?;
716+
Ok(task)
717+
}
718+
703719
/// get_persistent_cache_task gets the persistent cache task metadata.
704720
#[instrument(skip_all)]
705721
pub fn get_persistent_cache_task(&self, id: &str) -> Result<Option<PersistentCacheTask>> {

dragonfly-client-storage/src/storage_engine/rocksdb.rs

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,7 @@ impl RocksdbStorageEngine {
117117

118118
// If the storage is kept, open the db and drop the unused column families.
119119
// Otherwise, destroy the db.
120-
if keep {
121-
drop_unused_cfs(&dir);
122-
} else {
120+
if !keep {
123121
rocksdb::DB::destroy(&options, &dir).unwrap_or_else(|err| {
124122
warn!("destroy {:?} failed: {}", dir, err);
125123
});
@@ -259,24 +257,3 @@ where
259257
db.cf_handle(cf_name)
260258
.ok_or_else(|| Error::ColumnFamilyNotFound(cf_name.to_string()))
261259
}
262-
263-
/// drop_unused_cfs drops the unused column families.
264-
fn drop_unused_cfs(dir: &Path) {
265-
let old_cf_names = vec!["task", "piece", "cache_task"];
266-
let unused_cf_names = vec!["cache_task"];
267-
268-
let mut db = match rocksdb::DB::open_cf(&rocksdb::Options::default(), dir, old_cf_names) {
269-
Ok(db) => db,
270-
Err(err) => {
271-
warn!("open cf failed: {}", err);
272-
return;
273-
}
274-
};
275-
276-
for cf_name in unused_cf_names {
277-
match db.drop_cf(cf_name) {
278-
Ok(_) => info!("drop cf [{}] success", cf_name),
279-
Err(err) => warn!("drop cf [{}] failed: {}", cf_name, err),
280-
}
281-
}
282-
}

dragonfly-client/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ percent-encoding.workspace = true
6464
tokio-rustls.workspace = true
6565
serde_json.workspace = true
6666
lru.workspace = true
67+
fs2.workspace = true
6768
lazy_static = "1.5"
6869
tracing-log = "0.2"
6970
tracing-subscriber = { version = "0.3", features = ["env-filter", "time", "chrono"] }
@@ -81,7 +82,6 @@ sysinfo = "0.32.1"
8182
tower = "0.4.13"
8283
indicatif = "0.17.9"
8384
dashmap = "6.1.0"
84-
fs2 = "0.4.3"
8585
hashring = "0.3.6"
8686
fslock = "0.2.1"
8787
leaky-bucket = "1.1.2"

dragonfly-client/src/bin/dfcache/import.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@ pub struct ImportCommand {
3737
#[arg(help = "Specify the path of the file to import")]
3838
path: PathBuf,
3939

40+
#[arg(
41+
long = "id",
42+
required = false,
43+
help = "Specify the id of the persistent cache task, its length must be 64 bytes. If id is none, dfdaemon will generate the new task id based on the file content, tag and application by wyhash algorithm."
44+
)]
45+
id: Option<String>,
46+
4047
#[arg(
4148
long = "persistent-replica-count",
4249
default_value_t = default_dfcache_persistent_replica_count(),
@@ -321,6 +328,7 @@ impl ImportCommand {
321328

322329
let persistent_cache_task = dfdaemon_download_client
323330
.upload_persistent_cache_task(UploadPersistentCacheTaskRequest {
331+
task_id: self.id.clone(),
324332
path: self.path.clone().into_os_string().into_string().unwrap(),
325333
persistent_replica_count: self.persistent_replica_count,
326334
tag: self.tag.clone(),
@@ -341,6 +349,15 @@ impl ImportCommand {
341349

342350
/// validate_args validates the command line arguments.
343351
fn validate_args(&self) -> Result<()> {
352+
if let Some(id) = self.id.as_ref() {
353+
if id.len() != 64 {
354+
return Err(Error::ValidationError(format!(
355+
"id length must be 64 bytes, but got {}",
356+
id.len()
357+
)));
358+
}
359+
}
360+
344361
if self.path.is_dir() {
345362
return Err(Error::ValidationError(format!(
346363
"path {} is a directory",

dragonfly-client/src/bin/dfcache/main.rs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ use tracing::Level;
2626

2727
pub mod export;
2828
pub mod import;
29-
pub mod remove;
3029
pub mod stat;
3130

3231
#[derive(Debug, Parser)]
@@ -83,15 +82,6 @@ pub enum Command {
8382
long_about = "Stat a file in Dragonfly P2P network by task ID. If stat successfully, it will return the file information."
8483
)]
8584
Stat(stat::StatCommand),
86-
87-
#[command(
88-
name = "rm",
89-
author,
90-
version,
91-
about = "Remove a file from Dragonfly P2P network",
92-
long_about = "Remove the P2P cache in Dragonfly P2P network by task ID."
93-
)]
94-
Remove(remove::RemoveCommand),
9585
}
9686

9787
/// Implement the execute for Command.
@@ -102,7 +92,6 @@ impl Command {
10292
Self::Import(cmd) => cmd.execute().await,
10393
Self::Export(cmd) => cmd.execute().await,
10494
Self::Stat(cmd) => cmd.execute().await,
105-
Self::Remove(cmd) => cmd.execute().await,
10695
}
10796
}
10897
}

0 commit comments

Comments
 (0)