From ff26e9cfb7d567addb143ba06dcb2eca0438e927 Mon Sep 17 00:00:00 2001 From: ldm0 Date: Tue, 18 Aug 2026 05:02:17 +0800 Subject: [PATCH] simplify indexeddb storage bucket integration --- moli-renderer-v8/src/context_bootstrap.rs | 1 - .../src/context_bootstrap/indexed_db/core.rs | 11 +- .../context_bootstrap/indexed_db/core/env.rs | 21 ++- .../indexed_db/core/env/manager.rs | 56 +++++++ .../indexed_db/core/env/origin.rs | 8 - .../indexed_db/core/env/storage.rs | 140 ------------------ .../context_bootstrap/indexed_db/database.rs | 2 +- .../indexed_db/database/factory.rs | 4 +- .../indexed_db/database/factory/databases.rs | 5 +- .../database/factory/delete_database.rs | 5 +- .../indexed_db/database/factory/open.rs | 5 +- .../src/context_bootstrap/indexed_db/mod.rs | 8 +- .../context_bootstrap/indexed_db/runtime.rs | 32 ++-- .../indexed_db/storage_bucket.rs | 100 +++++++++++++ .../src/context_bootstrap/indexed_db/tasks.rs | 2 +- .../indexed_db/tasks/open_delete/delete.rs | 4 +- .../indexed_db/tasks/open_delete/open.rs | 4 +- .../indexed_db/typed_state.rs | 17 ++- .../src/context_bootstrap/indexed_db/types.rs | 6 - .../window_runtime/navigator.rs | 10 +- 20 files changed, 209 insertions(+), 232 deletions(-) create mode 100644 moli-renderer-v8/src/context_bootstrap/indexed_db/core/env/manager.rs delete mode 100644 moli-renderer-v8/src/context_bootstrap/indexed_db/core/env/storage.rs create mode 100644 moli-renderer-v8/src/context_bootstrap/indexed_db/storage_bucket.rs diff --git a/moli-renderer-v8/src/context_bootstrap.rs b/moli-renderer-v8/src/context_bootstrap.rs index b96bf1a46e..bc78fc4bc7 100644 --- a/moli-renderer-v8/src/context_bootstrap.rs +++ b/moli-renderer-v8/src/context_bootstrap.rs @@ -258,7 +258,6 @@ pub(crate) use self::image_data::{ ImageDataClonePayload, build_image_data_object_from_clone_payload, image_data_clone_payload_from_object, is_image_data_object, }; -pub(in crate::context_bootstrap) use self::indexed_db::IndexedDbStorageBucketContext; pub(crate) use self::indexed_db::{ IndexedDbTaskId, discard_indexed_db_task_by_id, flush_blocked_indexed_db_requests, flush_indexed_db_task_by_id, flush_next_indexed_db_task, indexed_db_has_pending_tasks, diff --git a/moli-renderer-v8/src/context_bootstrap/indexed_db/core.rs b/moli-renderer-v8/src/context_bootstrap/indexed_db/core.rs index 43bff3e92f..9fd7de11b4 100644 --- a/moli-renderer-v8/src/context_bootstrap/indexed_db/core.rs +++ b/moli-renderer-v8/src/context_bootstrap/indexed_db/core.rs @@ -8,12 +8,11 @@ use super::{ INDEXED_DB_TRANSACTION_DB_KEY_SLOT, INDEXED_DB_TRANSACTION_FINISHED_SLOT, INDEXED_DB_TRANSACTION_HANDLE_SLOT, IdbKeyRangeQuery, IndexEntry, IndexInfo, IndexedDbError, IndexedDbExecutionOwner, IndexedDbExternalObject, IndexedDbManager, - IndexedDbObjectStoreMetadata, IndexedDbQuotaCheck, IndexedDbRuntimeArray, - IndexedDbStorageBucketContext, IndexedDbStorageScope, IndexedDbValue, IndexedDbWrapperKind, - Key, KeyPath, ObjectStoreInfo, PreparedObjectStoreWrite, PreparedObjectStoreWriteError, - TransactionHandle, TransactionMode, context_host_ptr_from_global_bridge, - dispatch_version_change_event, global_constructor_prototype, - indexed_db_database_store_metadata, indexed_db_object_store_database, + IndexedDbObjectStoreMetadata, IndexedDbRuntimeArray, IndexedDbStorageScope, IndexedDbValue, + IndexedDbWrapperKind, Key, KeyPath, ObjectStoreInfo, PreparedObjectStoreWrite, + PreparedObjectStoreWriteError, TransactionHandle, TransactionMode, + context_host_ptr_from_global_bridge, dispatch_version_change_event, + global_constructor_prototype, indexed_db_database_store_metadata, indexed_db_object_store_metadata, indexed_db_runtime_array, indexed_db_typed_execution_owner, indexed_db_typed_storage_scope, new_null_prototype_object, object_bool_property, object_hidden_value, object_number_property, object_property_as_object, object_string_property, diff --git a/moli-renderer-v8/src/context_bootstrap/indexed_db/core/env.rs b/moli-renderer-v8/src/context_bootstrap/indexed_db/core/env.rs index 22efd2b714..84424aaf66 100644 --- a/moli-renderer-v8/src/context_bootstrap/indexed_db/core/env.rs +++ b/moli-renderer-v8/src/context_bootstrap/indexed_db/core/env.rs @@ -2,8 +2,8 @@ use super::*; mod dom_string_list; mod errors; +mod manager; mod origin; -mod storage; pub(in crate::context_bootstrap::indexed_db) use self::dom_string_list::{ idb_dom_string_list_backing_values, install_dom_string_list_template_bindings, @@ -12,18 +12,15 @@ pub(in crate::context_bootstrap::indexed_db) use self::dom_string_list::{ pub(in crate::context_bootstrap::indexed_db) use self::errors::{ dom_exception_value, request_error_object, }; +pub(in crate::context_bootstrap) use self::manager::indexed_db_usage_bytes_for_storage_key; +pub(crate) use self::manager::set_indexed_db_manager_for_context; +pub(in crate::context_bootstrap::indexed_db) use self::manager::with_indexed_db_manager; +#[cfg(test)] +pub(crate) use self::manager::{ + indexed_db_manager_context_slot_present_for_test, + indexed_db_manager_isolate_slot_present_for_test, +}; pub(in crate::context_bootstrap::indexed_db) use self::origin::{ current_storage_scope, origin_allows_indexed_db, storage_scope_for_current_partition, storage_scope_for_window_execution_context, }; -pub(in crate::context_bootstrap) use self::storage::indexed_db_usage_bytes_for_storage_key; -pub(crate) use self::storage::set_indexed_db_manager_for_context; -#[cfg(test)] -pub(crate) use self::storage::{ - indexed_db_manager_context_slot_present_for_test, - indexed_db_manager_isolate_slot_present_for_test, -}; -pub(in crate::context_bootstrap::indexed_db) use self::storage::{ - storage_bucket_quota_check_for_object_store, storage_bucket_quota_check_for_transaction, - validate_storage_bucket_indexed_db_context, with_indexed_db_manager, -}; diff --git a/moli-renderer-v8/src/context_bootstrap/indexed_db/core/env/manager.rs b/moli-renderer-v8/src/context_bootstrap/indexed_db/core/env/manager.rs new file mode 100644 index 0000000000..84394d5455 --- /dev/null +++ b/moli-renderer-v8/src/context_bootstrap/indexed_db/core/env/manager.rs @@ -0,0 +1,56 @@ +//! IndexedDB manager access bound to the current V8 context. + +use super::{IndexedDbError, IndexedDbManager}; +use crate::context_bootstrap::indexed_db::WeakIndexedDbManager; + +#[derive(Clone, Debug)] +pub(crate) struct IndexedDbManagerSlot(pub(crate) Option); + +pub(crate) fn set_indexed_db_manager_for_context( + context: v8::Local<'_, v8::Context>, + manager: Option, +) { + let _previous = context.set_slot(std::rc::Rc::new(IndexedDbManagerSlot(manager))); +} + +pub(in crate::context_bootstrap::indexed_db) fn with_indexed_db_manager( + scope: &mut v8::PinScope<'_, '_>, + f: impl FnOnce(&mut IndexedDbManager) -> std::result::Result, +) -> std::result::Result { + let manager = scope + .get_current_context() + .get_slot::() + .as_deref() + .and_then(|slot| slot.0.as_ref()) + .and_then(WeakIndexedDbManager::upgrade) + .ok_or_else(|| { + IndexedDbError::InvalidState("IndexedDB browser context is closed".to_owned()) + })?; + let mut manager = manager.lock(); + f(&mut manager) +} + +pub(in crate::context_bootstrap) fn indexed_db_usage_bytes_for_storage_key( + scope: &mut v8::PinScope<'_, '_>, + storage_key: &str, +) -> u64 { + let usage = with_indexed_db_manager(scope, |manager| manager.origin_usage_bytes(storage_key)); + usage.unwrap_or(0) +} + +#[cfg(test)] +pub(crate) fn indexed_db_manager_context_slot_present_for_test( + scope: &mut v8::PinScope<'_, '_>, +) -> bool { + scope + .get_current_context() + .get_slot::() + .is_some() +} + +#[cfg(test)] +pub(crate) fn indexed_db_manager_isolate_slot_present_for_test( + scope: &mut v8::PinScope<'_, '_>, +) -> bool { + scope.get_slot::().is_some() +} diff --git a/moli-renderer-v8/src/context_bootstrap/indexed_db/core/env/origin.rs b/moli-renderer-v8/src/context_bootstrap/indexed_db/core/env/origin.rs index d1f0aa4f87..a12e41b8ec 100644 --- a/moli-renderer-v8/src/context_bootstrap/indexed_db/core/env/origin.rs +++ b/moli-renderer-v8/src/context_bootstrap/indexed_db/core/env/origin.rs @@ -2,7 +2,6 @@ use super::*; pub(in crate::context_bootstrap::indexed_db) fn current_storage_scope( scope: &mut v8::PinScope<'_, '_>, - bucket_context: Option, ) -> Option { if let Some(host_ptr) = context_host_ptr_from_global_bridge(scope) { let active_child_handle = crate::native_bridge::active_child_window_handle(scope); @@ -14,7 +13,6 @@ pub(in crate::context_bootstrap::indexed_db) fn current_storage_scope( let identity = host.browser_context_runtime().storage_partition_identity(); return Some(IndexedDbStorageScope::new( storage_key, - bucket_context, identity.browser_context_id(), identity.profile_partition_id(), )); @@ -23,7 +21,6 @@ pub(in crate::context_bootstrap::indexed_db) fn current_storage_scope( let identity = crate::worker::worker_storage_partition_identity(scope)?; Some(IndexedDbStorageScope::new( storage_key, - bucket_context, identity.browser_context_id(), identity.profile_partition_id(), )) @@ -32,7 +29,6 @@ pub(in crate::context_bootstrap::indexed_db) fn current_storage_scope( pub(in crate::context_bootstrap::indexed_db) fn storage_scope_for_window_execution_context( scope: &mut v8::PinScope<'_, '_>, execution_context: crate::native_bridge::WindowExecutionContextIdentity, - bucket_context: Option, ) -> Option { let host_ptr = context_host_ptr_from_global_bridge(scope)?; let host = unsafe { &mut *host_ptr }; @@ -51,7 +47,6 @@ pub(in crate::context_bootstrap::indexed_db) fn storage_scope_for_window_executi let identity = host.browser_context_runtime().storage_partition_identity(); Some(IndexedDbStorageScope::new( storage_context.storage_key().serialized_storage_key(), - bucket_context, identity.browser_context_id(), identity.profile_partition_id(), )) @@ -60,14 +55,12 @@ pub(in crate::context_bootstrap::indexed_db) fn storage_scope_for_window_executi pub(in crate::context_bootstrap::indexed_db) fn storage_scope_for_current_partition( scope: &mut v8::PinScope<'_, '_>, storage_key: impl Into, - bucket_context: Option, ) -> Option { if let Some(host_ptr) = context_host_ptr_from_global_bridge(scope) { let host = unsafe { &mut *host_ptr }; let identity = host.browser_context_runtime().storage_partition_identity(); return Some(IndexedDbStorageScope::new( storage_key, - bucket_context, identity.browser_context_id(), identity.profile_partition_id(), )); @@ -75,7 +68,6 @@ pub(in crate::context_bootstrap::indexed_db) fn storage_scope_for_current_partit let identity = crate::worker::worker_storage_partition_identity(scope)?; Some(IndexedDbStorageScope::new( storage_key, - bucket_context, identity.browser_context_id(), identity.profile_partition_id(), )) diff --git a/moli-renderer-v8/src/context_bootstrap/indexed_db/core/env/storage.rs b/moli-renderer-v8/src/context_bootstrap/indexed_db/core/env/storage.rs deleted file mode 100644 index c285c8ae88..0000000000 --- a/moli-renderer-v8/src/context_bootstrap/indexed_db/core/env/storage.rs +++ /dev/null @@ -1,140 +0,0 @@ -use super::*; -use crate::context_bootstrap::indexed_db::WeakIndexedDbManager; -use crate::context_bootstrap::storage_buckets::{ - storage_bucket_quota_owner_for_locator, with_storage_bucket_store_entry, -}; - -pub(in crate::context_bootstrap::indexed_db) struct StorageBucketIndexedDbQuotaCommit { - pub quota_check: IndexedDbQuotaCheck, - _reservation: moli_storage_service::StorageQuotaReservation, -} - -#[derive(Clone, Debug)] -pub(crate) struct IndexedDbManagerSlot(pub(crate) Option); - -pub(crate) fn set_indexed_db_manager_for_context( - context: v8::Local<'_, v8::Context>, - manager: Option, -) { - let _previous = context.set_slot(std::rc::Rc::new(IndexedDbManagerSlot(manager))); -} - -pub(in crate::context_bootstrap::indexed_db) fn with_indexed_db_manager( - scope: &mut v8::PinScope<'_, '_>, - f: impl FnOnce(&mut IndexedDbManager) -> std::result::Result, -) -> std::result::Result { - let manager = scope - .get_current_context() - .get_slot::() - .as_deref() - .and_then(|slot| slot.0.as_ref()) - .and_then(WeakIndexedDbManager::upgrade) - .ok_or_else(|| { - IndexedDbError::InvalidState("IndexedDB browser context is closed".to_owned()) - })?; - let mut manager = manager.lock(); - f(&mut manager) -} - -pub(in crate::context_bootstrap) fn indexed_db_usage_bytes_for_storage_key( - scope: &mut v8::PinScope<'_, '_>, - storage_key: &str, -) -> u64 { - let usage = with_indexed_db_manager(scope, |manager| manager.origin_usage_bytes(storage_key)); - usage.unwrap_or(0) -} - -pub(in crate::context_bootstrap::indexed_db) fn storage_bucket_quota_check_for_database<'s>( - scope: &mut v8::PinScope<'s, '_>, - database: v8::Local<'s, v8::Object>, -) -> Option> { - let storage_scope = indexed_db_typed_storage_scope(scope, database)?.clone(); - let locator = if let Some(context) = storage_scope.bucket_context() { - let Some(locator) = with_storage_bucket_store_entry(scope, |store| { - store.bucket_locator_for_identity(&context.identity) - }) else { - return Some(Err(IndexedDbError::InvalidState( - "StorageBucket IndexedDB quota store is unavailable".to_owned(), - ))); - }; - let Some(locator) = locator else { - return Some(Err(IndexedDbError::InvalidState( - "StorageBucket IndexedDB bucket is no longer current".to_owned(), - ))); - }; - locator - } else { - moli_storage_service::StorageBucketLocator::default_bucket(storage_scope.storage_key()) - }; - let Some(owner) = storage_bucket_quota_owner_for_locator(scope, &locator) else { - return Some(Err(IndexedDbError::InvalidState( - "StorageBucket IndexedDB aggregate quota owner is unavailable".to_owned(), - ))); - }; - let reservation = owner.reserve_commit(); - let (quota, non_indexed_db_usage) = match owner.quota_and_non_indexed_db_usage() { - Ok(usage) => usage, - Err(error) => { - return Some(Err(IndexedDbError::InvalidState(error.to_string()))); - } - }; - Some(Ok(StorageBucketIndexedDbQuotaCommit { - quota_check: IndexedDbQuotaCheck { - quota, - non_indexed_db_usage, - }, - _reservation: reservation, - })) -} - -pub(in crate::context_bootstrap::indexed_db) fn validate_storage_bucket_indexed_db_context( - scope: &mut v8::PinScope<'_, '_>, - context: &IndexedDbStorageBucketContext, -) -> std::result::Result<(), IndexedDbError> { - let is_current = with_storage_bucket_store_entry(scope, |store| { - store.bucket_identity_is_live(&context.identity) - }) - .ok_or_else(|| { - IndexedDbError::InvalidState("StorageBucket IndexedDB store is unavailable".to_owned()) - })?; - if is_current { - Ok(()) - } else { - Err(IndexedDbError::InvalidState( - "StorageBucket IndexedDB bucket is no longer current".to_owned(), - )) - } -} - -pub(in crate::context_bootstrap::indexed_db) fn storage_bucket_quota_check_for_object_store<'s>( - scope: &mut v8::PinScope<'s, '_>, - store: v8::Local<'s, v8::Object>, -) -> Option> { - let database = indexed_db_object_store_database(scope, store)?; - storage_bucket_quota_check_for_database(scope, database) -} - -pub(in crate::context_bootstrap::indexed_db) fn storage_bucket_quota_check_for_transaction<'s>( - scope: &mut v8::PinScope<'s, '_>, - transaction: v8::Local<'s, v8::Object>, -) -> Option> { - let database = object_property_as_object(scope, transaction, "db")?; - storage_bucket_quota_check_for_database(scope, database) -} - -#[cfg(test)] -pub(crate) fn indexed_db_manager_context_slot_present_for_test( - scope: &mut v8::PinScope<'_, '_>, -) -> bool { - scope - .get_current_context() - .get_slot::() - .is_some() -} - -#[cfg(test)] -pub(crate) fn indexed_db_manager_isolate_slot_present_for_test( - scope: &mut v8::PinScope<'_, '_>, -) -> bool { - scope.get_slot::().is_some() -} diff --git a/moli-renderer-v8/src/context_bootstrap/indexed_db/database.rs b/moli-renderer-v8/src/context_bootstrap/indexed_db/database.rs index 4264307cb4..e825e1d421 100644 --- a/moli-renderer-v8/src/context_bootstrap/indexed_db/database.rs +++ b/moli-renderer-v8/src/context_bootstrap/indexed_db/database.rs @@ -22,7 +22,7 @@ use super::{ storage_scope_for_window_execution_context, store_request_error, sync_transaction_object_store_names_from_database, throw_type_error, transaction_db_key, transaction_handle_from_value, unregister_open_database_connection, - unregister_readwrite_transaction, v8_string, v8str, validate_storage_bucket_indexed_db_context, + unregister_readwrite_transaction, v8_string, v8str, validate_storage_bucket_scope, with_indexed_db_manager, }; diff --git a/moli-renderer-v8/src/context_bootstrap/indexed_db/database/factory.rs b/moli-renderer-v8/src/context_bootstrap/indexed_db/database/factory.rs index 73a170c10f..5d3a3f316d 100644 --- a/moli-renderer-v8/src/context_bootstrap/indexed_db/database/factory.rs +++ b/moli-renderer-v8/src/context_bootstrap/indexed_db/database/factory.rs @@ -47,13 +47,13 @@ fn idb_factory_effective_storage_scope<'s>( }) .or_else(|| { owner.execution_context().and_then(|execution_context| { - storage_scope_for_window_execution_context(scope, execution_context, None) + storage_scope_for_window_execution_context(scope, execution_context) }) }) .or_else(|| { context_host_ptr_from_global_bridge(scope) .is_none() - .then(|| current_storage_scope(scope, None)) + .then(|| current_storage_scope(scope)) .flatten() })?; origin_allows_indexed_db(storage_scope.storage_key()).then_some(storage_scope) diff --git a/moli-renderer-v8/src/context_bootstrap/indexed_db/database/factory/databases.rs b/moli-renderer-v8/src/context_bootstrap/indexed_db/database/factory/databases.rs index e7133910b1..830568abba 100644 --- a/moli-renderer-v8/src/context_bootstrap/indexed_db/database/factory/databases.rs +++ b/moli-renderer-v8/src/context_bootstrap/indexed_db/database/factory/databases.rs @@ -32,10 +32,7 @@ pub(in crate::context_bootstrap::indexed_db) fn idb_factory_databases_callback<' return; }; let origin = storage_scope.storage_key().to_owned(); - let bucket_context = storage_scope.bucket_context().cloned(); - if let Some(context) = bucket_context.as_ref() - && let Err(error) = validate_storage_bucket_indexed_db_context(scope, context) - { + if let Err(error) = validate_storage_bucket_scope(scope, &storage_scope) { let error = request_error_object(scope, &error); schedule_databases_promise_settlement( scope, diff --git a/moli-renderer-v8/src/context_bootstrap/indexed_db/database/factory/delete_database.rs b/moli-renderer-v8/src/context_bootstrap/indexed_db/database/factory/delete_database.rs index 063e7e5e0d..718b02436c 100644 --- a/moli-renderer-v8/src/context_bootstrap/indexed_db/database/factory/delete_database.rs +++ b/moli-renderer-v8/src/context_bootstrap/indexed_db/database/factory/delete_database.rs @@ -38,7 +38,6 @@ pub(in crate::context_bootstrap::indexed_db) fn idb_factory_delete_database_call }; let _ = ensure_indexed_db_runtime_state(scope); let origin = storage_scope.storage_key().to_owned(); - let bucket_context = storage_scope.bucket_context().cloned(); let request_storage_scope = storage_scope.clone(); let Some(request) = create_open_request_object(scope, args.this(), owner, request_storage_scope) @@ -46,9 +45,7 @@ pub(in crate::context_bootstrap::indexed_db) fn idb_factory_delete_database_call rv.set_undefined(); return; }; - if let Some(context) = bucket_context.as_ref() - && let Err(error) = validate_storage_bucket_indexed_db_context(scope, context) - { + if let Err(error) = validate_storage_bucket_scope(scope, &storage_scope) { let error = request_error_object(scope, &error); store_request_error(scope, request, error); rv.set(request.into()); diff --git a/moli-renderer-v8/src/context_bootstrap/indexed_db/database/factory/open.rs b/moli-renderer-v8/src/context_bootstrap/indexed_db/database/factory/open.rs index 8370d3cd66..0aaee2b419 100644 --- a/moli-renderer-v8/src/context_bootstrap/indexed_db/database/factory/open.rs +++ b/moli-renderer-v8/src/context_bootstrap/indexed_db/database/factory/open.rs @@ -47,7 +47,6 @@ pub(in crate::context_bootstrap::indexed_db) fn idb_factory_open_callback<'s>( return; }; let origin = storage_scope.storage_key().to_owned(); - let bucket_context = storage_scope.bucket_context().cloned(); let request_storage_scope = storage_scope.clone(); let _ = ensure_indexed_db_runtime_state(scope); @@ -57,9 +56,7 @@ pub(in crate::context_bootstrap::indexed_db) fn idb_factory_open_callback<'s>( rv.set_undefined(); return; }; - if let Some(context) = bucket_context.as_ref() - && let Err(error) = validate_storage_bucket_indexed_db_context(scope, context) - { + if let Err(error) = validate_storage_bucket_scope(scope, &storage_scope) { let error = request_error_object(scope, &error); store_request_error(scope, request, error); rv.set(request.into()); diff --git a/moli-renderer-v8/src/context_bootstrap/indexed_db/mod.rs b/moli-renderer-v8/src/context_bootstrap/indexed_db/mod.rs index 8be486c26e..3651de6916 100644 --- a/moli-renderer-v8/src/context_bootstrap/indexed_db/mod.rs +++ b/moli-renderer-v8/src/context_bootstrap/indexed_db/mod.rs @@ -19,6 +19,7 @@ mod operation_state; mod runtime; mod slots; mod state; +mod storage_bucket; mod stores; mod tasks; mod typed_state; @@ -32,6 +33,10 @@ use self::event_target::*; use self::operation_state::*; use self::runtime::*; use self::slots::*; +use self::storage_bucket::{ + storage_bucket_quota_check_for_object_store, storage_bucket_quota_check_for_transaction, + validate_storage_bucket_scope, +}; use self::stores::*; use self::tasks::*; use self::typed_state::*; @@ -66,14 +71,13 @@ pub(crate) use self::install::install_worker_indexed_db_runtime_state; pub(super) use self::install::{ ensure_indexed_db_runtime_state, install_indexed_db_template_bindings, window_indexed_db_getter, }; -pub(in crate::context_bootstrap) use self::runtime::scoped_storage_bucket_indexed_db_factory; pub use self::state::{ SharedIndexedDbManager, WeakIndexedDbManager, clear_indexed_db_origin, clear_indexed_db_origins_with_prefix, downgrade_indexed_db_manager, indexed_db_origin_usage_bytes, indexed_db_origins_with_prefix_usage_bytes, new_indexed_db_manager, }; -pub(in crate::context_bootstrap) use self::types::IndexedDbStorageBucketContext; +pub(in crate::context_bootstrap) use self::storage_bucket::scoped_storage_bucket_indexed_db_factory; pub use moli_indexeddb::{ IndexedDbQuotaCheck, Key, ObjectStoreOptions, OpenOptions, TransactionMode, }; diff --git a/moli-renderer-v8/src/context_bootstrap/indexed_db/runtime.rs b/moli-renderer-v8/src/context_bootstrap/indexed_db/runtime.rs index 4427b0dcbf..2fe370c412 100644 --- a/moli-renderer-v8/src/context_bootstrap/indexed_db/runtime.rs +++ b/moli-renderer-v8/src/context_bootstrap/indexed_db/runtime.rs @@ -256,9 +256,16 @@ fn ensure_runtime_factory_field<'s>( pub(crate) fn scoped_indexed_db_factory<'s>( scope: &mut v8::PinScope<'s, '_>, storage_key: &str, +) -> Option> { + let storage_scope = storage_scope_for_current_partition(scope, storage_key)?; + build_scoped_indexed_db_factory(scope, storage_scope) +} + +pub(super) fn build_scoped_indexed_db_factory<'s>( + scope: &mut v8::PinScope<'s, '_>, + storage_scope: IndexedDbStorageScope, ) -> Option> { let factory = build_indexed_db_factory_object(scope)?; - let storage_scope = storage_scope_for_current_partition(scope, storage_key, None)?; register_indexed_db_wrapper( scope, factory, @@ -277,7 +284,7 @@ pub(crate) fn bind_indexed_db_factory_to_window_execution_context<'s>( return false; } let storage_scope = indexed_db_typed_storage_scope(scope, factory) - .or_else(|| storage_scope_for_window_execution_context(scope, execution_context, None)); + .or_else(|| storage_scope_for_window_execution_context(scope, execution_context)); register_indexed_db_wrapper_with_owner( scope, factory, @@ -288,23 +295,6 @@ pub(crate) fn bind_indexed_db_factory_to_window_execution_context<'s>( true } -pub(in crate::context_bootstrap) fn scoped_storage_bucket_indexed_db_factory<'s>( - scope: &mut v8::PinScope<'s, '_>, - storage_key: &str, - context: &IndexedDbStorageBucketContext, -) -> Option> { - let factory = scoped_indexed_db_factory(scope, storage_key)?; - let storage_scope = - storage_scope_for_current_partition(scope, storage_key, Some(context.clone()))?; - register_indexed_db_wrapper( - scope, - factory, - IndexedDbWrapperKind::Factory, - Some(storage_scope), - ); - Some(factory) -} - pub(in crate::context_bootstrap::indexed_db) fn indexed_db_factory_storage_scope<'s>( scope: &mut v8::PinScope<'s, '_>, factory: v8::Local<'s, v8::Object>, @@ -335,12 +325,12 @@ fn build_indexed_db_factory_object<'s>( let storage_scope = owner .execution_context() .and_then(|execution_context| { - storage_scope_for_window_execution_context(scope, execution_context, None) + storage_scope_for_window_execution_context(scope, execution_context) }) .or_else(|| { context_host_ptr_from_global_bridge(scope) .is_none() - .then(|| current_storage_scope(scope, None)) + .then(|| current_storage_scope(scope)) .flatten() }); register_indexed_db_wrapper_with_owner( diff --git a/moli-renderer-v8/src/context_bootstrap/indexed_db/storage_bucket.rs b/moli-renderer-v8/src/context_bootstrap/indexed_db/storage_bucket.rs new file mode 100644 index 0000000000..1b7fcee078 --- /dev/null +++ b/moli-renderer-v8/src/context_bootstrap/indexed_db/storage_bucket.rs @@ -0,0 +1,100 @@ +//! Storage Bucket identity, liveness, and quota integration for IndexedDB. + +use super::{ + IndexedDbError, IndexedDbQuotaCheck, IndexedDbStorageScope, build_scoped_indexed_db_factory, + indexed_db_object_store_database, indexed_db_typed_storage_scope, object_property_as_object, + storage_scope_for_current_partition, +}; +use crate::context_bootstrap::storage_buckets::{ + storage_bucket_quota_owner_for_locator, with_storage_bucket_store_entry, +}; +use moli_storage_service::{StorageBucketIdentity, StorageBucketLocator}; + +pub(in crate::context_bootstrap) fn scoped_storage_bucket_indexed_db_factory<'s>( + scope: &mut v8::PinScope<'s, '_>, + identity: &StorageBucketIdentity, +) -> Option> { + let storage_scope = + storage_scope_for_current_partition(scope, identity.indexed_db_storage_key())? + .with_bucket_identity(identity.clone()); + build_scoped_indexed_db_factory(scope, storage_scope) +} + +pub(in crate::context_bootstrap::indexed_db) struct IndexedDbBucketQuotaCommit { + pub quota_check: IndexedDbQuotaCheck, + _reservation: moli_storage_service::StorageQuotaReservation, +} + +fn live_bucket_locator( + scope: &mut v8::PinScope<'_, '_>, + identity: &StorageBucketIdentity, +) -> std::result::Result { + with_storage_bucket_store_entry(scope, |store| store.bucket_locator_for_identity(identity)) + .ok_or_else(|| { + IndexedDbError::InvalidState("StorageBucket IndexedDB store is unavailable".to_owned()) + })? + .ok_or_else(|| { + IndexedDbError::InvalidState( + "StorageBucket IndexedDB bucket is no longer current".to_owned(), + ) + }) +} + +pub(in crate::context_bootstrap::indexed_db) fn validate_storage_bucket_scope( + scope: &mut v8::PinScope<'_, '_>, + storage_scope: &IndexedDbStorageScope, +) -> std::result::Result<(), IndexedDbError> { + let Some(identity) = storage_scope.bucket_identity() else { + return Ok(()); + }; + live_bucket_locator(scope, identity).map(|_| ()) +} + +fn storage_bucket_quota_check_for_database<'s>( + scope: &mut v8::PinScope<'s, '_>, + database: v8::Local<'s, v8::Object>, +) -> Option> { + let storage_scope = indexed_db_typed_storage_scope(scope, database)?; + let locator = match storage_scope.bucket_identity() { + Some(identity) => match live_bucket_locator(scope, identity) { + Ok(locator) => locator, + Err(error) => return Some(Err(error)), + }, + None => StorageBucketLocator::default_bucket(storage_scope.storage_key()), + }; + let Some(owner) = storage_bucket_quota_owner_for_locator(scope, &locator) else { + return Some(Err(IndexedDbError::InvalidState( + "StorageBucket IndexedDB aggregate quota owner is unavailable".to_owned(), + ))); + }; + let reservation = owner.reserve_commit(); + let (quota, non_indexed_db_usage) = match owner.quota_and_non_indexed_db_usage() { + Ok(usage) => usage, + Err(error) => { + return Some(Err(IndexedDbError::InvalidState(error.to_string()))); + } + }; + Some(Ok(IndexedDbBucketQuotaCommit { + quota_check: IndexedDbQuotaCheck { + quota, + non_indexed_db_usage, + }, + _reservation: reservation, + })) +} + +pub(in crate::context_bootstrap::indexed_db) fn storage_bucket_quota_check_for_object_store<'s>( + scope: &mut v8::PinScope<'s, '_>, + store: v8::Local<'s, v8::Object>, +) -> Option> { + let database = indexed_db_object_store_database(scope, store)?; + storage_bucket_quota_check_for_database(scope, database) +} + +pub(in crate::context_bootstrap::indexed_db) fn storage_bucket_quota_check_for_transaction<'s>( + scope: &mut v8::PinScope<'s, '_>, + transaction: v8::Local<'s, v8::Object>, +) -> Option> { + let database = object_property_as_object(scope, transaction, "db")?; + storage_bucket_quota_check_for_database(scope, database) +} diff --git a/moli-renderer-v8/src/context_bootstrap/indexed_db/tasks.rs b/moli-renderer-v8/src/context_bootstrap/indexed_db/tasks.rs index 3bf8208f5b..5ed6ce0874 100644 --- a/moli-renderer-v8/src/context_bootstrap/indexed_db/tasks.rs +++ b/moli-renderer-v8/src/context_bootstrap/indexed_db/tasks.rs @@ -40,7 +40,7 @@ use super::{ storage_bucket_quota_check_for_object_store, storage_bucket_quota_check_for_transaction, take_indexed_db_operations_waiting_for_start, take_indexed_db_task_by_id, transaction_db_key, transaction_handle_from_value, unregister_blocked_database_context, - unregister_readwrite_transaction, v8_string, v8str, validate_storage_bucket_indexed_db_context, + unregister_readwrite_transaction, v8_string, v8str, validate_storage_bucket_scope, with_indexed_db_manager, }; use crate::util::enqueue_host_microtask; diff --git a/moli-renderer-v8/src/context_bootstrap/indexed_db/tasks/open_delete/delete.rs b/moli-renderer-v8/src/context_bootstrap/indexed_db/tasks/open_delete/delete.rs index 44a2e20bc5..a10cd7a79d 100644 --- a/moli-renderer-v8/src/context_bootstrap/indexed_db/tasks/open_delete/delete.rs +++ b/moli-renderer-v8/src/context_bootstrap/indexed_db/tasks/open_delete/delete.rs @@ -6,9 +6,7 @@ pub(in crate::context_bootstrap::indexed_db) fn execute_delete_database_request< storage_scope: IndexedDbStorageScope, name: String, ) { - if let Some(context) = storage_scope.bucket_context() - && let Err(error) = validate_storage_bucket_indexed_db_context(scope, context) - { + if let Err(error) = validate_storage_bucket_scope(scope, &storage_scope) { let error = request_error_object(scope, &error); store_request_error(scope, request, error); return; diff --git a/moli-renderer-v8/src/context_bootstrap/indexed_db/tasks/open_delete/open.rs b/moli-renderer-v8/src/context_bootstrap/indexed_db/tasks/open_delete/open.rs index a3461b5bf7..0fda9c896a 100644 --- a/moli-renderer-v8/src/context_bootstrap/indexed_db/tasks/open_delete/open.rs +++ b/moli-renderer-v8/src/context_bootstrap/indexed_db/tasks/open_delete/open.rs @@ -12,9 +12,7 @@ pub(in crate::context_bootstrap::indexed_db) fn execute_open_request<'s>( ) { let database_name = name.clone(); let storage_key = storage_scope.storage_key().to_owned(); - if let Some(context) = storage_scope.bucket_context() - && let Err(error) = validate_storage_bucket_indexed_db_context(scope, context) - { + if let Err(error) = validate_storage_bucket_scope(scope, &storage_scope) { let error = request_error_object(scope, &error); store_request_error(scope, request, error); return; diff --git a/moli-renderer-v8/src/context_bootstrap/indexed_db/typed_state.rs b/moli-renderer-v8/src/context_bootstrap/indexed_db/typed_state.rs index 6d8c143c2d..5867977e4b 100644 --- a/moli-renderer-v8/src/context_bootstrap/indexed_db/typed_state.rs +++ b/moli-renderer-v8/src/context_bootstrap/indexed_db/typed_state.rs @@ -1,4 +1,5 @@ use super::*; +use moli_storage_service::StorageBucketIdentity; use std::{cell::RefCell, collections::BTreeMap, rc::Rc}; #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] @@ -79,7 +80,7 @@ impl IndexedDbExecutionOwner { #[derive(Clone, Debug, Eq, PartialEq)] pub(super) struct IndexedDbStorageScope { storage_key: String, - bucket_context: Option, + bucket_identity: Option, browser_context_id: String, profile_partition_id: String, } @@ -87,24 +88,28 @@ pub(super) struct IndexedDbStorageScope { impl IndexedDbStorageScope { pub(super) fn new( storage_key: impl Into, - bucket_context: Option, browser_context_id: impl Into, profile_partition_id: impl Into, ) -> Self { Self { storage_key: storage_key.into(), - bucket_context, + bucket_identity: None, browser_context_id: browser_context_id.into(), profile_partition_id: profile_partition_id.into(), } } + pub(super) fn with_bucket_identity(mut self, identity: StorageBucketIdentity) -> Self { + self.bucket_identity = Some(identity); + self + } + pub(super) fn storage_key(&self) -> &str { &self.storage_key } - pub(super) fn bucket_context(&self) -> Option<&IndexedDbStorageBucketContext> { - self.bucket_context.as_ref() + pub(super) fn bucket_identity(&self) -> Option<&StorageBucketIdentity> { + self.bucket_identity.as_ref() } pub(super) fn browser_context_id(&self) -> &str { @@ -2011,7 +2016,6 @@ mod tests { let scope = IndexedDbStorageScope::new( "storage-key:v1;origin=https://example.test", - None, "browser-context:test", "profile-partition:test", ); @@ -2053,7 +2057,6 @@ mod tests { let mut table = IndexedDbRuntimeStateTable::default(); let storage_scope = IndexedDbStorageScope::new( "storage-key:v1;origin=https://task.example", - None, "browser-context:task", "profile-partition:task", ); diff --git a/moli-renderer-v8/src/context_bootstrap/indexed_db/types.rs b/moli-renderer-v8/src/context_bootstrap/indexed_db/types.rs index e1269b8d8d..ae376df459 100644 --- a/moli-renderer-v8/src/context_bootstrap/indexed_db/types.rs +++ b/moli-renderer-v8/src/context_bootstrap/indexed_db/types.rs @@ -1,5 +1,4 @@ use super::{IndexedDbError, IndexedDbValue, Key}; -use moli_storage_service::StorageBucketIdentity; #[derive(Debug, Clone)] pub(super) struct IdbKeyRangeQuery { @@ -28,11 +27,6 @@ pub(super) struct PreparedObjectStoreWrite<'s> { pub(super) value: v8::Local<'s, v8::Value>, } -#[derive(Debug, Clone, Eq, PartialEq)] -pub(in crate::context_bootstrap) struct IndexedDbStorageBucketContext { - pub(in crate::context_bootstrap) identity: StorageBucketIdentity, -} - pub(super) enum PreparedObjectStoreWriteError { Backend(IndexedDbError), DomException { diff --git a/moli-renderer-v8/src/context_bootstrap/window_runtime/navigator.rs b/moli-renderer-v8/src/context_bootstrap/window_runtime/navigator.rs index 690ad99e9e..92d09ccd50 100644 --- a/moli-renderer-v8/src/context_bootstrap/window_runtime/navigator.rs +++ b/moli-renderer-v8/src/context_bootstrap/window_runtime/navigator.rs @@ -1247,13 +1247,9 @@ pub(in crate::context_bootstrap) fn storage_bucket_indexed_db_getter_callback<'s rv.set_undefined(); return; }; - let context = IndexedDbStorageBucketContext { - identity: handle.identity.clone(), - }; - let value = - scoped_storage_bucket_indexed_db_factory(scope, &handle.indexed_db_storage_key, &context) - .map(Into::into) - .unwrap_or_else(|| v8::undefined(scope).into()); + let value = scoped_storage_bucket_indexed_db_factory(scope, &handle.identity) + .map(Into::into) + .unwrap_or_else(|| v8::undefined(scope).into()); rv.set(value); }