Skip to content

feat(tsdb): allow using ST capable XOR chunks - retain format on read#18013

Merged
krajorama merged 18 commits into
feature/start-timefrom
krajo/st-opt-append-to-chunk
Feb 20, 2026
Merged

feat(tsdb): allow using ST capable XOR chunks - retain format on read#18013
krajorama merged 18 commits into
feature/start-timefrom
krajo/st-opt-append-to-chunk

Conversation

@krajorama

@krajorama krajorama commented Feb 4, 2026

Copy link
Copy Markdown
Member

Two big changes

  • Use the new XOROPTST chunk format optionally for appending samples
  • When compacting/querying chunks via the populateWithDelChunkSeriesIterator take into account if the source samples have ST==0 or not.

The second change is there to make sure we don't convert existing chunks to a new format accidentally.
It does mean that we're converting to the old format some chunks that need deletion.

Based on #18103
Finishes #17791 for floats.

Which issue(s) does the PR fix:

Does this PR introduce a user-facing change?

NONE

@krajorama

Copy link
Copy Markdown
Member Author

/prombench main

@prombot

prombot commented Feb 5, 2026

Copy link
Copy Markdown
Contributor

⏱️ Welcome to Prometheus Benchmarking Tool. ⏱️

Compared versions: PR-18013 and main

After the successful deployment (check status here), the benchmarking results can be viewed at:

Available Commands:

  • To restart benchmark: /prombench restart main
  • To stop benchmark: /prombench cancel
  • To print help: /prombench help

@krajorama
krajorama force-pushed the krajo/st-opt-append-to-chunk branch from 72f1857 to 06546bb Compare February 5, 2026 07:33
@krajorama

Copy link
Copy Markdown
Member Author

/prombench cancel

@prombot

prombot commented Feb 5, 2026

Copy link
Copy Markdown
Contributor

Benchmark cancel is in progress.

@krajorama

Copy link
Copy Markdown
Member Author

/prombench main

@prombot

prombot commented Feb 5, 2026

Copy link
Copy Markdown
Contributor

⏱️ Welcome to Prometheus Benchmarking Tool. ⏱️

Compared versions: PR-18013 and main

After the successful deployment (check status here), the benchmarking results can be viewed at:

Available Commands:

  • To restart benchmark: /prombench restart main
  • To stop benchmark: /prombench cancel
  • To print help: /prombench help

Comment thread tsdb/querier.go

