EN OpenGemini - AlanDevise/TsGate GitHub Wiki
2.1.3 is published through the GitHub source/tag and Maven Central; same-SHA CI and public artifact verification passed. Current coordinates: 2.1.3; see 2.1.3 release notes.
The common HTTP path and the adapted native ping() / version() health requests disable automatic redirects; the common write path also inherits the 64 MiB combined prepared application-batch budget (tsdb.opengemini.max-batch-bytes, positive bytes). Over-budget batches fail before I/O as ARGUMENT_ERROR / NOT_COMMITTED. Structured aggregate names are unique after case-preserving normalization; query and count reject collisions before I/O. Existing integer precision preflight, exact missing-measurement normalization, native-client ownership, unsupported strict cursors and asynchronous series visibility remain unchanged.
Version 2.1.2 does not add a new engine, server version, topology or alternate SDK. Its actual four-deployment regression is recorded in 2.1.2 verification evidence; historical pass counts below must not be presented as a rerun. The initial source-build cluster attempts for both versions recorded three errors in total, including uncertain writes; their evidence is retained under history/pre-readiness/. The first readiness gate had a separate 1.4.1 log-field assumption defect and was interrupted with successful cleanup; its evidence remains in history/readiness-v1/. Final source 2ba077a corrects only version-specific test observation. Its fresh full matrix passed all four deployments, 46 cases each (184 total), with zero failures/errors/skips, unchanged source/Git identities and all owned containers/networks removed.
InfluxDB 1.x and OpenGemini aggregate responses also include the implicit physical time column, so an exact aggregate alias or grouping tag named time is rejected before I/O. Case-distinct Time remains available. This protocol-specific reservation does not add a reserved time alias to IoTDB or InfluxDB 3.
TsGate 2.1.0 adds independent OpenGemini adapter and starter modules and manages them in the 2.1.0 BOM. The existing Central 2.0.0 artifacts do not contain these modules. For direct Maven Central integration, use aligned 2.1.0 dependencies. To use the current 2.1.2 fixes, first install v2.1.2 locally and align all TsGate dependencies/BOM at 2.1.2. Release status is separate from compatibility validation.
The adapter targets openGemini 1.5.2 and 1.4.1, using the default storage engine's InfluxQL interface. It implements the existing TSDBAdapter contract and exposes the same TGTemplate, TGQueryBuilder, TG* annotations and error/result types as the other backends. The backend changes only the dependency, configuration and native query dialect. The shared SPI, business POJO mapping and query model are unchanged.
Modules: tsgate-opengemini for direct Java integration, and tsgate-opengemini-spring-boot-starter for Spring Boot. The adapter reuses the bounded InfluxDB 1.x HTTP/InfluxQL implementation through composition. It has its own backend identity and property namespace. The compatible native client type is org.influxdb.InfluxDB, not the separate openGemini asynchronous SDK.
Use the starter for Spring Boot, or depend on tsgate-opengemini directly for a manually owned adapter. The 2.1.0 BOM manages both modules:
<dependency>
<groupId>io.github.alandevise</groupId>
<artifactId>tsgate-opengemini-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>tsdb:
query-log-enabled: true
opengemini:
enable: true
fail-fast: true
url: http://127.0.0.1:8086
database: business_metrics
username: ""
password: ""
retention-policy: ""
max-batch-records: 10000
max-batch-bytes: 67108864
max-query-rows: 10000
max-query-response-bytes: 16777216
http-client:
max-idle-connections: 8
keep-alive-duration-ms: 300000
connect-timeout-ms: 3000
read-timeout-ms: 60000
write-timeout-ms: 60000
call-timeout-ms: 0
retry-on-connection-failure: falseThe default URL is http://localhost:8086; the default database is tsdb. Create the selected database and any named retention policy beforehand. A blank retention policy uses the server default. Empty credentials select unauthenticated access; configured credentials use HTTP Basic authentication. Supply secrets through application deployment configuration.
Only explicit tsdb.opengemini.enable=true activates this starter. All other backends remain disabled unless explicitly enabled. Enabling OpenGemini and InfluxDB1 together is an error even though the OpenGemini implementation depends on the InfluxDB1 module. Multiple starter dependencies may coexist, but one Spring context still selects at most one backend. Backend-specific components can use @Conditional(TSDBAdapterEnabledCondition.OpenGemini.class).
Inject TGTemplate as before. For example, with the application's existing annotated Reading POJO:
tgTemplate.write(reading);
tgTemplate.batchWrite(readings);
BatchWriteResult written = tgTemplate.batchWriteDetailed(readings);
List<Reading> rows = tgTemplate.query(Reading.class)
.whereTag("device", "sensor-a")
.timeRange(startMillis, endMillis)
.orderByTimeAsc()
.limit(100)
.list();
PageResult<Reading> page = tgTemplate.query(Reading.class)
.orderByTimeAsc().page(1, 100);Direct integration uses OpenGeminiProperties, optional OpenGeminiHttpClientProperties, and OpenGeminiAdapter. Call init() before using an adapter constructed manually, and close it when its owner shuts down. Configuration is copied at construction; later mutation does not redirect adapter or native-client operations. Initialization is idempotent, failed resource initialization can be retried, and close is terminal. Startup fail-fast=false follows the existing optional native-client policy; it does not probe server/database availability.
Both topologies use the same business API and YAML shape. For a cluster, url is a reachable ts-sql endpoint or a deployment-managed load balancer. The adapter does not discover meta/store nodes or automatically replay a failed write through another SQL endpoint. Configure any ingress routing and failover in the deployment. HTTP connection-failure retries default to false for this backend so uncertain writes are not silently retried by the transport.
The local cluster fixture runs three separate Docker containers, each with one ts-meta, one ts-store and one ts-sql. Cluster readiness requires three registered meta nodes and three registered stores, followed by cross-endpoint write/read verification. Three independent single-node databases do not count as a cluster. The fixture records server versions, image/source provenance, membership and readback results.
Healthy cluster membership and metadata do not establish readiness of a newly created database's data-Raft peers. The owned three-replica fixture observes initial transfers after each test CREATE DATABASE and before its first write, using a read-only, version-specific gate with a 45-second deadline:
-
1.5.2: require the exact target database/partition completion records from the three stores, uniquely covering partitions
{0,1,2}. -
1.4.1: bind to the official binary's exact commit
42678b4a23e0c7921548f6ceacb812659591d0bfand one complete, unrotated startup log per store. Its finish messages lack database/partition fields, so they are not assigned to a database. Instead, the full log must balance all initial-transfer and explicitly logged RPC starts against anonymous finishes, using each record'srepeatedcount. Explicit target-database init records must uniquely cover{0,1,2}across the three stores; the balanced ledgers must remain identical in two observations. Missing, ambiguous, malformed or incompatible evidence fails the gate.
This is an initial readiness observation for a controlled, exclusive, serial fixture. Buffered logs and subsequent background RPCs mean it cannot provide an atomic health snapshot or guarantee continued availability. Single-node tests do not need it. The dedicated matrix runner supplies absolute fixture script/state paths automatically; external SQL URLs alone do not provide the owned-log evidence required by these cluster tests.
This preparation writes no warmup points, changes no server settings, forces no leadership transfer and replays no writes. Production adapters still connect to external three-replica clusters without Docker/log access. New-series index visibility remains a separate read-side condition below.
The default engine flushes newly created series indexes asynchronously. A successful write acknowledgement can precede query visibility for a new measurement or tag combination. Appending to a series whose index is already visible may be immediately readable. The common write result reports the confirmed request boundary; it does not promise strong read-after-write consistency. Applications that need to observe a particular point should poll reads with a deadline and a concrete expected result. The adapter performs one query request; it does not replay writes or delay an empty query. Docker tests establish complete point visibility through an independent HTTP oracle before asserting the query under test.
Measurement names follow the server's printable-name rules: comma, semicolon, slash, backslash, and the complete names . / .. are rejected. The entire batch is checked before any request, producing NOT_COMMITTED for an invalid name. Accepted names retain their identity, including equals signs, ordinary spaces and Chinese text. Field/tag backslashes remain supported by the line-protocol and InfluxQL escaping rules.
The exact server query error measurement not found is normalized to an empty successful result by the common structured query and to zero by count. executeQuery and borrowed native query DTOs retain server errors, including missing measurements: native statements may address multiple measurements or subqueries, so converting their failure to empty rows would hide an invalid query. Other server errors remain errors.
getNativeClient() returns one stable InfluxDB compatibility proxy. Its ping() validates a successful real HTTP response and reads X-Geminidb-Version; version() caches only a confirmed version. Health requests honor the constructor-time URL, credentials and timeout settings and release their temporary HTTP resources. Other methods, native exceptions and close operations delegate to the original client. Fluent client settings preserve proxy identity. The adapter owns shutdown, including local validation and result normalization; callers coordinate borrowed native calls separately.
The tested 1.4.1/1.5.2 Influx-compatible HTTP write path converts integer fields through float64 before storing them. An integer protocol suffix does not prevent this conversion: 9007199254740993i reads back as 9007199254740992. The OpenGemini adapter therefore checks the complete batch before I/O and accepts integer-typed fields only within signed-int64 bounds and when their exact value is representable by IEEE 754 float64. All integers from -2^53 to 2^53 are exact; some larger values, including 2^53+2 and Long.MIN_VALUE, are also exact. 2^53+1, Long.MAX_VALUE and Long.MIN_VALUE+1 are rejected with ARGUMENT_ERROR, NOT_COMMITTED and zero physical requests, without coercion or string encoding. Structured query/count also preflight exact integer filter literals, including every IN/BETWEEN value, because backend numeric comparisons can round them. Extreme integer-valued BigDecimal predicates are compared with signed-int64 bounds before integer expansion, so very large exponents cannot bypass validation or force unbounded allocation. Float/Double and fractional query literals retain ordinary floating-point semantics; existing BigDecimal field checks still apply. Epoch-millisecond timestamps use their separate time path. Native SQL and borrowed native writes bypass these checks and retain backend precision limitations; aggregate overflow and floating-point accumulation are not made exact by this validation. This restriction is specific to the HTTP adapter, not a claim about every OpenGemini engine or alternate ingestion protocol.
| Operation | Default-engine contract |
|---|---|
| POJO/record single and batch writes | Existing annotation mapping, preflight validation and detailed commit states |
| Time ranges, tag/field predicates and field selection | Existing fluent API and bounded mapped results |
| ASC/DESC time ordering and offset pagination | Supported through the common query API |
| Time-cursor pagination | Supported; rows sharing a boundary timestamp can be omitted by a time-only cursor |
| Aggregates, tag grouping and UTC/fixed-offset windows | Existing aggregation API; time windows require explicit start and end bounds |
| Count | Result-row semantics before pagination; sparse fields do not define row identity; response-byte limit still applies |
| Read-only native queries | Single SELECT, SHOW, or supported EXPLAIN [ANALYZE] SELECT; native administration uses the borrowed client |
| Strict composite cursors, FIELD ordering, tag-only projection | Explicit UNSUPPORTED_OPERATION in the inherited compatibility contract |
| Regional calendar-day windows/DST | Explicit UNSUPPORTED_OPERATION; use supported UTC or fixed-offset windows |
| COLUMNSTORE/Arrow/PromQL/cluster management | Outside this first adapter's verified contract; no claim covering every openGemini feature |
Ordinary/native queries obey the configured row and decompressed-response limits. Page lookahead may read one additional row. Count ignores pagination and cursors while retaining time-bound validation and the response-byte cap. Unsupported operations fail explicitly rather than returning an empty successful result.
Writes report confirmed request boundaries. A preflight rejection is NOT_COMMITTED; errors that may have persisted data remain UNKNOWN with confirmed earlier batch counts retained. Do not automatically replay an uncertain batch. Native operations bypass common validation/limits and must coordinate with adapter shutdown; callers must not close the borrowed client.
OpenGemini keeps the same API, compatible native client, HTTP integer checks and asynchronous visibility behavior. The shared template's exact numeric time conversion and usable continuation checks apply here too; time-only cursor limits remain unchanged. Strict composite cursors and FIELD sorting still fail explicitly with UNSUPPORTED_OPERATION.
Reusable test contracts record these supported/unsupported boundaries without adding a production capability SPI. Automatic CI includes OpenGemini when its own modules, shared core/build inputs or reused InfluxDB 1.x implementation change. Routine checks run 1.4.1 and 1.5.2 single nodes. Release/full manual checks retain the four-deployment matrix; use run-matrix.py --mode single or --mode cluster for explicit subsets, or omit the selector for the full matrix. See runner commands.
The results below belong to the recorded 2.1.0/source snapshots. This release's actual results are in 2.1.1 verification evidence, rather than inferred from historical passes.
A source regression on 2026-10-03 reran all four deployments: each passed 44 adapter/starter tests, with zero failures/errors/skips. Source hashes and cleanup records were retained for that pre-release snapshot. Final 2.1.0 release verification is tracked separately in Compatibility and validation. Earlier evidence retains its original snapshot.
Local Docker validation on 2026-10-03 used ARM64, Temurin 17 and Spring Boot 2.7.18. Each environment ran the actual adapter and auto-discovered starter tests. Compatibility covers these exact default-engine releases and settings.
| Server | Topology | Replicas | Java integration results |
|---|---|---|---|
| 1.4.1 | Single node | 1 | 44 passed; 0 failed/errors/skipped |
| 1.4.1 | Three-node cluster | 3 | 44 passed; 0 failed/errors/skipped |
| 1.5.2 | Single node | 1 | 44 passed; 0 failed/errors/skipped |
| 1.5.2 | Three-node cluster | 3 | 44 passed; 0 failed/errors/skipped |
The cluster has three separate meta/store/SQL containers with a real three-voter Raft quorum and three registered stores. Database and retention-policy metadata confirm three replicas. Tests write through each SQL endpoint with both TGTemplate and the borrowed compatible client, then read the complete data set through every endpoint. Every owned test container/network was removed.
Reproduce from the repository root with Java/Maven pointing to the same JDK:
python3 tsgate-opengemini/src/test/scripts/run-matrix.py \
--output .local-test/opengemini-matrixThe fixture verifies official archive checksums, records binary/source provenance, and may download archives even when a matching image is cached. The runner saves fresh Failsafe XML reports and source hashes under its output directory. The 1.4.1 official binary reports build commit 42678b4a23e0c7921548f6ceacb812659591d0bf; its release tag points to 5ff486d020cf52df11d8de73aa4664fd843a4e53. Those are recorded separately rather than treating the attachment as a build of the tag commit.
The recorded source regression snapshot passed 888 unit tests on each documented JDK/Boot combination (17/2.7.18, 21/3.5.14 and 25/4.1.0), 114 representative existing-backend Docker tests, 176 OpenGemini Docker tests across four environments, 27 unsigned binary/source/Javadoc archive checks in nine JAR modules, and 34 Python runner tests. These are historical source-regression results, not final 2.1.0 publication evidence. TLS, authenticated deployments, ingress failover and node-failure recovery were not exercised by the local topology matrix.
The 1.4.1 fixture uses the official complete binary distribution. The 1.5.2 release has no binary attachments, so its fixture builds the exact official tag commit 19ba0e2d9b428579004eb53d37d0c9b23034e2a9; it does not substitute main or a release candidate.
The existing representative three-database runner retains its IoTDB/InfluxDB coverage. OpenGemini integration tests require an explicitly supplied endpoint or the dedicated fixture; excluding them from that runner without an endpoint is not evidence of OpenGemini compatibility. See the local validation report for the separate four-topology matrix.