Skip to content

Commit 8394cf4

Browse files
fix: cleanup startup check process for stage and data path (#619)
* fix error message in case of deployment mismatch * data directory creation should not happen in case of deployment mismatch * staging should be overwritten in case of new staging * default staging and data directory should not be created if env var has different path Fixes #573
1 parent 76cd676 commit 8394cf4

File tree

6 files changed

+37
-24
lines changed

6 files changed

+37
-24
lines changed

Cargo.lock

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

server/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ url = "2.4.0"
102102
http-auth-basic = "0.3.3"
103103
serde_repr = "0.1.17"
104104
hashlru = { version = "0.11.0", features = ["serde"] }
105+
path-clean = "1.0.1"
105106

106107
[build-dependencies]
107108
cargo_toml = "0.15"

server/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ use crate::localcache::LocalCacheManager;
5555
async fn main() -> anyhow::Result<()> {
5656
env_logger::init();
5757
let storage = CONFIG.storage().get_object_store();
58-
CONFIG.validate_staging()?;
5958
migration::run_metadata_migration(&CONFIG).await?;
6059
let metadata = storage::resolve_parseable_metadata().await?;
60+
CONFIG.validate_staging()?;
6161
banner::print(&CONFIG, &metadata).await;
6262
rbac::map::init(&metadata);
6363
metadata.set_global();

server/src/option.rs

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ use clap::{command, value_parser, Arg, ArgGroup, Args, Command, FromArgMatches};
2121

2222
use once_cell::sync::Lazy;
2323
use parquet::basic::{BrotliLevel, GzipLevel, ZstdLevel};
24-
use std::path::{Path, PathBuf};
24+
use std::env;
25+
use std::path::PathBuf;
2526
use std::sync::Arc;
2627
use url::Url;
2728

@@ -43,15 +44,14 @@ pub struct Config {
4344
impl Config {
4445
fn new() -> Self {
4546
let cli = parseable_cli_command().get_matches();
46-
4747
match cli.subcommand() {
4848
Some(("local-store", m)) => {
4949
let server = match Server::from_arg_matches(m) {
5050
Ok(server) => server,
5151
Err(err) => err.exit(),
5252
};
5353
let storage = match FSConfig::from_arg_matches(m) {
54-
Ok(server) => server,
54+
Ok(storage) => storage,
5555
Err(err) => err.exit(),
5656
};
5757

@@ -85,7 +85,7 @@ impl Config {
8585
Err(err) => err.exit(),
8686
};
8787
let storage = match S3Config::from_arg_matches(m) {
88-
Ok(server) => server,
88+
Ok(storage) => storage,
8989
Err(err) => err.exit(),
9090
};
9191

@@ -108,7 +108,7 @@ impl Config {
108108
self.storage.clone()
109109
}
110110

111-
pub fn staging_dir(&self) -> &Path {
111+
pub fn staging_dir(&self) -> &PathBuf {
112112
&self.parseable.local_staging_path
113113
}
114114

@@ -611,12 +611,14 @@ impl From<Compression> for parquet::basic::Compression {
611611

612612
pub mod validation {
613613
use std::{
614-
fs::{canonicalize, create_dir_all},
614+
env, io,
615615
net::ToSocketAddrs,
616-
path::PathBuf,
616+
path::{Path, PathBuf},
617617
str::FromStr,
618618
};
619619

620+
use path_clean::PathClean;
621+
620622
use crate::option::MIN_CACHE_SIZE_BYTES;
621623
use crate::storage::LOCAL_SYNC_INTERVAL;
622624
use human_size::{multiples, SpecificSize};
@@ -634,16 +636,22 @@ pub mod validation {
634636

635637
Ok(path)
636638
}
639+
pub fn absolute_path(path: impl AsRef<Path>) -> io::Result<PathBuf> {
640+
let path = path.as_ref();
641+
642+
let absolute_path = if path.is_absolute() {
643+
path.to_path_buf()
644+
} else {
645+
env::current_dir()?.join(path)
646+
}
647+
.clean();
648+
649+
Ok(absolute_path)
650+
}
637651

638652
pub fn canonicalize_path(s: &str) -> Result<PathBuf, String> {
639653
let path = PathBuf::from(s);
640-
641-
create_dir_all(&path)
642-
.map_err(|err| err.to_string())
643-
.and_then(|_| {
644-
canonicalize(&path)
645-
.map_err(|_| "Cannot use the path provided as an absolute path".to_string())
646-
})
654+
Ok(absolute_path(path).unwrap())
647655
}
648656

649657
pub fn socket_addr(s: &str) -> Result<String, String> {

server/src/storage/localfs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ impl ObjectStorage for LocalFS {
187187
};
188188
let to_path = self.root.join(key);
189189
if let Some(path) = to_path.parent() {
190-
fs::create_dir_all(path).await?
190+
fs::create_dir_all(path).await?;
191191
}
192192
let _ = fs_extra::file::copy(path, to_path, &op)?;
193193
Ok(())

server/src/storage/store_metadata.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ impl StorageMetadata {
6666
Self {
6767
version: "v3".to_string(),
6868
mode: CONFIG.storage_name.to_owned(),
69-
staging: CONFIG.staging_dir().canonicalize().unwrap(),
69+
staging: CONFIG.staging_dir().to_path_buf(),
7070
storage: CONFIG.storage().get_endpoint(),
7171
deployment_id: uid::gen(),
7272
users: Vec::new(),
@@ -104,7 +104,7 @@ pub async fn resolve_parseable_metadata() -> Result<StorageMetadata, ObjectStora
104104
if staging.deployment_id == remote.deployment_id {
105105
EnvChange::None(remote)
106106
} else {
107-
EnvChange::DeploymentMismatch
107+
EnvChange::NewRemote
108108
}
109109
}
110110
(None, Some(remote)) => EnvChange::NewStaging(remote),
@@ -116,16 +116,14 @@ pub async fn resolve_parseable_metadata() -> Result<StorageMetadata, ObjectStora
116116
let mut overwrite_staging = false;
117117
let mut overwrite_remote = false;
118118

119-
const MISMATCH: &str = "Could not start the server because metadata file found in staging directory does not match one in the storage";
120119
let res = match check {
121120
EnvChange::None(metadata) => {
122121
// overwrite staging anyways so that it matches remote in case of any divergence
123122
overwrite_staging = true;
124123
Ok(metadata)
125-
}
126-
EnvChange::DeploymentMismatch => Err(MISMATCH),
124+
},
127125
EnvChange::NewRemote => {
128-
Err("Could not start the server because metadata not found in storage")
126+
Err("Could not start the server because staging directory indicates stale data from previous deployment, please choose an empty staging directory and restart the server")
129127
}
130128
EnvChange::NewStaging(mut metadata) => {
131129
create_dir_all(CONFIG.staging_dir())?;
@@ -171,9 +169,8 @@ pub async fn resolve_parseable_metadata() -> Result<StorageMetadata, ObjectStora
171169
#[derive(Debug, Clone, PartialEq, Eq)]
172170
pub enum EnvChange {
173171
/// No change in env i.e both staging and remote have same id
172+
/// or deployment id of staging is not matching with that of remote
174173
None(StorageMetadata),
175-
/// Mismatch in deployment id. Cannot use this staging for this remote
176-
DeploymentMismatch,
177174
/// Metadata not found in storage. Treated as possible misconfiguration on user side.
178175
NewRemote,
179176
/// If a new staging is found then we just copy remote metadata to this staging.

0 commit comments

Comments
 (0)