for currentValueType := firstValueType; currentValueType != chunkenc.ValNone; currentValueType = p.currDelIter.Next() {
var (
newChunk chunkenc.Chunk

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to reviewers: I think this was a bug, since we never cleared newChunk . However it only hits if a series went from histogram to float and the histogram needed a new chunk right before this.

@krajorama krajorama changed the title feat(tsdb): allow using ST capable XOR chunk optionally feat(tsdb): allow using ST capable XOR chunks - retain format on read Feb 5, 2026
@bwplotka

bwplotka commented Feb 6, 2026

Copy link
Copy Markdown
Member

I like what I see (:

image

Base automatically changed from krajo/st-in-xorchunk to feature/start-time February 6, 2026 18:28
@krajorama

Copy link
Copy Markdown
Member Author

/prombench cancel

@prombot

prombot commented Feb 6, 2026

Copy link
Copy Markdown
Contributor

Benchmark cancel is in progress.

@krajorama
krajorama force-pushed the krajo/st-opt-append-to-chunk branch from 9cf544c to 4ac8ffb Compare February 17, 2026 18:15
@krajorama
krajorama changed the base branch from feature/start-time to bwplotka/scrape-parsest February 17, 2026 18:15
@krajorama
krajorama force-pushed the krajo/st-opt-append-to-chunk branch 2 times, most recently from b4b2f9d to e4c96d5 Compare February 17, 2026 19:15
@krajorama
krajorama marked this pull request as ready for review February 17, 2026 19:17
Base automatically changed from bwplotka/scrape-parsest to feature/start-time February 18, 2026 09:15
@krajorama
krajorama force-pushed the krajo/st-opt-append-to-chunk branch from e4c96d5 to cb90f9f Compare February 18, 2026 10:01

@bwplotka bwplotka left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First glance, one question around retaining implementaiton

Comment thread promql/value.go Outdated
Comment thread storage/buffer_test.go Outdated
Comment thread tsdb/querier.go Outdated
// For the first sample, the following condition will always be true as
// ValNone != ValFloat | ValHistogram | ValFloatHistogram.
if currentValueType != prevValueType {
encoding := p.currDelIter.Encoding()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds like this is the only place where we actually use chunkenc.Iterator Encoding.

Is there another way we should decide what new chunk to use? One is your previous solution - based on flag, with different semantics.

Here I'm worried about interface explosion and leaking abstraction. In majority of chunk iterator implementations returning Encoding() makes no sense as it's not a chunk even. Avoiding this would be amazing.

So flag change is one way (and not retaking).

But it feels this currDelIter will always have same a chunk as a source - so why not persisting what was the original encoding (ST with or without, or even full encoding) in

p.currMeta = p.metas[p.i]

Side question is around this logic for value types. How a single chunk can have a mixed value types? When this can happen? I think currDelIter is only formed from a single chunk, looking on func (p *populateWithDelChunkSeriesIterator) Next() bool { and func (p *populateWithDelGenericSeriesIterator) next(copyHeadChunk bool) bool

@krajorama krajorama Feb 18, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated the code to not use this new interface, rather take into account ST==0 or not.
This does mean that some chunks with ST support that we return on query or write at compaction, might get turned into the original non ST capable chunks if the written ST is actually 0 AND the chunk need recoding due to:

  • vertical merge is needed due to overlapping in-order and out-of-order chunks

Comment thread tsdb/querier.go Outdated
See PR description for uptodate info on details.

Signed-off-by: György Krajcsovits <[email protected]>
When querying chunks from storage, take into account the source
encoding instead of losing ST.

Signed-off-by: György Krajcsovits <[email protected]>
Generated with Claude Opus 4.5.

Signed-off-by: György Krajcsovits <[email protected]>
Also add tests by Claude Opus 4.5.

Signed-off-by: György Krajcsovits <[email protected]>
Generated with Claude Opus 4.5.

Signed-off-by: György Krajcsovits <[email protected]>
Signed-off-by: György Krajcsovits <[email protected]>
@krajorama
krajorama force-pushed the krajo/st-opt-append-to-chunk branch from 5bce7a8 to 1ef2063 Compare February 18, 2026 17:56
Comment thread tsdb/chunkenc/chunk.go
}

func (v ValueType) ChunkEncoding() Encoding {
func (v ValueType) ChunkEncoding(storeST bool) Encoding {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

much cleaner, thanks!

@bwplotka bwplotka left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed in detail.

Generally logic and semantics LGTM, thanks for this! I'd missed OOO impl in my attempt, good findings. I love the new ST detection on querier, so much cleaner

Suggesting changes around the maintenance toil reducing opportunities

  • Let's not increase function signatures with new feature flag if we won't need to. E.g. chunkOptions can be reused. If we can't reuse opts, I propose we add ff as the last argument because this likely will be removed eventually and it's not a first thing you need to know when reading signatures.
  • Kill AppenderV1 test for STs

Some styling nits that I deeply care about and I know you disagree on some 🙃 . World will not burn if you ignore me there:

  • Odd // AppendV2 signature: (ref, labels, st, t, v, h, fh, opts) comments
  • Trailing dots missing on comments.
  • Table tests should use slices IMO (unless we change globally to maps)

Comment thread tsdb/db_append_v2_test.go Outdated
Comment thread tsdb/db_append_v2_test.go Outdated
Comment thread tsdb/db_append_v2_test.go Outdated
Comment thread tsdb/db_append_v2_test.go Outdated
Comment thread tsdb/db_test.go Outdated
Comment thread tsdb/head_test.go Outdated
Comment thread tsdb/head_wal.go Outdated
}

if _, chunkCreated := ms.append(s.T, s.V, 0, appendChunkOpts); chunkCreated {
if _, chunkCreated := ms.append(wp.storeST, s.ST, s.T, s.V, 0, appendChunkOpts); chunkCreated {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto -it would be better if ff would be in appendChunkOpts (fewer changes, easier to remove later)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Comment thread tsdb/ooo_head.go Outdated
Comment thread tsdb/querier.go
}

loop:
for vt := valueType; vt != chunkenc.ValNone; vt = p.currDelIter.Next() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is now way cleaner!

Comment thread tsdb/querier.go
// For the first sample, the following condition will always be true as
// ValNone != ValFloat | ValHistogram | ValFloatHistogram.
if currentValueType != prevValueType {
// Also if we need to store start time (ST), but the current chunk is

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

super clean!

@bwplotka bwplotka left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you agree with my comments but they were not fully addressed (in all related places). I pointed to the places when this happens.

Otherwise LGTM

Comment thread tsdb/chunks/chunks_test.go Outdated
Comment thread tsdb/chunks/chunks_test.go Outdated
Comment thread tsdb/chunks/chunks_test.go Outdated
Comment thread tsdb/head_append.go Outdated
Comment thread tsdb/head_append.go Outdated
Comment thread tsdb/head_test.go
Comment thread tsdb/head_test.go
Comment thread tsdb/ooo_head_test.go
Comment thread tsdb/ooo_head_test.go
Comment thread tsdb/ooo_head_test.go
By AI

Signed-off-by: György Krajcsovits <[email protected]>
Round 2 for cutNewOOOHeadChunk, mmapCUrrentOOOHeadChunk.

Signed-off-by: György Krajcsovits <[email protected]>
@krajorama
krajorama merged commit 223f016 into feature/start-time Feb 20, 2026
48 of 49 checks passed
@krajorama
krajorama deleted the krajo/st-opt-append-to-chunk branch February 20, 2026 08:15
bwplotka added a commit that referenced this pull request Mar 19, 2026
…ncoding` (#18062)

* feat(tsdb/chunkenc): add float chunk format with start timestamp support


Signed-off-by: György Krajcsovits <[email protected]>

* optimize code path and layout

Signed-off-by: György Krajcsovits <[email protected]>

* make new format usable in head

Signed-off-by: György Krajcsovits <[email protected]>

* fix issue with seeking to last sample again

Signed-off-by: György Krajcsovits <[email protected]>

* fix iterator benchmark for chunks not supporting ST

Signed-off-by: György Krajcsovits <[email protected]>

* reduce footprint of the xoroptst chunk iterator object

It was 80 bytes with a lot of padding compared to the 56 bytes of the
original xor chunk iterator. Made it 64 bytes, tightly packed.

Signed-off-by: György Krajcsovits <[email protected]>

* Fix benchmark expectations on ST in interator

Signed-off-by: György Krajcsovits <[email protected]>

* add inclusive delta test case

Signed-off-by: György Krajcsovits <[email protected]>

* make testcases independent of order

Signed-off-by: György Krajcsovits <[email protected]>

* drop unused code

Signed-off-by: György Krajcsovits <[email protected]>

* Drop commented out line

Signed-off-by: György Krajcsovits <[email protected]>

* documentation

Signed-off-by: György Krajcsovits <[email protected]>

* Small simplification in the doc

Signed-off-by: György Krajcsovits <[email protected]>

* Add delta st inclusive test case for random vt

Signed-off-by: György Krajcsovits <[email protected]>

* Switch to delta of difference of st to prev t

from delta of delta of st.

Signed-off-by: György Krajcsovits <[email protected]>

* Write ST after T and V so we can write a single bit on the second sample

Signed-off-by: György Krajcsovits <[email protected]>

* verify chunk sample len function

Signed-off-by: György Krajcsovits <[email protected]>

* Reduce size of first st stored a little

Signed-off-by: György Krajcsovits <[email protected]>

* test the case where st equals the t

Signed-off-by: György Krajcsovits <[email protected]>

* add st equal t to bechmarks

Signed-off-by: György Krajcsovits <[email protected]>

* test(chunkenc): test that appender can contonue chunks

Test that initializing a chunk appender from an existing chunk
works correctly.

Signed-off-by: György Krajcsovits <[email protected]>

* fix(chunkenc): bug in initializing appender on existing chunk

Signed-off-by: György Krajcsovits <[email protected]>

* Add cases with jitter in the start time as well


Signed-off-by: György Krajcsovits <[email protected]>

* tsdb: ST-in-WAL: Counter implementation and benchmarks (#17671)

Initial implementation of #17790.
Only implements ST-per-sample for Counters. Tests and benchmarks updated.

Note: This increases the size of the RefSample object for all users, whether st-per-sample is turned on or not.

Signed-off-by: Owen Williams <[email protected]>

* refactor: sed enableStStorage/enableSTStorage

Signed-off-by: bwplotka <[email protected]>

* feat[scrape]: add ST parsing support to scrape AppenderV2 flow (#18103)

Signed-off-by: bwplotka <[email protected]>

* feat(tsdb): change head opt EnableSTStorage to atomic (#18107)

In downstream projects this needs to be set dynamically per tenant.

Signed-off-by: György Krajcsovits <[email protected]>

* Merge pull request #18108 from prometheus/bwplotka/fix

scrape: add tests for ST appending; add warnings for ST feature flag users around _created drop

* refact(tsdb): trivial rename (#18109)

Signed-off-by: György Krajcsovits <[email protected]>

* fix(tsdb): missing passing head option to wal/wbl write (#18113)

Signed-off-by: György Krajcsovits <[email protected]>

* feat(tsdb): allow using ST capable XOR chunks - retain format on read (#18013)

* feat(tsdb): allow appending to ST capable XOR chunk optionally

Only for float samples as of now.  Supports for in-order and out-of-order
samples.

Make sure that on readout the ST capable chunks are returned automatically.
When the chunks are returned as is, this is trivially true.
When a chunk needs to be re-coded due to deletion (tombstone) markers,
we take the encoding of the original chunk.
When a chunk needs to be created from overlapping chunks, we observe
whether ST is zero or not and create the new chunk based on that.

Signed-off-by: György Krajcsovits <[email protected]>

* fix test after merge

Signed-off-by: bwplotka <[email protected]>

* feat: RW2 sending ST support

Signed-off-by: bwplotka <[email protected]>

tmp

Signed-off-by: bwplotka <[email protected]>

* tests: test ST in a cheapest way possible

Signed-off-by: bwplotka <[email protected]>

* tests: add bench CLI recommended invokations

Signed-off-by: bwplotka <[email protected]>

* fixed tests after rebase

Signed-off-by: bwplotka <[email protected]>

* feat(chunkenc): replace xoroptst chunk encoding with xor2

XOR2 is based on #18238
With additional ST support.

Signed-off-by: György Krajcsovits <[email protected]>

* feat: add compliance RW sender test for agent

Signed-off-by: bwplotka <[email protected]>

* feat(agent): add support for appending ST

Signed-off-by: bwplotka <[email protected]>

* replace stray xoroptst words

Signed-off-by: György Krajcsovits <[email protected]>

* Apply suggestions from code review

Co-authored-by: Copilot <[email protected]>
Signed-off-by: Bartlomiej Plotka <[email protected]>

* post merge conflict fixes

Signed-off-by: bwplotka <[email protected]>

* feat(tsdb): register st_storage in feature API

Register the st-storage feature flag in the feature registry via
the TSDB options, consistent with how other TSDB features like
exemplar_storage and delayed_compaction are registered.

Signed-off-by: György Krajcsovits <[email protected]>
Coded with Claude Sonnet 4.6.

* Document xor2-encoding feature flag

Signed-off-by: Carrie Edwards <[email protected]>

* Add xor2-encoding feature flag

Signed-off-by: Carrie Edwards <[email protected]>

* Update CHANGELOG

Signed-off-by: Carrie Edwards <[email protected]>

* Fix linting

Signed-off-by: Carrie Edwards <[email protected]>

* Remove setting of xor2 encoding option in db open

Signed-off-by: Carrie Edwards <[email protected]>

* Fix tests

Signed-off-by: Carrie Edwards <[email protected]>

* Fix linting

Signed-off-by: Carrie Edwards <[email protected]>

* Update feature flag description

Signed-off-by: Carrie Edwards <[email protected]>

* Update comments and feature flag description

Signed-off-by: Carrie Edwards <[email protected]>

* Update documentation for st-storage feature

Signed-off-by: Carrie Edwards <[email protected]>

* st: disconnect st-storage with xor2-encoding given planned experiments (#18316)

* st: disconnect st-storage with xor2-encoding given planned experiments

Signed-off-by: bwplotka <[email protected]>

* Update docs/feature_flags.md

Co-authored-by: George Krajcsovits <[email protected]>
Signed-off-by: Bartlomiej Plotka <[email protected]>

* Update docs/feature_flags.md

Co-authored-by: George Krajcsovits <[email protected]>
Signed-off-by: Bartlomiej Plotka <[email protected]>

* Update docs/feature_flags.md

Co-authored-by: George Krajcsovits <[email protected]>
Signed-off-by: Bartlomiej Plotka <[email protected]>

* Update docs/feature_flags.md

Co-authored-by: George Krajcsovits <[email protected]>
Signed-off-by: Bartlomiej Plotka <[email protected]>

---------

Signed-off-by: bwplotka <[email protected]>
Signed-off-by: Bartlomiej Plotka <[email protected]>
Co-authored-by: George Krajcsovits <[email protected]>

---------

Signed-off-by: György Krajcsovits <[email protected]>
Signed-off-by: Ganesh Vernekar <[email protected]>
Signed-off-by: Bryan Boreham <[email protected]>
Signed-off-by: Aleksandr Smirnov <[email protected]>
Signed-off-by: Mohammad Abbasi <[email protected]>
Signed-off-by: matt-gp <[email protected]>
Signed-off-by: Ian Kerins <[email protected]>
Signed-off-by: SuperQ <[email protected]>
Signed-off-by: dependabot[bot] <[email protected]>
Signed-off-by: Arve Knudsen <[email protected]>
Signed-off-by: ffgan <[email protected]>
Signed-off-by: Patryk Prus <[email protected]>
Signed-off-by: Owen Williams <[email protected]>
Signed-off-by: bwplotka <[email protected]>
Signed-off-by: 3Juhwan <[email protected]>
Signed-off-by: Sammy Tran <[email protected]>
Signed-off-by: Casie Chen <[email protected]>
Signed-off-by: Dan Cech <[email protected]>
Signed-off-by: kakabisht <[email protected]>
Signed-off-by: Jeanette Tan <[email protected]>
Signed-off-by: Divyansh Mishra <[email protected]>
Signed-off-by: Varun Chawla <[email protected]>
Signed-off-by: Martin Valiente Ainz <[email protected]>
Signed-off-by: Kyle Eckhart <[email protected]>
Signed-off-by: Julien Pivotto <[email protected]>
Signed-off-by: Matthieu MOREL <[email protected]>
Signed-off-by: Linas Medziunas <[email protected]>
Signed-off-by: Björn Rabenstein <[email protected]>
Signed-off-by: beorn7 <[email protected]>
Signed-off-by: Sayuru <[email protected]>
Signed-off-by: Matt <[email protected]>
Signed-off-by: Bartlomiej Plotka <[email protected]>
Signed-off-by: Carrie Edwards <[email protected]>
Co-authored-by: Bartlomiej Plotka <[email protected]>
Co-authored-by: Ganesh Vernekar <[email protected]>
Co-authored-by: Bryan Boreham <[email protected]>
Co-authored-by: Sasha <[email protected]>
Co-authored-by: Mohammad Abbasi <[email protected]>
Co-authored-by: matt-gp <[email protected]>
Co-authored-by: Ian Kerins <[email protected]>
Co-authored-by: SuperQ <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Arve Knudsen <[email protected]>
Co-authored-by: Julien <[email protected]>
Co-authored-by: ffgan <[email protected]>
Co-authored-by: Patryk Prus <[email protected]>
Co-authored-by: Ganesh Vernekar <[email protected]>
Co-authored-by: Joe Adams <[email protected]>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Owen Williams <[email protected]>
Co-authored-by: 3Juhwan <[email protected]>
Co-authored-by: Casie Chen <[email protected]>
Co-authored-by: Dan Cech <[email protected]>
Co-authored-by: hridyesh bisht <[email protected]>
Co-authored-by: zenador <[email protected]>
Co-authored-by: Divyansh Mishra <[email protected]>
Co-authored-by: Varun Chawla <[email protected]>
Co-authored-by: Martin Valiente Ainz <[email protected]>
Co-authored-by: Kyle Eckhart <[email protected]>
Co-authored-by: Matthieu MOREL <[email protected]>
Co-authored-by: Linas Medžiūnas <[email protected]>
Co-authored-by: Björn Rabenstein <[email protected]>
Co-authored-by: beorn7 <[email protected]>
Co-authored-by: Sayuru <[email protected]>
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Carrie Edwards <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants