Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reset cache if version becomes active #4791

Merged
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions massa-execution-worker/src/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ pub(crate) struct ExecutionState {
pub(crate) execution_info: Arc<RwLock<ExecutionInfo>>,
#[cfg(feature = "dump-block")]
block_storage_backend: Arc<RwLock<dyn StorageBackend>>,
cur_execution_version: u32,
}

impl ExecutionState {
Expand Down Expand Up @@ -188,14 +189,16 @@ impl ExecutionState {
})));

// Create an empty placeholder execution context, with shared atomic access
let execution_context = Arc::new(Mutex::new(ExecutionContext::new(
let unwrapped_execution_context = ExecutionContext::new(
Leo-Besancon marked this conversation as resolved.
Show resolved Hide resolved
config.clone(),
final_state.clone(),
active_history.clone(),
module_cache.clone(),
mip_store.clone(),
execution_trail_hash,
)));
);
let cur_execution_version = unwrapped_execution_context.execution_component_version;
let execution_context = Arc::new(Mutex::new(unwrapped_execution_context));

// Instantiate the interface providing ABI access to the VM, share the execution context with it
let execution_interface = Box::new(InterfaceImpl::new(
Expand Down Expand Up @@ -238,6 +241,7 @@ impl ExecutionState {
config,
#[cfg(feature = "dump-block")]
block_storage_backend,
cur_execution_version,
}
}

Expand Down Expand Up @@ -1458,7 +1462,7 @@ impl ExecutionState {
/// # Returns
/// An `ExecutionOutput` structure summarizing the output of the executed slot
pub fn execute_slot(
&self,
&mut self,
slot: &Slot,
exec_target: Option<&(BlockId, ExecutionBlockMetadata)>,
selector: Box<dyn SelectorController>,
Expand Down Expand Up @@ -1488,6 +1492,11 @@ impl ExecutionState {
);

let execution_version = execution_context.execution_component_version;
if self.cur_execution_version != execution_version {
// Reset the cache because a new execution version has become active
Leo-Besancon marked this conversation as resolved.
Show resolved Hide resolved
self.module_cache.write().reset();
self.cur_execution_version = execution_version;
}

let mut deferred_calls_slot_gas = 0;

Expand Down
5 changes: 5 additions & 0 deletions massa-module-cache/src/controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ impl ModuleCache {
}
}

pub fn reset(&mut self) {
self.lru_cache.reset();
self.hd_cache.reset();
}

/// Internal function to compile and build `ModuleInfo`
fn compile_cached(
&mut self,
Expand Down
40 changes: 34 additions & 6 deletions massa-module-cache/src/hd_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use massa_hash::Hash;
use massa_sc_runtime::{CondomLimits, GasCosts, RuntimeModule};
use massa_serialization::{DeserializeError, Deserializer, Serializer};
use rand::RngCore;
use rocksdb::{Direction, IteratorMode, WriteBatch, DB};
use rocksdb::{Direction, IteratorMode, Options, WriteBatch, DB};
use std::path::PathBuf;
use tracing::debug;

Expand Down Expand Up @@ -36,7 +36,7 @@ macro_rules! metadata_key {

pub(crate) struct HDCache {
/// RocksDB database
db: DB,
db: Option<DB>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why it is now Option ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In order to destroy the DB to reset it, I needed a way to drop the current DB, which is not possible without the Option as I can't fully drop the HDCache.
The only alternative I thought was to iterate through the DB to remove elements, but this may be a heavy operation.

Copy link
Member

@damip damip Dec 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the only other solution I see (without using Option) is

        unsafe {
            std::ptr::drop_in_place(&mut self.db);
            std::ptr::write(&mut self.db, create_new_db());
        }

but not great because unsafe

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maye we can use the unsafe snippet here but check with Miri first if the code looks ok and sound?
If you want I can have a look at it?

/// How many entries are in the db. Count is initialized at creation time by iterating
/// over all the entries in the db then it is maintained in memory
entry_count: usize,
Expand All @@ -63,7 +63,7 @@ impl HDCache {
let entry_count = db.iterator(IteratorMode::Start).count();

Self {
db,
db: Some(db),
entry_count,
max_entry_count,
snip_amount,
Expand All @@ -72,6 +72,20 @@ impl HDCache {
}
}

pub fn reset(&mut self) {
Leo-Besancon marked this conversation as resolved.
Show resolved Hide resolved
let path = self.db.as_ref().unwrap().path().to_path_buf();

// Close the existing database by dropping it
let _ = self.db.take();

// Destroy the database files
DB::destroy(&Options::default(), &path).expect("Failed to destroy the database");
// Reopen the database
let db = DB::open_default(&path).expect(OPEN_ERROR);
self.db = Some(db);
self.entry_count = 0;
}

/// Insert a new module in the cache
pub fn insert(&mut self, hash: Hash, module_info: ModuleInfo) {
if self.entry_count >= self.max_entry_count {
Expand Down Expand Up @@ -103,7 +117,11 @@ impl HDCache {
let mut batch = WriteBatch::default();
batch.put(module_key!(hash), ser_module);
batch.put(metadata_key!(hash), ser_metadata);
self.db.write(batch).expect(CRUD_ERROR);
self.db
.as_ref()
.expect(CRUD_ERROR)
.write(batch)
.expect(CRUD_ERROR);

self.entry_count = self.entry_count.saturating_add(1);

Expand All @@ -121,6 +139,8 @@ impl HDCache {
.serialize(&ModuleMetadata::Delta(init_cost), &mut ser_metadata)
.expect(DATA_SER_ERROR);
self.db
.as_ref()
.expect(CRUD_ERROR)
.put(metadata_key!(hash), ser_metadata)
.expect(CRUD_ERROR);
}
Expand All @@ -132,6 +152,8 @@ impl HDCache {
.serialize(&ModuleMetadata::Invalid(err_msg), &mut ser_metadata)
.expect(DATA_SER_ERROR);
self.db
.as_ref()
.expect(CRUD_ERROR)
.put(metadata_key!(hash), ser_metadata)
.expect(CRUD_ERROR);
}
Expand All @@ -145,6 +167,8 @@ impl HDCache {
) -> Option<ModuleInfo> {
let mut iterator = self
.db
.as_ref()
.expect(CRUD_ERROR)
.iterator(IteratorMode::From(&module_key!(hash), Direction::Forward));

if let (Some(Ok((key_1, ser_module))), Some(Ok((key_2, ser_metadata)))) =
Expand Down Expand Up @@ -181,7 +205,7 @@ impl HDCache {

/// Try to remove as much as `self.amount_to_snip` entries from the db
fn snip(&mut self) {
let mut iter = self.db.raw_iterator();
let mut iter = self.db.as_ref().expect(CRUD_ERROR).raw_iterator();
let mut batch = WriteBatch::default();
let mut snipped_count: usize = 0;

Expand Down Expand Up @@ -218,7 +242,11 @@ impl HDCache {
}

// delete the key and reduce entry_count
self.db.write(batch).expect(CRUD_ERROR);
self.db
.as_ref()
.expect(CRUD_ERROR)
.write(batch)
.expect(CRUD_ERROR);
self.entry_count -= snipped_count;
}
}
Expand Down
4 changes: 4 additions & 0 deletions massa-module-cache/src/lru_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ impl LRUCache {
}
}

pub fn reset(&mut self) {
self.cache.clear();
}

/// If the module is contained in the cache:
/// * retrieve a copy of it
/// * move it up in the LRU cache
Expand Down
Loading