Skip to content
Prev Previous commit
Next Next commit
prefix write check
  • Loading branch information
sanlee42 committed Nov 14, 2025
commit 4faa2d3d4a57761467472f01ca295b9a564da902
111 changes: 110 additions & 1 deletion commons/exec-merge/src/reuse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ use starcoin_vm2_types::transaction::{Transaction, TransactionInfo, TransactionS
use starcoin_vm2_types::vm_error::KeptVMStatus;
use starcoin_vm2_vm_types::state_store::state_key::{inner::StateKeyInner, StateKey};
use starcoin_vm2_vm_types::write_set::{WriteOp, WriteSet, WriteSetMut};
use starcoin_vm2_vm_types::state_store::TStateView;
use starcoin_vm_runtime::reuse_recorder;
use std::collections::HashSet;
use std::collections::{HashMap, HashSet};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::time::Instant;
Expand Down Expand Up @@ -137,6 +138,44 @@ struct ReusePlanner<'a> {
epoch_id: u64,
}

struct PrefixEffects<'a> {
state: &'a ChainStateDB,
cache: HashMap<StateKey, bool>,
}

impl<'a> PrefixEffects<'a> {
fn new(state: &'a ChainStateDB) -> Self {
Self {
state,
cache: HashMap::new(),
}
}

fn exists(&mut self, key: &StateKey) -> Option<bool> {
if let Some(exists) = self.cache.get(key) {
return Some(*exists);
}
match self.state.get_state_value(key) {
Ok(opt) => {
let exists = opt.is_some();
self.cache.insert(key.clone(), exists);
Some(exists)
}
Err(err) => {
warn!(
"reuse planner failed to query state for key {:?}: {:?}",
key, err
);
None
}
}
}

fn set(&mut self, key: &StateKey, exists: bool) {
self.cache.insert(key.clone(), exists);
}
}

impl<'a> ReusePlanner<'a> {
fn new(
statedb: &'a ChainStateDB,
Expand Down Expand Up @@ -197,6 +236,15 @@ impl<'a> ReusePlanner<'a> {
entry.decision = decision;
}

let mut effects = PrefixEffects::new(self.statedb);
for entry in entries.iter_mut() {
if entry.decision == PlanDecision::Reuse
&& !self.validate_and_apply_reuse(entry, &mut effects)
{
entry.decision = PlanDecision::Reexec;
}
}

let elapsed_ms = plan_start.elapsed().as_millis();
let read_checked = *diff.stats.get("read_checked").unwrap_or(&0);

Expand Down Expand Up @@ -312,6 +360,67 @@ impl<'a> ReusePlanner<'a> {
StateKeyInner::AccessPath(_) | StateKeyInner::TableItem { .. }
)
}

fn validate_and_apply_reuse(
&self,
entry: &PlanEntry,
effects: &mut PrefixEffects,
) -> bool {
use starcoin_vm2_vm_types::write_set::WriteOp::{Creation, Deletion, Modification};

let rec = match entry.witness.as_ref() {
Some(rec) => rec,
None => return false,
};

let read_map = match rec.read_set.as_ref() {
Some(reads) => {
let mut map = HashMap::with_capacity(reads.len());
for read in reads {
map.insert(read.key.clone(), read.existed);
}
map
}
None => return false,
};

for (key, op) in rec.write_set.iter() {
match op {
Creation { .. } => {
if read_map.get(key).copied() != Some(false) {
return false;
}
match effects.exists(key) {
Some(false) => effects.set(key, true),
Some(true) => return false,
None => return false,
}
}
Modification { .. } => {
if read_map.get(key).copied() != Some(true) {
return false;
}
match effects.exists(key) {
Some(true) => effects.set(key, true),
Some(false) => return false,
None => return false,
}
}
Deletion { .. } => {
if read_map.get(key).copied() != Some(true) {
return false;
}
match effects.exists(key) {
Some(true) => effects.set(key, false),
Some(false) => return false,
None => return false,
}
}
}
}

true
}
}

struct ReuseExecutor<'a> {
Expand Down