Skip to content

Parquet add no convert marker - #7625

Merged
SungJin1212 merged 7 commits into
cortexproject:masterfrom
siddarth2810:parquet-add-no-convert-marker
Sep 7, 2026
Merged

Parquet add no convert marker#7625
SungJin1212 merged 7 commits into
cortexproject:masterfrom
siddarth2810:parquet-add-no-convert-marker

Conversation

@siddarth2810

@siddarth2810 siddarth2810 commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

What this PR does:
If a TSDB block exceeds a configurable threshold of distinct label names, the converter writes a parquet-no-convert-mark.json marker and skips the block.

  • Added no-convert marker with read/write logic
  • Added parquet-converter.max-block-label-names limit

Which issue(s) this PR fixes:
Fixes #7195

Checklist

  • Tests updated
  • Documentation added
  • CHANGELOG.md updated - the order of entries should be [CHANGE], [FEATURE], [ENHANCEMENT], [BUGFIX]
  • docs/configuration/v1-guarantees.md updated if this PR introduces experimental flags

Notes from the Previous PR review

  • Removed the incorrect log under cortex_parquet.ValidConverterMarkVersion
  • Embedded LabelNamesCount and Threshold into Reason field
  • Added buffer for system columns and generated data columns
  • Cleaned up skipped-block metrics when deleting tenant metrics

