Compare commits

..

3 commits

Author SHA1 Message Date
3661a597fa Merge pull request 'feat: add use_local_tz configuration' (#908) from ragazenta/garage:feat/local-timezone into main
Reviewed-on: Deuxfleurs/garage#908
Reviewed-by: maximilien <me@mricher.fr>
2024-12-01 13:23:24 +00:00
0fd3c0e794
doc: add use_local_tz configuration 2024-11-25 10:35:00 +07:00
4c1bf42192
feat: add use_local_tz configuration
Used in lifecycle_worker to determine midnight time
2024-11-23 05:51:12 +07:00
7 changed files with 31 additions and 54 deletions

12
Cargo.lock generated
View file

@ -1355,7 +1355,6 @@ dependencies = [
"tokio", "tokio",
"toml", "toml",
"tracing", "tracing",
"tracing-journald",
"tracing-subscriber", "tracing-subscriber",
] ]
@ -4407,17 +4406,6 @@ dependencies = [
"tracing", "tracing",
] ]
[[package]]
name = "tracing-journald"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba316a74e8fc3c3896a850dba2375928a9fa171b085ecddfc7c054d39970f3fd"
dependencies = [
"libc",
"tracing-core",
"tracing-subscriber",
]
[[package]] [[package]]
name = "tracing-log" name = "tracing-log"
version = "0.2.0" version = "0.2.0"

View file

@ -79,7 +79,6 @@ pretty_env_logger = "0.5"
structopt = { version = "0.3", default-features = false } structopt = { version = "0.3", default-features = false }
syslog-tracing = "0.3" syslog-tracing = "0.3"
tracing = "0.1" tracing = "0.1"
tracing-journald = "0.3"
tracing-subscriber = { version = "0.3", features = ["env-filter"] } tracing-subscriber = { version = "0.3", features = ["env-filter"] }
heed = { version = "0.11", default-features = false, features = ["lmdb"] } heed = { version = "0.11", default-features = false, features = ["lmdb"] }

View file

