stable-worldmodel-a-high-performance-platform-for-reproducible-world-model-research
Ayush Chaurasia
Quentin Lhoest
Lucas Maes
Quentin Le Lidec
reproducible-data-curation-in-the-multimodal-lakehouse
Prashanth Rao
newsletter-may-2026
ChanChan Mao
newsletter-april-2026
ChanChan Mao
how-lancedb-accelerates-vector-search-at-10-billion-scale
Yang Cen
opensearch-vs-lancedb-for-vector-search-query-cost-and-infrastructure
Justin Miller
volcano-engine-autonomous-driving-data-lake-solution
Kejian Ju
unifying-the-av-ml-stack-lancedb
Ayush Chaurasia
lance-json-support-why-you-might-not-really-need-variant
Jack Ye
building-a-storage-format-for-the-next-era-of-biology
Pavan Ramkumar
newsletter-march-2026
ChanChan Mao
smart-parsing-meets-sharp-retrieval-combining-liteparse-and-lancedb
Clelia Astra Bertelli
Prashanth Rao
lance-format-v2-2-benchmarks-half-the-storage-none-of-the-slowdown
Xuanwo
make-your-sql-workflows-multimodal-with-lancedb-x-duckdb
Prashanth Rao
agentic-coding-as-community-stewardship
Xuanwo
what-we-mean-by-multimodal
Prashanth Rao
ai-native-development-local-continue-lancedb
Ty Dunn
lance-file-format-2-2-taming-complex-data
Xuanwo
lance-blob-v2
Xuanwo
Jack Ye
openclaw-lancedb-memory-layer
Xuanwo
Prashanth Rao
openclaw-lancedb-seed2
LanceDB
openclaw-memory-from-zero-to-lancedb-pro
Prashanth Rao
upload-lance-datasets-to-hf-hub
Prashanth Rao
zero-shot-image-classification-with-vector-search
Vipul Maheshwari
werides-data-platform-transformation-how-lancedb-fuels-model-development-velocity
Qian Zhu
Fei Chen
training-a-variational-autoencoder-from-scratch-with-the-lance-file-format
LanceDB
track-ai-trends-crewai-agents-rag
LanceDB
tokens-per-second-is-not-all-you-need
Mingran Wang
Tan Li
the-future-of-open-source-table-formats-iceberg-and-lance
Jack Ye
the-case-for-random-access-i-o
LanceDB
series-a-funding
Chang She
semanticdotart
Ayush Chaurasia
second-dinners-secret-weapon-lancedb-powered-rag-for-faster-smarter-game-development
Qian Zhu
search-within-an-image-331b54e4285e
Kaushal Choudhary
scalable-computer-vision-with-lancedb-voxel51-d8b65066d5f6
LanceDB
rethinking-table-file-paths-lance-multi-base-layout
Jack Ye
rag-isnt-one-size-fits-all
Leonard Marcq
python-package-to-convert-image-datasets-to-lance-type
Vipul Maheshwari
one-million-iops
Weston Pace
november-feature-roundup
Will Jones
newsletter-september-2025
Jasmine Wang
newsletter-october-2025
Jasmine Wang
newsletter-november-2025
ChanChan Mao
newsletter-june-2025
David Myriel
newsletter-july-2025
Jasmine Wang
newsletter-january-2026
ChanChan Mao
newsletter-february-2026
ChanChan Mao
newsletter-december-2025
ChanChan Mao
newsletter-august-2025
Jasmine Wang
my-summer-internship-experience-at-lancedb-2
Raunak Sinha
my-simd-is-faster-than-yours-fb2989bf25e7
LanceDB
multimodal-myntra-fashion-search-engine-using-lancedb
LanceDB
multimodal-lakehouse
David Myriel
multi-document-agentic-rag-a-walkthrough
Vipul Maheshwari
modified-rag-parent-document-bigger-chunk-retriever-62b3d1e79bc6
Mahesh Deshwal
memgpt-os-inspired-llms-that-manage-their-own-memory-793d6eed417e
Ayush Chaurasia
late-interaction-efficient-multi-modal-retrievers-need-more-than-just-a-vector-index
Ayush Chaurasia
lancedb-x-continue
LanceDB
lance-x-huggingface-a-new-era-of-sharing-multimodal-data
Prashanth Rao
Quentin Lhoest
Xuanwo
Ayush Chaurasia
lance-x-duckdb-sql-retrieval-on-the-multimodal-lakehouse-format
Xuanwo
lance-windows-windows-lance
Chang She
lance-v2
Weston Pace
lance-namespace-lancedb-and-ray
Jack Ye
lance-file-2-1-stable
Weston Pace
lance-file-2-1-smaller-and-simpler
Weston Pace
lance-data-viewer
Gordon Murray
lance-community-governance
Jack Ye
introducing-lance-namespace-spark-integration
Jack Ye
implementing-corrective-rag-in-the-easiest-way-2
LanceDB
hybrid-search-rag-for-real-life-production-grade-applications-e1e727b3965a
Mahesh Deshwal
hybrid-search-combining-bm25-and-semantic-search-for-better-results-with-lan-1358038fe7e6
LanceDB
hybrid-search-and-custom-reranking-with-lancedb-4c10a6a3447e
LanceDB
how-to-reduce-hallucinations-from-llm-powered-agents-using-long-term-memory-72f262c3cc1f
Tevin Wang
guide-to-use-contextual-retrieval-and-prompt-caching-with-lancedb
LanceDB
grpo-understanding-and-fine-tuning-the-next-gen-reasoning-model-2
Mahesh Deshwal
graphrag-hierarchical-approach-to-retrieval-augmented-generation
Akash Desai
gpu-accelerated-indexing-in-lancedb-27558fa7eee5
LanceDB
geo-support
Jack Ye
geneva-twelvelabs
David Myriel
geneva-feature-engineering
Jonathan Hsieh
from-bi-to-ai-lance-and-iceberg
Jack Ye
Prashanth Rao
fluss-integration
Wayne Wang
file-readers-in-depth-parallelism-without-row-groups
Weston Pace
feature-rabitq-quantization
David Myriel
Yang Cen
feature-full-text-search
David Myriel
enhance-rag-integrate-contextual-compression-and-filtering-for-precision-a29d4a810301
Kaushal Choudhary
effortlessly-loading-and-processing-images-with-lance-a-code-walkthrough
LanceDB
designing-a-table-format-for-ml-workloads
Weston Pace
custom-dataset-for-llm-training-using-lance
LanceDB
creating-a-fintech-agent
Vipul Maheshwari
convert-any-image-dataset-to-lance
LanceDB
columnar-file-readers-in-depth-structural-encoding
Weston Pace
columnar-file-readers-in-depth-repetition-definition-levels
Weston Pace
columnar-file-readers-in-depth-compression-transparency
Weston Pace
columnar-file-readers-in-depth-column-shredding
Weston Pace
columnar-file-readers-in-depth-backpressure
Weston Pace
columnar-file-readers-in-depth-apis-and-fusion
Weston Pace
chunking-techniques-with-langchain-and-llamaindex
Prashant Kumar
chunking-analysis-which-is-the-right-chunking-approach-for-your-language
Shresth Shukla
chat-with-csv-excel-using-lancedb
LanceDB
case-study-netflix
David Myriel
case-study-dosu
Qian Zhu
Michael Ludden
case-study-cognee
David Myriel
Vasilije Markovic
case-study-coderabbit
Qian Zhu
building-rag-on-codebases-part-2
Sankalp Shubham
building-rag-on-codebases-part-1
Sankalp Shubham
branching-and-shallow-clone
Jack Ye
better-rag-with-active-retrieval-augmented-generation-flare-3b66646e2a9f
LanceDB
benchmarking-random-access-in-lance
Chang She
benchmarking-lancedb-92b01032874a-2
LanceDB
benchmarking-cohere-reranker-with-lancedb
LanceDB
anythingllms-competitive-edge-lancedb-for-seamless-rag-and-agent-workflows
Ayush Chaurasia
announcing-lance-sdk
Weston Pace
agentic-rag-using-langgraph-building-a-simple-customer-support-autonomous-agent
LanceDB
advanced-rag-precise-zero-shot-dense-retrieval-with-hyde-0946c54dfdcb
LanceDB
accelerate-vector-search-applications-using-openvino-lancedb
LanceDB
a-primer-on-text-chunking-and-its-types-a420efc96a13
Prashant Kumar
a-practical-guide-to-training-custom-rerankers
Ayush Chaurasia
a-practical-guide-to-fine-tuning-embedding-models
Ayush Chaurasia
keep-your-data-fresh-with-cocoindex-and-lancedb
Prashanth Rao
Linghua Jin

