Skip to content

Add IndexMode.TSDB as the preferred metrics mode#152901

Open
kkrik-es wants to merge 21 commits into
elastic:mainfrom
kkrik-es:indexmode-add-tsdb
Open

Add IndexMode.TSDB as the preferred metrics mode#152901
kkrik-es wants to merge 21 commits into
elastic:mainfrom
kkrik-es:indexmode-add-tsdb

Conversation

@kkrik-es

@kkrik-es kkrik-es commented Jul 3, 2026

Copy link
Copy Markdown
Member

Summary

Add IndexMode.TSDB as a new, first-class enum value that behaves identically to TIME_SERIES (delegates every overridden method), so index.mode: tsdb is now accepted anywhere index.mode: time_series is — without renaming or changing anything about existing time_series indices, which keep emitting/persisting exactly as before (time_series remains the canonical output string; tsdb is a preferred alias).

  • New helpers IndexMode#isTsdb(), IndexMode.isTsdb(IndexMode) (null-safe), and IndexMode.isTsdbName(String) (for raw, un-parsed index.mode setting strings) replace direct == IndexMode.TIME_SERIES comparisons across the codebase, so both spellings are treated identically everywhere.
  • Enum.valueOf(IndexMode.class, ...) / IndexMode.valueOf parse sites were deliberately left untouched — since TSDB is a new constant (not a rename) whose name already uppercases to match "tsdb", these already accept both spellings for free.
  • New TransportVersion (index_mode_tsdb_added) gates TSDB's wire serialization for mixed-version clusters.
  • New TsdbIndexModeTests covering fromString, getName, isTsdb/isTsdbName, the index.mode setting parser, serialization round-trip + version-gate failure, and behavior parity with TIME_SERIES.
  • New TimeSeriesToTsdbIndexModeRollingUpgradeIT — a real rolling-upgrade test that creates a data stream on time_series, upgrades the cluster, switches the template to tsdb and rolls over, and verifies the old backing index stays time_series, the new one is tsdb, and both remain queryable together (verified via FROM ds METADATA _index | STATS count = COUNT(*) BY _index).

Notable bugs found and fixed along the way

  • EsqlSession's _index_mode term filter (used to gate TS/PROMQL command queries) was built from the command's fixed sentinel mode, so it only ever matched "time_series" — it would have silently excluded any concrete index.mode: tsdb index from a TS query, and incorrectly rejected it as "not a time series index" on retry. Fixed with a TermsQueryBuilder matching both aliases.
  • Two colon-style switch/if statements (FollowingEngineTests, LogsdbIndexModeSettingsProvider) with a default/hardcoded branch would have broken once TSDB became reachable via randomFrom(IndexMode.availableModes()) — not caught by the compiler since these aren't exhaustive expression switches.
  • A couple of randomValueOtherThan(IndexMode.TIME_SERIES, ...) test patterns would let a randomly-picked TSDB slip through as "not time series," causing spurious failures — fixed with randomValueOtherThanMany(m -> m.isTsdb(), ...).

Test plan

  • TsdbIndexModeTests (new) — all pass
  • IndexSettingsTests, MapperServiceTests, MappingLookupTests, IndexModeFieldTypeTests, SourceFieldMapperTests, PerFieldMapperCodecTests, TSDBDocValuesFormatSelectorTests, ResolveIndexTests — all pass
  • ESQL analysis, optimizer, datasources, session test suites — all pass
  • FollowingEngineTests (ccr), IndexCommitTimestampFieldRangeTests (stateless) — all pass
  • TimeSeriesToTsdbIndexModeRollingUpgradeIT (new) — run against real rolling upgrades from both 9.5.0 and 8.19.0
  • Full compile sweep across every touched module
  • spotlessJavaCheck clean across every touched module

Follow-up (separate PR)

Updating YAML REST tests and existing Java tests to prefer/cover tsdb alongside time_series is intentionally deferred to a follow-up PR.

Related to #152902

Users and docs already call time-series indices tsdb; add a new
IndexMode.TSDB constant that behaves identically to TIME_SERIES so
index.mode: tsdb is now also accepted, without renaming or changing
anything about existing time_series indices, which keep emitting and
persisting exactly as before. TSDB delegates every behavior to
TIME_SERIES and is treated identically everywhere via new
isTsdb()/isTsdb(IndexMode)/isTsdbName(String) helpers, replacing
direct == TIME_SERIES comparisons across the codebase.

Adds a transport version gating TSDB's wire serialization for
mixed-version clusters, unit tests for the new alias, and a rolling
upgrade test that switches a data stream from time_series to tsdb
mid-upgrade and verifies both backing indices stay queryable together.
@elasticsearchmachine

Copy link
Copy Markdown
Collaborator

Hi @kkrik-es, I've created a changelog YAML for you. Note that since this PR is labelled release highlight, you need to update the changelog YAML to fill out the extended information sections.

kkrik-es and others added 2 commits July 3, 2026 20:38
Introduced `IndexMode.TSDB` as an alias for `TIME_SERIES`, added new tests, and fixed related bugs. Deferred updates to YAML REST tests for a follow-up PR.
NumberFieldType/GeoPointFieldType/ScaledFloatFieldType/
UnsignedLongFieldType all have a real (non-test-only) code path where
indexMode is null, e.g. TokenCountFieldType passes null explicitly.
The earlier == IndexMode.TIME_SERIES checks tolerated that; the
isTsdb() instance-method replacements did not. Switch these four call
sites to the null-safe IndexMode.isTsdb(IndexMode) static instead.

