mirror of
https://github.com/servo/servo.git
synced 2025-09-30 08:39:16 +01:00
Switch indexeddb backend to sqlite and improve IPC messaging (#38187)
- Use sqlite instead of heed. (one indexed database = one sqlite database) - Implement the backend for indexes - Use keyranges where needed (as specified by the spec) - Implement `getKey` - Fix channel error messaging (led to a bunch of changes to how async requests are handled) Note: `components/net/indexeddb/engines/sqlite/serialize.rs` is unused; I can delete it if needed. Testing: Switching to sqlite eliminated many panics (exposing some new failures). Fixes: #38040 --------- Signed-off-by: Ashwin Naren <arihant2math@gmail.com>
This commit is contained in:
parent
f4bbdf8010
commit
fc3feceee5
59 changed files with 2002 additions and 818 deletions
|
@ -8,13 +8,15 @@ use constellation_traits::StructuredSerializedData;
|
|||
use dom_struct::dom_struct;
|
||||
use ipc_channel::router::ROUTER;
|
||||
use js::jsapi::Heap;
|
||||
use js::jsval::{JSVal, UndefinedValue};
|
||||
use js::jsval::{DoubleValue, JSVal, UndefinedValue};
|
||||
use js::rust::HandleValue;
|
||||
use net_traits::IpcSend;
|
||||
use net_traits::indexeddb_thread::{
|
||||
AsyncOperation, IdbResult, IndexedDBThreadMsg, IndexedDBTxnMode,
|
||||
AsyncOperation, BackendResult, IndexedDBKeyType, IndexedDBThreadMsg, IndexedDBTxnMode,
|
||||
PutItemResult,
|
||||
};
|
||||
use profile_traits::ipc;
|
||||
use profile_traits::ipc::IpcReceiver;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use stylo_atoms::Atom;
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::IDBRequestBinding::{
|
||||
|
@ -42,8 +44,61 @@ struct RequestListener {
|
|||
request: Trusted<IDBRequest>,
|
||||
}
|
||||
|
||||
pub enum IdbResult {
|
||||
Key(IndexedDBKeyType),
|
||||
Data(Vec<u8>),
|
||||
Count(u64),
|
||||
Error(Error),
|
||||
None,
|
||||
}
|
||||
|
||||
impl From<IndexedDBKeyType> for IdbResult {
|
||||
fn from(value: IndexedDBKeyType) -> Self {
|
||||
IdbResult::Key(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<u8>> for IdbResult {
|
||||
fn from(value: Vec<u8>) -> Self {
|
||||
IdbResult::Data(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PutItemResult> for IdbResult {
|
||||
fn from(value: PutItemResult) -> Self {
|
||||
match value {
|
||||
PutItemResult::Success => Self::None,
|
||||
PutItemResult::CannotOverwrite => Self::Error(Error::Constraint),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<()> for IdbResult {
|
||||
fn from(_value: ()) -> Self {
|
||||
Self::None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Option<T>> for IdbResult
|
||||
where
|
||||
T: Into<IdbResult>,
|
||||
{
|
||||
fn from(value: Option<T>) -> Self {
|
||||
match value {
|
||||
Some(value) => value.into(),
|
||||
None => IdbResult::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for IdbResult {
|
||||
fn from(value: u64) -> Self {
|
||||
IdbResult::Count(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl RequestListener {
|
||||
fn handle_async_request_finished(&self, result: Result<Option<IdbResult>, ()>) {
|
||||
fn handle_async_request_finished(&self, result: BackendResult<IdbResult>) {
|
||||
let request = self.request.root();
|
||||
let global = request.global();
|
||||
let cx = GlobalScope::get_cx();
|
||||
|
@ -53,7 +108,7 @@ impl RequestListener {
|
|||
let _ac = enter_realm(&*request);
|
||||
rooted!(in(*cx) let mut answer = UndefinedValue());
|
||||
|
||||
if let Ok(Some(data)) = result {
|
||||
if let Ok(data) = result {
|
||||
match data {
|
||||
IdbResult::Key(key) => {
|
||||
key_type_to_jsval(GlobalScope::get_cx(), &key, answer.handle_mut())
|
||||
|
@ -68,6 +123,17 @@ impl RequestListener {
|
|||
warn!("Error reading structuredclone data");
|
||||
}
|
||||
},
|
||||
IdbResult::Count(count) => {
|
||||
answer.handle_mut().set(DoubleValue(count as f64));
|
||||
},
|
||||
IdbResult::None => {
|
||||
// no-op
|
||||
},
|
||||
IdbResult::Error(_err) => {
|
||||
request.set_result(answer.handle());
|
||||
Self::handle_async_request_error(request, &global);
|
||||
return;
|
||||
},
|
||||
}
|
||||
|
||||
request.set_result(answer.handle());
|
||||
|
@ -92,30 +158,33 @@ impl RequestListener {
|
|||
transaction.set_active_flag(false);
|
||||
} else {
|
||||
request.set_result(answer.handle());
|
||||
|
||||
// FIXME:(rasviitanen)
|
||||
// Set the error of request to result
|
||||
|
||||
let transaction = request
|
||||
.transaction
|
||||
.get()
|
||||
.expect("Request has no transaction");
|
||||
|
||||
let event = Event::new(
|
||||
&global,
|
||||
Atom::from("error"),
|
||||
EventBubbles::Bubbles,
|
||||
EventCancelable::Cancelable,
|
||||
CanGc::note(),
|
||||
);
|
||||
|
||||
transaction.set_active_flag(true);
|
||||
event
|
||||
.upcast::<Event>()
|
||||
.fire(request.upcast(), CanGc::note());
|
||||
transaction.set_active_flag(false);
|
||||
Self::handle_async_request_error(request, &global);
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_async_request_error(request: DomRoot<IDBRequest>, global: &GlobalScope) {
|
||||
// FIXME:(rasviitanen)
|
||||
// Set the error of request to result
|
||||
|
||||
let transaction = request
|
||||
.transaction
|
||||
.get()
|
||||
.expect("Request has no transaction");
|
||||
|
||||
let event = Event::new(
|
||||
global,
|
||||
Atom::from("error"),
|
||||
EventBubbles::Bubbles,
|
||||
EventCancelable::Cancelable,
|
||||
CanGc::note(),
|
||||
);
|
||||
|
||||
transaction.set_active_flag(true);
|
||||
event
|
||||
.upcast::<Event>()
|
||||
.fire(request.upcast(), CanGc::note());
|
||||
transaction.set_active_flag(false);
|
||||
}
|
||||
}
|
||||
|
||||
#[dom_struct]
|
||||
|
@ -174,12 +243,16 @@ impl IDBRequest {
|
|||
}
|
||||
|
||||
// https://www.w3.org/TR/IndexedDB-2/#asynchronously-execute-a-request
|
||||
pub fn execute_async(
|
||||
pub fn execute_async<T>(
|
||||
source: &IDBObjectStore,
|
||||
operation: AsyncOperation,
|
||||
receiver: IpcReceiver<BackendResult<T>>,
|
||||
request: Option<DomRoot<IDBRequest>>,
|
||||
can_gc: CanGc,
|
||||
) -> Fallible<DomRoot<IDBRequest>> {
|
||||
) -> Fallible<DomRoot<IDBRequest>>
|
||||
where
|
||||
T: Into<IdbResult> + for<'a> Deserialize<'a> + Serialize + Send + Sync + 'static,
|
||||
{
|
||||
// Step 1: Let transaction be the transaction associated with source.
|
||||
let transaction = source.transaction().expect("Store has no transaction");
|
||||
let global = transaction.global();
|
||||
|
@ -208,10 +281,6 @@ impl IDBRequest {
|
|||
IDBTransactionMode::Versionchange => IndexedDBTxnMode::Versionchange,
|
||||
};
|
||||
|
||||
let (sender, receiver) =
|
||||
ipc::channel::<Result<Option<IdbResult>, ()>>(global.time_profiler_chan().clone())
|
||||
.unwrap();
|
||||
|
||||
let response_listener = RequestListener {
|
||||
request: Trusted::new(&request),
|
||||
};
|
||||
|
@ -227,7 +296,7 @@ impl IDBRequest {
|
|||
let response_listener = response_listener.clone();
|
||||
task_source.queue(task!(request_callback: move || {
|
||||
response_listener.handle_async_request_finished(
|
||||
message.expect("Could not unwrap message"));
|
||||
message.expect("Could not unwrap message").map(|t| t.into()));
|
||||
}));
|
||||
}),
|
||||
);
|
||||
|
@ -237,7 +306,6 @@ impl IDBRequest {
|
|||
.resource_threads()
|
||||
.sender()
|
||||
.send(IndexedDBThreadMsg::Async(
|
||||
sender,
|
||||
global.origin().immutable().clone(),
|
||||
transaction.get_db_name().to_string(),
|
||||
source.get_name().to_string(),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue