simplify indexeddb storage bucket integration

This commit is contained in:
ldm0
2026-08-21 11:23:44 +08:00
committed by Donough Liu
parent cca374e0bf
commit ff26e9cfb7
20 changed files with 209 additions and 232 deletions
@@ -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,
@@ -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,
@@ -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,
};
@@ -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<WeakIndexedDbManager>);
pub(crate) fn set_indexed_db_manager_for_context(
context: v8::Local<'_, v8::Context>,
manager: Option<WeakIndexedDbManager>,
) {
let _previous = context.set_slot(std::rc::Rc::new(IndexedDbManagerSlot(manager)));
}
pub(in crate::context_bootstrap::indexed_db) fn with_indexed_db_manager<R>(
scope: &mut v8::PinScope<'_, '_>,
f: impl FnOnce(&mut IndexedDbManager) -> std::result::Result<R, IndexedDbError>,
) -> std::result::Result<R, IndexedDbError> {
let manager = scope
.get_current_context()
.get_slot::<IndexedDbManagerSlot>()
.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::<IndexedDbManagerSlot>()
.is_some()
}
#[cfg(test)]
pub(crate) fn indexed_db_manager_isolate_slot_present_for_test(
scope: &mut v8::PinScope<'_, '_>,
) -> bool {
scope.get_slot::<IndexedDbManagerSlot>().is_some()
}
@@ -2,7 +2,6 @@ use super::*;
pub(in crate::context_bootstrap::indexed_db) fn current_storage_scope(
scope: &mut v8::PinScope<'_, '_>,
bucket_context: Option<IndexedDbStorageBucketContext>,
) -> Option<IndexedDbStorageScope> {
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<IndexedDbStorageBucketContext>,
) -> Option<IndexedDbStorageScope> {
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<String>,
bucket_context: Option<IndexedDbStorageBucketContext>,
) -> Option<IndexedDbStorageScope> {
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(),
))
@@ -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<WeakIndexedDbManager>);
pub(crate) fn set_indexed_db_manager_for_context(
context: v8::Local<'_, v8::Context>,
manager: Option<WeakIndexedDbManager>,
) {
let _previous = context.set_slot(std::rc::Rc::new(IndexedDbManagerSlot(manager)));
}
pub(in crate::context_bootstrap::indexed_db) fn with_indexed_db_manager<R>(
scope: &mut v8::PinScope<'_, '_>,
f: impl FnOnce(&mut IndexedDbManager) -> std::result::Result<R, IndexedDbError>,
) -> std::result::Result<R, IndexedDbError> {
let manager = scope
.get_current_context()
.get_slot::<IndexedDbManagerSlot>()
.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<std::result::Result<StorageBucketIndexedDbQuotaCommit, IndexedDbError>> {
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<std::result::Result<StorageBucketIndexedDbQuotaCommit, IndexedDbError>> {
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<std::result::Result<StorageBucketIndexedDbQuotaCommit, IndexedDbError>> {
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::<IndexedDbManagerSlot>()
.is_some()
}
#[cfg(test)]
pub(crate) fn indexed_db_manager_isolate_slot_present_for_test(
scope: &mut v8::PinScope<'_, '_>,
) -> bool {
scope.get_slot::<IndexedDbManagerSlot>().is_some()
}
@@ -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,
};
@@ -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)
@@ -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,
@@ -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());
@@ -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());
@@ -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,
};
@@ -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<v8::Local<'s, v8::Object>> {
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<v8::Local<'s, v8::Object>> {
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<v8::Local<'s, v8::Object>> {
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(
@@ -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<v8::Local<'s, v8::Object>> {
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<StorageBucketLocator, IndexedDbError> {
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<std::result::Result<IndexedDbBucketQuotaCommit, IndexedDbError>> {
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<std::result::Result<IndexedDbBucketQuotaCommit, IndexedDbError>> {
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<std::result::Result<IndexedDbBucketQuotaCommit, IndexedDbError>> {
let database = object_property_as_object(scope, transaction, "db")?;
storage_bucket_quota_check_for_database(scope, database)
}
@@ -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;
@@ -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;
@@ -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;
@@ -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<IndexedDbStorageBucketContext>,
bucket_identity: Option<StorageBucketIdentity>,
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<String>,
bucket_context: Option<IndexedDbStorageBucketContext>,
browser_context_id: impl Into<String>,
profile_partition_id: impl Into<String>,
) -> 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",
);
@@ -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 {
@@ -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);
}