Skip to content

Commit

Permalink
perf: Cache OperationPlan creation (#2951)
Browse files Browse the repository at this point in the history
Co-authored-by: Tushar Mathur <[email protected]>
Co-authored-by: laststylebender <[email protected]>
  • Loading branch information
3 people authored Oct 20, 2024
1 parent 43d9975 commit 295e0d5
Show file tree
Hide file tree
Showing 51 changed files with 982 additions and 869 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ node_modules/
tailcall-/cloudflare/build

*.snap.new
flamegraph.svg
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.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ num = "0.4.3"
indenter = "0.3.3"
derive_more = { workspace = true }
strum = "0.26.2"
dashmap = "6.1.0"

[dev-dependencies]
datatest-stable = "0.2.9"
Expand Down
2 changes: 1 addition & 1 deletion benches/impl_path_string_for_evaluation_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ fn request_context() -> RequestContext {
http,
env: Arc::new(Env {}),
file: Arc::new(File {}),
cache: Arc::new(InMemoryCache::new()),
cache: Arc::new(InMemoryCache::default()),
extensions: Arc::new(vec![]),
cmd_worker: None,
worker: None,
Expand Down
1 change: 1 addition & 0 deletions examples/jsonplaceholder.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ type Query {
posts: [Post] @http(path: "/posts")
users: [User] @http(path: "/users")
user(id: Int!): User @http(path: "/users/{{.args.id}}")
greet: String @expr(body: "Hello World!")
}

type User {
Expand Down
10 changes: 5 additions & 5 deletions lint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ run_cargo_clippy() {
run_prettier() {
MODE=$1
if [ "$MODE" == "check" ]; then
prettier -c .prettierrc --check "**/*.$FILE_TYPES"
npx prettier -c .prettierrc --check "**/*.$FILE_TYPES"
else
prettier -c .prettierrc --write "**/*.$FILE_TYPES"
npx prettier -c .prettierrc --write "**/*.$FILE_TYPES"
fi
return $?
}
Expand All @@ -54,6 +54,9 @@ case $MODE in
run_autogen_schema $MODE
AUTOGEN_SCHEMA_EXIT_CODE=$?

run_prettier $MODE
PRETTIER_EXIT_CODE=$?

# Commands that uses nightly toolchains are run from `.nightly` directory
# to read the nightly version from `rust-toolchain.toml` file
pushd .nightly
Expand All @@ -62,9 +65,6 @@ case $MODE in
run_cargo_clippy $MODE
CLIPPY_EXIT_CODE=$?
popd

run_prettier $MODE
PRETTIER_EXIT_CODE=$?
;;
*)
echo "Invalid mode. Please use --mode=check or --mode=fix"
Expand Down
2 changes: 1 addition & 1 deletion src/cli/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ fn init_http2_only(blueprint: &Blueprint) -> Arc<dyn HttpIO> {
}

fn init_in_memory_cache<K: Hash + Eq, V: Clone>() -> InMemoryCache<K, V> {
InMemoryCache::new()
InMemoryCache::default()
}

pub fn init(blueprint: &Blueprint) -> TargetRuntime {
Expand Down
4 changes: 4 additions & 0 deletions src/core/app_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::sync::Arc;

use async_graphql::dynamic::{self, DynamicRequest};
use async_graphql_value::ConstValue;
use dashmap::DashMap;

use super::lift::Lift;
use crate::core::async_graphql_hyper::OperationId;
Expand All @@ -14,6 +15,7 @@ use crate::core::grpc::data_loader::GrpcDataLoader;
use crate::core::http::{DataLoaderRequest, HttpDataLoader};
use crate::core::ir::model::{DataLoaderId, IoId, IO, IR};
use crate::core::ir::Error;
use crate::core::jit::{OPHash, OperationPlan};
use crate::core::rest::{Checked, EndpointSet};
use crate::core::runtime::TargetRuntime;

Expand All @@ -28,6 +30,7 @@ pub struct AppContext {
pub auth_ctx: Arc<GlobalAuthContext>,
pub dedupe_handler: Arc<DedupeResult<IoId, ConstValue, Error>>,
pub dedupe_operation_handler: DedupeResult<OperationId, Lift<async_graphql::Response>, Error>,
pub operation_plans: DashMap<OPHash, OperationPlan<async_graphql_value::Value>>,
}

impl AppContext {
Expand Down Expand Up @@ -148,6 +151,7 @@ impl AppContext {
auth_ctx: Arc::new(auth_ctx),
dedupe_handler: Arc::new(DedupeResult::new(false)),
dedupe_operation_handler: DedupeResult::new(false),
operation_plans: DashMap::new(),
}
}

Expand Down
9 changes: 3 additions & 6 deletions src/core/cache/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,16 @@ pub struct InMemoryCache<K: Hash + Eq, V> {
miss: AtomicUsize,
}

// TODO: take this from the user instead of hardcoding it
const CACHE_CAPACITY: usize = 100000;

impl<K: Hash + Eq, V: Clone> Default for InMemoryCache<K, V> {
fn default() -> Self {
Self::new()
Self::new(100000)
}
}

impl<K: Hash + Eq, V: Clone> InMemoryCache<K, V> {
pub fn new() -> Self {
pub fn new(capacity: usize) -> Self {
InMemoryCache {
data: Arc::new(RwLock::new(TtlCache::new(CACHE_CAPACITY))),
data: Arc::new(RwLock::new(TtlCache::new(capacity))),
hits: AtomicUsize::new(0),
miss: AtomicUsize::new(0),
}
Expand Down
10 changes: 3 additions & 7 deletions src/core/ir/resolver_context_like.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ use async_graphql::{Name, ServerError, Value};
use async_graphql_value::ConstValue;
use indexmap::IndexMap;

use crate::core::jit::Nested;

pub trait ResolverContextLike: Clone {
fn value(&self) -> Option<&Value>;
fn args(&self) -> Option<&IndexMap<Name, Value>>;
Expand Down Expand Up @@ -85,16 +83,14 @@ impl From<async_graphql::SelectionField<'_>> for SelectionField {
}
}

impl<'a> From<&'a crate::core::jit::Field<Nested<ConstValue>, ConstValue>> for SelectionField {
fn from(value: &'a crate::core::jit::Field<Nested<ConstValue>, ConstValue>) -> Self {
impl<'a> From<&'a crate::core::jit::Field<ConstValue>> for SelectionField {
fn from(value: &'a crate::core::jit::Field<ConstValue>) -> Self {
Self::from_jit_field(value)
}
}

impl SelectionField {
fn from_jit_field(
field: &crate::core::jit::Field<Nested<ConstValue>, ConstValue>,
) -> SelectionField {
fn from_jit_field(field: &crate::core::jit::Field<ConstValue>) -> SelectionField {
let name = field.output_name.to_string();
let type_name = field.type_of.name();
let selection_set = field
Expand Down
Loading

1 comment on commit 295e0d5

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Running 30s test @ http://localhost:8000/graphql

4 threads and 100 connections

Thread Stats Avg Stdev Max +/- Stdev
Latency 10.19ms 3.73ms 123.98ms 89.19%
Req/Sec 2.49k 243.36 3.33k 81.92%

296988 requests in 30.03s, 1.49GB read

Requests/sec: 9891.19

Transfer/sec: 50.77MB

Please sign in to comment.