Skip to content

Commit 4ef9c03

Browse files
committed
Add pending payment batch removal
Expose a pending-store batch removal path so callers can prune expired pending payments without repeatedly taking the pending-store mutation lock. Co-Authored-By: HAL 9000
1 parent d4e67d1 commit 4ef9c03

2 files changed

Lines changed: 63 additions & 8 deletions

File tree

src/data_store.rs

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,19 @@ where
112112
}
113113

114114
pub(crate) async fn remove(&self, id: &SO::Id) -> Result<(), Error> {
115+
self.remove_batch(std::slice::from_ref(id)).await?;
116+
Ok(())
117+
}
118+
119+
pub(crate) async fn remove_batch(&self, ids: &[SO::Id]) -> Result<Vec<SO>, Error> {
115120
let _guard = self.mutation_lock.lock().await;
116-
let should_remove = { self.objects.lock().expect("lock").contains_key(id) };
117-
if should_remove {
121+
let mut removed_objects = Vec::new();
122+
for id in ids {
123+
let should_remove = { self.objects.lock().expect("lock").contains_key(id) };
124+
if !should_remove {
125+
continue;
126+
}
127+
118128
let store_key = id.encode_to_hex_str();
119129
KVStore::remove(
120130
&*self.kv_store,
@@ -135,9 +145,12 @@ where
135145
);
136146
Error::PersistenceFailed
137147
})?;
138-
self.objects.lock().expect("lock").remove(id);
148+
149+
if let Some(object) = self.objects.lock().expect("lock").remove(id) {
150+
removed_objects.push(object);
151+
}
139152
}
140-
Ok(())
153+
Ok(removed_objects)
141154
}
142155

143156
/// Returns the current in-memory object for `id`.
@@ -422,6 +435,45 @@ mod tests {
422435
assert!(data_store.get(&new_id).is_none());
423436
}
424437

438+
#[tokio::test]
439+
async fn batch_remove_removes_persisted_objects() {
440+
let store: Arc<DynStore> = Arc::new(DynStoreWrapper(InMemoryStore::new()));
441+
let logger = Arc::new(TestLogger::new());
442+
let primary_namespace = "datastore_batch_remove_test_primary".to_string();
443+
let secondary_namespace = "datastore_batch_remove_test_secondary".to_string();
444+
let data_store: DataStore<TestObject, Arc<TestLogger>> = DataStore::new(
445+
Vec::new(),
446+
primary_namespace.clone(),
447+
secondary_namespace.clone(),
448+
Arc::clone(&store),
449+
logger,
450+
);
451+
452+
let first = TestObject { id: TestObjectId { id: [1u8; 4] }, data: [23u8; 3] };
453+
let second = TestObject { id: TestObjectId { id: [2u8; 4] }, data: [42u8; 3] };
454+
let missing_id = TestObjectId { id: [3u8; 4] };
455+
assert_eq!(Ok(false), data_store.insert(first).await);
456+
assert_eq!(Ok(false), data_store.insert(second).await);
457+
458+
assert_eq!(
459+
Ok(vec![first, second]),
460+
data_store.remove_batch(&[first.id, missing_id, second.id]).await
461+
);
462+
assert_eq!(None, data_store.get(&first.id));
463+
assert_eq!(None, data_store.get(&second.id));
464+
465+
for id in [first.id, second.id] {
466+
assert!(KVStore::read(
467+
&*store,
468+
&primary_namespace,
469+
&secondary_namespace,
470+
&id.encode_to_hex_str()
471+
)
472+
.await
473+
.is_err());
474+
}
475+
}
476+
425477
#[tokio::test]
426478
async fn insert_does_not_mutate_memory_if_persist_fails() {
427479
let id = TestObjectId { id: [42u8; 4] };

src/payment/pending_payment_store.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -240,11 +240,14 @@ where
240240
}
241241

242242
pub(crate) async fn remove(&self, id: &PaymentId) -> Result<(), Error> {
243+
self.remove_batch(std::slice::from_ref(id)).await
244+
}
245+
246+
pub(crate) async fn remove_batch(&self, ids: &[PaymentId]) -> Result<(), Error> {
243247
let _guard = self.mutation_lock.lock().await;
244-
let before = self.inner.get(id);
245-
self.inner.remove(id).await?;
246-
if let Some(payment) = before.as_ref() {
247-
self.remove_from_index(payment);
248+
let removed_payments = self.inner.remove_batch(ids).await?;
249+
for payment in removed_payments {
250+
self.remove_from_index(&payment);
248251
}
249252
Ok(())
250253
}

0 commit comments

Comments
 (0)