Also gate AllSupportedFieldsTestCase's mode=tsdb parameterization on
minVersion().supports(IndexMode.INDEX_MODE_TSDB_ADDED), matching the
existing pattern for vectordb_document/columnar, so multi-cluster BWC
runs skip creating a tsdb index against a remote that predates it.
@kkrik-es kkrik-es added the test-release Trigger CI checks against release build label Jul 3, 2026
@kkrik-es kkrik-es marked this pull request as ready for review July 3, 2026 19:10
@kkrik-es kkrik-es requested a review from a team as a code owner July 3, 2026 19:10
@elasticsearchmachine

Copy link
Copy Markdown
Collaborator

Pinging @elastic/es-storage-engine (Team:StorageEngine)

# Conflicts:
#	server/src/main/resources/transport/upper_bounds/9.5.csv
@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

🔍 Preview links for changed docs

⏳ Building and deploying preview... View progress

This comment will be updated with preview links when the build is complete.

@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

ℹ️ Important: Docs version tagging

👋 Thanks for updating the docs! Just a friendly reminder that our docs are now cumulative. This means all 9.x versions are documented on the same page and published off of the main branch, instead of creating separate pages for each minor version.

We use applies_to tags to mark version-specific features and changes.

Expand for a quick overview

When to use applies_to tags:

✅ At the page level to indicate which products/deployments the content applies to (mandatory)
✅ When features change state (e.g. preview, ga) in a specific version
✅ When availability differs across deployments and environments

What NOT to do:

❌ Don't remove or replace information that applies to an older version
❌ Don't add new information that applies to a specific version without an applies_to tag
❌ Don't forget that applies_to tags can be used at the page, section, and inline level

🤔 Need help?

Extend unit tests to assert IndexMode.TSDB behaves identically to
IndexMode.TIME_SERIES wherever production code now uses isTsdb().
@felixbarny

Copy link
Copy Markdown
Member

Instead of creating a whole new IndexMode, have you considered keeping just the existing TIME_SERIES one but accepting two string representations for it? If feasible, that seems like a smaller, more contained change.

@kkrik-es

kkrik-es commented Jul 5, 2026

Copy link
Copy Markdown
Member Author

I did, this mostly works but there are cases where we invoke Enum.valueOf(IndexMode.class, ..). This doesn't like different strings and may fail in weird ways. There's also a question how we serialize in this case - use time_series or tsdb in the output?

It's cleaner to introduce a new mode and start using it - although it's quite a change to make sure it's used and tested everywhere..

Fix IndexSettingsTests assertion to expect the canonical
time_series message text, and add FeatureMetric TSDB coverage.
Rename TsdbAlias-style identifiers to Tsdb and reword comments,
since alias has a specific meaning (index aliases) in Elasticsearch.
Also add TS-command TSDB coverage in TimeSeriesIT after confirming
no production bug: concrete, wildcard, and mixed-mode alias lookups
all resolve correctly today.
Covers IndexMode.java's own javadoc plus test files touched by
other concurrent agents that the earlier sweep missed.
IndexMode.TSDB delegated validateWithOtherSettings/validateMapping/
validateAlias straight to TIME_SERIES's method bodies, where
unqualified getName()/this always resolved to TIME_SERIES. Extract
shared static utilities that take the calling mode explicitly, so
a tsdb-mode index's validation errors correctly say index.mode=tsdb
instead of always canonicalizing to time_series. Add TSDB coverage
for the sort-setting and routing-partition-size rejection paths.
@kkrik-es kkrik-es changed the title Add IndexMode.TSDB as a preferred alias for TIME_SERIES Add IndexMode.TSDB as the preferred metrics mode Jul 5, 2026
@kkrik-es kkrik-es requested a review from dnhatn July 5, 2026 15:13
@kkrik-es

kkrik-es commented Jul 5, 2026

Copy link
Copy Markdown
Member Author

Adding @dnhatn for the esql part, @gmarouli for lifecycle and downsampling.

kkrik-es and others added 2 commits July 6, 2026 10:33
Mirrors the existing logsdb/vectordb_document/columnar index mode
capabilities so YAML tests can gate on cluster support for tsdb.
@gmarouli

gmarouli commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Instead of creating a whole new IndexMode, have you considered keeping just the existing TIME_SERIES one but accepting two string representations for it? If feasible, that seems like a smaller, more contained change.

Renaming could be considered a breaking API change. Currently, there might be users relying on this string to detect their time series data. So, we have 2 options but they have trade-offs:

  1. Add a new one, prefer it when a user doesn't explicitly specify time_series.
    We can use tsdb as a default, for example, when we perform the migration, if tsdb is supported by all nodes. We could change our managed templates (again as long as the cluster is fully upgraded), but we shouldn't overwrite the user's input. This is the conservative approach.

  2. We simply rename it in the API. The wire serialisation of the enum is based on the byte id, so that's not an issue, but we need extra care on the XContent serialisation and we need again a cluster feature to ensure that the cluster state recovery will not encounter any issues when parsing XContent. And we need to inform our customers about this because it will change on every output, component and composable templates, settings, data streams etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants