Skip to content

Commit

Permalink
Add migrate_kv_store_data util method
Browse files Browse the repository at this point in the history
.. allowing to migrate data from one store to another.
  • Loading branch information
tnull committed Dec 12, 2024
1 parent b75d953 commit 7bc6a5e
Showing 1 changed file with 47 additions and 0 deletions.
47 changes: 47 additions & 0 deletions lightning/src/util/persist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,53 @@ pub trait MigratableKVStore: KVStore {
fn list_all_keys(&self) -> Result<Vec<(String, String, String)>, io::Error>;
}

/// Migrates all data from one store to another.
///
/// This operation assumes that `target_store` is empty, i.e., any data present under copied keys
/// might get overriden. User must ensure `source_store` is not modified during operation,
/// otherwise no consistency guarantees can be given.
///
/// Will abort and return an error if any IO operation fails. Note that in this case the
/// `target_store` might get left in an intermediate state.
///
/// **Caution**: Will delete all data from `source_store` if `move_data` is set.
pub fn migrate_kv_store_data<S: MigratableKVStore, T: MigratableKVStore>(
source_store: &mut S, target_store: &mut T, move_data: bool,
) -> Result<(), io::Error> {
let keys_to_migrate = source_store.list_all_keys()?;

// First copy over all data.
for (primary_namespace, secondary_namespace, key) in &keys_to_migrate {
let data = source_store.read(primary_namespace, secondary_namespace, key)?;
target_store.write(primary_namespace, secondary_namespace, key, &data)?;

// Now validate what we've written.
let read_data = target_store.read(primary_namespace, secondary_namespace, &key)?;
if data != read_data {
let err =
io::Error::new(io::ErrorKind::InvalidData, "Failed to validate migrated data");
return Err(err);
}
}

// If we succeeded and `move_data` is set, remove all migrated keys.
if move_data {
for (primary_namespace, secondary_namespace, key) in &keys_to_migrate {
source_store.remove(primary_namespace, secondary_namespace, &key, false)?;
}

if !source_store.list_all_keys()?.is_empty() {
let err = io::Error::new(
io::ErrorKind::InvalidData,
"Source store is not empty. Was it modified during migration? This should never happen!"
);
return Err(err);
}
}

Ok(())
}

/// Trait that handles persisting a [`ChannelManager`], [`NetworkGraph`], and [`WriteableScore`] to disk.
///
/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
Expand Down

0 comments on commit 7bc6a5e

Please sign in to comment.