Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cache): Allow using in-memory compression dicts #510

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
10 changes: 1 addition & 9 deletions pingora-cache/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ use crate::max_file_size::MaxFileSizeMissHandler;
pub use key::CacheKey;
use lock::{CacheLock, LockStatus, Locked};
pub use memory::MemCache;
pub use meta::{set_compression_dict_content, set_compression_dict_path};
pub use meta::{CacheMeta, CacheMetaDefaults};
pub use storage::{HitHandler, MissHandler, PurgeType, Storage};
pub use variance::VarianceBuilder;
Expand Down Expand Up @@ -1237,12 +1238,3 @@ impl HttpCache {
.set_tag(|| Tag::new("is_subrequest", true))
}
}

/// Set the header compression dictionary, which helps serialize http header.
///
/// Return false if it is already set.
pub fn set_compression_dict_path(path: &str) -> bool {
crate::meta::COMPRESSION_DICT_PATH
.set(path.to_string())
.is_ok()
}
89 changes: 44 additions & 45 deletions pingora-cache/src/meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,13 @@
//! Metadata for caching

pub use http::Extensions;
use log::warn;
use once_cell::sync::{Lazy, OnceCell};
use pingora_error::{Error, ErrorType::*, OrErr, Result};
use pingora_header_serde::HeaderSerde;
use pingora_http::{HMap, ResponseHeader};
use serde::{Deserialize, Serialize};
use std::borrow::Cow;
use std::time::{Duration, SystemTime};

use crate::key::HashBinary;
Expand Down Expand Up @@ -561,53 +565,20 @@ impl CacheMetaDefaults {
}
}

use log::warn;
use once_cell::sync::{Lazy, OnceCell};
use pingora_header_serde::HeaderSerde;
use std::fs::File;
use std::io::Read;

/* load header compression engine and its dictionary globally */
pub(crate) static COMPRESSION_DICT_PATH: OnceCell<String> = OnceCell::new();

fn load_file(path: &String) -> Option<Vec<u8>> {
let mut file = File::open(path)
.map_err(|e| {
warn!(
"failed to open header compress dictionary file at {}, {:?}",
path, e
);
e
})
.ok()?;
let mut dict = Vec::new();
file.read_to_end(&mut dict)
.map_err(|e| {
warn!(
"failed to read header compress dictionary file at {}, {:?}",
path, e
);
e
})
.ok()?;

Some(dict)
}
/// The dictionary content for header compression.
///
/// Used during initialization of [`HEADER_SERDE`].
static COMPRESSION_DICT_CONTENT: OnceCell<Cow<'static, [u8]>> = OnceCell::new();

static HEADER_SERDE: Lazy<HeaderSerde> = Lazy::new(|| {
let dict_path_opt = COMPRESSION_DICT_PATH.get();

if dict_path_opt.is_none() {
warn!("COMPRESSION_DICT_PATH is not set");
}

let result = dict_path_opt.and_then(load_file);

if result.is_none() {
warn!("HeaderSerde not loaded from file");
}

HeaderSerde::new(result)
let dict_opt = if let Some(dict_content) = COMPRESSION_DICT_CONTENT.get() {
Some(dict_content.to_vec())
} else {
warn!("no header compression dictionary loaded - use set_compression_dict_content() or set_compression_dict_path() to set one");
None
};

HeaderSerde::new(dict_opt)
});

pub(crate) fn header_serialize(header: &ResponseHeader) -> Result<Vec<u8>> {
Expand All @@ -617,3 +588,31 @@ pub(crate) fn header_serialize(header: &ResponseHeader) -> Result<Vec<u8>> {
pub(crate) fn header_deserialize<T: AsRef<[u8]>>(buf: T) -> Result<ResponseHeader> {
HEADER_SERDE.deserialize(buf.as_ref())
}

/// Load the header compression dictionary from a file, which helps serialize http header.
///
/// Returns false if it is already set or if the file could not be read.
///
/// Use [`set_compression_dict_content`] to set the dictionary from memory instead.
pub fn set_compression_dict_path(path: &str) -> bool {
match std::fs::read(path) {
Ok(dict) => COMPRESSION_DICT_CONTENT.set(dict.into()).is_ok(),
Err(e) => {
warn!(
"failed to read header compress dictionary file at {}, {:?}",
path, e
);
false
}
}
}

/// Set the header compression dictionary content, which helps serialize http header.
///
/// Returns false if it is already set.
///
/// This is an alernative to [`set_compression_dict_path`], allowing use of
/// a dictionary without an external file.
pub fn set_compression_dict_content(content: Cow<'static, [u8]>) -> bool {
COMPRESSION_DICT_CONTENT.set(content).is_ok()
}
Loading