Skip to content

Enable hypercore compression by default on the asset_datapoint table - #2352

Merged
richturner merged 55 commits into
masterfrom
feature/enabeling-hypercore
May 7, 2026
Merged

richturner merged 55 commits into
masterfrom
feature/enabeling-hypercore

Conversation

@Miggets7

@Miggets7 Miggets7 commented Dec 16, 2025 •

Copy link
Copy Markdown
Contributor

Enables columnstore compression on the asset_datapoint table for storage savings and faster purges.

Changes

  • BREAKING Migration: Enable HyperCore with auto-compression policy (1 week) migration script will fail hard and fast if postgresql image doesn't support hypercore, ensure the postgres container is up to date
  • BREAKING Asset datapoint data is now retained infinitely by default and now uses weeks instead of days
  • Purging: Use drop_chunks() instead of DELETE to avoid decompression overhead on compressed chunks
  • Utility: Add TimeUtil.toInstant() for datetime conversions
  • Test: Validate compression and purge

Benefits

  • Significant storage reduction
  • Instant chunk drops vs slow row-by-row deletes
  • Improved query performance on historical data

@Miggets7
Miggets7 requested a review from richturner December 16, 2025 14:34
@Miggets7 Miggets7 added the Enhancement Improvement of an existing feature label Dec 16, 2025

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

Going to want to change DATA_POINTS_MAX_AGE_DAYS to be something that aligns with DB chunks i.e. weeks as discussed in calls.

Will need a DB migration script to convert old DAYS to weeks

Comment thread model/src/main/java/org/openremote/model/util/TimeUtil.java Outdated

Copilot AI left a comment •

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.

Pull request overview

This pull request enables TimescaleDB HyperCore (columnstore compression) for the asset_datapoint table to achieve storage savings and improve purge performance. The changes include a database migration to enable columnstore with a 3-month auto-compression policy, an optimized purge strategy using TimescaleDB's drop_chunks() function to avoid decompression overhead, a utility method for datetime conversions, and a comprehensive test validating compression and purging with 2.5 million datapoints.

Key Changes:

  • Database migration enables columnstore compression with configurable compression interval
  • Purge logic enhanced to use drop_chunks() for efficient chunk removal, falling back to DELETE when necessary
  • New TimeUtil.toInstant() utility method for handling various datetime types

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
V20251216_01__EnableHyperCore.sql Enables columnstore compression and sets up auto-compression policy for datapoint tables
AssetDatapointService.java Adds optimized purge logic using TimescaleDB's drop_chunks() to avoid decompression overhead
TimeUtil.java Adds utility method to convert various datetime types to Instant
PersistenceService.java Adds configuration property for columnstore compression interval with Flyway placeholder support
AssetDatapointHypercoreTest.groovy Comprehensive test validating compression and purging with 2.5M datapoints across storage measurements

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread manager/src/main/java/org/openremote/manager/datapoint/AssetDatapointService.java Outdated
Comment thread manager/src/main/java/org/openremote/manager/datapoint/AssetDatapointService.java Outdated
Comment thread model/src/main/java/org/openremote/model/util/TimeUtil.java Outdated
Comment thread manager/src/main/java/org/openremote/manager/datapoint/AssetDatapointService.java Outdated
Comment thread manager/src/main/java/org/openremote/manager/datapoint/AssetDatapointService.java Outdated
Comment thread manager/src/main/java/org/openremote/manager/datapoint/AssetDatapointService.java Outdated
@richturner

richturner commented Jan 15, 2026 •

Copy link
Copy Markdown
Member

Saw this error in the logs of an instance running compression:

1766567833906,"WARNING [ContainerExecutor-22235       ] com.zaxxer.hikari.pool.ProxyConnection   : or-pool - Connection org.postgresql.jdbc.PgConnection@5459544f marked as broken because of SQLSTATE(0A000), ErrorCode(0)"
1766567833906,org.postgresql.util.PSQLException: ERROR: insert with ON CONFLICT or RETURNING clause is not supported on compressed chunks
1766567833906,	at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2736)
1766567833906,	at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2421)
1766567833906,	at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:372)
1766567833906,	at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:525)
1766567833906,	at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:435)
1766567833906,	at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:196)
1766567833906,	at org.postgresql.jdbc.PgPreparedStatement.executeUpdate(PgPreparedStatement.java:157)
1766567833906,	at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeUpdate(ProxyPreparedStatement.java:61)
1766567833906,	at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate(HikariProxyPreparedStatement.java)
1766567833906,	at org.openremote.manager.datapoint.AbstractDatapointService.lambda$upsertValue$1(AbstractDatapointService.java:110)
1766567833906,	at org.hibernate.jdbc.WorkExecutor.executeWork(WorkExecutor.java:39)
1766567833906,	at org.hibernate.internal.AbstractSharedSessionContract.lambda$doWork$4(AbstractSharedSessionContract.java:1086)
1766567833906,	at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.coordinateWork(JdbcCoordinatorImpl.java:303)
1766567833906,	at org.hibernate.internal.AbstractSharedSessionContract.doWork(AbstractSharedSessionContract.java:1097)
1766567833906,	at org.hibernate.internal.AbstractSharedSessionContract.doWork(AbstractSharedSessionContract.java:1085)
1766567833906,	at org.openremote.manager.datapoint.AbstractDatapointService.lambda$upsertValue$2(AbstractDatapointService.java:102)
1766567833906,	at org.openremote.container.persistence.PersistenceService.lambda$doTransaction$4(PersistenceService.java:420)
1766567833906,	at org.openremote.container.persistence.PersistenceService.doReturningTransaction(PersistenceService.java:430)
1766567833906,	at org.openremote.container.persistence.PersistenceService.doTransaction(PersistenceService.java:419)
1766567833906,	at org.openremote.manager.datapoint.AbstractDatapointService.upsertValue(AbstractDatapointService.java:101)
1766567833906,	at org.openremote.manager.datapoint.AbstractDatapointService.upsertValue(AbstractDatapointService.java:98)
1766567833906,	at org.openremote.manager.datapoint.AssetDatapointService.onAttributeEvent(AssetDatapointService.java:125)
1766567833906,	at org.openremote.manager.event.ClientEventService.lambda$sendToSubscribers$14(ClientEventService.java:399)
1766567833906,	at java.base/java.util.concurrent.CopyOnWriteArrayList.forEach(CopyOnWriteArrayList.java:891)
1766567833906,	at java.base/java.util.concurrent.CopyOnWriteArraySet.forEach(CopyOnWriteArraySet.java:425)
1766567833906,	at org.openremote.manager.event.ClientEventService.sendToSubscribers(ClientEventService.java:384)
1766567833906,	at org.openremote.manager.event.ClientEventService.lambda$configure$13(ClientEventService.java:378)
1766567833906,	at org.apache.camel.support.processor.DelegateSyncProcessor.process(DelegateSyncProcessor.java:67)
1766567833906,	at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$RedeliveryTask.doRun(RedeliveryErrorHandler.java:777)
1766567833906,	at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$RedeliveryTask.run(RedeliveryErrorHandler.java:720)
1766567833906,	at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.doRun(DefaultReactiveExecutor.java:199)
1766567833906,	at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.executeReactiveWork(DefaultReactiveExecutor.java:189)
1766567833906,	at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.tryExecuteReactiveWork(DefaultReactiveExecutor.java:166)
1766567833906,	at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:148)
1766567833906,	at org.apache.camel.impl.engine.DefaultReactiveExecutor.schedule(DefaultReactiveExecutor.java:54)
1766567833906,	at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$RedeliveryTask.lambda$doRun$0(RedeliveryErrorHandler.java:782)
1766567833906,	at org.apache.camel.processor.ThreadsProcessor$ProcessCall.run(ThreadsProcessor.java:81)
1766567833906,	at io.micrometer.core.instrument.internal.TimedRunnable.run(TimedRunnable.java:49)
1766567833906,	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
1766567833906,	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
1766567833906,	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
1766567833906,	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
1766567833906,	at java.base/java.lang.Thread.run(Thread.java:1583)
1766567833959,WARNING [ContainerExecutor-22235       ] .manager.datapoint.AssetDatapointService : Failed to insert/update data point: 

@Miggets7

Copy link
Copy Markdown
Contributor Author

@richturner which instance was it? Do you know which version of TimescaleDB is running there?
According to this blog post should upsert should work on version 2.11+

@Miggets7
Miggets7 requested a review from richturner February 4, 2026 09:25
@sonarqubecloud

Copy link
Copy Markdown

@richturner

Copy link
Copy Markdown
Member

Need to decide what the fallback is if the postgres instance doesn't support hypercore, should configuration be part of DB image and then manager warns if drop_chunks() function is not available?

@Miggets7

Miggets7 commented May 6, 2026

Copy link
Copy Markdown
Contributor Author

@richturner Looks good. I cannot approve it, because I'm the author

@richturner

Copy link
Copy Markdown
Member

The quick look over is fine, I will do the review of the code you wrote as well

@sonarqubecloud

sonarqubecloud Bot commented May 7, 2026

Copy link
Copy Markdown

@richturner
richturner enabled auto-merge (squash) May 7, 2026 13:15
@richturner
richturner merged commit a34c0df into master May 7, 2026
3 checks passed
@richturner
richturner deleted the feature/enabeling-hypercore branch May 7, 2026 13:38
@MartinaeyNL MartinaeyNL changed the title Feature/enabeling hypercore Enable hypercore compression by default on the asset_datapoint table May 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Enhancement Improvement of an existing feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Validate postgres hypercore performance on a large instance

6 participants