Columnar File Readers in Depth: Backpressure

March 25, 2024
Engineering

Streaming data applications can be tricky. When you can read data faster than you can process the data then bad things tend to happen. The most common scenario is you run out of memory and your process crashes. When the process doesn’t crash, it often breaks performance (e.g. swapping or pausing inefficiently). The various solutions to this problem are largely classified as “backpressure”. It’s been a while since I last posted in this series and one of the things I’ve been spending a lot of time on is getting backpressure right. It’s proven to be quite tricky 🙃 In this blog post I want to explain some classic approaches for backpressure and then describe the approach we’ve been taking in the Lance file reader.

💡 📚 Series Navigation

This is part of a series of posts on the details we’ve encountered building a columnar file reader:

  1. Parallelism without Row Groups
  2. APIs and Fusion
  3. Backpressure (this article)
  4. Compression Transparency
  5. Column Shredding
  6. Repetition & Definition Levels

Push vs. Pull?

Whenever we talk about backpressure we also often talk about push vs. pull. In a push-based system a producer creates and launches a task as soon as data is available. This makes parallelism automatic but backpressure is tricky. In a pull-based system the consumer creates a task to pull a batch of data and process it. This makes backpressure automatic but parallelism is tricky.

The reality is that every multi-threaded scanner / query engine is doing both push and pull somewhere if you look hard enough. Both approaches have to solve this problem and systems tend to use the same classic solution to do so.

Classic Solution: Row Group Queue

The classic solution is to limit the number of row groups that can be processed with a queue somewhere between the producer and the consumer. If the queue fills up the then file reader will stop reading. There are a variety of ways this queue can be implemented (e.g. a blocking queue in a push-based workflow or a readahead queue in a pull-based workflow).

Classic Row Group Queue
A classic reader adds batches to a queue which a classic engine pulls from

As an example we can consider the pyarrow scanner which has a from_dataset method with the following parameter:

batch_readahead - int, default 16

    The number of batches to read ahead in a file. This might not work for all file formats. Increasing this number will increase RAM usage but could also improve IO utilization.

I don’t want this post to be too long so I’m going to summarize the issues I’ve historically encountered with the row group queue approach:

  • It’s often unclear whether this limit applies to file-based row groups (which tend to be large) or compute-based batches (which tend to be small).
  • The correct limit will depend on the query (how many columns are being loaded)
  • Not all batches are the same size and so the correct limit can even fluctuate within a single query.
  • Queuing batches means you are inserting a thread transfer between decode and compute. This is something we wanted to avoid in Lance.
Variable Batch Sizes
All three queues hold the same number of batches but have drastically different RAM usage

Our motivation for Lance is to find an approach that is simple to configure, can be consistently applied to all datasets, and can work without a concept of row groups.

Lance Solution: I/O Buffer

To understand the Lance solution we need to revisit the concept of separating I/O from decoding that we described in an earlier post. Every Lance reader has a “scheduling thread” and a “decode thread”. The scheduling thread determines what I/O we need to issue and the decode thread takes the data, as it arrives, and decodes it.

In between these two threads is a special component called the I/O scheduler. It receives I/O requests from the scheduling thread, sorts them according to their priority order, throttles how many concurrent requests we can make, and then delivers the results to the decoders. This gives us the perfect place to apply backpressure.

