feat(mobilebackup2): Transactional backups#101
Conversation
|
Hey thanks for the draft, excited to see where this goes. Is it not possible to implement your journal system with the current trait system? Do you mind dropping the commit for CarPlay? |
8ef8808 to
762da2a
Compare
|
There are some options for the changes needed to support clean transactional backups, this is your call. The new trait is not radically different from the old one. It mostly changes the semantics around path handling and file replacement. The current public trait is approximately: pub trait BackupDelegate: Send + Sync {
fn get_free_disk_space(&self, path: &Path) -> u64;
fn open_file_read(&self, path: &Path) -> Future<Result<Box<dyn Read + Send>>>;
fn create_file_write(&self, path: &Path) -> Future<Result<Box<dyn Write + Send>>>;
fn create_dir_all(&self, path: &Path) -> Future<Result<()>>;
fn remove(&self, path: &Path) -> Future<Result<()>>;
fn rename(&self, from: &Path, to: &Path) -> Future<Result<()>>;
fn copy(&self, src: &Path, dst: &Path) -> Future<Result<()>>;
fn exists(&self, path: &Path) -> Future<bool>;
fn is_dir(&self, path: &Path) -> Future<bool>;
fn list_dir(&self, path: &Path) -> Future<Result<Vec<DirEntryInfo>>>;
fn on_file_received(&self, path: &str, file_count: u32) {}
fn on_progress(&self, bytes_done: u64, bytes_total: u64, overall_progress: f64) {}
}My proposed internal/new trait is approximately: #[async_trait]
pub trait BackupStore: Send {
fn get_free_disk_space(&self) -> u64;
async fn open_file_read(
&self,
path: &BackupPath,
) -> Result<Box<dyn Read + Send>, IdeviceError>;
async fn begin_replace(
&mut self,
path: &BackupPath,
) -> Result<Box<dyn BackupFileReplacement + Send>, IdeviceError>;
async fn create_dir_all(&mut self, path: &BackupPath) -> Result<(), IdeviceError>;
async fn remove(&mut self, path: &BackupPath) -> Result<(), IdeviceError>;
async fn rename(&mut self, from: &BackupPath, to: &BackupPath) -> Result<(), IdeviceError>;
async fn copy(&mut self, src: &BackupPath, dst: &BackupPath) -> Result<(), IdeviceError>;
async fn exists(&self, path: &BackupPath) -> bool;
async fn is_dir(&self, path: &BackupPath) -> bool;
async fn list_dir(&self, path: &BackupPath) -> Result<Vec<DirEntryInfo>, IdeviceError>;
fn on_file_received(&self, path: &BackupPath, file_count: u32) {}
fn on_progress(&self, bytes_done: u64, bytes_total: u64, overall_progress: f64) {}
}
pub trait BackupFileReplacement: Write + Send {
async fn finish(self: Box<Self>) -> Result<(), IdeviceError>;
async fn abort(self: Box<Self>) -> Result<(), IdeviceError>;
}Most of the API is the same. The meaningful changes are:
Public facing API change options
The strongest technical reason for the new shape is file upload correctness: MobileBackup2 gives us the final success/error status after the file stream, while I think keeping both traits public and marking BackupDelegate as deprecated would be reasonable? |
|
Ok, just wanted to check first, you are actually writing this code, correct? I understand that LLMs can be used as a tool to help and clean, but for a change this deep I'd prefer that a human is actually the one authoring and understanding this.
No thanks, I'd prefer the traits explicitly written as they are now until async traits are stable in the language itself. Under the hood, we are basically doing the same thing anyways.
I don't understand what the difference is. Path already isn't validated against a real file system, it's just a chain of strings.
In the current architecture, this can already done, no?
makes sense to me
where backup support wasn't added that long ago, I'd say just replace it. As per the readme, we are explicitly not stable yet until 0.2.0, and the changes aren't that drastic for the end user. FFI shouldn't change much either. |
WIP: Keep a journal for rollback of backup on-disk state when the backup is aborted/interrupted before finishing.
Introducing some breaking changes (existing code is migrated, we might still want to keep unjournaled backups around?) -> Replacing BackupDelegate with a new API
BackupStorewhich natively supports transactional-style operations.