feat: configurable parameters for incremental backups
ci/woodpecker/push/lint Pipeline was successful Details
ci/woodpecker/push/clippy Pipeline failed Details
ci/woodpecker/push/build Pipeline was successful Details

incremental-backups
Jef Roosens 2023-06-18 22:45:35 +02:00
parent b51d951688
commit b48c531d80
Signed by: Jef Roosens
GPG Key ID: B75D4F293C7052DB
5 changed files with 51 additions and 31 deletions

View File

@ -9,12 +9,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
* Added `backup` CLI command * `backup` CLI command
* Incremental backups
* Chain length descibres how many incremental backups to create from the
same full backup
* "backups to keep" has been replaced by "chains to keep"
### Changed ### Changed
* Running the server now uses the `run` CLI subcommand * Running the server now uses the `run` CLI subcommand
### Removed
* `max_backups` setting
## [0.2.2](https://git.rustybever.be/Chewing_Bever/alex/src/tag/0.2.2) ## [0.2.2](https://git.rustybever.be/Chewing_Bever/alex/src/tag/0.2.2)
### Fixed ### Fixed

View File

@ -35,15 +35,24 @@ pub struct Cli {
)] )]
pub backup: PathBuf, pub backup: PathBuf,
/// How many backups to keep /// Length of a backup chain
#[arg(
short = 'l',
long,
default_value_t = 4,
env = "ALEX_CHAIN_LEN",
global = true
)]
pub chain_len: u64,
/// How many backup chains to keep
#[arg( #[arg(
short = 'n', short = 'n',
long, long,
default_value_t = 7, default_value_t = 7,
env = "ALEX_MAX_BACKUPS", env = "ALEX_CHAINS",
global = true global = true
)] )]
pub max_backups: u64, pub chains: u64,
} }
#[derive(Subcommand)] #[derive(Subcommand)]

View File

