Skip to content

Commit 94ce349

Browse files
committed
Add migrate_kv_store_data util method
.. allowing to migrate data from one store to another.
1 parent 971c63f commit 94ce349

File tree

1 file changed

+47
-0
lines changed

1 file changed

+47
-0
lines changed

lightning/src/util/persist.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,53 @@ pub trait MigratableKVStore: KVStore {
176176
fn list_all_keys(&self) -> Result<Vec<(String, String, String)>, io::Error>;
177177
}
178178

179+
/// Migrates all data from one store to another.
180+
///
181+
/// This operation assumes that `target_store` is empty, i.e., any data present under copied keys
182+
/// might get overriden. User must ensure `source_store` is not modified during operation,
183+
/// otherwise no consistency guarantees can be given.
184+
///
185+
/// Will abort and return an error if any IO operation fails. Note that in this case the
186+
/// `target_store` might get left in an intermediate state.
187+
///
188+
/// **Caution**: Will delete all data from `source_store` if `move_data` is set.
189+
pub fn migrate_kv_store_data<S: MigratableKVStore, T: MigratableKVStore>(
190+
source_store: &mut S, target_store: &mut T, move_data: bool,
191+
) -> Result<(), io::Error> {
192+
let keys_to_migrate = source_store.list_all_keys()?;
193+
194+
// First copy over all data.
195+
for (primary_namespace, secondary_namespace, key) in &keys_to_migrate {
196+
let data = source_store.read(primary_namespace, secondary_namespace, key)?;
197+
target_store.write(primary_namespace, secondary_namespace, key, &data)?;
198+
199+
// Now validate what we've written.
200+
let read_data = target_store.read(primary_namespace, secondary_namespace, &key)?;
201+
if data != read_data {
202+
let err =
203+
io::Error::new(io::ErrorKind::InvalidData, "Failed to validate migrated data");
204+
return Err(err);
205+
}
206+
}
207+
208+
// If we succeeded and `move_data` is set, remove all migrated keys.
209+
if move_data {
210+
for (primary_namespace, secondary_namespace, key) in &keys_to_migrate {
211+
source_store.remove(primary_namespace, secondary_namespace, &key, false)?;
212+
}
213+
214+
if !source_store.list_all_keys()?.is_empty() {
215+
let err = io::Error::new(
216+
io::ErrorKind::InvalidData,
217+
"Source store is not empty. Was it modified during migration? This should never happen!"
218+
);
219+
return Err(err);
220+
}
221+
}
222+
223+
Ok(())
224+
}
225+
179226
/// Trait that handles persisting a [`ChannelManager`], [`NetworkGraph`], and [`WriteableScore`] to disk.
180227
///
181228
/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager

0 commit comments

Comments
 (0)