@siddarth2810
siddarth2810 marked this pull request as ready for review June 16, 2026 12:19
Comment thread pkg/parquetconverter/converter.go Outdated
Comment on lines +410 to +413
if cortex_parquet.ValidNoConvertMarkVersion(noConvertMark.Version) {
level.Debug(logger).Log("msg", "skipping block, no-convert marker already exists", "block", b.ULID.String())
c.metrics.skippedBlocks.WithLabelValues(userID, cortex_parquet.NoConvertReasonMarkerExists).Inc()
continue

@SungJin1212 SungJin1212 Jun 22, 2026

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.

  1. If noConvertMark is upgraded (v1 -> v2), is it correct that the noConvertMark file is overwritten to v2?
  2. When the user increases this limit (1000 -> 2000), I think we should convert the previous unconverted blocks. (ex. 1500)
    ㄴ We can track the current applied limit in noConvertMark and utilize it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

There is only v1 version right now. I'm not quite sure in which cases the noConvertMark would be upgraded.

My implementation is based on comparing the current limit and label count. By tracking the applied limit, do you mean comparing the limits ?

Like, if current limit > old noConvertMark limit -> Retry conversion

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.

When the configured limit changes, I think we should re-evaluate the block against the new limit, instead of unconditionally skipping it just because a noConvertMark already exists.

Comment thread pkg/parquetconverter/converter.go Outdated
Comment on lines +412 to +415
if cortex_parquet.ValidNoConvertMarkVersion(noConvertMark.Version) && noConvertMark.ShouldSkipBlock(maxBlockLabelNames) {
level.Debug(logger).Log("msg", "skipping block, no-convert marker already exists", "block", b.ULID.String())
c.metrics.skippedBlocks.WithLabelValues(userID, cortex_parquet.NoConvertReasonMarkerExists).Inc()
continue

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.

wdyt?

Suggested change
if cortex_parquet.ValidNoConvertMarkVersion(noConvertMark.Version) && noConvertMark.ShouldSkipBlock(maxBlockLabelNames) {
level.Debug(logger).Log("msg", "skipping block, no-convert marker already exists", "block", b.ULID.String())
c.metrics.skippedBlocks.WithLabelValues(userID, cortex_parquet.NoConvertReasonMarkerExists).Inc()
continue
if cortex_parquet.ValidNoConvertMarkVersion(noConvertMark.Version) {
level.Debug(logger).Log("msg", "skipping block, no-convert marker already exists", "block", b.ULID.String())
c.metrics.skippedBlocks.WithLabelValues(userID, cortex_parquet.NoConvertReasonMarkerExists).Inc()
continue
}
if noConvertMark.ShouldSkipBlock(maxBlockLabelNames) {
level.Debug(logger).Log(
"msg", "skipping block because label count still exceeds current limit",
"block", b.ULID.String(),
"label_names_count", noConvertMark.LabelNamesCount,
"current_limit", maxBlockLabelNames,
)
c.metrics.skippedBlocks.WithLabelValues(userID, cortex_parquet.NoConvertReasonTooManyLabels).Inc()
continue
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If we change to this way, it means that if the no converter marker already exists we won't re-evaluate the no convert marker check?

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.

ah, I mean

if cortex_parquet.ValidNoConvertMarkVersion(noConvertMark.Version) {
	if noConvertMark.Reason != cortex_parquet.NoConvertReasonTooManyLabels {
		level.Debug(logger).Log(
			"msg", "skipping block, no-convert marker already exists",
			"block", b.ULID.String(),
		)
		c.metrics.skippedBlocks.WithLabelValues(userID, cortex_parquet.NoConvertReasonMarkerExists).Inc()
		continue
	}

	if noConvertMark.ShouldSkipBlock(maxBlockLabelNames) {
		level.Debug(logger).Log(
			"msg", "skipping block because label count still exceeds current limit",
			"block", b.ULID.String(),
			"label_names_count", noConvertMark.LabelNamesCount,
			"current_limit", maxBlockLabelNames,
		)
		c.metrics.skippedBlocks.WithLabelValues(userID, cortex_parquet.NoConvertReasonTooManyLabels).Inc()
		continue
	}
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yep, if we change this way, then every no converter marker will be skipped immediately. ShouldSkipBlock(maxBlockLabelNames) is never be checked

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

ah, I mean

if cortex_parquet.ValidNoConvertMarkVersion(noConvertMark.Version) {
	if noConvertMark.Reason != cortex_parquet.NoConvertReasonTooManyLabels {
		level.Debug(logger).Log(
			"msg", "skipping block, no-convert marker already exists",
			"block", b.ULID.String(),
		)
		c.metrics.skippedBlocks.WithLabelValues(userID, cortex_parquet.NoConvertReasonMarkerExists).Inc()
		continue
	}

	if noConvertMark.ShouldSkipBlock(maxBlockLabelNames) {
		level.Debug(logger).Log(
			"msg", "skipping block because label count still exceeds current limit",
			"block", b.ULID.String(),
			"label_names_count", noConvertMark.LabelNamesCount,
			"current_limit", maxBlockLabelNames,
		)
		c.metrics.skippedBlocks.WithLabelValues(userID, cortex_parquet.NoConvertReasonTooManyLabels).Inc()
		continue
	}
}

This makes sense. I made the same check here:

func (m NoConvertMark) ShouldSkipBlock(currentMaxBlockLabelNamesLimit int) bool {
	// Manual no-convert marks are not tied to the label-name limit
	if m.Reason != NoConvertReasonTooManyLabels {
		return true
	}

But, I think writing in the way you suggested make it easier to understand on the first read.

@siddarth2810
siddarth2810 force-pushed the parquet-add-no-convert-marker branch from ee56065 to 6299415 Compare June 29, 2026 12:57

@SungJin1212 SungJin1212 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.

lgtm

@dosubot dosubot Bot added the lgtm This PR has been approved by a maintainer label Jun 30, 2026
@SungJin1212
SungJin1212 requested a review from friedrichg July 29, 2026 01:28
Comment thread CHANGELOG.md Outdated

@friedrichg friedrichg 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.

LGTM


converterMetaPrefix = "converter-meta-"

parquetConverterDataColumnDuration = time.Hour * 8

@SungJin1212 SungJin1212 Jul 29, 2026

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.

would be nice if we use the parquetConverterDataColumnDuration in baseConverterOptions.

baseConverterOptions := []convert.ConvertOption{
		convert.WithColDuration(parquetConverterDataColumnDuration),
		convert.WithRowGroupSize(cfg.MaxRowsPerRowGroup),
	}

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.

@siddarth2810
Can you get the rebase?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done, sorry for the delay

Changes:
- Add parquet no-convert marker and read/write logic
- Add max-block-label-names limit, blocks exceeding it get a no-convert marker instead of being converted.
- Add parquet_converter_max_block_label_names to exporter test
- Add integration test for parquet no-convert marker

Signed-off-by: Siddarth Gundu <siddarthg0910@gmail.com>
Signed-off-by: Siddarth Gundu <siddarthg0910@gmail.com>
The converter only read no-convert markers when the label-name limit was
enabled, so manually marked blocks were still converted when the limit was 0.
Read the marker unconditionally before conversion so these blocks stay skipped.

Signed-off-by: Siddarth Gundu <siddarthg0910@gmail.com>
Retry conversion if the current limit has increased beyond the label count stored
in the old no-convert mark.

Update converter tests for the new marker fields and retry behavior

Signed-off-by: Siddarth Gundu <siddarthg0910@gmail.com>
- Update tests to check skip with lower current limit

Signed-off-by: Siddarth Gundu <siddarthg0910@gmail.com>
@siddarth2810
siddarth2810 force-pushed the parquet-add-no-convert-marker branch from e139dda to b40cdb3 Compare August 20, 2026 07:54
Comment thread integration/parquet_converter_test.go Outdated
@@ -0,0 +1,142 @@
//go:build integration

@SungJin1212 SungJin1212 Aug 20, 2026

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 this test cannot execute in CI.
change to requires_docker or something?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done and solved small merge conflicts. Thank you :)

…ert-marker

Signed-off-by: Siddarth Gundu <siddarthg0910@gmail.com>

# Conflicts:
#	docs/configuration/v1-guarantees.md
…uns in CI

Signed-off-by: Siddarth Gundu <siddarthg0910@gmail.com>
@siddarth2810
siddarth2810 requested a review from a team as a code owner September 6, 2026 09:31
@SungJin1212
SungJin1212 merged commit a0d4fcc into cortexproject:master Sep 7, 2026
40 checks passed
CharlieTLe added a commit to CharlieTLe/cortex that referenced this pull request Sep 11, 2026
Get the unreleased section into the shape RELEASE.md asks for before the
release-1.22 cut, so operators reading the notes see the changes that affect them:

- Delete the stale duplicate of cortexproject#7375, which already shipped in 1.21.0 as cortexproject#7370.
- Re-sort into CHANGE -> FEATURE -> ENHANCEMENT -> BUGFIX.
- Correct the gRPC entry: the bump landed at v1.82.1, not v1.79.3.
- Fold follow-up PRs into the entry they belong to.
- Add three missing user-facing entries: cortexproject#7513, cortexproject#7514 and cortexproject#7559.
- Reclassify as CHANGE the entries that break existing configs or log consumers:
  the sign-key validation (cortexproject#7587), the Alertmanager per-tenant *_file rejections
  (cortexproject#7767, cortexproject#7768, now one entry) and the time_taken -> time_taken_ms rename (cortexproject#7649).
- Note the operator impact of the distroless base image (cortexproject#7637) and of the
  500 -> 499 reclassification (cortexproject#7717).

Rebased onto master, which added eight entries after this was first written.
They are curated the same way:

- Sorted into their categories: the deprecated flag removal (cortexproject#7790) and the
  max-exemplars deprecation (cortexproject#7793) under CHANGE, the X-Grafana-User query log
  (cortexproject#7799) under ENHANCEMENT, the YAML zero-value validation (cortexproject#7700) and the
  ReadPartitionedGroupInfo error handling (cortexproject#7766) under BUGFIX.
- Folded the Go toolchain bump (cortexproject#7807, cortexproject#7814) into the existing build image
  entry, which now reads 1.27.0 rather than carrying a second entry for it.
- Folded cortexproject#7745 into cortexproject#7698: both are the same wipe-on-transient-DNS-failure bug,
  cortexproject#7698 on the A record path and cortexproject#7745 on the SRV path.
- Folded cortexproject#7743 into cortexproject#7640: both are panics in the active request tracker's
  truncation of match[]/query values.

Rebased again onto master, which added eight more entries. Same treatment:

- Sorted into their categories: the evaluation-delay-duration removal (cortexproject#7792)
  and the fifocache/ingester-metadata-streaming removals (cortexproject#7791) under CHANGE,
  the parquet max-block-label-names limit (cortexproject#7625), the non-pointer
  HistogramBucket slice (cortexproject#7809) and the merge iterator BatchSize (cortexproject#7823) under
  ENHANCEMENT, and the CSV-list empty-string fix (cortexproject#7714) under BUGFIX.
- Folded the Thanos/promql-engine refresh (cortexproject#7788) into the existing upgrade
  entry, which already carries cortexproject#7691, cortexproject#7505 and cortexproject#7740.

Signed-off-by: Charlie Le <charlie_le@apple.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lgtm This PR has been approved by a maintainer size/XL storage/blocks Blocks storage engine tool/blocksconvert type/feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Parquet] Stop converting TSDB block to parquet if it has too many labels

4 participants