Skip to content

Commit

Permalink
perf: add shared cache
Browse files Browse the repository at this point in the history
  • Loading branch information
winstxnhdw committed Oct 22, 2024
1 parent eaafe5a commit 11cdc10
Show file tree
Hide file tree
Showing 7 changed files with 199 additions and 8 deletions.
148 changes: 147 additions & 1 deletion Cargo.lock

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

12 changes: 11 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ lto = "fat"
codegen-units = 1
panic = "abort"

[build]
rustflags = ["-C", "target-cpu=native"]

[package]
name = "tectonic-api"
version = "0.1.0"
Expand All @@ -17,4 +20,11 @@ tower-http = { version = "0.6.1", features = ["util"] }
utoipa = { version = "5.1.1", features = ["axum_extras"] }
utoipa-swagger-ui = { version = "8.0.2", features = ["axum"] }
utoipauto = "0.2.0"
tectonic = { git = "https://github.com/tectonic-typesetting/tectonic.git", default-features = false, features = ["geturl-curl"] }
tectonic = { git = "https://github.com/tectonic-typesetting/tectonic.git", default-features = false, features = [
"geturl-curl",
] }
moka = { version = "0.12.8", features = ["future"] }
gxhash = "3.4.1"

[features]
hybrid = ["gxhash/hybrid"]
2 changes: 1 addition & 1 deletion Dockerfile.build
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ COPY . .
RUN apt update
RUN apt install -y curl g++ libssl-dev libfontconfig-dev libharfbuzz-dev
RUN rustup default nightly
RUN cargo install --locked --path .
RUN cargo install --locked --features hybrid --path .


FROM rust:slim AS texlive-builder
Expand Down
13 changes: 11 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
mod state;
mod v1;

use axum::routing::get;
use axum::Router;
use utoipa::OpenApi;

Expand All @@ -11,11 +11,20 @@ struct ApiSpecification;

pub fn app() -> Router {
let root_path = "/api";
let shared_state = std::sync::Arc::new(state::AppState {
cache: moka::future::Cache::builder()
.weigher(|_, v: &Vec<u8>| v.len().try_into().unwrap_or(u32::MAX))
.max_capacity(12 * 1024 * 1024 * 1024)
.time_to_idle(std::time::Duration::from_secs(3600))
.build_with_hasher(gxhash::GxBuildHasher::default()),
});

Router::new()
.nest(
root_path,
Router::new().route("/", get(())).merge(v1::router()),
Router::new()
.route("/", axum::routing::get(()))
.merge(v1::router(shared_state)),
)
.merge(
utoipa_swagger_ui::SwaggerUi::new(format!("{}/docs", root_path))
Expand Down
5 changes: 5 additions & 0 deletions src/state.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
use gxhash::GxBuildHasher;

pub struct AppState {
pub cache: moka::future::Cache<std::string::String, Vec<u8>, GxBuildHasher>,
}
5 changes: 4 additions & 1 deletion src/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@ use axum::{
Router,
};

pub fn router() -> Router {
use crate::state::AppState;

pub fn router(shared_state: std::sync::Arc<AppState>) -> Router {
Router::new()
.route("/v1", get(index::index))
.route("/v1/compile", post(compile::compile))
.with_state(shared_state)
}
22 changes: 20 additions & 2 deletions src/v1/compile.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
use std::sync::Arc;

use axum::body::Body;
use axum::extract::State;
use axum::http::header::{CONTENT_DISPOSITION, CONTENT_TYPE};
use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
use axum::Json;

use crate::state::AppState;

#[derive(serde::Deserialize, utoipa::ToSchema)]
pub struct CompileSchema {
#[schema(example = "\\documentclass{article}\\begin{document}Hello, world!\\end{document}")]
Expand All @@ -19,8 +24,21 @@ pub struct CompileSchema {
(status = 400, body = String)
)
)]
pub async fn compile(Json(payload): Json<CompileSchema>) -> impl IntoResponse {
match tectonic::latex_to_pdf(payload.latex) {
pub async fn compile(
State(state): State<Arc<AppState>>,
Json(payload): Json<CompileSchema>,
) -> impl IntoResponse {
let result = state
.cache
.try_get_with(payload.latex.clone(), async {
match tectonic::latex_to_pdf(payload.latex) {
Ok(pdf) => Ok(pdf),
Err(error) => Err(error.to_string()),
}
})
.await;

match result {
Ok(pdf) => Response::builder()
.status(StatusCode::OK)
.header(CONTENT_TYPE, "application/pdf")
Expand Down

0 comments on commit 11cdc10

Please sign in to comment.