MCPcopy Index your code
hub / github.com/XiangpengHao/liquid-cache

github.com/XiangpengHao/liquid-cache @v0.1.13

Chat with this repo
repository ↗ · DeepWiki ↗ · release v0.1.13 ↗ · + Follow
2,071 symbols 6,677 edges 155 files 419 documented · 20%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

liquid_cache_logo

Crates.io Version docs.rs

Rust CI codecov Codacy Badge ClickBench TPC-H TPC-DS

LiquidCache understands both your data and your query. - It transcodes storage data into an optimized, cache-only format, so you can keep using your favorite formats without worrying about performance. - It keeps the data that matters in memory and uses modern SSDs efficiently. For example, if your query groups by year, LiquidCache stores only the year in memory and keeps the full timestamp on disk.

LiquidCache is a research project funded by InfluxData, SpiralDB, and Bauplan.

You may want to consider Foyer if you're looking for a black-box cache: easier to setup, but not as "smart" as LiquidCache.

Quick start

This quick start uses the core cache API from src/core. Add these dependencies to your project: liquid-cache, arrow, and datafusion. The example below shows insert, get, get with selection, and get with predicate pushdown.

use arrow::array::{BooleanArray, UInt64Array};
use arrow::buffer::BooleanBuffer;
use datafusion::logical_expr::Operator;
use datafusion::physical_plan::PhysicalExpr;
use datafusion::physical_plan::expressions::{BinaryExpr, Column, Literal};
use datafusion::scalar::ScalarValue;
use liquid_cache::cache::{EntryID, LiquidCacheBuilder};
use std::sync::Arc;

tokio_test::block_on(async {
    let cache = LiquidCacheBuilder::new().build().await;
    let entry_id = EntryID::from(1);
    let values = Arc::new(UInt64Array::from(vec![10, 11, 12, 13, 14, 15]));

    // 1) insert
    cache.insert(entry_id, values.clone()).await;

    // 2) get
    let all_rows = cache.get(&entry_id).await.expect("entry should exist");

    // 3) get filtered (selection pushdown): keep rows 0, 2, 4
    let selection = BooleanBuffer::from(vec![true, false, true, false, true, false]);
    let selected_rows = cache
        .get(&entry_id)
        .with_selection(&selection)
        .await
        .expect("entry should exist");

    // 4) get with predicate pushdown: col > 12
    let predicate: Arc<dyn PhysicalExpr> = Arc::new(BinaryExpr::new(
        Arc::new(Column::new("col", 0)),
        Operator::Gt,
        Arc::new(Literal::new(ScalarValue::UInt64(Some(12)))),
    ));
    let predicate_mask = cache
        .eval_predicate(&entry_id, &predicate)
        .await
        .expect("entry should exist")
        .expect("predicate should be evaluated in cache");

    // Conceptual expectations:
    assert_eq!(all_rows.as_ref(), values.as_ref()); // [10, 11, 12, 13, 14, 15]
    assert_eq!(selected_rows.as_ref(), &UInt64Array::from(vec![10, 12, 14]));
    assert_eq!(
        predicate_mask,
        BooleanArray::from(vec![
        Some(false),
        Some(false),
        Some(false),
        Some(true),
        Some(true),
        Some(true),
        ]),
    );
});

Development

See dev/README.md

Benchmark

See benchmark/README.md

Performance troubleshooting

Use LiquidCache with DataFusion

LiquidCache requires a few non-default DataFusion configurations:

ListingTable:

let (ctx, _) = LiquidCacheLocalBuilder::new().build(config).await?;

let listing_options = ParquetReadOptions::default()
    .to_listing_options(&ctx.copied_config(), ctx.copied_table_options());
ctx.register_listing_table("default", &table_path, listing_options, None, None)
    .await?;

Or register Parquet directly:

let (ctx, _) = LiquidCacheLocalBuilder::new().build(config).await?;
ctx.register_parquet("default", "examples/nano_hits.parquet", Default::default())
    .await?;

Disable background transcoding

