Merge branch 'main' into next-0.10

This commit is contained in:
Alex Auvolat
2024-03-26 16:34:40 +01:00
12 changed files with 166 additions and 190 deletions
+48 -12
View File
@@ -1,3 +1,4 @@
use std::collections::HashMap;
use std::path::PathBuf;
use serde::{Deserialize, Serialize};
@@ -13,9 +14,12 @@ const DRIVE_NPART: usize = 1024;
const HASH_DRIVE_BYTES: (usize, usize) = (2, 3);
const MARKER_FILE_NAME: &str = "garage-marker";
#[derive(Serialize, Deserialize, Debug, Clone)]
pub(crate) struct DataLayout {
pub(crate) data_dirs: Vec<DataDir>,
markers: HashMap<PathBuf, String>,
/// Primary storage location (index in data_dirs) for each partition
/// = the location where the data is supposed to be, blocks are always
@@ -75,16 +79,17 @@ impl DataLayout {
Ok(Self {
data_dirs,
markers: HashMap::new(),
part_prim,
part_sec,
})
}
pub(crate) fn update(&mut self, dirs: &DataDirEnum) -> Result<(), Error> {
pub(crate) fn update(self, dirs: &DataDirEnum) -> Result<Self, Error> {
// Make list of new data directories, exit if nothing changed
let data_dirs = make_data_dirs(dirs)?;
if data_dirs == self.data_dirs {
return Ok(());
return Ok(self);
}
let total_cap = data_dirs.iter().filter_map(|x| x.capacity()).sum::<u64>();
@@ -214,11 +219,43 @@ impl DataLayout {
}
// Apply newly generated config
*self = Self {
Ok(Self {
data_dirs,
markers: self.markers,
part_prim,
part_sec,
};
})
}
pub(crate) fn check_markers(&mut self) -> Result<(), Error> {
let data_dirs = &self.data_dirs;
self.markers
.retain(|k, _| data_dirs.iter().any(|x| x.path == *k));
for dir in self.data_dirs.iter() {
let mut marker_path = dir.path.clone();
marker_path.push(MARKER_FILE_NAME);
let existing_marker = std::fs::read_to_string(&marker_path).ok();
match (existing_marker, self.markers.get(&dir.path)) {
(Some(m1), Some(m2)) => {
if m1 != *m2 {
return Err(Error::Message(format!("Mismatched content for marker file `{}` in data directory `{}`. If you moved data directories or changed their mountpoints, you should remove the `data_layout` file in Garage's metadata directory and restart Garage.", MARKER_FILE_NAME, dir.path.display())));
}
}
(None, Some(_)) => {
return Err(Error::Message(format!("Could not find expected marker file `{}` in data directory `{}`, make sure this data directory is mounted correctly.", MARKER_FILE_NAME, dir.path.display())));
}
(Some(mkr), None) => {
self.markers.insert(dir.path.clone(), mkr);
}
(None, None) => {
let mkr = hex::encode(garage_util::data::gen_uuid().as_slice());
std::fs::write(&marker_path, &mkr)?;
self.markers.insert(dir.path.clone(), mkr);
}
}
}
Ok(())
}
@@ -255,6 +292,7 @@ impl DataLayout {
pub(crate) fn without_secondary_locations(&self) -> Self {
Self {
data_dirs: self.data_dirs.clone(),
markers: self.markers.clone(),
part_prim: self.part_prim.clone(),
part_sec: self.part_sec.iter().map(|_| vec![]).collect::<Vec<_>>(),
}
@@ -322,14 +360,12 @@ fn make_data_dirs(dirs: &DataDirEnum) -> Result<Vec<DataDir>, Error> {
fn dir_not_empty(path: &PathBuf) -> Result<bool, Error> {
for entry in std::fs::read_dir(&path)? {
let dir = entry?;
if dir.file_type()?.is_dir()
&& dir
.file_name()
.into_string()
.ok()
.and_then(|hex| hex::decode(&hex).ok())
.is_some()
{
let ft = dir.file_type()?;
let name = dir.file_name().into_string().ok();
if ft.is_file() && name.as_deref() == Some(MARKER_FILE_NAME) {
return Ok(true);
}
if ft.is_dir() && name.and_then(|hex| hex::decode(&hex).ok()).is_some() {
return Ok(true);
}
}
+5 -7
View File
@@ -127,17 +127,15 @@ impl BlockManager {
// Load or compute layout, i.e. assignment of data blocks to the different data directories
let data_layout_persister: Persister<DataLayout> =
Persister::new(&system.metadata_dir, "data_layout");
let data_layout = match data_layout_persister.load() {
Ok(mut layout) => {
layout
.update(&config.data_dir)
.ok_or_message("invalid data_dir config")?;
layout
}
let mut data_layout = match data_layout_persister.load() {
Ok(layout) => layout
.update(&config.data_dir)
.ok_or_message("invalid data_dir config")?,
Err(_) => {
DataLayout::initialize(&config.data_dir).ok_or_message("invalid data_dir config")?
}
};
data_layout.check_markers()?;
data_layout_persister
.save(&data_layout)
.expect("cannot save data_layout");
+3
View File
@@ -59,6 +59,7 @@ opentelemetry.workspace = true
opentelemetry-prometheus = { workspace = true, optional = true }
opentelemetry-otlp = { workspace = true, optional = true }
prometheus = { workspace = true, optional = true }
syslog-tracing = { workspace = true, optional = true }
[dev-dependencies]
aws-config.workspace = true
@@ -97,6 +98,8 @@ kubernetes-discovery = [ "garage_rpc/kubernetes-discovery" ]
metrics = [ "garage_api/metrics", "opentelemetry-prometheus", "prometheus" ]
# Exporter for the OpenTelemetry Collector.
telemetry-otlp = [ "opentelemetry-otlp" ]
# Logging to syslog
syslog = [ "syslog-tracing" ]
# NOTE: bundled-libs and system-libs should be treat as mutually exclusive;
# exactly one of them should be enabled.
+54 -11
View File
@@ -138,17 +138,8 @@ async fn main() {
let opt = Opt::from_clap(&Opt::clap().version(version.as_str()).get_matches());
// Initialize logging as well as other libraries used in Garage
if std::env::var("RUST_LOG").is_err() {
let default_log = match &opt.cmd {
Command::Server => "netapp=info,garage=info",
_ => "netapp=warn,garage=warn",
};
std::env::set_var("RUST_LOG", default_log)
}
tracing_subscriber::fmt()
.with_writer(std::io::stderr)
.with_env_filter(tracing_subscriber::filter::EnvFilter::from_default_env())
.init();
init_logging(&opt);
sodiumoxide::init().expect("Unable to init sodiumoxide");
let res = match opt.cmd {
@@ -171,6 +162,58 @@ async fn main() {
}
}
fn init_logging(opt: &Opt) {
if std::env::var("RUST_LOG").is_err() {
let default_log = match &opt.cmd {
Command::Server => "netapp=info,garage=info",
_ => "netapp=warn,garage=warn",
};
std::env::set_var("RUST_LOG", default_log)
}
let env_filter = tracing_subscriber::filter::EnvFilter::from_default_env();
if std::env::var("GARAGE_LOG_TO_SYSLOG")
.map(|x| x == "1" || x == "true")
.unwrap_or(false)
{
#[cfg(feature = "syslog")]
{
use std::ffi::CStr;
use syslog_tracing::{Facility, Options, Syslog};
let syslog = Syslog::new(
CStr::from_bytes_with_nul(b"garage\0").unwrap(),
Options::LOG_PID | Options::LOG_PERROR,
Facility::Daemon,
)
.expect("Unable to init syslog");
tracing_subscriber::fmt()
.with_writer(syslog)
.with_env_filter(env_filter)
.with_ansi(false) // disable ANSI escape sequences (colours)
.with_file(false)
.with_level(false)
.without_time()
.compact()
.init();
return;
}
#[cfg(not(feature = "syslog"))]
{
eprintln!("Syslog support is not enabled in this build.");
std::process::exit(1);
}
}
tracing_subscriber::fmt()
.with_writer(std::io::stderr)
.with_env_filter(env_filter)
.init();
}
async fn cli_command(opt: Opt) -> Result<(), Error> {
let config = if (opt.secrets.rpc_secret.is_none() && opt.secrets.rpc_secret_file.is_none())
|| opt.rpc_host.is_none()
+2
View File
@@ -10,6 +10,7 @@ use crate::common;
use crate::json_body;
#[tokio::test]
#[ignore = "currently broken"]
async fn test_poll_item() {
let ctx = common::context();
let bucket = ctx.create_bucket("test-k2v-poll-item");
@@ -98,6 +99,7 @@ async fn test_poll_item() {
}
#[tokio::test]
#[ignore = "currently broken"]
async fn test_poll_range() {
let ctx = common::context();
let bucket = ctx.create_bucket("test-k2v-poll-range");