Skip to content

Commit 5b0210f

Browse files
committed
fix: order transaction seal after wal range
1 parent 4d9eac9 commit 5b0210f

3 files changed

Lines changed: 32 additions & 24 deletions

File tree

src/db/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1614,7 +1614,7 @@ where
16141614
}
16151615

16161616
/// Set or replace the sealing policy used by this DB.
1617-
pub fn set_seal_policy(&mut self, policy: Arc<dyn SealPolicy + Send + Sync>) {
1617+
pub(crate) fn set_seal_policy(&mut self, policy: Arc<dyn SealPolicy + Send + Sync>) {
16181618
self.policy = policy;
16191619
}
16201620

src/inmem/policy.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ impl SealPolicy for NeverSeal {
9595
///
9696
/// These values aim to provide sensible out-of-the-box behavior while avoiding
9797
/// overly aggressive sealing for small workloads. Callers can override this
98-
/// policy via `DB::set_seal_policy`.
98+
/// policy at build time via `DbBuilder::with_seal_policy`.
9999
pub fn default_policy() -> Arc<dyn SealPolicy + Send + Sync> {
100100
use std::time::Duration;
101101
Arc::new(AnyOf::new(vec![

src/transaction/mod.rs

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,7 @@ where
630630
)?)
631631
};
632632

633+
let mut maintenance_deferred = false;
633634
if let Some(wal) = db.wal_handle().cloned() {
634635
let provisional_id = wal.next_provisional_id();
635636
let prev_live_floor = db.wal_live_frame_floor();
@@ -655,10 +656,6 @@ where
655656
publish_ctx.finalize_manifest(wal_range).await?;
656657
}
657658
CommitAckMode::Fast => {
658-
// NOTE: Fast mode has a known limitation - if auto-seal triggers during
659-
// apply_staged_payloads, the sealed segment's WAL range won't include this
660-
// transaction's frames (they're recorded asynchronously). This is acceptable
661-
// for Fast mode as it prioritizes latency over strict durability ordering.
662659
apply_staged_payloads(
663660
&*db,
664661
upsert_payload.take(),
@@ -667,7 +664,8 @@ where
667664
)?;
668665
let publish_ctx = db.txn_publish_context(prev_live_floor);
669666
let executor = Arc::clone(db.executor());
670-
spawn_publish_task(executor, publish_ctx, tickets);
667+
spawn_publish_task(executor, Arc::clone(&db), publish_ctx, tickets);
668+
maintenance_deferred = true;
671669
}
672670
}
673671
} else {
@@ -690,14 +688,9 @@ where
690688
)?;
691689
}
692690

693-
db.maybe_seal_after_insert()
694-
.map_err(TransactionCommitError::Apply)?;
695-
#[cfg(test)]
696-
db.maybe_run_minor_compaction()
697-
.await
698-
.map_err(TransactionCommitError::MinorCompaction)?;
699-
#[cfg(not(test))]
700-
DbInner::schedule_background_minor_compaction(Arc::clone(&db));
691+
if !maintenance_deferred {
692+
run_post_commit_maintenance(&db).await?;
693+
}
701694

702695
drop(key_guards);
703696
Ok(())
@@ -1368,6 +1361,7 @@ impl AckRange {
13681361

13691362
fn spawn_publish_task<FS, E>(
13701363
executor: Arc<E>,
1364+
db: Arc<DbInner<FS, E>>,
13711365
publish_ctx: TxnWalPublishContext<FS, E>,
13721366
tickets: WalTxnTickets<E>,
13731367
) where
@@ -1378,7 +1372,11 @@ fn spawn_publish_task<FS, E>(
13781372
executor.spawn(async move {
13791373
match tickets.await_range().await {
13801374
Ok(range) => {
1381-
if let Err(err) = publish_ctx.finalize(range).await {
1375+
publish_ctx.record_wal_range(&range);
1376+
if let Err(err) = run_post_commit_maintenance(&db).await {
1377+
eprintln!("transaction post-commit maintenance failed: {err}");
1378+
}
1379+
if let Err(err) = publish_ctx.finalize_manifest(range).await {
13821380
eprintln!("transaction post-commit publish failed: {err}");
13831381
}
13841382
}
@@ -1460,15 +1458,25 @@ where
14601458

14611459
Ok(())
14621460
}
1461+
}
14631462

1464-
/// Combined record and finalize for async publish tasks.
1465-
///
1466-
/// This is used by the Fast mode async task which handles both
1467-
/// WAL range recording and manifest update together.
1468-
async fn finalize(&self, wal_range: WalFrameRange) -> Result<(), TransactionCommitError> {
1469-
self.record_wal_range(&wal_range);
1470-
self.finalize_manifest(wal_range).await
1471-
}
1463+
async fn run_post_commit_maintenance<FS, E>(
1464+
db: &Arc<DbInner<FS, E>>,
1465+
) -> Result<(), TransactionCommitError>
1466+
where
1467+
FS: crate::manifest::ManifestFs<E>,
1468+
E: Executor + Timer + Clone + 'static,
1469+
<FS as fusio::fs::Fs>::File: fusio::durability::FileCommit,
1470+
{
1471+
db.maybe_seal_after_insert()
1472+
.map_err(TransactionCommitError::Apply)?;
1473+
#[cfg(test)]
1474+
db.maybe_run_minor_compaction()
1475+
.await
1476+
.map_err(TransactionCommitError::MinorCompaction)?;
1477+
#[cfg(not(test))]
1478+
DbInner::schedule_background_minor_compaction(Arc::clone(db));
1479+
Ok(())
14721480
}
14731481

14741482
/// Errors raised while staging transactional mutations.

0 commit comments

Comments
 (0)