Skip to content
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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 6 additions & 5 deletions crates/core/js-runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@ version.workspace = true
license-file.workspace = true

[dependencies]
v8 = "135.1.0"
datafusion.workspace = true
thiserror.workspace = true
async-trait.workspace = true
blake3.workspace = true
num-traits = "0.2.19"
datafusion.workspace = true
deadpool = "0.12.2"
lru = "0.16.3"
num-traits = "0.2.19"
num_cpus = "1.16.0"
thiserror.workspace = true
tokio.workspace = true
async-trait.workspace = true
v8 = "135.1.0"

[dev-dependencies]
hex.workspace = true
Expand Down
21 changes: 16 additions & 5 deletions crates/core/js-runtime/src/isolate.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use datafusion::common::HashMap;
use std::num::NonZero;

use lru::LruCache;
use v8::{
Handle as _,
script_compiler::{CompileOptions, NoCacheReason},
Expand All @@ -10,6 +12,9 @@ use crate::{
init_platform,
};

/// Maximum number of compiled scripts cached per isolate.
const SCRIPT_CACHE_CAPACITY: NonZero<usize> = NonZero::<usize>::new(1000).unwrap();

/// Errors that occur during JavaScript isolate operations
///
/// This error type is used by [`Isolate::invoke`], [`Isolate::invoke_batch`],
Expand Down Expand Up @@ -61,12 +66,18 @@ pub enum Error {
PoolError(#[source] deadpool::unmanaged::PoolError),
}

/// A single-threaded V8 isolate with an LRU cache of compiled scripts.
///
/// Each isolate owns a V8 engine instance and caches compiled scripts keyed by
/// content hash, evicting least-recently-used entries when the cache is full.
/// Isolates are not `Send` or `Sync` — use [`crate::IsolatePool`] for async access.
#[derive(Debug)]
pub struct Isolate {
/// The underlying V8 engine instance owned by this isolate.
isolate: v8::OwnedIsolate,

// TODO: Use cache capable of evicting
scripts: HashMap<blake3::Hash, v8::Global<v8::UnboundScript>>,
/// LRU cache of compiled scripts, keyed by blake3 hash of the script source.
scripts: LruCache<blake3::Hash, v8::Global<v8::UnboundScript>>,
}

impl Default for Isolate {
Expand All @@ -83,7 +94,7 @@ impl Isolate {
let isolate = v8::Isolate::new(v8::CreateParams::default());
Self {
isolate,
scripts: HashMap::new(),
scripts: LruCache::new(SCRIPT_CACHE_CAPACITY),
}
}

Expand Down Expand Up @@ -121,7 +132,7 @@ impl Isolate {
None => return Err(Error::Exception(Box::new(catch(s)))),
}
};
self.scripts.insert(key, compiled_script.clone());
self.scripts.put(key, compiled_script.clone());
Ok(compiled_script)
}

Expand Down