@ -32,7 +32,8 @@ fn command_run(cli: &Cli, args: &RunArgs) -> io::Result<()> {
.backup(cli.backup.clone()) .backup(cli.backup.clone())
.xms(args.xms) .xms(args.xms)
.xmx(args.xmx) .xmx(args.xmx)
.max_backups(cli.max_backups); .chain_len(cli.chain_len)
.chains_to_keep(cli.chains);
cmd.canonicalize()?; cmd.canonicalize()?;
if args.dry { if args.dry {
@ -58,12 +59,13 @@ fn command_run(cli: &Cli, args: &RunArgs) -> io::Result<()> {
} }
fn commands_backup(cli: &Cli, _args: &BackupArgs) -> io::Result<()> { fn commands_backup(cli: &Cli, _args: &BackupArgs) -> io::Result<()> {
let mut manager = server::BackupManager::open( let mut manager = server::BackupManager::new(
cli.backup.clone(), cli.backup.clone(),
cli.config.clone(), cli.config.clone(),
cli.world.clone(), cli.world.clone(),
cli.max_backups, cli.chain_len,
)?; cli.chains,
);
manager.create_backup()?; manager.create_backup()?;
manager.remove_old_backups() manager.remove_old_backups()

View File

@ -1,5 +1,5 @@
use crate::server::path::PathExt; use crate::server::path::PathExt;
use chrono::{Local, Utc}; use chrono::Utc;
use flate2::write::GzEncoder; use flate2::write::GzEncoder;
use flate2::Compression; use flate2::Compression;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -7,7 +7,6 @@ use std::collections::{HashMap, HashSet};
use std::fs::File; use std::fs::File;
use std::io; use std::io;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sync::Arc;
#[link(name = "c")] #[link(name = "c")]
extern "C" { extern "C" {
@ -21,13 +20,6 @@ pub enum BackupType {
Incremental, Incremental,
} }
#[derive(Debug)]
pub enum BackupError {
NoFullAncestor,
}
type BackupResult<T> = Result<T, BackupError>;
/// Represents the changes relative to the previous backup /// Represents the changes relative to the previous backup
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct BackupDelta { pub struct BackupDelta {
@ -113,6 +105,8 @@ pub struct Backup {
impl Backup { impl Backup {
const FILENAME_FORMAT: &str = "%Y-%m-%d_%H-%M-%S.tar.gz"; const FILENAME_FORMAT: &str = "%Y-%m-%d_%H-%M-%S.tar.gz";
/// Resolve the state of the list of backups by applying their deltas in-order to an initially
/// empty state.
pub fn state(backups: &Vec<Backup>) -> HashMap<PathBuf, HashSet<PathBuf>> { pub fn state(backups: &Vec<Backup>) -> HashMap<PathBuf, HashSet<PathBuf>> {
let mut state: HashMap<PathBuf, HashSet<PathBuf>> = HashMap::new(); let mut state: HashMap<PathBuf, HashSet<PathBuf>> = HashMap::new();
@ -232,29 +226,27 @@ pub struct BackupManager {
world_dir: PathBuf, world_dir: PathBuf,
chain_len: u64, chain_len: u64,
chains_to_keep: u64, chains_to_keep: u64,
max_backups: u64,
last_backup: Option<Arc<Backup>>,
chains: Vec<Vec<Backup>>, chains: Vec<Vec<Backup>>,
} }
impl BackupManager { impl BackupManager {
const METADATA_FILE: &str = "alex.json"; const METADATA_FILE: &str = "alex.json";
/// Initialize a new instance of a `BackupManager`.
pub fn new( pub fn new(
backup_dir: PathBuf, backup_dir: PathBuf,
config_dir: PathBuf, config_dir: PathBuf,
world_dir: PathBuf, world_dir: PathBuf,
max_backups: u64, chain_len: u64,
chains_to_keep: u64,
) -> Self { ) -> Self {
BackupManager { BackupManager {
backup_dir, backup_dir,
config_dir, config_dir,
world_dir, world_dir,
max_backups, chain_len,
chain_len: 2, chains_to_keep,
chains_to_keep: 1,
chains: Vec::new(), chains: Vec::new(),
last_backup: None,
} }
} }
@ -262,9 +254,10 @@ impl BackupManager {
backup_dir: PathBuf, backup_dir: PathBuf,
config_dir: PathBuf, config_dir: PathBuf,
world_dir: PathBuf, world_dir: PathBuf,
max_backups: u64, chain_len: u64,
chains_to_keep: u64,
) -> std::io::Result<Self> { ) -> std::io::Result<Self> {
let mut manager = Self::new(backup_dir, config_dir, world_dir, max_backups); let mut manager = Self::new(backup_dir, config_dir, world_dir, chain_len, chains_to_keep);
manager.load_json()?; manager.load_json()?;
Ok(manager) Ok(manager)

View File

@ -35,7 +35,8 @@ pub struct ServerCommand {
backup_dir: PathBuf, backup_dir: PathBuf,
xms: u64, xms: u64,
xmx: u64, xmx: u64,
max_backups: u64, chain_len: u64,
chains_to_keep: u64,
} }
impl ServerCommand { impl ServerCommand {
@ -50,7 +51,8 @@ impl ServerCommand {
backup_dir: PathBuf::from("backups"), backup_dir: PathBuf::from("backups"),
xms: 1024, xms: 1024,
xmx: 2048, xmx: 2048,
max_backups: 7, chain_len: 4,
chains_to_keep: 7,
} }
} }
@ -91,8 +93,13 @@ impl ServerCommand {
self self
} }
pub fn max_backups(mut self, v: u64) -> Self { pub fn chain_len(mut self, v: u64) -> Self {
self.max_backups = v; self.chain_len = v;
self
}
pub fn chains_to_keep(mut self, v: u64) -> Self {
self.chains_to_keep = v;
self self
} }
@ -183,7 +190,8 @@ impl ServerCommand {
self.backup_dir.clone(), self.backup_dir.clone(),
self.config_dir.clone(), self.config_dir.clone(),
self.world_dir.clone(), self.world_dir.clone(),
self.max_backups, self.chain_len,
self.chains_to_keep,
)?; )?;
let mut cmd = self.create_cmd(); let mut cmd = self.create_cmd();
self.accept_eula()?; self.accept_eula()?;