Repository navigation
Releases
26.11.1
ArcadeDB 26.11.1
Overview
887 issues and pull requests closed under the 26.11.1 milestone - 651 issues and 236 pull requests - out of 483 pull requests merged and about 690 commits since 26.10.2. 468 of the closed issues are bug fixes, 28 of them rated critical.
The headline work is in six places:
- Transactions that behave like SQL - a statement that fails inside a transaction is now taken back on its own (statement-level savepoints) and the transaction goes on,
UPDATE ... SETreads the row as it was before the statement, an explicitNULLis stored asNULL, andCREATE INDEXno longer misses records other sessions have not committed yet. - Crash safety and durability - recovery after a power loss (Jepsen LazyFS) repairs torn pages and quarantines what it cannot recover instead of serving it, vector and sparse vector indexes survive a crash right after their build, and a growing record can no longer overwrite its neighbour on the page.
- Vector search - the Cypher 25
SEARCHclause, Neo4j'sCREATE VECTOR INDEX/CREATE FULLTEXT INDEXDDL, a pre-filter fordb.index.vector.queryNodes,PRODUCTandBINARYindexes that search on their compressed codes and re-rank, and a graph build 2.3x faster on largeINT8indexes. - Operations - databases nobody uses can close and reopen on demand, a database that is only read holds no WAL file, every Docker image runs as UID 1000, the native image states its CPU baseline (with a compatibility archive for older x86 CPUs) and is built at
-O3, and Claude Code can connect to your own server through the new ArcadeDB plugin. - Wire protocols - the PostgreSQL catalog answers what psql, pgjdbc and psqlodbc ask (
\d,\dt,\di,\dm,\df,\du, JDBC metadata), PostgreSQL results stream in chunks, Redis pipelining runs at 0.8-0.9x of Redis on one connection and 2x under heavy load, and every protocol re-resolves a database after a close, restore or drop. - Security hardening - the users, groups and API-token files are never replaced by a default on a bad reload, plugin routes answer only the method they declare, wrong Basic credentials answer 401, and the HA cluster token can no longer change silently on a rolling restart.
Upgrading is recommended for every deployment. This release changes several answers to be correct (SQL, Cypher temporals, string functions, HTTP status codes), changes the Docker user and drops the plain Kubernetes StatefulSet: read the Upgrade notes before upgrading.
Contents: New features Β· Highlights Β· Security Β· Performance Β· Major fixes and improvements Β· Upgrade notes Β· Dependency updates
New features
Vector and full-text search
- Cypher 25
SEARCHclause (#10776, #10783).MATCH (d:Doc) SEARCH d IN (VECTOR INDEX idx FOR $q [WHERE p] LIMIT k) SCORE AS sruns the vector search first and bindsdto theknearest records; the innerWHEREis tested on each candidate during the search, which widens until it haskmatching rows. It used to be parsed and dropped, answering everyDoc. - Neo4j index DDL in openCypher (#10678, #10864, #10914, #10994, #10915, #10992).
CREATE VECTOR INDEXandCREATE FULLTEXT INDEXbuildLSM_VECTORandFULL_TEXTindexes, withIF NOT EXISTS,OPTIONSfrom a map or a parameter, several labels or relationship types (FOR (n:Article|Post)) under one logical name, and a vector index that takes its dimension from the first vector it receives.SHOW INDEXESlists acreateStatementthat runs as written. Requested by @chetto1983. IS :: VECTOR<T>(n)property type constraint and avector(v, n, T)that builds the array of its coordinate type (#10862, #10918, #10917, #10991).- Pre-filter for
db.index.vector.queryNodes(#10685, #10808): an optional options map withwhereandfilter, tested during the search, so a multi-tenant query no longer returns fewer rows than asked.vector.neighborsandvector.sparseNeighborstake the samewhereoption, evaluated only on the candidates the search visits (#10169). PRODUCTandBINARYindexes search on their codes (#10514, #10968, #10975). The walk scores on the in-memory PQ codes (or the one-bit codes) and re-ranksk * rerankOversamplecandidates on the stored vectors, so the returned distances stay exact. New index settingsrerankOversampleandfusedPQ, a per-queryrerankoption, andpqTrainingLimitis now honoured. APRODUCTgraph file is about 8x smaller.- Full-text filters decided before the load (#11069): a condition on another indexed property next to
SEARCH_INDEX()/SEARCH_FIELDS()is checked against that index first; withLIMIT 10the reported query loads 10 records instead of about 2,000. Reported by @shaunpatterson.
Server and operations
- Close idle databases and reopen them on demand (#11068). Off by default:
arcadedb.server.databaseIdleTimeoutcloses a database after that long without activity,arcadedb.server.maxOpenDatabaseskeeps at most that many open (least recently used first), and the next request over any protocol (HTTP, gRPC, PostgreSQL, Bolt, Gremlin, MCP) reopens it. A database with an open transaction, a running query or async work, or under HA, is never closed. Requested by @singh-hovr. - WAL files and housekeeping on demand (#10234, #10218). One shared scheduler replaces a timer thread per database, a WAL file is opened by the first commit that needs it and released after 60 s idle (
arcadedb.txWalIdleTimeout), so a database that is only read holds no WAL file. A background warm-up afterONLINEcuts the first HTTP query from about 160 ms to 60 ms (arcadedb.server.queryWarmUp). - MCP for Claude Code (#11170). The repository is a Claude Code plugin marketplace (
claude plugin marketplace add ArcadeData/arcadedb --sparse .claude-plugin claude-plugin, thenclaude plugin install arcadedb@arcadedb) to connect Claude Code to your own server with an API token. Every MCP tool now carries read-only / destructive / open-world annotations, and thequeryandexecute_commandtools refuse scripting languages. - Native image: built at
-O3, about 25% faster on warm loops (#11070, contributed by @tae898); an explicit CPU baseline (x86-64-v3on amd64,armv8-aon arm64) with a "CPU requirements" section indocs/native-image.md(#10581, #10715); and a new linux/amd64-compatarchive built with-march=compatibilityfor CPUs below x86-64-v3 (#10623, #11253). arcadedb.fileSync(defaulttrue) skips every fsync when set tofalse, for test runs and throwaway databases; the unit-test lanes now run twice as fast (#11149).arcadedb.txWalGroupCommit(opt-in): concurrent commits share one WAL flush; about 4x the commits per second for writers into the same type (#10499).arcadedb.graph.ghostEdgeProbe: a database known to hold no dangling adjacency entries can skip the per-vertex probe of variable-length walks (#10658).arcadedb.bucketSelfDescribingChunkLinks(opt-in, defaultfalse): the new chunk-link format that lets a multi-page record link position 0. A database that stored it cannot be read by an older version (#10853, #10949).
Query languages and engine
- Time series samples can be deleted (#10342, #10428):
DELETE FROM <ts type> WHERE <time range> [AND tag = value]andTRUNCATE TYPEremove samples from the mutable and sealed storage, replicate under HA and refresh the continuous aggregates over the type. - Graph algorithms:
algo.personalizedPageRanktakesdirectionandweightProperty, andalgo.labelpropagationtakes pre-assigned labels (seedProperty,fixedSeeds) and refuses unknown keys ([#11146](https://githu...
26.10.2
ArcadeDB 26.10.2
Overview
682 issues and pull requests closed under the 26.10.2 milestone - 485 issues and 197 pull requests - out of 355 pull requests merged and about 1,360 commits since 26.10.1. 377 of the closed issues are bug fixes, 20 of them rated critical.
The headline work is in six places:
- Query control and speed - a JVM-wide query admission gate, list and terminate running queries over HTTP and every wire protocol, SQL and openCypher statements that differ only in their literals now share one parsed statement and one plan (a point lookup with the value in the text is 3 to 7 times faster), a parallel
GROUP BYthat evaluates each key once, and Customizable Contraction Hierarchies for shortest paths. - High availability (Raft) - schema and database-setting changes made outside a DDL statement now reach every node, vectors inserted on a follower no longer replace other vectors, an in-place Ratis restart no longer double-applies a commit, and a node removed from the Raft configuration is fenced. A follower's refusal of a write is a redirect on Bolt, MongoDB, Redis and gRPC, naming the leader.
- Time series and Prometheus - retention and compaction no longer corrupt or resurrect data in the sealed store, writes that used to be stored silently wrong are refused or reported, and PromQL follows Prometheus on a dozen edge cases.
- openCypher - temporal values (
time(),localtime(), zoneddatetime(),duration()) are stored natively,MERGEmatches exactly whatMATCHmatches, GQL constructs the engine used to ignore are refused, and thepath.*procedures answer as APOC does. - Security hardening - open wire-protocol and
/wssessions re-check the user on every request, SQL classifies a statement by everything nested inside it, lightweight edge types enforce create and delete grants, a type'sEXTERNALbucket follows the type's permissions, and Studio no longer runs HTML from an AI answer. - Silent wrong data - lost keys during a concurrent commit, a schema reload that issued the same RID twice, a schema change lost at close, LSM compaction resetting the null strategy, and WAL recovery re-issuing transaction ids.
Upgrading is recommended for every deployment, and in particular for every HA cluster and every time series workload. Behavior changes are collected in Upgrade notes.
Contents: New features Β· Highlights Β· Security Β· Major fixes and improvements Β· Upgrade notes Β· Dependency updates
New features
Server and operations
- Query admission gate (#9518). A FIFO queue in front of every remote protocol (HTTP, Postgres, Bolt, Redis, MongoDB, gRPC, MCP): when the server is busy, requests wait and start in arrival order instead of all starting at once and exhausting the heap. On by default (
arcadedb.queryMaxConcurrent, 2 x cores and at least 4,0disables it), bounded byarcadedb.queryQueueTimeoutandarcadedb.queryQueueMaxSize, and heap-aware througharcadedb.queryAdmissionHeapWatermark. A refused request is retryable on every protocol (HTTP 503, Postgres40001, RedisTRYAGAIN). - List and terminate running queries (#9680, #9689).
list queries [database <db>] [tag <t>],terminate query <id>,terminate queries tag <t>,list transactionsandterminate transaction <sessionId>overPOST /api/v1/server, with anX-ArcadeDB-Query-Tagheader to find your own statements and an acknowledgement that says whether the statement stopped. Bolt, gRPC (streaming loads included), MCP, the Postgres wire and/wsinsert sessions register their work too, and every entry names its client (#9774, #9838, #9875, #9962). - Statement and plan cache by query shape (#8307). SQL and openCypher texts that differ only in their literals are parsed and planned once. Measured on a unique-index point lookup, Cypher drops from 42 to 6.1 microseconds per query and SQL from 21.5 to 6.6; a query that already uses parameters costs what it did.
- Docker images run on Java 25 (
eclipse-temurin:25-alpine), so compact object headers are finally enabled in the image (#9602). The native image now ships Raft HA, metrics and tracing (#9407), runs the e2e battery in CI (#9495), and uses scalar vector math instead of the uncompiled Vector API, which was 6 to 27 times slower (#10072). - Studio is served with a Content-Security-Policy that refuses inline script (#9681), and the saved-query and history sidebar, the Reference panel, the sample-database cards, the API endpoint list and the Profiler rows are keyboard accessible (#8740, #9375, #9508).
- HA operations: an operator override to lift a quarantine or the stale-snapshot read floor on a sole voter (
POST /api/v1/cluster/accept-diverged/{database}) (#9449, #9498);GET /api/v1/clusterexposes the follower's replication-path and unreachable-leader state and in-place restart counters, with matching alerts (#9399, #9429); an alert when every voter has quarantined the same database (#9553); the remaining Raft executors published as pool metrics (#8856); and a configurable DEFLATE level for snapshot ship (arcadedb.ha.snapshotCompressionLevel) (#9295). - Backups: SQL
BACKUP DATABASEapplies the retention policy (#9844), and a full backup archives a vector index's graph consistently so a restore reuses it (#9917).
Query languages and engine
- Native openCypher temporals: four new property types,
OFFSET_TIME,LOCAL_TIME,ZONED_DATETIMEandDURATION, indexable byLSM_TREEandHASH; a String is never reinterpreted as a time again (#8572, #9462, #9636). - Customizable Contraction Hierarchies: a Graph Analytical View keeps a CCH per weight property (
CREATE GRAPH ANALYTICAL VIEW ... CCH (distance)), so weighted point-to-point shortest paths no longer depend on the distance (cchShortestPath(),algo.cch.shortestPath), and the hierarchy keeps up with weight updates in milliseconds (#9437, #9915). path.*procedures answer asapoc.path.*: APOC's filter syntax, nineuniquenessmodes,endNodes,terminatorNodes,allowlistNodes,denylistNodes,optional, a lazy walk that alimitreally stops, and a heap-charged breadth-first walk (#10025, #10048, #10049, #10017).- openCypher label expressions on variable-length relationships (
[:!R*],[:%*],shortestPath((a)-[:!R*]-(b))) now run (#9117). - SQL:
CREATE INDEX ... METADATA {"buildMode": "SORTED"}selects the sorted build (#9291);CREATE GRAPH ANALYTICAL VIEW v PROPERTIES ()builds a view with no vertex properties (#9831);algo.labelpropagationtakes atieBreakProperty(#9285);CHECK DATABASEreports unreadable stripe directories (#9266); GremlinhasLabelsees types created earlier in the same traversal (#9335). - PromQL: the
boolcomparison modifier (a > bool 1) (#9644).
Remote clients
- Typed "already exists" exceptions: the Java remote clients raise
RemoteAlreadyExistsExceptionfor a taken user, token or database name, and the server answers 409 for them over HTTP (#10073, #10074, #10075). RemoteSchema.alterMaterializedView()is implemented (#8726), a streamed error line rebuilds its typed exception ([#8874](https://github.co...
26.10.1
ArcadeDB 26.10.1
Overview
1,615 issues and pull requests closed under the 26.10.1 milestone - 1,244 issues and 371 pull requests - out of 846 pull requests merged and about 3,100 commits since 26.9.1. 984 of the closed issues are bug fixes, 75 of them rated critical.
The headline work is in six places:
- High availability (Raft) - snapshot install, follower catch-up, leadership hand-off, readiness gating and restart recovery were hardened end to end. Followers stuck at a stale term, divergence after a graceful restart and resyncs that reopened stale files are closed.
- Lost updates and silent wrong data - concurrent read-modify-write on growing and multi-page records, hash-index key changes applied twice,
MERGE ... ON MATCH SET n = n + 1losing an increment, and stale-read writes are now refused or merged correctly. - Query speed - parallel filtered scans, parallel
DISTINCTand Cypher aggregation,ORDER BY ... LIMITanswered from index order,LIKE 'prefix%'andmin()/max()served by the index, a striped database lock so concurrent RID lookups scale, and a LET subquery cache. - Equality and comparison now agree everywhere - index, SQL scan and Cypher gave different answers for
FLOAT/DOUBLE,DECIMAL,DATETIME,BOOLEAN, null and signed zero. They give the same answer now. - Wire protocols - the Postgres, MongoDB, Redis, Bolt, gRPC and Gremlin front ends got more than a hundred protocol-fidelity fixes, plus TLS for the Postgres wire protocol.
- Vector search - rebuild loops, compaction races, grouped search, empty filters and sparse-vector ranking.
Upgrading is recommended for every deployment, and in particular for every HA cluster. Behaviour changes are collected in Upgrade notes.
Contents: New features Β· Highlights Β· Security advisories Β· Major fixes and improvements Β· Upgrade notes Β· Dependency updates
New features
Server and operations
- TLS/SSL for the Postgres wire protocol (#8840).
- Opt-in OTLP log export, an OTLP/HTTP metrics endpoint fix, and
service.namein tracing (#7727, #7294, #7295). - Persistent instance id (
adb-<uuid>) shown in Studio, thearcadedb.support.idsetting, and Studio support requests that run a read-only query support asked for and send the result back (#8685, #8682, #8861). - A configurable config directory (#7415) and compact object headers enabled by
server.shwhen the JVM accepts them (#4537). HEADon/readyand/health(#8133); the HTTP server binds every local address the configured host resolves to (#8692).- Pool metrics for the per-server security executors (#7856).
- Read-your-writes bookmark (
X-ArcadeDB-Commit-Index) on streamed HTTP responses (#7351), and streaming ingestion with a temporary-id mapping returned chunk by chunk (#7353). - Startup
restore:publishes progress and waits out a conflicting operation (#7440, #7652). - HA: a bulk schema scope so a DDL script replicates as one Raft entry, peer-capability negotiation, peer priority on
POST /api/v1/cluster/peer, joining a running node to a cluster, and per-peer capabilities in Studio (#6990, #7219, #7523, #7515, #7538).
Studio
- Index search and time series move into Query and Database, with a new Chart tab (#8788).
- A selected saved query is no longer run automatically (#7049), and the cluster page shows peer capabilities and rolling-upgrade readiness.
Query languages and engine
- Property rename as an in-place primitive, in the Java API and SQL (#7589).
COPY (<query>) TO STDOUTover the Postgres wire, in text and binary format (#7188), and NaN-transparent TimeSeriesSUM/AVG(#7089).algo.personalizedPageRanktakes a personalization vector (#8715); Cypherpoint()returns Neo4j SRIDs (#3993).- TimeSeries: bucket origin/offset on
ts.timeBucket, per-column codec syntax inCREATE TIMESERIES TYPE, andAggregationMetricsover HTTP (#8798, #7690, #7717). - Vector:
vector.neighborsaccepts a subquery result as its filter, dense vector search sees the open transaction's rows, and sparse-vector indexes can be built over existing rows and rank by exact score (#7125, #7378, #8536, #8576). - Graph Importer imports JSON array properties (vector embeddings) from JSONL (#7185).
apoc.merge.node/apoc.merge.relationshiponMatchPropsanddb.index.fulltext.query*options (#8117, #8103).
Remote clients and gRPC
A spec-driven client generation epic (#4894) closed the gaps between the HTTP, gRPC and Java remote APIs: a gRPC control plane (database lifecycle, backup, security, profiler, restore and import, groups and API tokens), a gRPC time-series API, an HTTP streaming query and vector search, an HTTP//ws insert session with a Java client, and RemoteDatabase access to /ts/* (#7304, #7305, #7306, #7307, #7403, #7406).
Highlights
High availability: a hardening pass on every path a cluster takes to recover
Around 300 issues carry the ha label this cycle. The ones that mattered most in practice:
- A follower stuck at a stale term after a restart or rolling restart, costing quorum on the next failure, is fixed at the root: the leader looped on install-snapshot notifications for ever after a follower installed at
leaderStart-1(#8289, #8341, #8360, #8449). - Stale entries after a snapshot install. A follower that re-applied its local log while a leader snapshot arrived applied stale entries onto the fresh copy and halted. Every install path now carries a boundary index, and a leader snapshot that is behind what the follower already applied is refused (#8577, #8579, #8454, #8651).
- A resync reopened pre-resync files. A snapshot resync skipped a database that was closed on the follower; a node could serve a snapshot of a database it had quarantined; a node elected leader could reopen an unverified closed copy as the cluster's copy (#8464, #8468, #8605, #8589). An audited override now exists for a peer that can never answer (#8641).
- Divergence after a graceful restart under load (extra rows and a corrupt unique LSM index) (#8270); a leader DDL that published its pages before its schema entry, so a concurrent replica transaction on the same pages merged against the old schema (#7438, #8686).
- Leadership hand-off. The autom...
26.9.1
ArcadeDB 26.9.1
Overview
This is the largest release ArcadeDB has ever shipped: 992 issues and pull requests closed under the 26.9.1 milestone - 675 issues and 317 pull requests - out of 655 pull requests merged and 1,500 commits in total since 26.8.1.
The headline work is in five places:
- Backup and restore - a full backup is 27.6x faster, a restore runs in parallel, and neither freezes page flushing any more, so writers keep working while a backup runs.
- Storage integrity - the family of defects around records that outgrow a page is closed: silent lost updates, a record returned twice by a scan, false conflicts, and a 16% chunk-slot space leak that nothing ever reclaimed.
- Query correctness -
NOT INon an indexed property returned theINresult set,DISTINCT ... ORDER BY ... LIMITreturned too few rows, a multi-keyGROUP BYgrouped on the last key only, and an index range scan could return rows theWHEREclause excluded. All fixed, with regression tests. - Indexes are used where they were not - a literal
IN (...)list, a composite-index prefix withORDER BY,BETWEEN,@rid IN [...]and a Cypher label disjunction all take the index now instead of a full scan. - Vector search - opening a database is constant-time again regardless of index size, rebuilds are scheduled instead of blocking the first query, and recall stopped degrading past 10,000 vectors.
Upgrading is strongly recommended for every deployment. There are breaking changes and behaviour changes - they are collected in Breaking changes and upgrade notes and each is called out again where it belongs. No schema migration is required, and no existing database is rewritten.
Contents: Highlights Β· Security advisories Β· New features Β· Major fixes and improvements Β· Breaking changes and upgrade notes Β· Dependency updates
Highlights
Backups are 27.6x faster and no longer stall the database
A full backup ran single-threaded deflate at level 9, CPU-bound at 20-40 MB/s, and it suspended page flushing for the whole window: dirty pages piled up until arcadedb.flushSuspendMaxDeferredRAM was reached, committers were throttled, and LSM compaction was postponed. HA snapshot shipping and cluster verify did the same thing (#6072, #6075, #6086).
Measured on a 1.25 GB database:
| measurement | before | after |
|---|---|---|
| full backup | 18.88 s | 0.68 s (27.6x) |
| concurrent writer throughput during the backup | 4.3% of baseline | 77% of baseline |
| restore | 2.9 s | 0.68 s |
| archive size | 323 MB | 348 MB (+7.5%) |
- Parallel compression, tunable with
arcadedb.backup.compressionLevel(new default 1, was 9),arcadedb.backup.compressionThreadsandarcadedb.backup.maxMBPerSecond. The ZIP format is unchanged and archives written by older versions restore normally. - Parallel restore, largest entry first, behind a 256 KB buffered read instead of
ZipInputStream's unbuffered 512-byte reads (arcadedb.restore.threads). Even the sequential path went 5.16 s to 3.96 s. - A page-level copy-on-write snapshot replaces flush suspension:
arcadedb.pageSnapshotEnabled,arcadedb.pageSnapshotMaxRAM,arcadedb.pageSnapshotMaxSize,arcadedb.pageSnapshotSpillPath. Backups, HA snapshot shipping and the/checksumsendpoint now take a point-in-time view without ever stopping the flusher. - Two JVM-wide stalls are gone with it. The deferred-flush backpressure gate was process-wide, so one database's backlog stopped the flush thread for every database on the server (#6200), and
publishPagesblocked inside the global page-manager lock whenever the flush queue filled, serialising the commits of every database behind one database's write burst (#6259). Both are now per-database.
Records larger than a page: lost updates, phantom rows and a 16% space leak
A record that outgrows its page is stored as a chunk chain or behind a placeholder pointer. Re-triaging #5279 turned up a whole family of defects on that path, every one of them silent:
- A lost update. Two transactions updating the same placeholder-backed record (pointer on one page, content on another) both committed and one write vanished, with no
ConcurrentModificationException(#6141). The content page is version-checked now, so the conflict is raised. - A record returned twice. A
SELECTreturned a placeholder-backed record under two different RIDs when its content had spilled into chunks, socount(@rid)reported 2 for one record (#6196). - A 16% space leak.
CRUDTest.multiUpdatesOverlapended with 243,821 orphaned chunk slots out of 1,545,495 because a shrink ending exactly on a chunk boundary never freed the tail, and nothing ever reclaimed them although three code comments promised otherwise (#6319, #6294).CHECK DATABASE FIXnow sweeps them and reportsorphanedChunks/orphanedChunksReclaimed. - False conflicts. Reading a multi-page record failed with "was modified during read after N retries" when an unrelated record's chunk on a shared page was written (#6217), and eight threads rewriting different large records on one page got
ConcurrentModificationExceptionwith five of eight exhaustingTX_RETRIES(#6129). Chunked head slots take part in the disjoint-slot merge now, and a read validates only its own chain. - A permanent size ratchet. A chunked record's head chunk shrank to the smallest size it ever had and never recovered, so a record oscillating in size degraded for ever into a longer chain with unusable gaps (#6163). A record that shrinks back inside its slot is now collapsed to a plain record again (#6178, #6286).
- A checker that reported a clean database. After
CHECK DATABASE FIXforce-deleted a record with a broken chain, the placeholder pointing at it was left dangling, socount(*)said 8 and a scan said 7, permanently, while the report saidtotalErrors: 0(#6292).
Free-space accounting was fixed with them (#6154, #6339), and a self-referencing edge-list chunk no longer hangs an ordinary traversal in a request thread (#6278).
Wrong results in ordinary SQL
Five independent defects, all of them returning a plausible answer to the wrong question:
NOT INreturned theINresult set.WHERE prop NOT IN [...]on an indexed property returned 1 row where 25,089 matched, because the index planner served the lookup without consulting the NOT flag. Present since 26.7.1 (#6796).SELECT DISTINCT ... ORDER BY ... LIMIT nreturned fewer thannrows, because the Top-K bound was applied before deduplication (#6923).- A multi-key
GROUP BYgrouped on the last key only - the synthetic alias counter wasfinal int i = 0outside the loop, so every key got the same alias (#6924) - andDISTINCTwas silently dropped whenever the statement also hadGROUP BY,UNWINDorexpand()(#6925). - An index range scan ignored its own transaction's deletes. A range query inside a transaction returned rows deleted or re-keyed in that same transaction, including rows that did not match the
WHEREclause (#6927). - An indexed range over non-ASCII text returned nothing.
BinaryComparatorordered STRINGs by UTF-16 code units while LSM index pages order them by unsigned UTF-8 bytes, so a scan whose bounds fell where the two orders disagree returned zero rows although both keys were in range (#6997).
Also: the ?? null-coalescing operator always returned its right operand because the AST builder had no visitor for it (#6393); WHERE @rid > :param returned nothing while the same RID as a literal worked, breaking RID-cursor paging (#6188); @rid IN (SELECT ...) never matched (#7054); TRUNCATE TYPE inside an explicit transaction committed the caller's transaction from the inside, so BEGIN; TRUNCATE TYPE; ROLLBACK destroyed 1,000 records (#6220); and EXPLAIN UPDATE ... submitted as sqlscript executed the update, which ran unbounded for hours in production ([#6648](https://github.com/ArcadeData...
26.8.1
ArcadeDB 26.8.1
Overview
This is a major release: 381 issues and pull requests closed under the 26.8.1 milestone - 281 issues and 100 PRs - out of 298 pull requests merged and 669 commits in total since 26.7.2. It also carries everything shipped in the 26.7.3 hotfix.
The headline work is in four places:
- Security - 13 advisories closed, most of them on the wire protocols and the MCP endpoint.
- Concurrency - concurrent writes to unrelated records of the same page no longer conflict, which is what made ArcadeDB usable under real multi-writer load on types with few buckets.
- Graph integrity - a family of vertex/edge delete defects that could silently lose edges under concurrency is closed, and deleting a super-node vertex got 5x faster along the way.
- Storage and indexes - bloom filters on compacted LSM series, a schema dictionary that is no longer capped at one page, a geospatial index that costs one entry per point instead of eleven, and TimeSeries TAG columns that are dictionary-encoded.
Upgrading is strongly recommended for every deployment. There are breaking changes and behaviour changes - they are collected in Breaking changes and upgrade notes and each is called out again where it belongs. No schema migration is required, and no existing database is rewritten.
Contents: Highlights Β· Security advisories Β· New features Β· Major fixes and improvements Β· Breaking changes and upgrade notes Β· Dependency updates
Highlights
Concurrent writes to unrelated records of the same page no longer conflict
ArcadeDB detects write conflicts per page, so two transactions that touched the same bucket page raised a ConcurrentModificationException even when they wrote completely unrelated records that merely happened to share it. On a type with few buckets and many concurrent writers this made a retry pointless: the retry ran straight into the same collision (#5279).
All three halves of that are gone:
- Inserts into one page reserve their slot per in-flight transaction, so concurrent inserts get different positions (and different RIDs) instead of all being handed the same one.
- Updates are replayed by the commit-time disjoint-slot merge whenever they stayed inside the page, which now includes a record that grew - a longer string, one more property - and not only an overwrite of the same size or smaller. Growth is the normal update shape, so leaving it out kept concurrent updates conflicting.
- Deletes of a plain in-place record are replayed too (#5569). Such a delete only zeroes one slot-table entry, so it commutes with writes to every other slot.
Measured on the reported workload (one single bucket, attempts=1, no retry):
| Scenario | Before | After |
|---|---|---|
| Concurrent inserts | ~1750 conflicts / 2000 | 0 |
| Concurrent sub-graph creation (6 vertices + 5 edges per transaction) | ~270 / 320 | 0 |
| 10 transactions updating 10 different records of one page | 9 failed / 10 | 0 |
| Sustained updates, 8 writers on their own records of one page | ~2083 / 2880 | 0 |
| 8 deletes + 8 updates of 16 different records of one page | 15 failed / 16 | 0 |
| 10 transactions deleting 10 different records of one page | 9 failed / 10 | 0 |
A ConcurrentModificationException is still raised - by design - when two transactions really write the same record: a byte-for-byte pre-image check makes sure no concurrent write is ever silently overwritten. Nothing changes for single-writer workloads and no application change is needed. The merge can be switched off with arcadedb.txPageSlotMerge=false.
The merges also prove their coverage now instead of trusting every writer to declare its pages (#5596): a page carrying even one byte written outside a declared, replayable write is refused and falls back to the ordinary retry. The three merge counters (edgeAppendMerges, txPageSlotMerges, mergesDeclinedByCoverage) are now visible to an operator in the PAGE-MANAGER block, in /api/v1/server, in Studio and on /prometheus (#5608).
Deleting a vertex no longer loses its edges - and is up to 5x faster
Four defects, all on the same path, all capable of committing a graph with edges pointing at a vertex that is gone (#5670, #5680, #5725, #5760):
- An edge-list chunk that is momentarily unreadable - a normal MVCC window on a hot vertex, not a fact about the graph - was read as "nothing to remove here". The removal ended having removed nothing and the edge record was deleted anyway, leaving a back-reference on a neighbour. It is now a retryable
ConcurrentModificationException, so the transaction re-reads a consistent view and completes the removal. - The same window on the vertex's own list meant no edges collected, and the vertex record deleted on top of that empty view.
- An edge appended while the delete was running survived the delete with a live
outand aninnaming a record that no longer exists. A vertex delete now pins every page its edge list can grow through, at the version it read the list at. - Each edge was disconnected from both endpoints, one of which is always the vertex being deleted - whose lists are dropped wholesale moments later. Each edge is now disconnected from its far end only.
That last one is also where the performance is. 100k edges into one hub, on an Apple M-series laptop:
| layout | before | after |
|---|---|---|
| promoted super-node (striped) | 2374 ms | 446 ms |
| classic single chain | 350 ms | 308 ms |
The removal walk streams now: deleteVertex no longer materialises every edge into a list first, so there is no per-degree allocation on the path at all (tens of megabytes of retained heap on a million-edge super-node).
Visible effect.
vertex.delete()/DELETE VERTEXandedge.delete()/DELETE EDGEcan now raise a retryableConcurrentModificationExceptionwhere they previously "succeeded" while losing an edge. It is aNeedRetryException, sodatabase.transaction(...)and the server's auto-retry for single-request commands absorb it. A client-managed explicit transaction overRemoteDatabasespans several HTTP requests, so its commit is not auto-retried and the caller should retry the transaction. A delete that keeps failing however often it is retried means the list is genuinely broken: the error now names the repair,CHECK DATABASE RECORD #12:3 FIX, and the retry after it goes through.
Bloom filters on compacted LSM indexes (enabled by default)
An LSM index lookup walks every compacted series from newest to oldest, and a series whose key range covers the key still costs a root-page search and a data-page read to discover it does not hold it. Each compacted series now carries a bloom filter that answers from a single 8 KB page (#5517).
Measured on 2M keys across 9 series (LSMTreeBloomFilterBenchmark):
| measurement | filters off | filters on | gain |
|---|---|---|---|
| absent-key lookups (a duplicate check) | 199,743/s | 386,138/s | 1.9x |
| pages read for those lookups | 1,490 | 705 | 2.1x fewer |
| bytes read for those lookups | 372 MB | 176 MB | 2.1x fewer |
| present-key lookups | 244,000/s | 281,150/s | 1.2x |
- On by default at a 1% target false-positive rate:
arcadedb.indexBloomFilterRate=0.01. Set0to disable. - ~1.2 bytes per key on disk, about 3% of the index it describes, in a
<index>_bf.bfidxcomponent. - No rebuild and no migration. Filters are written by compaction, so an existing index gains them at its next compaction. They replicate over HA and are included in backups.
- Helps most when compacted series overlap in key range - an email, a UUID, a business id. Ascending keys give each series a disjoint slice the root page already rules out. Range scans never consult them.
- Observability:
bloomSkippedSeriesandbloomProbedSeriesin the index statistics.
Backward and forward compatible with no version bump: an older ArcadeDB does not recognise the .bfidx extension and reads the index exactly as it does today.
The schema dictionary is no longer capped at a single page
Every type and property name is mapped to a small integer id, and that table lived in one page: 48,396 short names measured. Past it, CREATE PROPERTY and inserting a document with a new field name failed permanently with No space left in dictionary file, with no way to grow and no way back (#5560).
Names now roll over onto further pages, so the cap is gone.
- No migration, and existing databases are not rewritten. A dictionary written by an earlier version is a dictionary of one page and loads unchanged; it gains rollover on the next write that needs it.
- Appending a name is no longer quadratic. Growing to 500,000 names took 11.2s of pure array copying; it now takes 2ms.
- New databases use a 65,536-byte dictionary page instead of 327,680, so a new name dirties and flushes 5x less. Existing databases keep the page size they were created with.
**Rolling upgrade: upgrade followers b...
26.7.3
ArcadeDB 26.7.3
Overview
This is a focused hotfix on top of 26.7.2. It closes three security advisories from the internal audit - two in the MCP server transport and one in the JavaScript/Java trigger authorization gate - and repairs a data-loss regression in the 26.7.2 commutative super-node edge-append merge.
Upgrading from 26.7.2 is recommended, especially for deployments that expose the MCP server, run in server / multi-tenant mode, or store high-degree (super-node) graphs.
There are no breaking changes and no schema migration in this release.
Security Advisories
All three advisories were found in the same internal audit that produced the 26.7.2 fixes; they are MCP-transport and trigger issues that were not covered there.
- MCP command transport disabled all engine permission checks (GHSA-6x73-v3rc-f57c). The MCP transport never bound the authenticated principal onto the request thread's
DatabaseContext, so the engine permission gates (which are deliberate no-ops when no user is bound) silently passed for every MCP caller. A non-root, MCP-allowed reader could perform arbitrary writes, DDL and schema/security mutation; thequery+jssub-case could execute arbitrary in-JVM JavaScript. The principal is now bound at the single DB-resolution chokepoint and cleared on the pooled worker thread, so the engine per-user gates enforce for MCP exactly as for the HTTP, Bolt, PostgreSQL and gRPC transports. - MCP
get_server_settingsleaked the HA clusterToken in cleartext (GHSA-p9wc-4fhr-78wm). The MCPget_server_settingstool masked only settings whose key contained"password", soarcadedb.ha.clusterTokenwas returned raw. That token is the trust anchor for cluster-forwarded authentication, so leaking it enables full root impersonation. This is the MCP sibling of the 26.7.2 fix (GHSA-46hj-24h4-j8gf); the tool now redacts value and default viaGlobalConfiguration.isHidden(), matchingGetServerHandler. - JavaScript / Java triggers could escalate a schema admin to server-wide admin (GHSA-38pf-6hp2-pxww). A
JAVASCRIPTtrigger binds the real database object into a GraalVM context, so its script could calldatabase.getSecurity().createUser(...)and escalate anUPDATE_SCHEMA(schema-admin) user to a server-wide admin; aJAVAtrigger runs an arbitrary loaded class. Creating both host-code trigger types now requiresUPDATE_SECURITYat theLocalSchema.createTriggerchokepoint, mirroring theDEFINE FUNCTION ... LANGUAGE jsgate (GHSA-vwjc-v7x7-cm6g). Declarative SQL triggers keepUPDATE_SCHEMA, and schema reload of existing triggers is unaffected.
Major Fixes
Graph engine
- Edge-append merge no longer reverts concurrent writes on multi-page edge chunks (#5302). The commutative edge-append merge (
GRAPH_EDGE_APPEND_MERGE, introduced in 26.7.2) resolved a commit-time page conflict by re-deriving the conflicted page and replaying the transaction's tracked appends. For an edge chunk stored as a multi-page record (a chunk that straddles a page boundary) this re-derivation was unsound: the rebase re-read the chunk through the transaction's stale in-transaction page copy and committed it, silently reverting concurrently committed appends on the continuation page - zeroed chunk tails, shifted/aliased pairs, lost edges, andBufferUnderflowExceptionon later traversals of the vertex. Only records living entirely in place on the conflicted page are now re-derived; multi-page and indirected (placeholder) chunk records fall back to the standard full-transaction retry. Single-page chunks - the vast majority, including all super-node stripe chunks - keep the merge.
MCP server
get_schemanow builds its schema through a dedicatedbuildSchemapath, and the MCP dispatcher handles a missing resource with a properMCPResourceNotFoundExceptioninstead of a generic failure.
Full Changelog: 26.7.2...26.7.3
26.7.2
ArcadeDB 26.7.2
Overview
This release is a large stability and correctness milestone. It ships the results of a deep engine audit (storage, WAL/recovery, transactions/MVCC, LSM indexes and concurrency), hardens High Availability (Raft) recovery, completes the Neo4j Bolt driver compatibility certification, and fixes a broad set of OpenCypher and SQL query bugs.
It also closes five security advisories from an internal audit (see Security Advisories below); upgrading is strongly recommended for server-mode and multi-tenant deployments.
Two changes require attention before upgrading (see Breaking Changes): Raft storage is now durable by default, and the Bolt protocol now carries native temporal types instead of ISO-8601 strings.
Over 130 issues were closed for this milestone.
Security Advisories
This release closes several security advisories found in an internal audit. Upgrading is strongly recommended for any server-mode or multi-tenant deployment.
- RCE via JavaScript triggers (GHSA-x9f9-r4m8-9xc2). A JavaScript trigger could look up
java.lang.*host classes and reachRuntime.getRuntime().exec(...), obtaining OS command execution with onlyUPDATE_SCHEMAprivileges.java.lang.*is removed from the trigger host-class allow-list; only the benign value packages (java.util,java.time,java.math) remain. - Arbitrary JavaScript execution via
DEFINE FUNCTION ... LANGUAGE js(GHSA-vwjc-v7x7-cm6g). The SQL route to JavaScript bypassed the polyglot scripting gate, letting a user with schema (or lesser) access define and run arbitrary JavaScript. Defining ajsfunction now requiresUPDATE_SECURITY, and the polyglot engine runs withIOAccess.NONE(closingload(path|url)host-file read and SSRF) andPolyglotAccess.NONE(no cross-language pivot). SQL and Cypher user functions keep the standard schema-level protection. - Secret disclosure / root impersonation via
GET /api/v1/server(GHSA-46hj-24h4-j8gf). The server-settings export masked only keys literally containing "password", leakingarcadedb.ha.clusterTokenin clear - which, combined with the cluster-forwarded-auth headers, let a low-privilege authenticated user impersonate root. Every setting flaggedisHidden()(clusterToken and all password/secret keys) is now redacted, for both the current and default value. - Cross-database IDOR on time-series / batch / Prometheus / Grafana endpoints (GHSA-x8mg-6r4p-87pf). Fourteen handlers extended the base HTTP handler directly and resolved the path database with no
canAccessToDatabasecheck, so a user authorized for one database could read and write any other database on the server. All affected handlers now enforce database authorization (HTTP 403) before any payload handling and fail closed on a missing database name; the batch handler checks before leader-forwarding. - Read-only identity could mutate persisted schema (GHSA-8vr5-263f-x5r3). Several schema/config mutators reachable from a remote command were missing the
UPDATE_SCHEMAguard:ALTER TYPE ... CUSTOM/BUCKETSELECTIONSTRATEGY,ALTER MATERIALIZED VIEW ... REFRESH,DROP MATERIALIZED VIEW/DROP CONTINUOUS AGGREGATE,ALTER TIMESERIES TYPE ... DOWNSAMPLING POLICY,DEFINE FUNCTION, and the stats-onlyREBUILD INDEXpath. All are now gated (database-settings mutators useUPDATE_DATABASE_SETTINGS); every guard is a no-op for embedded, schema-load and HA-replication paths.
Major Highlights
Engine deep-audit 2026-07 (storage, transactions, LSM, concurrency)
A multi-area audit (#4962) hardened the core engine against data-loss and corruption edge cases under crashes, concurrency and load. Notable outcomes:
- The WAL append is now the transaction's point of no return. Page versions are validated and bumped
before the WAL write, so an aborted transaction can no longer be left in the WAL and partially replayed by
recovery; a post-append failure is resolved by recovery replay and fences the database until reopen
(#4936, #4937). - Torn 64KB page writes are repaired on recovery even when the on-disk version header already advanced (#4926); a clean close whose data fsync failed now
preserves the WAL for recovery instead of deleting it (#4934). - Page-cache correctness: an older page version can no longer overwrite a newer committed one (lost
update) and RAM accounting can no longer drift negative and disable eviction (unbounded growth) (#4925, #4933). - LSM index hardening: compaction no longer loses re-inserted keys or leaks orphaned pages on failure,
range scans are no longer truncated by tombstoned keys, and non-unique point lookups no longer resurrect
deleted RIDs (#4942, #4943, #4944, #4945, #4946, #4947). - Transactions: updating the same indexed record twice in one transaction no longer corrupts the index
(#4935); dead-thread cleanup now rolls back abandoned
transactions and releases their file locks, and is correct for virtual threads (#4941, #4956, #4939, #4940). - Async executor and shutdown: the stall detector no longer false-positives on slow tasks, shutdown no
longer drops queued tasks or hangs completion waiters, andclose()/drop()are now bounded so a wedged
worker cannot hang shutdown forever (#4953, #4954, #5080, #4991).
Parallel query safety
Parallel bucket scans (enabled by default) could self-deadlock under pool saturation and wedge HTTP workers, race on the shared command context, or pin a CPU core at 100% when a consumer stopped draining. Scan producers now run on a dedicated pool, each worker gets its own context, and the native select().parallel() iterator bounds its producer offer and closes cleanly (#4948, #4949, #4950, #4951, #5065).
High Availability (Raft) recovery
- Durable Raft storage by default removes a class of permanent follower divergence after a full-cluster cold restart (see Breaking Changes, #4835).
- Diverged-follower resync no longer floods the logs and starves the snapshot download it triggers; only the first gap logs loudly (#4741 follow-up).
- The leader now auto-recovers a follower's replication channel wedged on stale DNS after a Kubernetes pod-IP change, instead of dropping to bare quorum until a manual leadership transfer (#4696).
- A distinct contract for "committed cluster-wide, local apply failed"
(TransactionCommittedRemotelyException, mapped to HTTP 409) so applications no longer retry and create duplicates (#5064, #5017, #5018). - Offline bootstrap leadership-transfer path now commits its baseline (#5099).
Neo4j Bolt driver compatibility certification
The Bolt epic (#4882) reached certification: a shared conformance spec, per-language driver e2e suites (Java, Python, JS, Go, C#) CI-gated with a nightly run, and broad type-fidelity work. Highlights: native temporal PackStream structs in both directions (see Breaking Changes), native Path/Duration/Point structures, retryable-conflict mapping so drivers auto-retry, HA-aware ROUTE responses, Bolt 5.x negotiation and populated write-result counters (#4883-#4892, #4905, #4907, [#4908(https://github.com//issues/4908), #4922,
#4997-#5002, [#5082](https://gi...
26.7.1
ArcadeDB 26.7.1 Release Notes
Overview
ArcadeDB 26.7.1 is a large stability, resilience and security release with over 420 commits, 238 resolved issues and 32 merged pull requests. The headline theme is a deep High Availability / Raft hardening wave that makes clustered deployments far more robust under leader churn, node restarts, snapshot transfers and Kubernetes scale events. On top of that come a security hardening pass (polyglot scripting lockdown, gRPC and cluster-management authorization, DoS bounding), a new OpenTelemetry distributed-tracing module plus structured JSON logging, native BM25 full-text scoring, continued ISO GQL compliance and vector engine work, and a long list of gRPC, MongoDB wire-protocol, SQL, OpenCypher, time-series and Studio fixes.
New Features
- OpenTelemetry distributed tracing - an optional module for end-to-end request tracing, with opt-in OTLP export. (#4467, #4465)
- Structured JSON logging with per-request correlation IDs. (#4466)
- Native BM25 full-text scoring - field boosts, caret syntax and
EXPLAIN/PROFILEsupport. (#4687) - ISO GQL compliance - strict numeric types (schema round-trip), session management (
SESSION SET/RESET/CLOSE) and transaction control (START TRANSACTION/COMMIT/ROLLBACK). (#4141) - New vector formats and helpers - MATLAB / MATLAB_COLUMN, JULIA and NUMPY formats,
asVector(),asSparse(), RRF array input andvectorDequantizeBinary. (#3099) - MongoDB wire protocol -
update,deleteandcreateIndexescommands plus SASL PLAIN authentication. (#4750, #4751, #4746) - HA auto-acquire of unseen databases - a joining node bootstraps databases it has never seen. (#4727)
- Kubernetes health probes - liveness/readiness/startup endpoints for orchestrated deployments. (#4464)
- Paginated remote fetching of edges and vertices across the remote API.
- Studio - cluster HA alerts and Restore / Delete row actions on the backup list. (#4737)
Major Highlights
High Availability & Raft resilience
The bulk of this release goes into making the Raft-based HA cluster survive real-world failure modes without data loss or node self-halt:
- No more node-wide halt on apply errors. Apply-time failures are now quarantined per-database instead of taking the whole node down, transient
NeedRetryExceptions are retried in Raft apply, and unexpected throwables no longer kill the process. (#4797, #4659) - Divergence self-recovery. A follower stuck on a divergent Raft log now performs follower-side reformat-and-rejoin instead of spinning on
INCONSISTENCY, and a WAL-version-gap / phase-2 commit failure no longer causes a node to self-halt. (#4741, #4740) - Snapshot integrity. Snapshot extraction, markers and the final swap are now fsynced before the backup is deleted, transfer completeness is verified with a manifest,
takeSnapshot()persists a real snapshot marker so a log purge can no longer orphan applied state, and the database-registry lock is held across snapshot close -> swap -> reopen. (#4830, #4831, #4829, #4832) - Membership & quorum safety. Raft membership now uses atomic deltas instead of last-write-wins
setConfiguration,removePeer/leaveClusterare guarded against dropping below quorum, andstepDownselects the highest-priority non-lagging peer while skipping priority-0 witnesses. (#4795, #4796, #4808) - Per-database applied-index tracking, so mixed-database clusters track progress correctly. (#4824)
- Silent write loss eliminated when replication times out after dispatch: the leader no longer acknowledges a write it failed to replicate. (#4790)
- Accurate lag diagnosis. New heartbeat-lag metrics, byte-bounded replication backpressure, resync logging (leader flood suppression + follower resync visibility), and a slow-but-progressing follower is now treated as catching up rather than stale.
ClusterMonitorper-replica lag state is reset on each new leadership term to prevent falseSTALLEDreports. (#4812, #4810, #4840, #4841) - Auto-acquire of unseen databases so a joining node bootstraps databases it has never seen, with a single deterministic bootstrap source instead of abandoning databases on first transfer. (#4727, #4807)
Kubernetes operations
- StatefulSet scale-up beyond
HA_SERVER_LISTno longer crash-loops: a local Raft peer is synthesized and auto-joins when the pod ordinal exceeds the static list. (#4836) - Raft storage is persisted by default under Kubernetes, so a pod restart no longer wipes the PVC-backed Raft log. (#4835)
- Kubernetes health/liveness/readiness probes and a graceful cluster-leave path owned solely by
RaftHAServer.stop(). (#4464, #4837)
Security hardening
- Polyglot scripting now requires admin privileges and the GraalVM sandbox has been hardened (reflection deny-list), closing an advisory (GHSA-48qw-824m-86pr) where a reader-role user could read host files via JavaScript on
/api/v1/command. - gRPC authorization is enforced centrally instead of being blanket-skipped:
getDatabaserejects path-traversal names and enforces auth, admin operations require admin auth, and cross-database access is covered by regression tests. (#4793, #4792, #4794) - Cluster-management HTTP endpoints now require root. (#4791)
- DoS bounding on gRPC: result materialization and worker busy-wait are bounded, abandoned gRPC transactions are reaped to stop an executor/transaction leak, and in-band command failures are correctly counted as errors. (#4803, #4802, #4804)
- Hardened
FileUtilspath-traversal guard.
Observability
- Optional OpenTelemetry distributed-tracing module for end-to-end request tracing. (#4467)
- Structured JSON logging with per-request correlation IDs. (#4466)
- Metrics depth (Pillar 1): RED timers, engine gauges and opt-in OTLP export, plus gRPC metrics published into the shared server registry with method/status tags and executor-pool gauges. (#4465, #4826)
Native BM25 full-text scoring
Full-text search gains native BM25 scoring with field boosts, caret syntax and EXPLAIN / PROFILE support, along with fixes so SEARCH_INDEX no longer leaks internal posting-RID strings into @rid, multi-property and rebuilt FULL_TEXT indexes no longer crash, and multi-dot SEARCH_INDEX queries are parsed correctly. (#4687, #4731, #4732, #4733, #4734)
ISO GQL compliance
Continued work toward the ISO GQL standard (#4141): strict numeric types on the write side (schema round-trip), session management (SESSION SET / RESET / CLOSE) and transaction control (START TRANSACTION / COMMIT / ROLLBACK).
Vector engine (Epic #3099)
- Quantization ergonomics,
asSparse(),asVector()(inverse ofasString), RRF array input andvectorDequantizeBinary. - New MATLAB / MATLAB_COLUMN, JULIA and NUMPY vector formats.
- Correctness fixes across the vector SQL functions, consistent
cosineSimilarityon zero vectors, and a consistentordinalToVectorIdsnapshot during brute-force scans. (#4583, #4581)
MongoDB wire protocol
The mongodbw plugin now supports update, delete and createIndexes commands, adds SASL PLAIN authentication, and returns correct data on find. (#4750, #4751, #4746, #4745)
Major Fixes
gRPC
InsertStreamis stopped after a mid-stream commit failure (and the error is no longer mis-indexed), the transaction is no longer begun/committed on different pool threads, andCONFLICT_UPDATEupsert now merges non-key columns. (#4806, #4656)- Streaming terminal calls are serialized on a thread-safe
StreamObserver. (#4801) DATETIME_MICROS/DATETIME_NANOSprecision is preserved on the write path, null-valued projected columns surviveExecuteQuery, and the configured compression codec is honored. (#4805, #4692, #4827)- Time-series
INSERTover gRPC no longer throws on empty@type/@rid. (#4688)
High Availability (additional)
TRUNCATE TYPE/TRUNCATE BUCKETare now HA-safe, using small batches and failing loud instead of silently truncating incompletely. (#4817)- Follower match/next indices are correlated by peer-id stability rather than array position, fixing mis-zipped follower states. (#4842)
- The Raft gRPC allowlist fails open only up to quorum, not the full peer set, and the state machine is rewired to
RaftHAServeron a HealthMonitor-driven Ratis restart. (#4828, #4839) AppendEntrieselement limit is configurable (default 64),RATIS-2523matchIndex rewind is atomic and fail-loud, and a replica stuckSTALLEDatmatchIndex=-1auto-recovers. (#4752, #4833, #4728)- LINEARIZABLE follower reads no longer serve stale state, and read-only statements honor the requested read consistency.
- Snapshot write watchdog now detects stalls rather than total elapsed time, proactive peer allowlist refresh + hardened DNS caching, and
GraphBatchbulk load survives a transient leader re-election. (#4729, #4696, #4724)
SQL
UPDATE SET map = map.remove(key)now persists map/collection key removal. (#4730)SELECT FROM <non-existent RID>returns an empty result set instead of HTTP 500.- Planner prefers a full-key index over a partial-key scan on a longer composite index. (#4600)
IN/NOT INthree-valued logic for NULL operands,GROUP BYon mixed-type numeric keys no longer splits equal groups, andmin()/max()over mixed numeric collections no longer throwsClassCastException. (#4591, #4592)DISTINCTresult can be used as a function argument / method base, backticks are stripped from quoted projection aliases, andalgo.allSimplePathssupportsskipVertexTypes. (#4691)- Assorted math/collection function fixes:
SplitFunctionon null delimiter,AbstractMathFunction.asDouble(null),TailFunctionsublist view,date.convert...
26.6.1
ArcadeDB 26.6.1 Release Notes
Overview
ArcadeDB 26.6.1 is a stability, durability and security hardening release with over 280 commits and 66 resolved issues. The headline news is end-to-end TLS/SSL for the HA cluster, a deep wave of durability and crash-recovery hardening across the WAL, page and serialization layers, and a broad security hardening pass (schema authorization, IMPORT DATABASE source validation, injection fixes and a full CodeQL cleanup). On top of that comes a long list of High Availability / Raft, OpenCypher, SQL, vector index and wire-protocol fixes, plus Studio and operational improvements.
Major Highlights
TLS/SSL Across the HA Cluster
The Raft-based HA cluster can now run fully encrypted. Inter-node replication traffic supports SSL/TLS, and the snapshot installer was fixed so a follower can download a leader snapshot over the HTTPS listener instead of crashing with Unsupported or unrecognized SSL message. (#4470)
Durability & Crash-Recovery Hardening
A large batch of fixes closes data-integrity gaps in the storage, WAL and serialization layers so committed transactions survive crashes and power loss, and recovery never silently drops data:
- WAL is now fsynced on commit by default, and data files are fsynced before WAL files are deleted on clean close. (#4330, #4332)
- Crash recovery now aborts on a WAL version gap and preserves the WAL files instead of silently skipping the gap. (#4331, #4320)
MutablePage.moveno longer mis-tracks the modified range on backward shifts, so defrag bytes are no longer omitted from the WAL. (#4319)- Binary serialization fixes: property count now matches the bytes written, and partial reads are handled via
readFully. (#4328, #4329) - Short-write / short-read returns are now respected in
PaginatedComponentFile. (#4321) - LZ4 compression no longer corrupts data when
Binary.position() > 0. (#4317) - Simple-8b codec validation no longer silently truncates
Long.MAX_VALUE/Long.MIN_VALUE. (#4336) migratedFileIdsis now persisted inschema.json, so compaction no longer silently drops in-flight transactions across restart. (#4333)java.lang.NegativeArraySizeExceptionon transaction commit fixed. (#4420)
Security Hardening
- All
LocalDocumentType/LocalPropertyschema mutators now require theUPDATE_SCHEMApermission (previously onlycreatePropertywas gated). (#4423) IMPORT DATABASEnow validates its source and requires admin privilege, closing SSRF / LFI vectors. (#4422)- SQL injection fixed in
RemoteVertex.newEdgeby switching to parameter binding (also fixes breakage on apostrophes). (#4327) - JavaScript injection in the polyglot engine closed by replacing the "looks-like-JSON" source-concatenation heuristic with
Value.execute(). (#4326) - Full CodeQL cleanup: open Java and JavaScript code-scanning alerts resolved at their true sources (workflow permissions, ReDoS, path-injection). (#4383, #4386, #4388)
Major Fixes
High Availability & Clustering
- TimeSeries data now replicates correctly across an HA cluster, and a compaction/append deadlock that caused a WAL version gap on Raft followers was eliminated. (#4414, #4458)
- Concurrent single-row time-series
INSERTs no longer silently lose samples (sealed-slot lost update). (#4453) - Bolt writes to a follower no longer fail with "no authenticated user in the current security context"; the authenticated user is now bound on
DatabaseContextin the Bolt executor. (#4456) PeerAddressAllowlistFilterno longer rejects legitimate peers during a Kubernetes DNS-resolution race (incomplete allowlist on startup/restart). (#4471)- Stale-follower recovery is fixed when a snapshot download fails on a quiet cluster.
- New configurable paths:
arcadedb.ha.raftStorageDirectoryfor the Raft storage directory (#4446), configurable server log directory for read-only root filesystems (#4451), andarcadedb.ha.clusterTokenPathto read the cluster shared secret from a file (#4431). RemoteDatabaseno longer reuses a session id across servers on HA failover during an open transaction; aTransactionExceptionis now raised on server switch. (#4373)RemoteHttpComponentno longer mutatesleaderServer/currentServernon-atomically during retries. (#4372)- New
STICKYstrategy pins HTTP transactions to a concrete cluster member. (#4273) getReplicaAddressesnow excludes the local peer instead of the leader. (#4274)/api/v1/server?mode=clusterreturns thehasection again after the Raft migration. (#4261)- New "Force Resync" button in Studio to recover a diverged follower from the leader.
- HA bootstrap-fingerprint replay race fixed, and HA node aliases corrected. (#4259)
- Massive-insertion cluster configuration issues resolved, plus assorted HA log improvements.
Concurrency & Async
FileManagerno longer mutates itsArrayList<ComponentFile>from multiple threads without synchronization (fixes CME / AIOOBE). (#4371)LockManager.tryLocknow re-attemptsputIfAbsentafter a wait timeout and tracks the remaining timeout per await. (#4367)DatabaseAsyncTransactionnow rolls back before retrying after aConcurrentModificationException, invokes the per-taskonErrorCallback, and no longer swallows final-retry failures or contaminates the shared transaction. (#4368, #4369, #4370)PageManager.putPageInReadCacheno longer leaks RAM accounting when replacing an existingCachedPage. (#4390)
OpenCypher
CREATE INDEXnow implicitly creates the referenced property (Neo4j-style lazy schema). (#4354)nodes(),relationships()andlength()on variable-length path patterns (e.g.[*1..3]) are now implemented. (#4353)- Records written via SQL are now visible to subsequent Cypher queries (and vice versa) within the same connection/transaction. (#4355)
EXPLAINno longer fails with an idempotency error on a multi-statement query containingCREATE. (#4366)- Label disjunction
(n:A|B)no longer returns 0 rows. (#4221) allShortestPaths()now returns all co-shortest paths instead of just one.MERGEnow uses a bound anchor as the traversal start instead of a full edge-type scan (performance), and no longer crashes on a single-quote property value withUNWINDor rebinds the variable from anOPTIONAL MATCHnull endpoint. (#4213, #4210)DATETIMEproperty comparison withdatetime()no longer returns 0 rows. (#4231)- Redundant
AND true/OR falsebranches are now simplified inWHEREclauses. (#4405) MATCH ... WHERE ID(n) IN $idsnow accepts along[]parameter array.- Query results are now consistent between parameterized and hard-coded values.
SQL
IN :paramwith a collection parameter now returns rows when an index is used. (#4468)MOVE VERTEXno longer generates an internal error. (#4461, #4347)expand()projection now honors itsASalias instead of always being namedvalue. (#4389)IN (SELECT β¦)no longer always returns empty (InConditionnow unwraps single-property results). (#4337)MERGEon a UNIQUE-indexed property no longer throwsDuplicatedKeyExceptionwhen the same key appears twice in a batch (Neo4j matches the second occurrence). (#4351)node.*andrel.*functions no longer silently return null/0 from SQL. (#4216)- TimeSeries timestamps are now returned in queries. (#4418)
- New
cypherRID(<cypher-rid>)SQL function andasCypherRID()method for interoperating with Cypher numeric ids. ResultInternal.getPropertyno longer re-surfaces removed properties via element fall-through. (#4398)EdgeLinkedList.removeVertex/removeEdgenow iterate all segments to remove every matching entry. (#4395)MultiIterator.countEntriesno longer discards the count for non-resettable iterables. (#4396)MATCHESnow keys its regexPatterncache by the regex string rather thanhashCode()(collision no longer returns the wrong pattern). (#4397)- Case conversions across the function library now use
Locale.ROOT. (#4393) RangeFunctionand the math functions are now guarded against long-range overflow / infinite loops. (#4391, #4392)CREATE INDEX ON ... (...)without an index type now raises a clear parsing error instead of an NPE.- Inserting edges between existing nodes with mandatory properties now works. (#4413)
- Multiple-inheritance handling fixed, and
point()over a latitude property surfaced as a string no longer throws aClassCastException. SEARCH_INDEX()negative Lucene clauses now return correct results. (#4220)
Vector & Index
TRUNCATE TYPEno longer resets anLSM_VECTORindex dimension to 0, nor leaves UNIQUE indexes in an inconsistent state requiringDROP TYPE. (#4359, #4352)LSMVectorIndexnow converts JVector's EUCLIDEAN return to L2Β² distance in all search paths, so K-NN no longer returns the worst matches first. (#4334)LSMVectorIndexCompactornow handles the old-format tombstone rewind correctly. (#4335)- NPE in
discoverAndLoadCompactedSubIndexthat prevented loading compacted vector sub-indexes at startup fixed. LSM_VECTORinactivity rebuild timer is now re-armed after a skip. (#4272)REBUILD INDEXnow works forBY ITEMindexes. (#4448)vector.fuse()is now recognised as a SQL function (no more "Unknown method name: fuse").
Wire Protocols
- Bolt: parameterized Cypher
MATCHqueries via the JavaScriptneo4j-drivernow work (#4452); integer property values are no longer coerced to strings afterCREATE INDEX, and index-backed lookups return rows. - PostgreSQL: scalar columns are now advertised with native OIDs. (#4202)
- gRPC: correct exceptions are now thrown (
NOT_FOUNDforRecordNotFoundExceptiononlookupByRid) (#4364);LocalDateTime/LocalDateand ISO-string fallback handled i...
26.5.1
ArcadeDB 26.5.1 Release Notes
Overview
ArcadeDB 26.5.1 is a major release with over 270 commits and 128 resolved issues. The headline news is the new sparse vector index with server-side hybrid retrieval and INT8 quantization end-to-end, a huge wave of OpenCypher correctness fixes, query partitioning, a new EXTERNAL property storage layout for heavy values, plus a long list of HA, wire-protocol, and Studio improvements.
Major Highlights
Sparse Vector Index + Hybrid Retrieval
A brand-new LSM_SPARSE_VECTOR index brings sparse-embedding retrieval (BM25/SPLADE-style) directly into the engine, with server-side fusion of dense and sparse results and diversified top-K. (#4065, #4066, #4067, #4068, #4070, #4078, #4119, #4130)
- New index type
LSM_SPARSE_VECTORfor sparse-embedding retrieval. vector.fuse(...)server-side hybrid fusion with RRF, DBSF and LINEAR strategies.vector.neighbors(...)gainsgroupBy/groupSizeoptions for diversified retrieval, including dotted nested-field grouping (#4072) and traversal-integrated grouping (#4071).- WAND / BlockMax-WAND dynamic pruning to scale sparse retrieval to 100M+ documents.
- Sparse-vector partitioning so a single index can be sharded by tenant / domain.
- Reranker SQL functions for two-stage retrieval pipelines.
- Bolt and HTTP wire support for the new sparse vector type, including
$bytes/$int8markers for INT8 query vectors.
INT8 Quantization for Dense Vectors
End-to-end INT8 support across the dense vector pipeline: ingest, storage and query path now share the same 8-bit representation, dramatically reducing disk and RSS without going through the FP32 path. (#3143, #4132, #4133, #4135, #4136)
EXTERNAL Property Storage
New paired-bucket layout for heavy property values (vectors, large strings, JSON). Hot row data stays compact in the main bucket while bulky payloads live in a sibling external bucket, sharply reducing scan cost on wide records. (#4027, #4028)
Query Partitioning
Query-level partitioning lands together with a partition-aware planner that prunes pruned partitions from SQL and Cypher plans, plus integrity guardrails for partitioned types. (#4087, #4088)
HA: Offline Cluster Bootstrap
You can now bootstrap a fresh HA cluster from a pre-seeded database (snapshot-and-restore), avoiding a full re-replication of large datasets when expanding or rebuilding a cluster. Includes regression integration tests for the cluster-formation edge cases. (#4147, #4205)
Production-Ready Helm Chart
The Helm chart has been reworked to align with the Raft-based HA subsystem introduced in 26.4.2 and is now suitable for production rollouts. (#4035)
Cypher: SHOW INDEXES / SHOW CONSTRAINTS
Standard Cypher administrative commands SHOW INDEXES and SHOW CONSTRAINTS are now supported. (#3972)
SQL: FIND REFERENCES
Restores the OrientDB-compatible FIND REFERENCES command for locating all records pointing to a given RID. (#4146)
C# End-to-End Tests
A new e2e suite exercises ArcadeDB over the Postgres wire via Npgsql and Testcontainers, validating the C# client path on every build. (#4036, #4038)
HA Operational Improvements
- Optional human-readable peer names in
HA_SERVER_LISTfor friendlier cluster topology. (#3974) - Studio gains peer add/remove controls in the HA cluster panel. (#4145)
Studio Improvements
- Full-screen mode for graph view. (#4032)
- Clear query button / textbox. (#4121)
- Session reset on token expire instead of silent failure. (#4082)
- Error messages now persist instead of disappearing after a few seconds. (#4124)
- Query history no longer auto-submits on selection. (#4022)
- Inherited indexes are now visible. (#4140)
Major Fixes
OpenCypher Correctness
A large batch of correctness fixes landed across pattern matching, write clauses, subqueries, list/temporal expressions and the optimizer fast-path. Highlights:
valueType(...)now reports theNOT NULLsuffix for non-null values. (#3991)point(...)WGS-84-3D exposes.heightas an alias for.z. (#3992)CALL ... YIELDno longer nullifies variables carried in fromWITH. (#3996, #4094)collect(r)followed by a variable-length match no longer drops all rows. (#3997)- Variable-length pattern segments no longer re-traverse a relationship bound in a prior
MATCH. (#4006) MERGEwith an unbound label-only endpoint now creates a fresh node instead of reusing an existing one. (#3998)SETnow propagates to all aliases bound to the same node within the same query. (#4000)- Self-referential property updates and
SET :Labelare now idempotent across row fanout. (#4016, #4017) - Temporal component access on
date/datetimevalues no longer returns null. (#4018) WITH-carried node variables are no longer nulled out by a laterCREATE/MERGE. (#4019)allReduce(...)no longer evaluates true cases as false. (#4043)- Anonymous middle nodes in multi-hop chains now match rows. (#4092)
- Backslashes in string literals and property values are preserved. (#4093)
- Consecutive directed and undirected relationship patterns must not reuse the same edge. (#4095, #4096)
EXISTS { ... }subqueries returning an outer-variable expression no longer evaluate as false. (#4097)- List literals containing
duration(...)no longer drop rows. (#4099) - List subscript with an inline aggregate index no longer returns null. (#4100)
MATCHimmediately afterCREATEnow sees newly created labeled nodes. (#4101)MATCHon a null carried variable now correctly filters out the row. (#4102)MERGE ... ON MATCH SETno longer returns the pre-update property value. (#4103)MERGEpatterns no longer reuse a newly created endpoint across input rows. (#4104)- Node label-union patterns now match when either label exists. (#4105)
- Pattern comprehensions over existing relationships are no longer empty. (#4106)
reduce(...)over an inline aggregate expression is now evaluated correctly. (#4107)- Relationship type predicates on bound relationship variables no longer evaluate as false. (#4108)
- Repeated relationship variables in
WHEREpatterns now match no rows (as expected). (#4109) - Uncorrelated pattern predicates now correctly reflect existing relationships. (#4110)
- Variable-length pattern comprehensions no longer duplicate projected elements. (#4111)
WHERE falseliteral predicates are no longer ignored. (#4112)datetime()values are now persisted onDATETIME-typed properties. (#4125)OR EXISTS + AND NOT (EXISTS ... OR EXISTS ...)returns the correct rows under two-outer-MATCHbinding. (#4126)- Optimizer fast path is now skipped when a write clause precedes
MATCH. (#4131) CALLsubquerySETno longer leaves the carried outer variable stale. (#4182)id(...)is now numeric and no longer breaks numeric predicates. (#4183)shortestPath/allShortestPathswith variable-length relationship type alternation now match. (#4190)- Write-only
CALLsubqueries no longer return an extra empty row. (#4191) MATCHon a parent edge type now matches sub-typed edges (polymorphic edge traversal). (#4192)- Batch fixes for #4184, #4185, #4186, #4188, #4189. (#4196)
SQL
CONTAINSALLnow works when comparing a list ofIdentifiables against a list of RID strings. (#4002)- Correlated
COLLECT { ... }/COUNT { ... }subqueries with outer-variable access now evaluate correctly instead of always returning empty/zero. (#4014, #4015) SEARCH_INDEXandSEARCH_FIELDSnow propagate return values in filters and correctly handle wildcards. (#4023, #4030)SELECTwith a non-unique LSM index no longer returns zero rows after partial deletes (per-RID tombstones no longer suppress the whole key). (#4024)- Edge creation with
CONTENTno longer silently ignores properties. (#4033) algo.dijkstrano longer yields a weight of zero. (#4042)LIST of STRINGin GraphBatch works again. (#4069)UPDATE EDGE SET @in/@outcorrectly rewires the vertex edge lists. (#4074)=combined withLIKEon time-series types no longer returns zero results. (#4128)- Range queries no longer raise a spurious "Non-existent edge type" error. (#4199)
point.withinBBox(...)now supports cross-meridian bounding boxes. (#3994)
Storage, Indexing and Schema
- HASH index lookups now return rows when data encryption is enabled (keys are kept deterministic). (#4137)
- Orphan
TypeIndexwrapper is now dropped when its last bucket child is removed. (#4179) - Indexes on a subclass are no longer incorrectly related to superclass indexes. (#4120)
- Manual index names are now respected on creation. (#4139)
- Inherited indexes are now shown in Studio. (#4140)
High Availability
- Schema changes now ship to followers, closing a WAL-gap source. (#4077)
- Cluster inconsistency reports after node shutdowns resolved. (#4081)
- Massive inserts over gRPC now replicate correctly. (#4076)
- Correct leader is now reported in the resume table. (#4075)
ClassCastException(RaftReplicatedDatabasetoLocalDatabase) on the leader during import / read-only property writes fixed. (#4144)/api/v1/batchno longer fails with "Error on updating dictionary" on follower nodes. (#4039, #4122)/batchendpoint no longer returns HTTP 500 NPE after a successful commit. (#4123)- Spurious index warnings from cluster followers removed. (#4063)
- e2e-ha integration tests stabilized, with on-demand Toxiproxy support. (#4013, #4020)