Skip to content

Commit

Permalink
refactor: add models for JIT (#2213)
Browse files Browse the repository at this point in the history
  • Loading branch information
tusharmath committed Jun 16, 2024
1 parent 5af4bcc commit d5c0a22
Show file tree
Hide file tree
Showing 19 changed files with 1,547 additions and 14 deletions.
54 changes: 50 additions & 4 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 @@ -158,6 +158,7 @@ base64 = "0.22.1"
tailcall-hasher = { path = "tailcall-hasher" }
serde_json_borrow = "0.3.0"
Inflector = "0.11.4"
num = "0.4.3"

[dev-dependencies]
tailcall-prettier = { path = "tailcall-prettier" }
Expand Down
24 changes: 23 additions & 1 deletion src/core/blueprint/blueprint.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::collections::{BTreeSet, HashMap};
use std::fmt::Formatter;
use std::sync::Arc;

use async_graphql::dynamic::{Schema, SchemaBuilder};
Expand Down Expand Up @@ -27,12 +28,33 @@ pub struct Blueprint {
pub telemetry: Telemetry,
}

#[derive(Clone, Debug)]
#[derive(Clone)]
pub enum Type {
NamedType { name: String, non_null: bool },
ListType { of_type: Box<Type>, non_null: bool },
}

impl std::fmt::Debug for Type {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Type::NamedType { name, non_null } => {
if *non_null {
write!(f, "{}!", name)
} else {
write!(f, "{}", name)
}
}
Type::ListType { of_type, non_null } => {
if *non_null {
write!(f, "[{:?}]!", of_type)
} else {
write!(f, "[{:?}]", of_type)
}
}
}
}
}

impl Default for Type {
fn default() -> Self {
Type::NamedType { name: "JSON".to_string(), non_null: false }
Expand Down
35 changes: 29 additions & 6 deletions src/core/counter.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,38 @@
use std::cell::Cell;
use std::sync::Mutex;

pub trait Count {
type Item;
fn next(&self) -> Self::Item;
}

#[allow(unused)]
#[derive(Default)]
pub struct Counter(Cell<usize>);
impl Counter {
pub fn new(start: usize) -> Self {
pub struct Counter<A>(Cell<A>);
impl<A> Counter<A> {
pub fn new(start: A) -> Self {
Self(Cell::new(start))
}
pub fn next(&self) -> usize {
}

impl<A: Copy + num::Num> Count for Counter<A> {
type Item = A;

fn next(&self) -> A {
let curr = self.0.get();
self.0.set(curr + 1);
self.0.set(curr + A::one());
curr
}
}

#[derive(Default)]
pub struct AtomicCounter<A>(Mutex<A>);

impl<A: Copy + num::Num> Count for AtomicCounter<A> {
type Item = A;

fn next(&self) -> A {
let mut x = self.0.lock().unwrap();
*x = *x + A::one();
*x
}
}
4 changes: 2 additions & 2 deletions src/core/generator/json/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ pub use query_generator::QueryGenerator;
pub use schema_generator::SchemaGenerator;
pub use types_generator::TypesGenerator;

use crate::core::counter::Counter;
use crate::core::counter::{Count, Counter};

pub struct NameGenerator {
counter: Counter,
counter: Counter<u64>,
prefix: String,
}

Expand Down
140 changes: 140 additions & 0 deletions src/core/ir/jit/blueprint_index.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
use std::collections::HashMap;

use crate::core::blueprint::{
Blueprint, Definition, FieldDefinition, InputFieldDefinition, SchemaDefinition,
};

///
/// A read optimized index of all the fields in the Blueprint. Provide O(1)
/// access to getting any field information.
#[allow(unused)]
pub struct BlueprintIndex {
map: HashMap<String, (Definition, HashMap<String, QueryField>)>,
schema: SchemaDefinition,
}

#[allow(unused)]
#[derive(Debug)]
pub enum QueryField {
Field((FieldDefinition, HashMap<String, InputFieldDefinition>)),
InputField(InputFieldDefinition),
}

#[allow(unused)]
impl QueryField {
pub fn get_arg(&self, arg_name: &str) -> Option<&InputFieldDefinition> {
match self {
QueryField::Field((_, args)) => args.get(arg_name),
QueryField::InputField(_) => None,
}
}
}

impl BlueprintIndex {
pub fn init(blueprint: &Blueprint) -> Self {
let mut map = HashMap::new();

for definition in blueprint.definitions.iter() {
match definition {
Definition::Object(object_def) => {
let type_name = object_def.name.clone();
let mut fields_map = HashMap::new();

for field in &object_def.fields {
let args_map = HashMap::from_iter(
field
.args
.iter()
.map(|v| (v.name.clone(), v.clone()))
.collect::<Vec<_>>(),
);
fields_map.insert(
field.name.clone(),
QueryField::Field((field.clone(), args_map)),
);
}

map.insert(
type_name,
(Definition::Object(object_def.to_owned()), fields_map),
);
}
Definition::Interface(interface_def) => {
let type_name = interface_def.name.clone();
let mut fields_map = HashMap::new();

for field in interface_def.fields.clone() {
let args_map = HashMap::from_iter(
field
.args
.iter()
.map(|v| (v.name.clone(), v.clone()))
.collect::<Vec<_>>(),
);
fields_map.insert(field.name.clone(), QueryField::Field((field, args_map)));
}

map.insert(
type_name,
(Definition::Interface(interface_def.to_owned()), fields_map),
);
}
Definition::InputObject(input_object_def) => {
let type_name = input_object_def.name.clone();
let mut fields_map = HashMap::new();

for field in input_object_def.fields.clone() {
fields_map.insert(field.name.clone(), QueryField::InputField(field));
}

map.insert(
type_name,
(
Definition::InputObject(input_object_def.to_owned()),
fields_map,
),
);
}
Definition::Scalar(scalar_def) => {
let type_name = scalar_def.name.clone();
map.insert(
type_name.clone(),
(Definition::Scalar(scalar_def.to_owned()), HashMap::new()),
);
}
Definition::Enum(enum_def) => {
let type_name = enum_def.name.clone();
map.insert(
type_name.clone(),
(Definition::Enum(enum_def.to_owned()), HashMap::new()),
);
}
Definition::Union(union_def) => {
let type_name = union_def.name.clone();
map.insert(
type_name.clone(),
(Definition::Union(union_def.to_owned()), HashMap::new()),
);
}
}
}

Self { map, schema: blueprint.schema.to_owned() }
}

#[allow(unused)]
pub fn get_field(&self, type_name: &str, field_name: &str) -> Option<&QueryField> {
self.map
.get(type_name)
.and_then(|(_, fields_map)| fields_map.get(field_name))
}

pub fn get_query(&self) -> &String {
&self.schema.query
}

#[allow(unused)]
pub fn get_mutation(&self) -> Option<&str> {
self.schema.mutation.as_deref()
}
}

1 comment on commit d5c0a22

@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 6.73ms 3.09ms 80.81ms 73.07%
Req/Sec 3.76k 198.79 4.07k 91.83%

449417 requests in 30.01s, 2.25GB read

Requests/sec: 14973.13

Transfer/sec: 76.85MB

Please sign in to comment.