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

More optimizations to package load #14762

Merged
merged 1 commit into from
Nov 10, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion crates/sui-core/src/authority.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4601,7 +4601,7 @@ impl NodeStateDump {
.runtime_packages_loaded_from_db
.values()
{
runtime_reads.push(obj.clone());
runtime_reads.push(obj.object().clone());
}

// All other input objects should already be in `inner_temporary_store.objects`
Expand Down
9 changes: 6 additions & 3 deletions crates/sui-single-node-benchmark/src/mock_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,31 @@ use once_cell::unsync::OnceCell;
use prometheus::core::{Atomic, AtomicU64};
use std::collections::HashMap;
use std::sync::Arc;
use sui_storage::package_object_cache::PackageObjectCache;
use sui_types::base_types::{
EpochId, ObjectID, ObjectRef, SequenceNumber, TransactionDigest, VersionNumber,
};
use sui_types::error::{SuiError, SuiResult};
use sui_types::object::{Object, Owner};
use sui_types::storage::{
get_module_by_id, load_package_object_from_object_store, BackingPackageStore,
ChildObjectResolver, GetSharedLocks, ObjectStore, PackageObjectArc, ParentSync,
get_module_by_id, BackingPackageStore, ChildObjectResolver, GetSharedLocks, ObjectStore,
PackageObjectArc, ParentSync,
};
use sui_types::transaction::{InputObjectKind, InputObjects, ObjectReadResult};

// TODO: We won't need a special purpose InMemoryObjectStore once the InMemoryCache is ready.
#[derive(Clone)]
pub(crate) struct InMemoryObjectStore {
objects: Arc<HashMap<ObjectID, Object>>,
package_cache: Arc<PackageObjectCache>,
num_object_reads: Arc<AtomicU64>,
}

impl InMemoryObjectStore {
pub(crate) fn new(objects: HashMap<ObjectID, Object>) -> Self {
Self {
objects: Arc::new(objects),
package_cache: PackageObjectCache::new(),
num_object_reads: Arc::new(AtomicU64::new(0)),
}
}
Expand Down Expand Up @@ -134,7 +137,7 @@ impl ObjectStore for InMemoryObjectStore {

impl BackingPackageStore for InMemoryObjectStore {
fn get_package_object(&self, package_id: &ObjectID) -> SuiResult<Option<PackageObjectArc>> {
load_package_object_from_object_store(self, package_id)
self.package_cache.get_package_object(package_id, self)
}
}

Expand Down
5 changes: 3 additions & 2 deletions crates/sui-types/src/inner_temporary_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::base_types::{SequenceNumber, VersionDigest};
use crate::effects::{TransactionEffects, TransactionEffectsAPI, TransactionEvents};
use crate::execution::DynamicallyLoadedObjectMetadata;
use crate::storage::InputKey;
use crate::storage::PackageObjectArc;
use crate::{
base_types::ObjectID,
object::{Object, Owner},
Expand All @@ -20,7 +21,7 @@ pub type WrittenObjects = BTreeMap<ObjectID, Object>;
pub type ObjectMap = BTreeMap<ObjectID, Arc<Object>>;
pub type TxCoins = (ObjectMap, WrittenObjects);

#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone)]
pub struct InnerTemporaryStore {
pub input_objects: ObjectMap,
pub mutable_inputs: BTreeMap<ObjectID, (VersionDigest, Owner)>,
Expand All @@ -30,7 +31,7 @@ pub struct InnerTemporaryStore {
pub events: TransactionEvents,
pub max_binary_format_version: u32,
pub no_extraneous_module_bytes: bool,
pub runtime_packages_loaded_from_db: BTreeMap<ObjectID, Object>,
pub runtime_packages_loaded_from_db: BTreeMap<ObjectID, PackageObjectArc>,
pub lamport_version: SequenceNumber,
}

Expand Down
2 changes: 1 addition & 1 deletion crates/sui-types/src/storage/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ pub trait Storage {

pub type PackageFetchResults<Package> = Result<Vec<Package>, Vec<ObjectID>>;

#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct PackageObjectArc {
package_object: Arc<Object>,
}
Expand Down
21 changes: 15 additions & 6 deletions sui-execution/latest/sui-adapter/src/temporary_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ pub struct TemporaryStore<'backing> {

/// Every package that was loaded from DB store during execution.
/// These packages were not previously loaded into the temporary store.
runtime_packages_loaded_from_db: RwLock<BTreeMap<ObjectID, Object>>,
runtime_packages_loaded_from_db: RwLock<BTreeMap<ObjectID, PackageObjectArc>>,

/// The set of objects that we may receive during execution. Not guaranteed to receive all, or
/// any of the objects referenced in this set.
Expand Down Expand Up @@ -1107,16 +1107,25 @@ impl<'backing> BackingPackageStore for TemporaryStore<'backing> {
// look into the types of each written object in the output, and some of them need the
// newly written packages for type checking.
// In production path though, this should never happen.
if let Some(obj) = self.read_object(package_id) {
if let Some(obj) = self.execution_results.written_objects.get(package_id) {
Ok(Some(PackageObjectArc::new(obj.clone())))
} else {
self.store.get_package_object(package_id).map(|obj| {
// Track object but leave unchanged
if let Some(v) = &obj {
// TODO: Can this lock ever block execution?
self.runtime_packages_loaded_from_db
.write()
.insert(*package_id, v.object().clone());
if !self
.runtime_packages_loaded_from_db
.read()
.contains_key(package_id)
{
// TODO: Can this lock ever block execution?
// TODO: Another way to avoid the cost of maintaining this map is to not
// enable it in normal runs, and if a fork is detected, rerun it with a flag
// turned on and start populating this field.
self.runtime_packages_loaded_from_db
.write()
.insert(*package_id, v.clone());
}
}
obj
})
Expand Down
17 changes: 12 additions & 5 deletions sui-execution/v0/sui-adapter/src/temporary_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ pub struct TemporaryStore<'backing> {

/// Every package that was loaded from DB store during execution.
/// These packages were not previously loaded into the temporary store.
runtime_packages_loaded_from_db: RwLock<BTreeMap<ObjectID, Object>>,
runtime_packages_loaded_from_db: RwLock<BTreeMap<ObjectID, PackageObjectArc>>,
Copy link
Contributor

Choose a reason for hiding this comment

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

ditto DashMap

}

impl<'backing> TemporaryStore<'backing> {
Expand Down Expand Up @@ -1003,10 +1003,17 @@ impl<'backing> BackingPackageStore for TemporaryStore<'backing> {
self.store.get_package_object(package_id).map(|obj| {
// Track object but leave unchanged
if let Some(v) = &obj {
// TODO: Can this lock ever block execution?
self.runtime_packages_loaded_from_db
.write()
.insert(*package_id, v.object().clone());
if !self
.runtime_packages_loaded_from_db
.read()
.contains_key(package_id)
{
// TODO: Can this lock ever block execution?
// TODO: Why do we need a RwLock anyway???
self.runtime_packages_loaded_from_db
Copy link
Contributor

Choose a reason for hiding this comment

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

This lock is for interior mutability since we only take self as read ref

.write()
.insert(*package_id, v.clone());
}
}
obj
})
Expand Down
17 changes: 12 additions & 5 deletions sui-execution/v1/sui-adapter/src/temporary_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ pub struct TemporaryStore<'backing> {

/// Every package that was loaded from DB store during execution.
/// These packages were not previously loaded into the temporary store.
runtime_packages_loaded_from_db: RwLock<BTreeMap<ObjectID, Object>>,
runtime_packages_loaded_from_db: RwLock<BTreeMap<ObjectID, PackageObjectArc>>,
Copy link
Contributor

Choose a reason for hiding this comment

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

we should consider just switching to DashMap


/// The set of objects that we may receive during execution. Not guaranteed to receive all, or
/// any of the objects referenced in this set.
Expand Down Expand Up @@ -1113,10 +1113,17 @@ impl<'backing> BackingPackageStore for TemporaryStore<'backing> {
self.store.get_package_object(package_id).map(|obj| {
// Track object but leave unchanged
if let Some(v) = &obj {
// TODO: Can this lock ever block execution?
self.runtime_packages_loaded_from_db
.write()
.insert(*package_id, v.object().clone());
if !self
.runtime_packages_loaded_from_db
.read()
.contains_key(package_id)
{
// TODO: Can this lock ever block execution?
// TODO: Why do we need a RwLock anyway???
self.runtime_packages_loaded_from_db
.write()
.insert(*package_id, v.clone());
}
}
obj
})
Expand Down
Loading