refactor(ext/cache): Remove custom shutdown and use fast async ops (#20107)

The original implementation of `Cache` used a custom `shutdown` method
on the resource, but to simplify fast streams work we're going to move
this to an op of its own.

While we're in here, we're going to replace `opAsync` with
`ensureFastOps`. `op2` work will have to wait because of some
limitations to our async support, however.
This commit is contained in:
Matt Mastracci 2023-08-09 11:45:35 -06:00 committed by GitHub
parent ddfcf1add4
commit 2ed85c7dd6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 68 additions and 31 deletions

28
ext/cache/01_cache.js vendored
View file

@ -1,5 +1,5 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
// deno-lint-ignore-file camelcase
const core = globalThis.Deno.core; const core = globalThis.Deno.core;
import * as webidl from "ext:deno_webidl/00_webidl.js"; import * as webidl from "ext:deno_webidl/00_webidl.js";
const primordials = globalThis.__bootstrap.primordials; const primordials = globalThis.__bootstrap.primordials;
@ -20,7 +20,15 @@ import { toInnerResponse } from "ext:deno_fetch/23_response.js";
import { URLPrototype } from "ext:deno_url/00_url.js"; import { URLPrototype } from "ext:deno_url/00_url.js";
import { getHeader } from "ext:deno_fetch/20_headers.js"; import { getHeader } from "ext:deno_fetch/20_headers.js";
import { readableStreamForRid } from "ext:deno_web/06_streams.js"; import { readableStreamForRid } from "ext:deno_web/06_streams.js";
const {
op_cache_delete,
op_cache_match,
op_cache_put,
op_cache_put_finish,
op_cache_storage_delete,
op_cache_storage_has,
op_cache_storage_open,
} = core.ensureFastOps();
class CacheStorage { class CacheStorage {
constructor() { constructor() {
webidl.illegalConstructor(); webidl.illegalConstructor();
@ -31,7 +39,7 @@ class CacheStorage {
const prefix = "Failed to execute 'open' on 'CacheStorage'"; const prefix = "Failed to execute 'open' on 'CacheStorage'";
webidl.requiredArguments(arguments.length, 1, prefix); webidl.requiredArguments(arguments.length, 1, prefix);
cacheName = webidl.converters["DOMString"](cacheName, prefix, "Argument 1"); cacheName = webidl.converters["DOMString"](cacheName, prefix, "Argument 1");
const cacheId = await core.opAsync("op_cache_storage_open", cacheName); const cacheId = await op_cache_storage_open(cacheName);
const cache = webidl.createBranded(Cache); const cache = webidl.createBranded(Cache);
cache[_id] = cacheId; cache[_id] = cacheId;
return cache; return cache;
@ -42,7 +50,7 @@ class CacheStorage {
const prefix = "Failed to execute 'has' on 'CacheStorage'"; const prefix = "Failed to execute 'has' on 'CacheStorage'";
webidl.requiredArguments(arguments.length, 1, prefix); webidl.requiredArguments(arguments.length, 1, prefix);
cacheName = webidl.converters["DOMString"](cacheName, prefix, "Argument 1"); cacheName = webidl.converters["DOMString"](cacheName, prefix, "Argument 1");
return await core.opAsync("op_cache_storage_has", cacheName); return await op_cache_storage_has(cacheName);
} }
async delete(cacheName) { async delete(cacheName) {
@ -50,7 +58,7 @@ class CacheStorage {
const prefix = "Failed to execute 'delete' on 'CacheStorage'"; const prefix = "Failed to execute 'delete' on 'CacheStorage'";
webidl.requiredArguments(arguments.length, 1, prefix); webidl.requiredArguments(arguments.length, 1, prefix);
cacheName = webidl.converters["DOMString"](cacheName, prefix, "Argument 1"); cacheName = webidl.converters["DOMString"](cacheName, prefix, "Argument 1");
return await core.opAsync("op_cache_storage_delete", cacheName); return await op_cache_storage_delete(cacheName);
} }
} }
@ -124,8 +132,7 @@ class Cache {
reqUrl.hash = ""; reqUrl.hash = "";
// Step 9-11. // Step 9-11.
const rid = await core.opAsync( const rid = await op_cache_put(
"op_cache_put",
{ {
cacheId: this[_id], cacheId: this[_id],
// deno-lint-ignore prefer-primordials // deno-lint-ignore prefer-primordials
@ -142,7 +149,7 @@ class Cache {
while (true) { while (true) {
const { value, done } = await reader.read(); const { value, done } = await reader.read();
if (done) { if (done) {
await core.shutdown(rid); await op_cache_put_finish(rid);
break; break;
} }
await core.writeAll(rid, value); await core.writeAll(rid, value);
@ -196,7 +203,7 @@ class Cache {
) { ) {
r = new Request(request); r = new Request(request);
} }
return await core.opAsync("op_cache_delete", { return await op_cache_delete({
cacheId: this[_id], cacheId: this[_id],
requestUrl: r.url, requestUrl: r.url,
}); });
@ -240,8 +247,7 @@ class Cache {
const url = new URL(r.url); const url = new URL(r.url);
url.hash = ""; url.hash = "";
const innerRequest = toInnerRequest(r); const innerRequest = toInnerRequest(r);
const matchResult = await core.opAsync( const matchResult = await op_cache_match(
"op_cache_match",
{ {
cacheId: this[_id], cacheId: this[_id],
// deno-lint-ignore prefer-primordials // deno-lint-ignore prefer-primordials

50
ext/cache/lib.rs vendored
View file

@ -14,6 +14,7 @@ use deno_core::ByteString;
use deno_core::OpState; use deno_core::OpState;
use deno_core::Resource; use deno_core::Resource;
use deno_core::ResourceId; use deno_core::ResourceId;
mod sqlite; mod sqlite;
pub use sqlite::SqliteBackedCache; pub use sqlite::SqliteBackedCache;
@ -28,6 +29,7 @@ deno_core::extension!(deno_cache,
op_cache_storage_has<CA>, op_cache_storage_has<CA>,
op_cache_storage_delete<CA>, op_cache_storage_delete<CA>,
op_cache_put<CA>, op_cache_put<CA>,
op_cache_put_finish<CA>,
op_cache_match<CA>, op_cache_match<CA>,
op_cache_delete<CA>, op_cache_delete<CA>,
], ],
@ -86,16 +88,24 @@ pub struct CacheDeleteRequest {
pub request_url: String, pub request_url: String,
} }
#[async_trait] #[async_trait(?Send)]
pub trait Cache: Clone { pub trait Cache: Clone + 'static {
type CachePutResourceType: Resource;
async fn storage_open(&self, cache_name: String) -> Result<i64, AnyError>; async fn storage_open(&self, cache_name: String) -> Result<i64, AnyError>;
async fn storage_has(&self, cache_name: String) -> Result<bool, AnyError>; async fn storage_has(&self, cache_name: String) -> Result<bool, AnyError>;
async fn storage_delete(&self, cache_name: String) -> Result<bool, AnyError>; async fn storage_delete(&self, cache_name: String) -> Result<bool, AnyError>;
async fn put( /// Create a put request.
async fn put_create(
&self, &self,
request_response: CachePutRequest, request_response: CachePutRequest,
) -> Result<Option<Rc<dyn Resource>>, AnyError>; ) -> Result<Option<Rc<Self::CachePutResourceType>>, AnyError>;
/// Complete a put request.
async fn put_finish(
&self,
resource: Rc<Self::CachePutResourceType>,
) -> Result<(), AnyError>;
async fn r#match( async fn r#match(
&self, &self,
request: CacheMatchRequest, request: CacheMatchRequest,
@ -113,7 +123,7 @@ pub async fn op_cache_storage_open<CA>(
cache_name: String, cache_name: String,
) -> Result<i64, AnyError> ) -> Result<i64, AnyError>
where where
CA: Cache + 'static, CA: Cache,
{ {
let cache = get_cache::<CA>(&state)?; let cache = get_cache::<CA>(&state)?;
cache.storage_open(cache_name).await cache.storage_open(cache_name).await
@ -125,7 +135,7 @@ pub async fn op_cache_storage_has<CA>(
cache_name: String, cache_name: String,
) -> Result<bool, AnyError> ) -> Result<bool, AnyError>
where where
CA: Cache + 'static, CA: Cache,
{ {
let cache = get_cache::<CA>(&state)?; let cache = get_cache::<CA>(&state)?;
cache.storage_has(cache_name).await cache.storage_has(cache_name).await
@ -137,7 +147,7 @@ pub async fn op_cache_storage_delete<CA>(
cache_name: String, cache_name: String,
) -> Result<bool, AnyError> ) -> Result<bool, AnyError>
where where
CA: Cache + 'static, CA: Cache,
{ {
let cache = get_cache::<CA>(&state)?; let cache = get_cache::<CA>(&state)?;
cache.storage_delete(cache_name).await cache.storage_delete(cache_name).await
@ -149,10 +159,10 @@ pub async fn op_cache_put<CA>(
request_response: CachePutRequest, request_response: CachePutRequest,
) -> Result<Option<ResourceId>, AnyError> ) -> Result<Option<ResourceId>, AnyError>
where where
CA: Cache + 'static, CA: Cache,
{ {
let cache = get_cache::<CA>(&state)?; let cache = get_cache::<CA>(&state)?;
match cache.put(request_response).await? { match cache.put_create(request_response).await? {
Some(resource) => { Some(resource) => {
let rid = state.borrow_mut().resource_table.add_rc_dyn(resource); let rid = state.borrow_mut().resource_table.add_rc_dyn(resource);
Ok(Some(rid)) Ok(Some(rid))
@ -161,13 +171,29 @@ where
} }
} }
#[op]
pub async fn op_cache_put_finish<CA>(
state: Rc<RefCell<OpState>>,
rid: ResourceId,
) -> Result<(), AnyError>
where
CA: Cache,
{
let cache = get_cache::<CA>(&state)?;
let resource = state
.borrow_mut()
.resource_table
.get::<CA::CachePutResourceType>(rid)?;
cache.put_finish(resource).await
}
#[op] #[op]
pub async fn op_cache_match<CA>( pub async fn op_cache_match<CA>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
request: CacheMatchRequest, request: CacheMatchRequest,
) -> Result<Option<CacheMatchResponse>, AnyError> ) -> Result<Option<CacheMatchResponse>, AnyError>
where where
CA: Cache + 'static, CA: Cache,
{ {
let cache = get_cache::<CA>(&state)?; let cache = get_cache::<CA>(&state)?;
match cache.r#match(request).await? { match cache.r#match(request).await? {
@ -186,7 +212,7 @@ pub async fn op_cache_delete<CA>(
request: CacheDeleteRequest, request: CacheDeleteRequest,
) -> Result<bool, AnyError> ) -> Result<bool, AnyError>
where where
CA: Cache + 'static, CA: Cache,
{ {
let cache = get_cache::<CA>(&state)?; let cache = get_cache::<CA>(&state)?;
cache.delete(request).await cache.delete(request).await
@ -194,7 +220,7 @@ where
pub fn get_cache<CA>(state: &Rc<RefCell<OpState>>) -> Result<CA, AnyError> pub fn get_cache<CA>(state: &Rc<RefCell<OpState>>) -> Result<CA, AnyError>
where where
CA: Cache + 'static, CA: Cache,
{ {
let mut state = state.borrow_mut(); let mut state = state.borrow_mut();
if let Some(cache) = state.try_borrow::<CA>() { if let Some(cache) = state.try_borrow::<CA>() {

21
ext/cache/sqlite.rs vendored
View file

@ -92,8 +92,10 @@ impl SqliteBackedCache {
} }
} }
#[async_trait] #[async_trait(?Send)]
impl Cache for SqliteBackedCache { impl Cache for SqliteBackedCache {
type CachePutResourceType = CachePutResource;
/// Open a cache storage. Internally, this creates a row in the /// Open a cache storage. Internally, this creates a row in the
/// sqlite db if the cache doesn't exist and returns the internal id /// sqlite db if the cache doesn't exist and returns the internal id
/// of the cache. /// of the cache.
@ -167,10 +169,10 @@ impl Cache for SqliteBackedCache {
.await? .await?
} }
async fn put( async fn put_create(
&self, &self,
request_response: CachePutRequest, request_response: CachePutRequest,
) -> Result<Option<Rc<dyn Resource>>, AnyError> { ) -> Result<Option<Rc<CachePutResource>>, AnyError> {
let db = self.connection.clone(); let db = self.connection.clone();
let cache_storage_dir = self.cache_storage_dir.clone(); let cache_storage_dir = self.cache_storage_dir.clone();
let now = SystemTime::now().duration_since(UNIX_EPOCH)?; let now = SystemTime::now().duration_since(UNIX_EPOCH)?;
@ -202,6 +204,13 @@ impl Cache for SqliteBackedCache {
} }
} }
async fn put_finish(
&self,
resource: Rc<CachePutResource>,
) -> Result<(), AnyError> {
resource.write_to_cache().await
}
async fn r#match( async fn r#match(
&self, &self,
request: CacheMatchRequest, request: CacheMatchRequest,
@ -346,7 +355,7 @@ impl CachePutResource {
Ok(data.len()) Ok(data.len())
} }
async fn shutdown(self: Rc<Self>) -> Result<(), AnyError> { async fn write_to_cache(self: Rc<Self>) -> Result<(), AnyError> {
let resource = deno_core::RcRef::map(&self, |r| &r.file); let resource = deno_core::RcRef::map(&self, |r| &r.file);
let mut file = resource.borrow_mut().await; let mut file = resource.borrow_mut().await;
file.flush().await?; file.flush().await?;
@ -377,10 +386,6 @@ impl Resource for CachePutResource {
} }
deno_core::impl_writable!(); deno_core::impl_writable!();
fn shutdown(self: Rc<Self>) -> AsyncResult<()> {
Box::pin(self.shutdown())
}
} }
pub struct CacheResponseResource { pub struct CacheResponseResource {