feat: store backup sizes in metadata file
							parent
							
								
									a4a03ca4c5
								
							
						
					
					
						commit
						c5193f0f3c
					
				|  | @ -13,7 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
|     * Chain length describes how many incremental backups to create from the | ||||
|       same full backup | ||||
|     * "backups to keep" has been replaced by "chains to keep" | ||||
| * Server type & version is now stored as metadata in the metadata file | ||||
| * Server type & version and backup size are now stored as metadata in the | ||||
|   metadata file | ||||
| * Backup layers | ||||
|     * Store multiple chains of backups in parallel, configuring each with | ||||
|       different parameters (son-father-grandfather principle) | ||||
|  |  | |||
							
								
								
									
										14
									
								
								Dockerfile
								
								
								
								
							
							
						
						
									
										14
									
								
								Dockerfile
								
								
								
								
							|  | @ -47,13 +47,15 @@ COPY --from=builder /app/target/debug/alex /bin/alex | |||
| RUN chmod +x /bin/alex | ||||
| 
 | ||||
| # Default value to keep users from eating up all ram accidentally | ||||
| ENV ALEX_XMS=1024 \ | ||||
| ENV ALEX_CONFIG_DIR=/app/config \ | ||||
|     ALEX_WORLD_DIR=/app/worlds \ | ||||
|     ALEX_BACKUP_DIR=/app/backups \ | ||||
|     ALEX_SERVER=paper \ | ||||
|     ALEX_XMS=1024 \ | ||||
|     ALEX_XMX=2048 \ | ||||
|     ALEX_JAR=/app/server.jar \ | ||||
|     ALEX_CONFIG_DIR=/app/config \ | ||||
|     ALEX_WORLD_DIR=/app/worlds \ | ||||
|     ALEX_BACKUPS_DIR=/app/backups \ | ||||
|     ALEX_SERVER_VERSION="${MC_VERSION}-${PAPERMC_VERSION}" | ||||
|     ALEX_SERVER_VERSION="${MC_VERSION}-${PAPERMC_VERSION}" \ | ||||
|     ALEX_LAYERS="2min,2,4,4;3min,3,2,2" | ||||
| 
 | ||||
| # Document exposed ports | ||||
| EXPOSE 25565 | ||||
|  | @ -62,4 +64,4 @@ EXPOSE 25565 | |||
| USER paper:paper | ||||
| 
 | ||||
| ENTRYPOINT ["/bin/dumb-init", "--"] | ||||
| CMD ["/bin/alex", "paper"] | ||||
| CMD ["/bin/alex", "run"] | ||||
|  |  | |||
|  | @ -0,0 +1,43 @@ | |||
| use std::io::{self, Write}; | ||||
| 
 | ||||
| /// Wrapper around the Write trait that counts how many bytes have been written in total.
 | ||||
| /// Heavily inspired by https://stackoverflow.com/a/42189386
 | ||||
| pub struct CountingWrite<W> { | ||||
|     inner: W, | ||||
|     count: usize, | ||||
| } | ||||
| 
 | ||||
| impl<W> CountingWrite<W> | ||||
| where | ||||
|     W: Write, | ||||
| { | ||||
|     pub fn new(writer: W) -> Self { | ||||
|         Self { | ||||
|             inner: writer, | ||||
|             count: 0, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn bytes_written(&self) -> usize { | ||||
|         self.count | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<W> Write for CountingWrite<W> | ||||
| where | ||||
|     W: Write, | ||||
| { | ||||
|     fn write(&mut self, buf: &[u8]) -> io::Result<usize> { | ||||
|         let res = self.inner.write(buf); | ||||
| 
 | ||||
|         if let Ok(count) = res { | ||||
|             self.count += count; | ||||
|         } | ||||
| 
 | ||||
|         res | ||||
|     } | ||||
| 
 | ||||
|     fn flush(&mut self) -> io::Result<()> { | ||||
|         self.inner.flush() | ||||
|     } | ||||
| } | ||||
|  | @ -1,4 +1,5 @@ | |||
| mod delta; | ||||
| mod io_ext; | ||||
| pub mod manager; | ||||
| mod path; | ||||
| 
 | ||||
|  | @ -30,6 +31,7 @@ pub enum BackupType { | |||
| pub struct Backup<T: Clone> { | ||||
|     /// When the backup was started (also corresponds to the name)
 | ||||
|     pub start_time: chrono::DateTime<Utc>, | ||||
|     pub size: usize, | ||||
|     /// Type of the backup
 | ||||
|     pub type_: BackupType, | ||||
|     pub delta: Delta, | ||||
|  | @ -84,7 +86,7 @@ impl<T: Clone> Backup<T> { | |||
|         let start_time = chrono::offset::Utc::now(); | ||||
| 
 | ||||
|         let path = Backup::path(backup_dir, start_time); | ||||
|         let tar_gz = File::create(path)?; | ||||
|         let tar_gz = io_ext::CountingWrite::new(File::create(path)?); | ||||
|         let enc = GzEncoder::new(tar_gz, Compression::default()); | ||||
|         let mut ar = tar::Builder::new(enc); | ||||
| 
 | ||||
|  | @ -104,9 +106,16 @@ impl<T: Clone> Backup<T> { | |||
|             delta.added.insert(dir_in_tar.to_path_buf(), added_files); | ||||
|         } | ||||
| 
 | ||||
|         let mut enc = ar.into_inner()?; | ||||
| 
 | ||||
|         // The docs recommend running try_finish before unwrapping using finish
 | ||||
|         enc.try_finish()?; | ||||
|         let tar_gz = enc.finish()?; | ||||
| 
 | ||||
|         Ok(Backup { | ||||
|             type_: BackupType::Full, | ||||
|             start_time, | ||||
|             size: tar_gz.bytes_written(), | ||||
|             delta, | ||||
|             metadata: None, | ||||
|         }) | ||||
|  | @ -122,7 +131,7 @@ impl<T: Clone> Backup<T> { | |||
|         let start_time = chrono::offset::Utc::now(); | ||||
| 
 | ||||
|         let path = Backup::path(backup_dir, start_time); | ||||
|         let tar_gz = File::create(path)?; | ||||
|         let tar_gz = io_ext::CountingWrite::new(File::create(path)?); | ||||
|         let enc = GzEncoder::new(tar_gz, Compression::default()); | ||||
|         let mut ar = tar::Builder::new(enc); | ||||
| 
 | ||||
|  | @ -154,9 +163,16 @@ impl<T: Clone> Backup<T> { | |||
|             } | ||||
|         } | ||||
| 
 | ||||
|         let mut enc = ar.into_inner()?; | ||||
| 
 | ||||
|         // The docs recommend running try_finish before unwrapping using finish
 | ||||
|         enc.try_finish()?; | ||||
|         let tar_gz = enc.finish()?; | ||||
| 
 | ||||
|         Ok(Backup { | ||||
|             type_: BackupType::Incremental, | ||||
|             start_time, | ||||
|             size: tar_gz.bytes_written(), | ||||
|             delta, | ||||
|             metadata: None, | ||||
|         }) | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue