v1.39.0 #7549
romange
announced in
Announcements
v1.39.0
#7549
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
Dragonfly v1.39.0
This release delivers a significant leap in full-text search capability —
FT.HYBRIDfuses vector similarity with text queries, exact phrase matching with slop arrives, Porter stemming is on by default for TEXT fields, and BM25STD/TFIDF scoring withWITHSCORESsupport rounds out a deeply improved search engine. Performance improves across the board: PubSub reply batching cuts syscalls by 24–70% and raises throughput up to +12% RPS, INFO REPLICATION becomes fully lock-free, and a new ShardedHashMap replaces the global RCU ChannelStore for pub/sub. Security is tightened with multiple Lua sandbox hardening patches, RESP injection prevention, and PII-safe error logging. Tiered hashes are now mutable. A significant sweep of zombie-key cleanup fixes closes a class of bugs where lazy field expiry across SORT, ZUNIONSTORE, ZINTERSTORE, SHRINK, and hash TTL commands left empty containers in the keyspace.Highlights
FT.HYBRIDcombining full-text and vector similarity search with LINEAR and RRF score fusion strategies, capping a major release cycle of search improvements (feat(search): implement FT.HYBRID command with LINEAR/RRF score fusion #7420)Search
FT.HYBRIDcombining full-text and VSIM search via LINEAR (ALPHA/BETA weighted sum of normalized scores) and RRF (Reciprocal Rank Fusion) strategies, with HNSW KNN and range-based vector queries,YIELD_SCORE_ASaliasing, LOAD projection, andFT.PROFILEsupport (feat(search): implement FT.HYBRID command with LINEAR/RRF score fusion #7420)"hello world") and approximate phrase matching with slop ("..."~N), backed by per-document token positions stored in compressed posting lists; BM25 scoring updated for phrase semantics (feat(search): exact phrase queries with slop and BM25 scoring #7319)NOSTEM, index-levelLANGUAGE(defaultenglish), and per-documentLANGUAGE_FIELDare all supported;FT.INFOsurfaces the new flags (feat(search): Porter stemming for TEXT fields with NOSTEM, LANGUAGE, LANGUAGE_FIELD #7295)TFIDF(TF × ln(N/n)) andTFIDF.DOCNORM(additionally normalized by field length) as new scorer options forFT.SEARCH,FT.PROFILE, andFT.AGGREGATE; scorer dispatch refactored to a function-pointer table (feat(search): add TFIDF and TFIDF.DOCNORM scorers #7200)FT.SEARCHnow supportsWITHSCORESandSCORERparameters;FT.AGGREGATEgainsADDSCORESto inject a__scorefield enabling downstream GROUPBY/SORTBY/REDUCE on relevance (feat(search): add WITHSCORES, SCORER, ADDSCORES command support for FT.SEARCH/FT.AGGREGATE #7181)search_usedmemory class and reported indragonfly_memory_used_bytesvia an atomic capacity-based footprint counter (feat: add memory consumption for HNSW #7205)Performance
sendmsgper message; single-message wakeups still flush immediately [+3% RPS at pipeline=1, +12% at pipeline=10, −24% to −70% syscalls at pipeline=1–500] (perf(facade): batch V2 control-path replies in ProcessControlMessages #7479)ShardedHashMap(16 independent shard locks), removing the pool-wide broadcast on every subscribe/unsubscribe (feat(pubsub): Replace RCU-based ChannelStore with ShardedHashMap #7174)NotifyWatchQueueexits in O(1) when a watched key is absent (previously O(N) over all waiters), directly benefiting BLPOP, BZPOPMIN, and XREAD workloads (fix: avoid O(n) scans in NotifyWatchQueue #7225)--container_iteration_yield_interval_usec(default 500 µs, 0 to disable) (feat(server): Yield fiber periodically during long container iterations #7391)--use_oah_set; threaded through RDB save/load, async deletion, defragmentation, and SHRINK (feat: integrate OAHSet #7246)TryBorrow()returns an encoded view with Copy-on-Write semantics; a thread-local pin registry defers buffer deallocation until all readers finish (core: zero-copy GET primitives #7412)Replication
serialization_tagged_chunksflag enabling the RDB serializer to split large entries into tagged chunks with envelope IDs; compression is applied per-blob; a related list-decoding crash during chunked load is also fixed (feat(server): tagged chunk write path #7416)/metrics:dragonfly_master_link_status,dragonfly_master_last_io_seconds_ago,dragonfly_sync_in_progress, anddragonfly_slave_repl_offset(feat: add replication info to/metricsendpoint #7069)Cluster
--cluster_coordinator_connect_timeout_msand--cluster_coordinator_response_timeout_msflags to control coordinator-to-shard timeouts (previously hard-coded at 3000 ms) (feat(cluster): add flags for coordinator timeouts #7221)Commands
CLIENT LISTnow supportsTYPE <normal|master|replica|slave|pubsub>andID <id> [id …]filter arguments; outbound replication links are surfaced asTYPE masterentries;CLIENT KILL IDon a master-link ID returns a descriptive error directing users toREPLICAOF NO ONE(feat(server): Support CLIENT LIST [TYPE ...] [ID ...] filters #7377)DEBUG TRAFFICnow supports per-listener recording (LISTENER <main|memcache|admin>), full Memcache protocol capture and replay (SET/GET/CAS/INCR/GAT/etc. with flags, expiry, and CAS tokens), and a v3 file format; v2 files remain readable (feat: DEBUG TRAFFIC per-listener recording and memcache replay #7192)DEBUG TRAFFIC START <path> REPLICArecords the replication stream received by a replica from its master; fails with a clear error on standalone/master instances (feat: DEBUG TRAFFIC REPLICA - record replication stream on replicas #7217)BF.SCANDUMPiteratively exports a Scalable Bloom Filter in chunks of up to 16 MiB, returning(cursor, data)pairs untilcursor=0signals end-of-stream (feat(bloom): Implement SCANDUMP cmd for SBF #7092)BF.LOADCHUNKreconstructs an SBF from chunks produced byBF.SCANDUMP, completing the SCANDUMP/LOADCHUNK round-trip; guards prevent other BF commands from operating on a partially-loaded filter (feat(bloom): Implement LOADCHUNK cmd for SBF #7169)BGSAVEnow accepts the optionalSCHEDULEsubcommand (case-insensitive) for Redis client compatibility; concurrent saves are still rejected rather than queued (fix: accept optionalSCHEDULEsubcommand in BGSAVE #7286)dfly_benchgains--json_out_fileto write a memtier_benchmark-compatible latency JSON report including per-operation aggregate stats (count, ops/sec, average/min/max, p50/p99/p99.9) and a per-second time-series (Add memtier-compatible latency JSON to dfly_bench #7269)Security
load()built-in is now wrapped to enforce text-only mode ("t"), closing a sandbox escape vector where a malicious script could supply binary Lua bytecode to bypass restrictions (fix(lua): Restrict load() to text-only mode #7376)rawset,setmetatable, andgetmetatableare overridden to block access to_Gand all global library tables; guard metatables are attached to prevent replacement or corruption across script executions (fix(lua): Harden sandbox by protecting rawset, setmetatable, and getmetatable #7370)INFO ACLsection added, exposing aggregate registry metrics (acl_num_users, password/glob counts, estimatedacl_total_bytes) maintained incrementally without holding the registry write lock (chore: add info acl subcommand and metrics #7149)Cloud & Storage
WITH_AWS+--s3_use_helio_client=false; builds withoutWITH_AWSno longer exit ons3://paths (feat(s3): make AwsS3SnapshotStorage always available; AWS SDK backend optional #7180)az://URIs are correctly routed,OpenWriteFile/OpenReadFileuse thecloud::azureAPI, and cursor-based pagination fixes truncation for large buckets (feat(server): complete AzureSnapshotStorage implementation #7131)AwsCredsProviderinstead of settingAWS_S3_ENDPOINTin the process environment, eliminating side effects for other processes (feat(aws): pass S3 endpoint directly to AwsCredsProvider #7408)Bug Fixes
Replication & Persistence
slave_repl_offsetreporting zero inINFO REPLICATIONwhen replicating from a Redis/Valkey master; offset is now correctly populated fromrepl_offs_(fix: slave_repl_offset should be non zero for valkey master #7517)ScheduleBatchInShard) allowing a journal DEL entry to execute before the RDB loader finished creating the key on a shard (fix(server): Disable single shard batch optimization #7507)SaveStringencoding was read back as raw bytes, crashing Dragonfly inRenamer::FinalizeRenameon COPY/DUMP (fix: enable rdb_sbf_chunked by default and fix sbf serialization bug #7475)DFLY LOADnot propagating to replicas; the journal ring buffer is now cleared and reconnecting replicas are forced into full sync (fix: replication for data loaded by DFLY LOAD command #6740)REPLCONF CLIENT-IDsending the replica's internal ID instead of its cluster node ID (fix: slot redirection after takeover corrupted #7263)StartNewSlotMigrationswas called before stale slot data was flushed, causing incomingDFLYMIGRATE FLOWwrites to be wiped (fix: migration restart flush race #7333)Security & Lua
redis.error_reply()/redis.status_reply()strings containing\r\ncould inject arbitrary frames into the response stream (fix: strip CRLF from Lua error_reply and status_reply #7332)dragonfly.randstr()accepting unbounded arguments; input is now validated for count (1–32768), size (1–16 MiB), and type (fix(lua): Add input size validation to dragonfly.randstr() #7368)EVAL/EVALSHAcrashing with a CHECK abort on negative or non-numericnumkeysarguments (e.g."-0") instead of returning an error reply (fix(server): reject negative numkeys in EVAL/EVALSHA to avoid CHECK abort #7203)Search
\.,\-,\:) symmetrically at index time and query time, causing escaped-punctuation queries to fail to match (fix(search): honor backslash escapes in TEXT tokenization #7438)StringMapAccessor's destructor now deletes the key if the hash is empty after access (fix: delete empty hash after FT.SEARCH lazy field expiry #7166)Commands & Data Structures
RESTOREnow performs deep (entry-by-entry) integrity validation on listpack, intset, quicklist, and stream payloads, preventing crafted payloads with malformed interior entries from causing OOB reads or crashes (fix: deep-validate listpack/intset payloads on RESTORE #7502)DenseSet::SetExpiryTimenot settingexpiration_used_, causingRandomPairsUniqueto skip expiry filtering and return already-expired keys (fix(string_map): mark DenseSet expiration_used in SetExpiryTime #7392)ExpireIfNeededInternal,Find2) where deleting a node leftnode/currdangling for subsequent iterations (fix(dense_set): avoid use-after-free in expiry chain walks #7393)max_map_field_len; listpack encoding is now preserved for single-field hashes regardless of value size (fix: single-field hash should use listpack even with large values #7257)BITCOUNTwithBITindex mode when the end index falls exactly on a byte boundary, and incorrect handling of both-negative inverted ranges on short strings (fix: OOB in BITCOUNT and some refactoring #7190)AutoUpdater::Run()processed a value whose object type changed (e.g., SORT STORE overwriting a SET with a LIST) (fix: correct per-type memory accounting when object type changes in AutoUpdater #7142)RecordJournalpreempted and triggered evictions before the stream size update;UpdateStreamSizeis now called beforeRecordJournal(fix: memory track before preemption in OpAdd #7235)MEMORY DEFRAGMENTsilently ignoring parse errors for the threshold float argument and proceeding with defaults (server: Handle errors in memory cmd parse #7346)CancelBlocking()from being reached (test(connection): add regression tests for MULTI/EXEC tx-queue stall #7273)Zombie Key / Empty Container Cleanup — Fixed a widespread class of bugs where lazy field or member expiry left empty containers as zombie keys, causing DFATAL crashes in subsequent SAVE or incorrect command behavior:
What's Changed
/metricsendpoint by @EricHayter in feat: add replication info to/metricsendpoint #7069SCHEDULEsubcommand in BGSAVE by @vyavdoshenko in fix: accept optionalSCHEDULEsubcommand in BGSAVE #7286Huge thanks to all the contributors! ❤️
New Contributors
Full Changelog: v1.38.0...v1.39.0
This discussion was created from the release v1.39.0.
Beta Was this translation helpful? Give feedback.
All reactions