Skip to content

Commit c8248bb

Browse files
joostjagerclaude
andcommitted
Use write_batch in MonitorUpdatingPersister flush()
Refactors flush() to batch all writes into a single write_batch() call instead of individual write() calls. On partial failure, failed and subsequent writes are re-queued at the front of the pending writes queue for retry on the next flush. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent eaa91ec commit c8248bb

1 file changed

Lines changed: 69 additions & 38 deletions

File tree

lightning/src/util/persist.rs

Lines changed: 69 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1130,60 +1130,91 @@ where
11301130
queue.drain(..n).collect::<Vec<_>>()
11311131
};
11321132

1133-
let mut completed = Vec::new();
1134-
for write in pending {
1133+
// Phase 1: Collect all batch entries
1134+
let mut batch_entries = Vec::with_capacity(pending.len());
1135+
let mut stale_cleanups = Vec::new();
1136+
1137+
for (i, write) in pending.iter().enumerate() {
11351138
match write {
11361139
PendingWrite::FullMonitor {
11371140
monitor_key,
11381141
monitor_bytes,
1139-
completion,
11401142
stale_update_cleanup,
1143+
..
11411144
} => {
1142-
self.0
1143-
.kv_store
1144-
.write(
1145-
CHANNEL_MONITOR_PERSISTENCE_PRIMARY_NAMESPACE,
1146-
CHANNEL_MONITOR_PERSISTENCE_SECONDARY_NAMESPACE,
1147-
&monitor_key,
1148-
monitor_bytes,
1149-
)
1150-
.await?;
1151-
completed.push(completion);
1152-
1153-
// Clean up stale updates after successfully writing a full monitor
1145+
batch_entries.push(BatchWriteEntry::new(
1146+
CHANNEL_MONITOR_PERSISTENCE_PRIMARY_NAMESPACE,
1147+
CHANNEL_MONITOR_PERSISTENCE_SECONDARY_NAMESPACE,
1148+
monitor_key.clone(),
1149+
monitor_bytes.clone(),
1150+
));
11541151
if let Some((start, end)) = stale_update_cleanup {
1155-
for update_id in start..end {
1156-
let update_name = UpdateName::from(update_id);
1157-
// Lazy delete - ignore errors as this is just cleanup
1158-
let _ = self
1159-
.0
1160-
.kv_store
1161-
.remove(
1162-
CHANNEL_MONITOR_UPDATE_PERSISTENCE_PRIMARY_NAMESPACE,
1163-
&monitor_key,
1164-
update_name.as_str(),
1165-
true,
1166-
)
1167-
.await;
1168-
}
1152+
stale_cleanups.push((i, monitor_key.clone(), *start, *end));
11691153
}
11701154
},
1171-
PendingWrite::Update { monitor_key, update_key, update_bytes, completion } => {
1172-
self.0
1155+
PendingWrite::Update { monitor_key, update_key, update_bytes, .. } => {
1156+
batch_entries.push(BatchWriteEntry::new(
1157+
CHANNEL_MONITOR_UPDATE_PERSISTENCE_PRIMARY_NAMESPACE,
1158+
monitor_key.clone(),
1159+
update_key.clone(),
1160+
update_bytes.clone(),
1161+
));
1162+
},
1163+
}
1164+
}
1165+
1166+
// Phase 2: Execute batch write
1167+
let successful_writes = if !batch_entries.is_empty() {
1168+
let result = self.0.kv_store.write_batch(batch_entries).await;
1169+
if let Some(err) = result.error {
1170+
// Re-queue failed and subsequent writes
1171+
let failed_writes =
1172+
pending.into_iter().skip(result.successful_writes).collect::<Vec<_>>();
1173+
if !failed_writes.is_empty() {
1174+
let mut queue = self.0.pending_writes.lock().unwrap();
1175+
// Prepend failed writes back to the front of the queue
1176+
for write in failed_writes.into_iter().rev() {
1177+
queue.insert(0, write);
1178+
}
1179+
}
1180+
return Err(err);
1181+
}
1182+
result.successful_writes
1183+
} else {
1184+
0
1185+
};
1186+
1187+
// Phase 3: Cleanup stale updates (only for successfully written monitors)
1188+
for (i, monitor_key, start, end) in stale_cleanups {
1189+
if i < successful_writes {
1190+
for update_id in start..end {
1191+
let update_name = UpdateName::from(update_id);
1192+
// Lazy delete - ignore errors as this is just cleanup
1193+
let _ = self
1194+
.0
11731195
.kv_store
1174-
.write(
1196+
.remove(
11751197
CHANNEL_MONITOR_UPDATE_PERSISTENCE_PRIMARY_NAMESPACE,
11761198
&monitor_key,
1177-
&update_key,
1178-
update_bytes,
1199+
update_name.as_str(),
1200+
true,
11791201
)
1180-
.await?;
1181-
completed.push(completion);
1182-
},
1202+
.await;
1203+
}
11831204
}
11841205
}
11851206

1186-
Ok(completed)
1207+
// Phase 4: Return completions for successful writes only
1208+
let completions = pending
1209+
.into_iter()
1210+
.take(successful_writes)
1211+
.map(|write| match write {
1212+
PendingWrite::FullMonitor { completion, .. } => completion,
1213+
PendingWrite::Update { completion, .. } => completion,
1214+
})
1215+
.collect();
1216+
1217+
Ok(completions)
11871218
}
11881219
}
11891220

0 commit comments

Comments
 (0)