For performance testing, disable background transcoding:

let (ctx, _) = LiquidCacheLocalBuilder::new()
    .with_squeeze_policy(Box::new(
        squeeze_policies::Evict,
    ))
    .build(config)
    .await?;

x86-64 optimization

LiquidCache is optimized for x86-64 with specific instructions. On ARM (e.g., Apple Silicon), fallback implementations are used. Contributions are welcome.

FAQ

Can I use LiquidCache in production today?

Not yet. Production readiness is our goal, but we are still implementing features and polishing the system. LiquidCache began as a research project exploring new approaches to cost-effective caching. Like most research projects, it takes time to mature—we welcome your help.

How does LiquidCache work?

See our paper for details. We are also working on a technical blog to introduce LiquidCache in a more accessible way.

How can I get involved?

We are always looking for contributors. Feedback and improvements are welcome—explore the issue list and contribute where you can. If you want to get involved in the research side, reach out.

Who is behind LiquidCache?

LiquidCache is a research project funded by: - SpiralDB - InfluxData - Bauplan - Taxpayers of the state of Wisconsin and the federal government.

LiquidCache is and will remain open source and free to use.

Your support for science is greatly appreciated!

License

Apache License 2.0

Extension points exported contracts — how you extend this code

LiquidArray (Interface)
A Liquid array. [7 implementers]
src/core/src/liquid_array/mod.rs
Cache (Interface)
(no doc) [4 implementers]
src/datafusion/bench/eviction_cache.rs
Benchmark (Interface)
(no doc) [3 implementers]
benchmark/src/client_runner.rs
LiquidCacheErrorExt (Interface)
Extension trait to add context to Results for better error reporting [1 implementers]
src/datafusion-server/src/errors.rs
LiquidSqueezedArray (Interface)
(no doc) [7 implementers]
src/core/src/liquid_array/mod.rs
SqueezePolicy (Interface)
Policy that chooses the next representation for an entry under memory pressure. [3 implementers]
src/core/src/cache/policies/squeeze.rs
ArrayBenchmark (Interface)
Trait for running benchmarks on different array types [3 implementers]
src/core/study/fsst_view.rs
EntryMetadata (Interface)
Per-entry metadata used by the cache. This trait covers only the metadata side of the cache: where to find a batch's co [2 …
src/core/src/cache/io_context.rs

Core symbols most depended-on inside this repo

clone
called by 690
src/core/src/liquid_array/raw/bit_pack_array.rs
as_ref
called by 219
src/core/src/utils/mod.rs
len
called by 135
src/core/src/liquid_array/float_array.rs
get
called by 110
src/core/src/cache/core.rs
path
called by 102
src/core/src/cache/expressions.rs
len
called by 79
src/core/src/liquid_array/byte_view_array/mod.rs
len
called by 64
src/datafusion/src/reader/utils/boolean_selection.rs
to_arrow_array
called by 55
src/core/src/liquid_array/byte_view_array/mod.rs

Shape

Method 956
Function 819
Class 235
Enum 43
Interface 18

Languages

Rust99%
Python1%

Modules by API surface

src/datafusion/src/optimizers/lineage_opt.rs109 symbols
src/core/src/liquid_array/raw/fsst_buffer.rs69 symbols
src/core/src/cache/core.rs56 symbols
src/core/src/liquid_array/float_array.rs47 symbols
src/datafusion/src/reader/runtime/liquid_cache_reader.rs38 symbols
src/core/src/liquid_array/squeezed_date32_array.rs38 symbols
src/core/src/liquid_array/linear_integer_array.rs38 symbols
src/core/src/liquid_array/byte_view_array/tests.rs38 symbols
src/datafusion/src/reader/runtime/liquid_stream.rs37 symbols
src/core/src/liquid_array/primitive_array.rs35 symbols
src/core/src/liquid_array/fix_len_byte_array.rs35 symbols
src/core/src/liquid_array/byte_view_array/mod.rs34 symbols

For agents

$ claude mcp add liquid-cache \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact

Ask about this repo answers extend the page