@ -16,6 +16,7 @@ data_dir = "/var/lib/garage/data"
metadata_fsync = true metadata_fsync = true
data_fsync = false data_fsync = false
disable_scrub = false disable_scrub = false
use_local_tz = false
metadata_auto_snapshot_interval = "6h" metadata_auto_snapshot_interval = "6h"
db_engine = "lmdb" db_engine = "lmdb"
@ -99,6 +100,7 @@ Top-level configuration options:
[`data_fsync`](#data_fsync), [`data_fsync`](#data_fsync),
[`db_engine`](#db_engine), [`db_engine`](#db_engine),
[`disable_scrub`](#disable_scrub), [`disable_scrub`](#disable_scrub),
[`use_local_tz`](#use_local_tz),
[`lmdb_map_size`](#lmdb_map_size), [`lmdb_map_size`](#lmdb_map_size),
[`metadata_auto_snapshot_interval`](#metadata_auto_snapshot_interval), [`metadata_auto_snapshot_interval`](#metadata_auto_snapshot_interval),
[`metadata_dir`](#metadata_dir), [`metadata_dir`](#metadata_dir),
@ -427,6 +429,13 @@ you should delete it from the data directory and then call `garage repair
blocks` on the node to ensure that it re-obtains a copy from another node on blocks` on the node to ensure that it re-obtains a copy from another node on
the network. the network.
#### `use_local_tz` {#use_local_tz}
By default, Garage runs the lifecycle worker every day at midnight in UTC. Set the
`use_local_tz` configuration value to `true` if you want Garage to run the
lifecycle worker at midnight in your local timezone. If you have multiple nodes,
you should also ensure that each node has the same timezone configuration.
#### `block_size` {#block_size} #### `block_size` {#block_size}
Garage splits stored objects in consecutive chunks of size `block_size` Garage splits stored objects in consecutive chunks of size `block_size`

View file

@ -60,7 +60,6 @@ opentelemetry-prometheus = { workspace = true, optional = true }
opentelemetry-otlp = { workspace = true, optional = true } opentelemetry-otlp = { workspace = true, optional = true }
prometheus = { workspace = true, optional = true } prometheus = { workspace = true, optional = true }
syslog-tracing = { workspace = true, optional = true } syslog-tracing = { workspace = true, optional = true }
tracing-journald = { workspace = true, optional = true }
[dev-dependencies] [dev-dependencies]
aws-config.workspace = true aws-config.workspace = true
@ -101,8 +100,6 @@ metrics = [ "garage_api/metrics", "opentelemetry-prometheus", "prometheus" ]
telemetry-otlp = [ "opentelemetry-otlp" ] telemetry-otlp = [ "opentelemetry-otlp" ]
# Logging to syslog # Logging to syslog
syslog = [ "syslog-tracing" ] syslog = [ "syslog-tracing" ]
# Logging to journald
journald = [ "tracing-journald" ]
# NOTE: bundled-libs and system-libs should be treat as mutually exclusive; # NOTE: bundled-libs and system-libs should be treat as mutually exclusive;
# exactly one of them should be enabled. # exactly one of them should be enabled.

View file

@ -208,36 +208,6 @@ fn init_logging(opt: &Opt) {
} }
} }
if std::env::var("GARAGE_LOG_TO_JOURNALD")
.map(|x| x == "1" || x == "true")
.unwrap_or(false)
{
#[cfg(feature = "journald")]
{
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
let registry = tracing_subscriber::registry()
.with(tracing_subscriber::fmt::layer().with_writer(std::io::sink))
.with(env_filter);
match tracing_journald::layer() {
Ok(layer) => {
registry.with(layer).init();
}
Err(e) => {
eprintln!("Couldn't connect to journald: {}.", e);
std::process::exit(1);
}
}
return;
}
#[cfg(not(feature = "journald"))]
{
eprintln!("Journald support is not enabled in this build.");
std::process::exit(1);
}
}
tracing_subscriber::fmt() tracing_subscriber::fmt()
.with_writer(std::io::stderr) .with_writer(std::io::stderr)
.with_env_filter(env_filter) .with_env_filter(env_filter)

View file

@ -70,7 +70,7 @@ pub fn register_bg_vars(
impl LifecycleWorker { impl LifecycleWorker {
pub fn new(garage: Arc<Garage>, persister: PersisterShared<LifecycleWorkerPersisted>) -> Self { pub fn new(garage: Arc<Garage>, persister: PersisterShared<LifecycleWorkerPersisted>) -> Self {
let today = today(); let today = today(garage.config.use_local_tz);
let last_completed = persister.get_with(|x| { let last_completed = persister.get_with(|x| {
x.last_completed x.last_completed
.as_deref() .as_deref()
@ -205,8 +205,9 @@ impl Worker for LifecycleWorker {
async fn wait_for_work(&mut self) -> WorkerState { async fn wait_for_work(&mut self) -> WorkerState {
match &self.state { match &self.state {
State::Completed(d) => { State::Completed(d) => {
let use_local_tz = self.garage.config.use_local_tz;
let next_day = d.succ_opt().expect("no next day"); let next_day = d.succ_opt().expect("no next day");
let next_start = midnight_ts(next_day); let next_start = midnight_ts(next_day, use_local_tz);
loop { loop {
let now = now_msec(); let now = now_msec();
if now < next_start { if now < next_start {
@ -218,7 +219,7 @@ impl Worker for LifecycleWorker {
break; break;
} }
} }
self.state = State::start(std::cmp::max(next_day, today())); self.state = State::start(std::cmp::max(next_day, today(use_local_tz)));
} }
State::Running { .. } => (), State::Running { .. } => (),
} }
@ -385,10 +386,16 @@ fn check_size_filter(version_data: &ObjectVersionData, filter: &LifecycleFilter)
true true
} }
fn midnight_ts(date: NaiveDate) -> u64 { fn midnight_ts(date: NaiveDate, use_local_tz: bool) -> u64 {
date.and_hms_opt(0, 0, 0) let midnight = date.and_hms_opt(0, 0, 0).expect("midnight does not exist");
.expect("midnight does not exist") if use_local_tz {
.timestamp_millis() as u64 return midnight
.and_local_timezone(Local)
.single()
.expect("bad local midnight")
.timestamp_millis() as u64;
}
midnight.timestamp_millis() as u64
} }
fn next_date(ts: u64) -> NaiveDate { fn next_date(ts: u64) -> NaiveDate {
@ -399,6 +406,9 @@ fn next_date(ts: u64) -> NaiveDate {
.expect("no next day") .expect("no next day")
} }
fn today() -> NaiveDate { fn today(use_local_tz: bool) -> NaiveDate {
if use_local_tz {
return Local::now().naive_local().date();
}
Utc::now().naive_utc().date() Utc::now().naive_utc().date()
} }

View file

@ -27,6 +27,10 @@ pub struct Config {
#[serde(default)] #[serde(default)]
pub disable_scrub: bool, pub disable_scrub: bool,
/// Use local timezone
#[serde(default)]
pub use_local_tz: bool,
/// Automatic snapshot interval for metadata /// Automatic snapshot interval for metadata
#[serde(default)] #[serde(default)]
pub metadata_auto_snapshot_interval: Option<String>, pub metadata_auto_snapshot_interval: Option<String>,