Lance I/O Buffer

When the I/O scheduler finishes an I/O request it places the data in a queue for the decoders, the I/O buffer. If this queue fills up then we know the decoders are falling behind. The I/O scheduler will then stop issuing new I/O requests. When the decoders catch up then the buffer will start to empty and we can start issuing I/O requests again.

The best part about the I/O buffer is that the I/O buffer size is in bytes and not rows. What’s more, we can easily calculate the correct value. We want to make sure that we have enough room in the buffer to saturate our I/O.

💡 Cloud Storage Considerations

If we are working with cloud storage, we need a lot of space! This is true even if your compute layer is operating on small 1MiB batches and this is often surprising to people. We typically want to make many concurrent requests to cloud storage (e.g. at least 64-128) and those requests should be large (at least 8-16MiB). Our current default is 2GiB which gives us enough space for 128x16-MiB requests.

One Small Problem…

Unfortunately, we have one small wrinkle that’s caused us a lot of trouble. When we are reading variable-size data types (e.g. strings, lists, etc.) we don’t know up-front how many items we need to read from disk. For example, if the user asks for 10,000 strings then will a column need 1KiB? 1MiB? 50MiB? We simply don’t know.

We never want to pause I/O. This means we don’t want to stop and wait until the string sizes come back before we continue reading other columns. As a result, we end up scheduling some “lower priority” requests while we are waiting for the string sizes to come back. Once we know the string sizes we can make a high priority request to get the data.

Unfortunately, if our I/O buffer fills up with low priority items then we might not have space for a high priority request once our string sizes get back to us. The decoder works in priority order and, since our high priority request is stuck, the decoder gets stuck and the whole system grinds to a deadlock.

Deadlock Scenario
Example deadlock scenario

Our solution today is to allow requests to bypass the backpressure limit if they are higher priority than anything in the backpressure queue. This works, but it’s a bit messy, and it got us thinking, “wouldn’t it be great if we knew the priority ahead of time?” It turns out that we can record that information when we write the file and this is exactly what we plan to do in our 2.1 format.

💡 Lance 2.1 Preview

I don’t think I’ve mentioned 2.1 yet but we learned a few things working on 2.0 (like this) and I’ll be doing a retrospective at some point to share them and talk about our upcoming plans.

It’s unlikely users will ever notice (the current system works very well anyways) but it will let us rip out several complicated branches from our scheduling and decoding logic once we have finalized 2.1 and so I’m excited to move to the new system.

Conclusion

Configuring backpressure in Lance is very easy. In fact, it is so easy you should never really have to mess with it in normal scenarios (the default of 2GiB works well for most situations). We can read massive data files, turn around and process them slowly, and never have to worry about the reader using way too much memory. This is absolutely essential when working with multi-modal data because the large data types make it all too easy to waste RAM on the machine whenever you have an expensive processing step.

What’s Next

LanceDB is upgrading the modern data lake (postmodern data lake?). Support for multimodal data, combining search and analytics, embracing embedded in-process workflows and more. If this sort of stuff is interesting then check us out and come join the conversation.

If you’re interested in learning more about our file format innovations or contributing to Lance, hop on over to our Discord or Github and we’d be happy to talk to you!

Weston Pace
Data engineer from the open source space, working on LanceDB, Arrow, Substrait.

Stable-Worldmodel: A High Performance Platform for Reproducible World Model Research

Ayush Chaurasia
Quentin Lhoest
Lucas Maes
Quentin Le Lidec
June 2, 2026
stable-worldmodel-a-high-performance-platform-for-reproducible-world-model-research

🌍 Lance-Backed World Model Platform, 🦆 Multimodal SQL with Lance DuckDB Extension, 💰 LanceDB vs OpenSearch Cost Breakdown

ChanChan Mao
May 28, 2026
newsletter-may-2026

Reproducible Data Curation In The Multimodal Lakehouse

Prashanth Rao
May 29, 2026
reproducible-data-curation-in-the-multimodal-lakehouse