Skip to content

Commit 2836726

Browse files
committed
Batch write to spk db
1 parent e90d54b commit 2836726

2 files changed

Lines changed: 36 additions & 7 deletions

File tree

src/crates/primitives/src/parser.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ use crate::{
1212
dense::{BlockFileId, TxId, TxOutId},
1313
indecies::{ConfirmedTxPtrIndex, DenseIndexSet, INID_NONE, OUTID_NONE, TxPtr},
1414
sled::spk_db::{SledScriptPubkeyDb, SledScriptPubkeyDbError},
15-
traits::ScriptPubkeyDb,
1615
};
1716

1817
/// Block file layout: 4-byte magic + 4-byte block size (LE) + block payload.
@@ -183,7 +182,6 @@ impl Parser {
183182
tx_out_base,
184183
current_in: 0,
185184
current_out: 0,
186-
spk_db,
187185
error: None,
188186
};
189187
bsl::Block::visit(block_slice, &mut collector)
@@ -218,6 +216,9 @@ impl Parser {
218216
.set(*out_id, *in_id)
219217
.map_err(BlockFileError::Io)?;
220218
}
219+
spk_db
220+
.insert_batch_if_absent(&batch.spk_inserts)
221+
.map_err(BlockFileError::SpkDb)?;
221222

222223
tx_total += batch.txptrs.len() as u64;
223224
if tx_total > u32::MAX as u64 {
@@ -253,6 +254,8 @@ struct BlockBatch {
253254
out_spents: Vec<u64>,
254255
/// `(out_id, in_id)` pairs for outputs spent within or before this block.
255256
out_spent_updates: Vec<(u64, u64)>,
257+
/// Script-pubkey index inserts; first-seen per hash wins.
258+
spk_inserts: Vec<(ScriptPubkeyHash, TxOutId)>,
256259
}
257260

258261
/// Visitor that collects TxIds (file + byte offset) for each transaction in a block.
@@ -277,7 +280,6 @@ struct TxIdCollector<'a> {
277280
tx_out_base: u64,
278281
current_in: u64,
279282
current_out: u64,
280-
spk_db: &'a mut SledScriptPubkeyDb,
281283
error: Option<BlockFileError>,
282284
}
283285

@@ -338,10 +340,7 @@ impl Visitor for TxIdCollector<'_> {
338340
return ControlFlow::Break(());
339341
}
340342
let spk_hash = script_pubkey_hash(tx_out.script_pubkey());
341-
if let Err(err) = self.spk_db.insert_if_absent(spk_hash, TxOutId::new(out_id)) {
342-
self.error = Some(BlockFileError::SpkDb(err));
343-
return ControlFlow::Break(());
344-
}
343+
self.batch.spk_inserts.push((spk_hash, TxOutId::new(out_id)));
345344
self.batch.out_spents.push(INID_NONE);
346345
self.current_out += 1;
347346
ControlFlow::Continue(())

src/crates/primitives/src/sled/spk_db.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::collections::HashSet;
2+
13
use crate::traits::ScriptPubkeyDb;
24
use crate::{ScriptPubkeyHash, dense::TxOutId};
35
use sled::{IVec, Tree};
@@ -59,6 +61,34 @@ impl SledScriptPubkeyDb {
5961
}
6062
}
6163

64+
impl SledScriptPubkeyDb {
65+
/// Insert all entries where the key is not already present, in a single
66+
/// `sled::Batch` for crash-atomic application.
67+
///
68+
/// Within `entries`, first-seen wins for duplicate keys. Keys already
69+
/// present in the tree are skipped, matching `insert_if_absent` semantics.
70+
pub fn insert_batch_if_absent(
71+
&mut self,
72+
entries: &[(ScriptPubkeyHash, TxOutId)],
73+
) -> Result<(), SledScriptPubkeyDbError> {
74+
let mut seen = HashSet::new();
75+
let mut batch = sled::Batch::default();
76+
for (spk_hash, out_id) in entries {
77+
if seen.insert(*spk_hash)
78+
&& !self
79+
.tree
80+
.contains_key(Self::key_bytes(spk_hash))
81+
.map_err(SledScriptPubkeyDbError::Backend)?
82+
{
83+
batch.insert(Self::key_bytes(spk_hash), Self::encode_out_id(*out_id));
84+
}
85+
}
86+
self.tree
87+
.apply_batch(batch)
88+
.map_err(SledScriptPubkeyDbError::Backend)
89+
}
90+
}
91+
6292
impl ScriptPubkeyDb for SledScriptPubkeyDb {
6393
type Error = SledScriptPubkeyDbError;
6494

0 commit comments

Comments
 (0)