Fix backup creation for collections > 1 GiB (#2423)

Co-authored-by: Damien Elmes <dae@users.noreply.github.com>
This commit is contained in:
RumovZ 2023-03-06 10:56:27 +01:00 committed by GitHub
parent 430a58a0d4
commit 0d92bd2ca8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 32 additions and 2 deletions

View File

@ -16,7 +16,7 @@ use itertools::Itertools;
use tracing::error;
use crate::import_export::package::export_colpkg_from_data;
use crate::io::read_file;
use crate::io::read_locked_db_file;
use crate::pb::config::preferences::BackupLimits;
use crate::prelude::*;
@ -39,7 +39,7 @@ impl Collection {
} else {
let tr = self.tr.clone();
self.storage.checkpoint()?;
let col_data = read_file(&self.col_path)?;
let col_data = read_locked_db_file(&self.col_path)?;
self.update_last_backup_timestamp()?;
Ok(Some(thread::spawn(move || {
backup_inner(&col_data, &backup_folder, limits, &tr)

View File

@ -2,6 +2,8 @@
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
use std::fs::File;
use std::io::Read;
use std::io::Seek;
use std::path::Component;
use std::path::Path;
@ -63,6 +65,34 @@ pub(crate) fn read_file(path: impl AsRef<Path>) -> Result<Vec<u8>> {
})
}
/// Like [read_file], but skips the section that is potentially locked by
/// SQLite.
pub(crate) fn read_locked_db_file(path: impl AsRef<Path>) -> Result<Vec<u8>> {
read_locked_db_file_inner(&path).context(FileIoSnafu {
path: path.as_ref(),
op: FileOp::Read,
})
}
const LOCKED_SECTION_START_BYTE: usize = 1024 * 1024 * 1024;
const LOCKED_SECTION_LEN_BYTES: usize = 512;
const LOCKED_SECTION_END_BYTE: usize = LOCKED_SECTION_START_BYTE + LOCKED_SECTION_LEN_BYTES;
fn read_locked_db_file_inner(path: impl AsRef<Path>) -> std::io::Result<Vec<u8>> {
let size = std::fs::metadata(&path)?.len() as usize;
if size < LOCKED_SECTION_END_BYTE {
return std::fs::read(path);
}
let mut file = File::open(&path)?;
let mut buf = vec![0; size];
file.read_exact(&mut buf[..LOCKED_SECTION_START_BYTE])?;
file.seek(std::io::SeekFrom::Current(LOCKED_SECTION_LEN_BYTES as i64))?;
file.read_exact(&mut buf[LOCKED_SECTION_END_BYTE..])?;
Ok(buf)
}
pub(crate) fn new_tempfile() -> Result<NamedTempFile> {
NamedTempFile::new().context(FileIoSnafu {
path: std::env::temp_dir(),