Commit Graph
574 Commits
Author SHA1 Message Date
6492fa011b enhance: remove unused C++ dependencies (rapidjson, OpenDAL backend) (#50552)
## What this PR does

Removes two unused C++ third-party dependencies from `internal/core` to
reduce dependency count, comprehension cost, and link/build surface.

### rapidjson
Linked into `milvus_core` but has **zero `#include` usage** in the C++
sources (only a stale comment in `common/Json.h`). knowhere v3.0.3 and
milvus-storage do not depend on it. Removes the conan requirement,
`find_package(RapidJSON)`, and the link target.

### OpenDAL backend
Experimental `ChunkManager` backend gated behind `USE_OPENDAL`
(**default OFF**) — released binaries never built it. Removes
`OpenDALChunkManager`, the vendored OpenDAL Rust dependency, and all
`USE_OPENDAL` build plumbing (Makefile / core_build.sh /
3rdparty_build.sh / CMake). The Go-side `"opendal"` storageType value
remains a backward-compatible alias to the standard remote chunk
manager.

### Kept
`simde` is **not** removed — knowhere v3.0.3 requires it
(`find_package(simde REQUIRED)`, used in
`src/index/sparse/codec/varintdecode.c`).

issue: #50551

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Signed-off-by: xiaofanluan <xf@hjjaq.com>
Co-authored-by: xiaofanluan <xf@hjjaq.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 15:02:23 +08:00
sthuangandGitHub ce5d6b5088 enhance: [RBAC] support role descriptions (#50184)
- Persist role descriptions when creating roles, expose them in role
list/describe results, and support updating descriptions through the
AlterRole path without changing role names.
- Store role descriptions in the role value body while keeping role
names in keys, and tolerate legacy empty role values plus undecodable
stored values by returning an empty description for that role row.
- Reject built-in/default roles and over-limit descriptions before WAL
writes, and share the role-description length validator between proxy
and rootcoord.

related: #50183

---------

Signed-off-by: shaoting-huang <shaoting.huang@zilliz.com>
2026-06-15 14:22:23 +08:00
Buqian ZhengandGitHub 270df10083 enhance: Make max array capacity configurable (#50264)
issue: https://github.com/milvus-io/milvus/issues/50263

This PR makes max array capacity configurable, preparing for row level
multi-user sharing

---------

Signed-off-by: Buqian Zheng <zhengbuqian@gmail.com>
2026-06-15 11:52:21 +08:00
sthuangandGitHub 5d80a9fd81 feat: [RBAC] support user description in credentials (#50186)
- Wire credential descriptions through create/update/read paths,
including proxy, HTTP v2, Go SDK options, length validation, optional
update presence handling, and internal credential proto/model
persistence.
- Preserve existing encrypted passwords and descriptions during
RootCoord credential updates when either field is omitted, reject
all-empty or partial direct password updates, and keep sha256 passwords
cache-only.
- Skip auth-cache refresh for description-only credential updates so
existing authentication state is not blanked, while still refreshing
caches for password updates.
- Return persisted user descriptions from select_user and HTTP v2
describe_user, including include_role_info=false, and reuse
already-loaded credential rows in user listing and RBAC backup to avoid
duplicate etcd reads while ignoring malformed credential keys.
- Use the upstream milvus-proto go-api/v3 version that includes the
credential description proto change; the temporary fork replaces in
root, pkg, client, and tests/go_client modules have been removed.

design doc:
docs/design-docs/design_docs/20260601-rbac-user-description.md

related: #50179

---------

Signed-off-by: shaoting-huang <shaoting.huang@zilliz.com>
2026-06-15 00:44:22 +08:00
sthuangandGitHub 0308c3de40 enhance: [Proxy] enforce collection description byte limit (#50178)
- Add a refreshable proxy.maxCollectionDescriptionLength setting with a
default 1024-byte limit and document it in milvus.yaml.
- Validate collection descriptions during CreateCollection and
AlterCollection PreExecute, including duplicate alter properties, while
leaving existing metadata loading unchanged.
- Document that restore or replication flows that recreate collections
through CreateCollection must satisfy the configured limit or raise it
first.
- Cover byte-length boundaries, CJK byte overflow, create rejection,
alter rejection, refreshability, duplicate alter-property rejection, and
generated YAML consistency in tests.

related: #50173

---------

Signed-off-by: shaoting-huang <shaoting.huang@zilliz.com>
2026-06-12 10:32:21 +08:00
jiaqizhoandGitHub 5e86706679 enhance: support storage format compaction and metrics (#50280)
#issue: #50182

Storage version compaction used to only care whether a segment had
reached the target storage version. That is not enough once StorageV3
segments can still have different column-group formats, because a
segment may already be V3 but still not match the format DataNode is
configured to write. This change lets DataCoord use the same compaction
path to refresh those segments by format as well.

The implementation adds a separate storage format compaction switch and
enables the policy when either version or format compaction is turned
on. For V3 segments, DataCoord now checks every field binlog format
against the configured target format, schedules only the segments that
actually need a rewrite, and keeps the existing health, L0, importing,
compacting, and snapshot-protection filters in place. External
collections are skipped so table-backed segments are not accidentally
pulled into this internal rewrite flow.

Segment metrics now include a segment format label in addition to state,
level, sorted status, and storage version. The metric update path also
tracks format transitions when binlogs are added or rewritten, including
legacy, unknown, and mixed-format cases, so DataCoord can report how
storage formats are distributed while segments move through refresh and
compaction.

---------

Signed-off-by: jiaqizho <jiaqi.zhou@zilliz.com>
2026-06-11 15:02:26 +08:00
f756c52a22 enhance:refactor flush source (#50300)
issue: #50425

Signed-off-by: luzhang <luzhang@zilliz.com>
Co-authored-by: luzhang <luzhang@zilliz.com>
2026-06-10 10:30:19 +08:00
yihao.daiandGitHub 0ef67e02ad fix: Preserve commit timestamps for import 2PC (#50164)
## What was fixed

This fixes import two-phase commit timestamp handling so imported
segments keep the commit timestamp assigned by the import transaction
instead of being made visible at an unrelated later timestamp.

Changes included:
- Preserve import commit timestamps in DataCoord segment metadata.
- Broadcast import commit and rollback through DML channels so
downstream consumers observe the 2PC result consistently.
- Apply delete visibility in sealed segments based on the imported
segment commit timestamp.
- Carry the import transaction DML position needed for commit/rollback
propagation.
- Guard import in replicating clusters behind a disabled-by-default
config switch, and only allow `auto_commit=false` when that switch is
enabled.
- Downgrade only unsupported `GetSalvageCheckpoint` errors for
compatibility with older StreamingCoord implementations.
- Move import jobs to `Committing` before handling per-vchannel commit
acknowledgements, including the race where the vchannel commit is
handled before the DDL ack callback.
- Sync the generated `configs/milvus.yaml` entry for the new import
replication guard.

Fixes #48525

## Test plan

- `source ./scripts/setenv.sh && make SKIP_3RDPARTY=1
build-cpp-with-unittest`
- `make build-go`
- `make static-check`
-
`CLANG_FORMAT=/opt/homebrew/Caskroom/miniconda/base/envs/milvus2/bin/clang-format
make cppcheck`
- `make rustcheck`
- `make fmt`
- `go test ./cmd/tools/config -run TestYamlFile -count=1`
- `go test -tags dynamic,test -gcflags="all=-N -l" ./internal/datacoord
-run 'TestHandleCommitVchannel|TestCommitImportCallback' -count=1`
- Local import commit timestamp tests under
`~/workspace/snippets/tests/test_import_commit_ts`:
  - `test_import_delete.py`
  - `test_import_auto_commit.py`
  - `test_import_basic.py`
  - `test_import_mvcc.py`
  - `test_import_insert_delete.py`
  - `test_import_insert_delete_auto_id.py`
  - `test_import_ttl.py`
- Local import + replication tests under
`~/workspace/snippets/tests/test_cdc/import`.

Local Python coverage used StorageV2. StorageV3 needs a separate run
with `common.storage.useLoonFFI=true`.

---------

Signed-off-by: Yihao Dai <yihao.dai@zilliz.com>
2026-06-08 15:50:19 +08:00
jiaqizhoandGitHub 148bcc3e87 enhance: force CRC32C when OpenSSL FIPS is enabled (#50239)
issue: #48359

This change makes Milvus automatically use CRC32C for S3 PutObject
requests when OpenSSL FIPS mode is active. In FIPS mode, checksum
choices are more constrained, so relying on the configured MinIO
checksum behavior can lead to requests using an algorithm that is not
acceptable in that runtime.

The implementation moves OpenSSL FIPS enablement into the shared
`pkg/util/fips` package and makes it return whether FIPS was actually
enabled. That lets startup code keep enabling OpenSSL FIPS as before,
while paramtable can also reuse the same state during config
initialization.

When FIPS is successfully enabled and `minio.ssl.useCRC32C` is still
false, Milvus now logs a warning and temporarily overrides the runtime
value to true. This keeps the user-facing config unchanged, but makes
the effective runtime behavior compatible with FIPS requirements.

Signed-off-by: jiaqizho <jiaqi.zhou@zilliz.com>
2026-06-03 15:18:19 +08:00
4fa49058c1 enhance: extend arrow IO thread pool config to DataNode init (#50099)
issue: #50098

## Summary

- Apply `common.arrow.ioThreadPoolCoefficient` /
`ioThreadPoolMaxCapacity` to DataNode at startup, mirroring the
QueryNode wiring from #49208/#49623. Without this, the paramtable keys
exist but have no effect on DataNode and the Arrow IO pool stays at
Arrow's hard-coded default of 8.
- Also call `initcore.InitArrowReaderConfig` so the parquet reader
range-coalescing limits (`hole`/`range` size) apply.
- Register paramtable watchers so capacity changes hot-reload without
restart, matching QueryNode behavior.
- Raise `dataCoord.import.fileNumPerSlot` default from 1 to 4 to reduce
per-import slot demand by 4x and leave more arrow IO pool headroom for
concurrent compactions on the same worker.

## Why

See #50098 for the full reproducer and analysis. Briefly: production
observed a 1.5M-row sort compaction taking >1 hour while the worker's
CPU sat at 12% and network at 14% of baseline — all 5 large
SortCompactions on different pods finished at nearly identical wall
times (variance < 1%), the classic shared-pool saturation signature.
Local bench at 50ms RTT with 100 concurrent readers:

| ARROW_IO_THREADS | conc=100 wall_ms | per-task p50_ms |
|---|---|---|
| 8 (default) | 36,917 | 35,908 |
| 32 | 18,174 | 16,074 |
| 64 | 17,320 | 15,702 |

## Test plan

- [x] `go test -count=1 -run TestComponentParam ./util/paramtable/` (pkg
module)
- [x] `go test -tags dynamic,test -gcflags="all=-N -l" -count=1 -run
TestRegisterArrowIOThreadPoolWatchers ./internal/datanode/index/`
- [x] `go test -tags dynamic,test -gcflags="all=-N -l" -count=1 -run
"TestImport" ./internal/datacoord/`
- [ ] CI

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Signed-off-by: cai.zhang <cai.zhang@zilliz.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 17:08:16 +08:00
congqixiaandGitHub 89659fd182 fix: [stv3] serialize L0 V3 manifest delta updates (#49917)
Related to #49706

Move L0 V3 manifest delta commits into the segment meta update path so
manifest pointer updates and deltalog metadata appends are protected by
the same DataCoord lock under concurrent compaction tasks.

---------

Signed-off-by: Congqi Xia <congqi.xia@zilliz.com>
2026-06-01 10:32:15 +08:00
wei liuandGitHub d8de464ff6 enhance: support take output for internal collections (#50079)
issue: https://github.com/milvus-io/milvus/issues/50078

This PR supports using the storage `take()` path for internal collection
query and search output fields.

What changed:
- Add a separate `queryNode.internalCollection.useTakeForOutput` config
and keep it disabled by default.
- Keep external collection take controlled by
`queryNode.externalCollection.useTakeForOutput`.
- Let internal collections request StorageV2/V3 field-id columns through
`take()`, while external collections keep using external field names.
- Extend Arrow take output conversion for binary, float16, bfloat16,
int8, and sparse vector fields.
- Add info logs when take falls back to `bulk_subscript`.
- Add Go client E2E coverage for internal take output fields across
scalar, array, vector, sparse vector, and vector-array outputs.

Validation:
- make plan-parser-lib
- make build-cpp
- make build-go
- git diff --check
- go test internal/querynodev2/segments
- go test internal/util/segcore
- go test pkg/v3/util/paramtable
- go test tests/go_client/testcases/helper
- cmake_build/unittest/all_tests with take-related gtest filters
- go_client E2E:
  - TestInternalCollectionTakeOutputFields
  - TestInternalCollectionTakeStructArrayOutputFields
  - TestExternalCollectionMultipleDataTypes
  - TestExternalCollectionAdditionalVectorTakeOutput
  - TestExternalCollectionSparseVectorCurrentlyRejected

---------

Signed-off-by: Wei Liu <wei.liu@zilliz.com>
2026-05-30 17:38:14 +08:00
sparknackandGitHub d5917c265e enhance: Add V3 entry streaming reader (#50073)
issue: #48957

- Add `IndexEntryReader::ReadEntryStream`, `GetEntrySize`, and
`HasEntry` for V3 entries.
- Stream plain and encrypted entries through ordered slices with
incremental CRC32c verification.
- Bound transient stream memory with a process-wide entry stream budget.
- Add dynamically refreshable `common.entryStream.streamBudgetRatio` to
tune the shared entry stream budget for current scalar index loading and
later field data loading.
- Use 16MB stream slices by default, aligned with the encrypted slice
size and existing V3 range size.
- Derive the entry stream budget from CPU core count: `CPU cores *
streamBudgetRatio * 16MB`.
- Harden stream error handling:
  - keep active futures bounded by the thread pool size
  - reject zero or too-small explicit slice sizes
  - use overflow-safe slice count calculation
  - verify CRC for empty entries
  - release budget when callbacks throw or task submission fails
  - wait for active workers before returning on abnormal exits
- validate decrypted slice length and include actual/expected CRC in
stream errors
- Document V3 streaming read behavior and shared budget configuration.

---------

Signed-off-by: Shawn Wang <shawn.wang@zilliz.com>
2026-05-30 16:20:13 +08:00
jiaqizhoandGitHub 9da2858dd5 enhance: add configurable storage writer format (#50067)
issue: #50147

This change pulls the Vortex writer-format switch into its own focused
update. The goal is to make the insert data storage format configurable
from Milvus config, so we can turn Vortex on for CI validation without
mixing it with the unrelated AssertInfo cleanup from the previous PR.

The implementation adds dataNode.storage.format and wires it through
paramtable as DataNodeCfg.StorageFormat, with vortex as the current
default for this branch. When storagev2 builds milvus-storage
properties, it now passes the selected value through writer.format,
which matches the updated milvus-storage property contract.

This also updates the C++ writer path to use PROPERTY_WRITER_FORMAT
instead of the old PROPERTY_FORMAT key. That keeps the growing-segment
flush path aligned with the new storage property naming while still
forcing the TEXT flush writer to parquet where that path expects parquet
output.

---------

Signed-off-by: jiaqizho <jiaqi.zhou@zilliz.com>
2026-05-29 16:46:14 +08:00
7841f8a9b0 enhance: use bump_schema_version to involve backfill and drop field compaction(#48808) (#49759)
related: https://github.com/milvus-io/milvus/issues/48808

Signed-off-by: MrPresent-Han <chun.han@gmail.com>
Co-authored-by: MrPresent-Han <chun.han@gmail.com>
2026-05-29 13:26:15 +08:00
Zhen YeandGitHub 9f7edeebb9 enhance: optimize QueryNode scheduler recovery performance from heavy load (#49825)
issue: #49707

- query node scheduler: make read tasks context-aware, use an unbuffered
add path, and cleanup canceled or near-deadline queued tasks before
queue limit checks
- query grouping: cap grouped NQ at 16 and add an NQ merge ratio guard
to avoid merging small queries into much larger groups
- REST timeout: propagate request timeout as a context deadline so
downstream query tasks receive timeout timestamps
- scheduler metrics: add ready NQ plus queue and execution duration
metrics while removing obsolete receive queue configuration
- proxy config: reduce the proxy task queue default to 256

---------

Signed-off-by: chyezh <chyezh@outlook.com>
2026-05-23 16:56:30 +08:00
sparknackandGitHub def1e79754 enhance: Expose Arrow reader config (#49620)
issue: #49616

- Expose Arrow reader range coalescing options through
`common.arrow.reader.holeSizeLimitBytes` and
`common.arrow.reader.rangeSizeLimitBytes`.
- Pass the configured Arrow reader properties into StorageV2
`FileRowGroupReader` paths.
- Propagate the same config into StorageV3 milvus-storage reader
properties (`reader.parquet.prebuffer.*`).
- Update milvus-storage to the official main revision that supports the
reader hole and range size options.

---------

Signed-off-by: Shawn Wang <shawn.wang@zilliz.com>
2026-05-20 16:02:30 +08:00
congqixiaandGitHub e7529437ea enhance: Disable storage v3 by default (#49880)
Set configuration to disable for storage v3

---------

Signed-off-by: Congqi Xia <congqi.xia@zilliz.com>
2026-05-19 01:58:29 +08:00
wei liuandGitHub 1cdbf351de fix: limit delegator post-load concurrency (#49808)
issue: #49767

## What changed

This patch adds a request-level CPU-factor limiter for QueryNode
delegator post-load work after worker `LoadSegments` returns.

The worker `LoadSegments` fan-out remains unchanged. The limiter covers
the delegator-side follow-up stages before the segment becomes visible:

- `LoadBloomFilterSet`
- `loadBM25Stats`
- `loadStreamDelete`
- distribution update

A refreshable config is added:

```text
queryNode.delegatorPostLoadConcurrencyFactor
```

Default factor is `1`, so the effective concurrency is CPU cores * 1.

## Why

Delegator post-load work can spike CPU when many load requests complete
around the same time. This is especially expensive when delete buffer
rows, loading segments, and historical BF entries multiply the amount of
BF work.

## Validation

- `git diff --check`
- `CONAN_CMD=/Users/wei.liu/Library/Python/3.9/bin/conan make build-cpp`
- `go test -tags dynamic,test
github.com/milvus-io/milvus/pkg/v3/util/paramtable -run
'TestComponentParam' -count=1 -v`
- `go test -gcflags="all=-N -l" -tags dynamic,test
github.com/milvus-io/milvus/internal/querynodev2/delegator -run
'TestDelegatorDataSuite/TestPostLoadLimiter' -count=1 -v -ldflags="-r
${RPATH}"`

Signed-off-by: Wei Liu <wei.liu@zilliz.com>
2026-05-18 20:02:31 +08:00
Bingyi SunandGitHub e36613c7ea enhance: make PK index warmup configurable (#49664)
## Summary
Make the StorageV2 system PK index use the configurable scalar index
warmup policy instead of a hardcoded sync policy. The default remains
sync, while deployments can set
`queryNode.segcore.tieredStorage.warmup.scalarIndex` to disable or async
for the PK index as well.

## Issue
issue: #49665

---------

Signed-off-by: sunby <sunbingyi1992@gmail.com>
2026-05-14 17:40:11 +08:00
Bingyi SunandGitHub f484f3c8cf enhance: improve the preformance of create partitions (#47486)
issue: https://github.com/milvus-io/milvus/issues/47403
this pr contains performance optimization for concurrent
CreatePartition:
1. add a version cache on proxy for partition level cache
2. avoid repeated updates of target when there're many CreatePartition
requests.
3. avoid unnecessary copy of meta data.

---------

Signed-off-by: sunby <sunbingyi1992@gmail.com>
2026-05-13 14:12:11 +08:00
sijie-ni-0214andGitHub 27773aa846 enhance: improve querycoord task scheduling and dist cleanup (#49528)
## Summary

- Keep QueryCoord waitQueue as the global priority queue while using
node-bucketed indexing for processQueue so Dispatch(node) scans only
related tasks.
- Index multi-node process tasks under all related nodes, including
MoveTask endpoints and LeaderAction worker/leader nodes.
- Dispatch LeaderAction through the leader executor to match the
SyncDistribution RPC target while preserving action.Node() as the worker
payload node.
- Remove the dist handler checkExecutedFlag ticker and avoid eager
task.String() formatting on non-error stale checks.
- Serialize RemoveByNode with scheduling to avoid re-adding tasks to
processQueue during node-down cleanup races.

Fixes #49512

## Test Plan

- git diff --check upstream/master...HEAD
- gofumpt -l internal/querycoordv2/dist/dist_handler.go
internal/querycoordv2/task/scheduler.go
internal/querycoordv2/task/task_test.go
- go test -v -count=1 -tags dynamic,test -gcflags="all=-N -l"
-ldflags="-r ${MILVUS_WORK_DIR}/cmake_build/lib -r
${MILVUS_WORK_DIR}/internal/core/output/lib"
./internal/querycoordv2/task -run
"TestTask/(TestRemoveByNodeWaitsForSchedule|TestLeaderTaskUsesLeaderExecutor|TestNoExecutor|TestTaskQueueRangePriority|TestNodeTaskQueueNodeBucketing|TestNodeTaskQueueMoveTaskDualNode|TestNodeTaskQueueLeaderActionDualNode|TestNodeTaskQueueRangeByNodePriority)"
-timeout 300s
- make static-check

---------

Signed-off-by: sijie-ni-0214 <sijie.ni@zilliz.com>
2026-05-09 08:52:08 +08:00
Buqian ZhengandGitHub 4884987b0c enhance: general optimizations (#49381)
* Optimize metadata and request handling hot paths
* Make replication pending-message queue capacity and max size
configurable instead of hard-coded.
* Batch QueryCoord collection metadata saves with MultiSave to avoid
oversized single writes while still reducing per-key etcd operations.
* Reduce avoidable allocations in DataCoord catalog tests, access log
list formatting, HTTP array joining, and HTTP JSON field extraction.
* Use WAL-specific message ID decoding during flusher recovery.
* Use set-based RootCoord collection-name filtering and structured
collection-not-found errors.

issue: #44452

Signed-off-by: Buqian Zheng <zhengbuqian@gmail.com>
2026-05-08 11:40:07 +08:00
beee282e0d fix: remove unused queryNode.ioPoolSize parameter (#48937)
## Summary

- Remove the unused `queryNode.ioPoolSize` config parameter and its dead
code
- The parameter was computed and read but never stored or used — only
logged

## Details

The `ioPoolSize` was calculated in `NewLoader()` and the config
`queryNode.ioPoolSize` was read to override it, but the resulting value
was never assigned to any struct field. The actual loading concurrency
is controlled by:
- **ConcurrencyLevel**: `min(CPUNum, segmentCount)` — hardcoded in
`segment_loader.go`
- **LoadPool**: `CPUNum * middlePriority` — controlled by
`common.threadCoreCoefficient.middlePriority`

## Changes

| File | Change |
|------|--------|
| `pkg/util/paramtable/component_param.go` | Remove `IoPoolSize` field
definition and init |
| `internal/querynodev2/segments/segment_loader.go` | Remove dead
`ioPoolSize` computation in `NewLoader()` |

issue: #48900

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Signed-off-by: xiaofanluan <xiaofan.luan@zilliz.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-04 23:12:53 +08:00
congqixiaandGitHub 7311d450a0 enhance: bump Go dependencies to v3 modules (#49485)
Related to #49398

Bump Go module references from pkg/v2 and milvus-proto/go-api/v2 to
pkg/v3 and milvus-proto/go-api/v3 so the client tracks the Milvus 3.x
release line.

This prepares the repository for the upcoming 3.x.y release by aligning
imports, module dependencies, and proto API references with the new
major-version module paths.

---------

Signed-off-by: Congqi Xia <congqi.xia@zilliz.com>
2026-05-01 10:30:13 +08:00
0fa822fc0a enhance: support search aggregation go-layer (#49071)
## Summary
- add `search_agg` package in proxy for context build, recursive
aggregation compute, and bucket ordering
- wire `group_by` aggregation through `task_search` and built-in
pipeline (`searchWithAggPipe` + aggregate operator serialization)
- upgrade querynode reduce key extraction for agg multi-field grouping,
and update related proxy/querynode tests
- keep local proto iteration path and local core build job defaults
aligned for this development workflow

## Test plan
- [x] bash
/home/zilliz/hc-claude-projects/hc-milvus-projects/search-aggregation/scripts/verify_baseline.sh
- [x] direct association tests passed
- [x] indirect association tests passed

issue: #49046

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Signed-off-by: MrPresent-Han <chun.han@gmail.com>
Co-authored-by: MrPresent-Han <chun.han@gmail.com>
Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-30 15:51:50 +08:00
8011bdfcd7 fix: reject oversized index params (#49409)
## Summary
- Add `proxy.maxIndexParamsSize` to cap create index parameter payloads
before coordinator persistence.
- Reject oversized raw `ExtraParams`, expanded JSON params, and final
merged index params in proxy.
- Cover normal-sized params and oversized payload regressions in
`parseIndexParams` tests.

issue: #48330

## Test plan
- [ ] Not run locally: `go test -tags dynamic,test -gcflags=\"all=-N
-l\" -count=1 ./internal/proxy -run
'Test_parseIndexParams(Rejects|Allows)'` requires generated segcore
C/C++ headers not available in this local checkout.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Signed-off-by: xiaofanluan <xiaofan.luan@zilliz.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 15:07:51 +08:00
df51830b58 enhance: add preferFieldDataWhenIndexHasRawData toggle for sealed retrieve (#49127)
## Summary

- New QueryNode toggle `queryNode.preferFieldDataWhenIndexHasRawData`
(default `false`) makes sealed retrieve serve scalar and vector fields
from resident column data instead of index-backed raw data, and the
loader keeps the column resident alongside the index on load/reload.
- Hot-path short-circuit: when the toggle is off, retrieve does not call
`HasFieldData` or take the segment's `shared_lock`, so the default
retrieve path is unchanged in cost.
- Observability: log at `InitQueryNode` when the toggle is on, calling
out the memory trade-off (field data + index both resident).

## Test plan

- [x] C++ unit:
`RetrieveScalarFieldFromColumnWhenIndexHasRawDataAndPreferFieldDataEnabled`
— seeds the scalar index with values deliberately desynchronized from
the column, then asserts the retrieved value equals the column value
under toggle=true. Positively proves the index branch is skipped rather
than just checking the API returns something.
- [x] Go unit (positive):
`TestLoadWithIndexPreferFieldDataWhenIndexHasRawData` — toggle=on,
asserts `HasFieldData=true`.
- [x] Go unit (negative): `TestLoadWithIndexSkipsFieldDataByDefault` —
toggle=off default, asserts `HasFieldData=false`. Guards the
memory-saving behavior existing deployments rely on.
- [ ] Integration smoke on local standalone.

## Trade-off

Enabling the toggle keeps both the raw field data and the index resident
in memory, roughly doubling the memory footprint for fields whose index
normally supplies raw data. The toggle is off by default, so no existing
deployment is affected.

issue: #49126

---------

Signed-off-by: Shawn Wang <shawn.wang@zilliz.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 00:05:46 +08:00
794710a7d5 enhance: configurable byte-size threshold for storage v2 cell packing (#49205)
## Summary

This PR ships two related commits:

1. **`enhance: fold calculate_size and write_to_target passes for
variable-length chunk writers`** — refactor String/JSON/Geometry chunk
writers from two Arrow passes (count + cache) to one Arrow pass that
fills a shared `offsets_` member. Eliminates per-row heap allocation (no
more `simdjson::padded_string` copies). `AssertInfo` guards `cursor <=
UINT32_MAX` before each narrowing cast so oversize chunks fail loudly
instead of silently wrapping.

2. **`enhance: configurable byte-size threshold for storage v2 cell
packing`** — replace the hardcoded `4 row groups per cell` constant with
a runtime-configurable byte-size target driven by
`queryNode.segcore.storageV2.cellTargetSizeBytes` (default `4 MiB`,
refreshable).
- At cell-build time, `rgs_per_cell = max(1, target /
avg_row_group_size)`, with cells never crossing file boundaries.
- Paramtable `Formatter` rejects non-positive values and falls back to 4
MiB with a warn log.
- Value pushed into segcore via a new CGO setter
(`SetStorageV2CellTargetSizeBytes`) on QueryNode startup and on
paramtable change, backed by an inline atomic in `GroupCTMeta.h`.

## Why

The fixed `4` constant does not scale across workloads: large row groups
make each cell too fat (coarse eviction, unpredictable memory), small
row groups waste cache slots and increase bookkeeping overhead. A
byte-target keeps cache cell footprint predictable regardless of parquet
row group layout, and gives operators a runtime tuning knob. Default 4
MiB preserves the prior `4 rgs × ~1 MiB/rg` footprint.

## Test plan

- [x] Dedicated `ComputeRowGroupsPerCell` unit tests with hardcoded
expected outputs pin helper behavior independently of the translator
integration tests.
- [x] `GroupChunkTranslatorTest` / `ManifestGroupTranslatorTest` read
`GetCellTargetSizeBytes()` so assertions track production.
- [ ] CI: `ci-v2/build-ut-cov`, `ci-v2/e2e-amd`
- [ ] Manual: toggle `queryNode.segcore.storageV2.cellTargetSizeBytes`
at runtime and confirm newly loaded segments observe the new pack size.

issue: #49204

---------

Signed-off-by: Shawn Wang <shawn.wang@zilliz.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 14:41:45 +08:00
5409a81f40 feat: support TEXT column with LOB storage for large text fields (#47567)
issue: #48783
design doc:
https://github.com/milvus-io/milvus-design-docs/blob/main/design_docs/20260407-text_lob_storage.md

Signed-off-by: luzhang <luzhang@zilliz.com>
Co-authored-by: luzhang <luzhang@zilliz.com>
2026-04-24 14:25:45 +08:00
wei liuandGitHub a10b7a20e9 enhance: [ExternalTable Part8 - 4/4] external segment load — reduce overhead, memory estimation, drop fragment mapping (#49176)
## Summary

Part 4/4 of the External Table Part 8 series. End-to-end optimization of
external segment load:
reduce the actual memory consumed during load via virtual system fields
and per-field column
projection, predict memory via row sampling injected as a synthetic
binlog so QueryNode can
reserve resources accurately, and drop the now-obsolete fragment row
mapping.

**Depends on [#49062](https://github.com/milvus-io/milvus/pull/49062)
(Part 2/4 control plane).**
Parallel to [#49172](https://github.com/milvus-io/milvus/pull/49172)
(Part 3/4 Iceberg) — no content dependency between 3/4 and 4/4.
This PR is stacked on top of #49062 — the diff includes both commits;
review the 4/4 commit in isolation via the "Commits" tab.

Related: [#45881](https://github.com/milvus-io/milvus/issues/45881)
(External Collection Lakehouse Integration tracking).

### Reduce load overhead

- **VirtualPKOffsetMap**: zero-storage OffsetMap for external
collections. Virtual PK = `(seg_id << 32) | offset`, so `pk→offset` is a
bit-extract, replacing `OffsetOrderedArray` — saves ~17 GB per 1B rows.
- **TimestampData**: compact timestamp container with lazy
materialization and a constant mode. External segments install constant
timestamps (all 0, rows always visible) — saves ~8 GB per 1B rows.
- **LoadColumnGroups per-field column projection**: split each column
group's fields into eager (`warmup=sync/async`) and lazy
(`warmup=disable`) subsets. Eager fields submit one task per group; lazy
fields submit one task per field so accessing one lazy field does not
co-load siblings from S3.
- Guard `reader_` assignment in `LoadColumnGroups` with `reader_mutex_`.
- Observability: `TaskStart / TaskDone / WaitStart / WaitOne /
WaitOneDone / WaitOneFail` with segment_id, cg index and elapsed time;
emit total elapsed on completion.

### Memory estimation via row sampling (fake binlog injection)

External table segments have no `BinlogPaths` and no format-level size
stats that can be trusted; inject a synthetic binlog so external
segments look like normal packed segments to downstream code.
- C++ `SampleExternalSegmentFieldSizes` (`external_utils_c.{cpp,h}`):
open a schemaless Reader against the manifest, `Take` N rows, measure
per-column Arrow buffer bytes/row.
- Go `SampleExternalFieldSizes` in `storagev2/packed` (shared by
QueryNode and DataNode).
- DataNode `buildFakeBinlogs()` at refresh time: pre-compute
`MemorySize` via sampling, synthesize `FieldBinlog` (`FieldID=0` with
`ChildFields`, allocator-assigned `LogID`, two IDs per segment), attach
to segment.
- DataCoord drops `ManifestPath` special-case checks; external segments
flow through the same code path as normal StorageV3 packed segments.
- `ManifestGroupTranslator` accepts `fallback_bytes_per_row`: when
format metadata reports `memory_size=0` for a cell, size it as
`cell_rows * bytes_per_row` instead of a 4KB last-resort.
- QueryNode `segment_loader` part 2.5: derive `fakeBinlogMemSize` from
`loadInfo.BinlogPaths`, set `EstimatedBytesPerRow = fakeBinlogMemSize /
numRows`, apply `externalRawDataFactor` only to the extra margin
(`factor - 1`), and subtract `fakeBinlogMemSize` under fully-lazy load.
- `isExternalCollectionLazyLoad` helper with companion test.
- `query_coord.proto` / `segcore.proto`: add `estimated_bytes_per_row`.
- Paramtable: external collection sample rows and rawDataFactor.

### Drop fragment row mapping

With fake binlogs in place, the fragment-level row index is no longer
consulted. Remove `SegmentRowMapping` / `FragmentRowRange` /
`NewSegmentRowMapping` / `GetFragmentByRowIndex`. The simplified task
tracks only segment-level state.

### 4-PR series scope

1/4 cross-bucket, schemaless reader, force nullable — merged in
[#49061](https://github.com/milvus-io/milvus/pull/49061)
2/4 control plane — DDL validation, refresh infrastructure —
[#49062](https://github.com/milvus-io/milvus/pull/49062)
3/4 Iceberg external table support —
[#49172](https://github.com/milvus-io/milvus/pull/49172)
4/4 **external segment load — reduce overhead, memory estimation, drop
fragment mapping** — this PR

## Test Plan

- [x] C++ unit tests (`TimestampDataTest`,
`InsertRecordOffsetOrderedArrayTest`, segcore load path)
- [x] Go unit tests under `internal/datanode/external`,
`internal/storagev2/packed`, `internal/querynodev2/segments`,
`internal/datacoord`
- [x] E2E refresh regression
(`tests/go_client/testcases/external_table_refresh_test.go`)
- [x] golangci-lint clean on all changed packages

Signed-off-by: Wei Liu <wei.liu@zilliz.com>
2026-04-23 10:15:48 +08:00
XuanYang-cnandGitHub 8fb3fef283 fix: self-heal compaction segment positions and add L0 force-select bypass (#48907)
Compaction inherits StartPosition/DmlPosition from source segments via
getMinPosition without recalculating from actual data. The import
position bug (PR #47276) wrote wrong timestamps on imported segments,
and these wrong positions persist and propagate through compaction. L0
compaction then misses L1/L2 segments due to StartPosition mismatches,
causing zombie L0 segments and silent delete loss.

There is also a latent bug: DmlPosition in mix/clustering compaction
uses getMinPosition, but DmlPosition represents the latest entity
timestamp and should use max.

See also: #46435

Signed-off-by: yangxuan <xuan.yang@zilliz.com>
2026-04-22 19:57:45 +08:00
919bdf15ba enhance: expose arrow IO thread pool capacity via paramtable (#49208)
## Summary

Expose Arrow's internal IO thread pool capacity as a refreshable
paramtable knob so operators can raise it beyond Arrow's fixed default
of 8, independently of segcore `HIGH/MIDDLE` pools and
`minio.maxConnections`.

- New keys (both refreshable, `common` scope):
- `common.arrow.ioThreadPoolCoefficient` (default `0` → keep Arrow's
built-in default)
  - `common.arrow.ioThreadPoolMaxCapacity` (default `0` → no cap)
- Effective size = `coefficient × CPU cores`, clamped by `maxCapacity`
when `> 0`.
- Wired through `init_c.{h,cpp}` + `initcore` + QueryNode paramtable
watcher; hot reloads apply without restart.

## Why

`GetIOThreadPool` runs the async range reads behind `ReadRangeCache`,
which is what actually issues S3 `GetObject` for storage v2 reads.
Milvus never calls `SetIOThreadPoolCapacity`, so this pool sticks at
Arrow's fixed default (`kDefaultNumIoThreads = 8` in arrow 17). Off-CPU
profiling on a QueryNode under heavy storage v2 load shows ~62% of
`HIGH`-pool wait time sitting on `curl_easy_perform -> poll` —
`HIGH`-pool threads blocked inside `ReadRangeCache::Wait` because
Arrow's IO pool cannot dispatch their range reads fast enough.

## Test plan

- [ ] CI: `ci-v2/build-ut-cov`, `ci-v2/e2e-amd`
- [ ] Manual: set `common.arrow.ioThreadPoolCoefficient=4` on a
QueryNode, confirm the `arrow io thread pool capacity set to N` log at
startup and that the pool is resized on subsequent config edits.
- [ ] Manual: re-run the storage-v2-heavy workload that produced the
off-CPU profile and confirm `curl_easy_perform -> poll` share drops from
~62%.

issue: #49207

---------

Signed-off-by: Shawn Wang <shawn.wang@zilliz.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 18:11:45 +08:00
fab6c33dce enhance: fast-fail for proxy-to-QueryNode gRPC retry and delegator stall detection (#49102)
issue: #48185

- Add retry.WithMaxAttemptsContext to cap inner gRPC client retry from
caller's context, enabling proxy LBPolicy to failover to another replica
immediately instead of burning the full backoff budget (~13s) on a dead
QueryNode.
- Apply retry cap=1 to searchShard, queryShard (covers requery path),
and HighlightTask.getHighlightOnShardleader.
- Fast-fail on connection closing error in gRPC client to avoid
unnecessary retries on dead connections.
- Fast-fail for delegator forward delete on ServerIDMismatch.
- waitTSafe stall detection using ContextCond with configurable
stallTimeout (queryNode.waitTsafeStallTimeout, default 3s).
- Mark segments offline on ServerIDMismatch in Search/Query/QueryStream
paths (in addition to existing ErrNodeNotFound handling).
- Fix nil pointer panic in IsServerIDMismatchErr and
IsCrossClusterRoutingErr when called with nil error.
- Add cache for ParamItem.GetAsDurationByParse.

Signed-off-by: chyezh <chyezh@outlook.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-22 16:01:45 +08:00
e6070874f8 enhance: make BM25 stats per-entry memory cost configurable, default 20 (#49145)
## Summary
Two improvements to BM25 stats memory accounting in idfOracle:

### 1. Per-entry estimate: 80 → 20 bytes/entry
The previous hardcoded `bm25StatsPerEntryBytes = 80` overestimates
`map[uint32]int32` memory by 4-7x. Empirical measurement on Go 1.24
(median of 5 runs, n ≥ 10K to avoid GC noise):

| n | heap delta | bytes/entry | overestimate vs 80 |
|---|---|---|---|
| 10K | 152 KB | 15.22 | 5.2× |
| 100K | 1.22 MB | 12.18 | 6.6× |
| 1M | 19.4 MB | 19.43 | 4.1× |
| 5M | 77.9 MB | 15.58 | 5.1× |
| 10M | 156 MB | 15.58 | 5.1× |
| 50M | 623 MB | 12.47 | 6.4× |

Steady-state cost oscillates between **12 and 19.5 bytes/entry**
depending on the swiss table fill ratio (peak ~19.5 right after a 2×
capacity grow, trough ~12 when near load factor 7/8).

Root cause: the original comment claimed "bucket overhead ~72B per
entry", but Go map buckets/groups hold 8 entries each, so amortized
overhead is ~10 bytes/entry, not 72.

**Fix**: lower the default to 20 (covers measured upper bound 19.5 with
small safety margin) and expose as
`queryNode.idfOracle.bm25StatsBytesPerEntry` (refreshable) for runtime
tuning.

### 2. Skip cgo Charge/Refund when tiered eviction is disabled
When `queryNode.segcore.tieredStorage.evictionEnabled = false` (the
default), the C++ caching layer's resource accounting is inert — no
eviction will be driven by it. The per-load `C.ChargeLoadedResource` /
`C.RefundLoadedResource` cgo calls are pure overhead in this case.

**Fix**: gate `syncResource` and `checkMemoryResource` on the eviction
flag. Skip entirely when eviction is off.

## Impact
- ~75% reduction in cache budget consumed by BM25 stats (when eviction
enabled)
- Eliminates per-segment cgo overhead in default deployments (eviction
off)
- Tunable per-entry estimate without redeploying

## Test plan
- [x] `TestIDFOracle` passes
- [x] `TestBM25Stats_MemSize` passes with the new configurable value
- [x] Verified memory measurement methodology with multiple sample sizes

issue: #46468

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Signed-off-by: aoiasd <zhicheng.yue@zilliz.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-20 19:47:44 +08:00
wei liuandGitHub 649fc385aa enhance: [ExternalTable Part8 - 1/4] cross-bucket, schemaless reader, force nullable (#49061)
issue: #45881
## Summary

Part 1/4 of the External Table Part 8 series. Foundation layer for
external collections — delivers data-plane primitives that Parts 2–4
build on.

- **Cross-bucket external data source**: detect same-bucket prefix;
route non-matching paths through `extfs`.
- **Schemaless reader**: open reader with `nullptr` arrow schema +
explicit `needed_columns` projection instead of full pre-built arrow
schema.
- **Force nullable**: external user fields set to `nullable=true` so
Arrow buffers from external sources are consumed uniformly (`valid_data`
populated in `ArrowToDataArray`).
- **API cleanup**: replace `external_access_mode` string with
`use_take_for_output` bool.
- **Load optimization**: skip redundant S3 data pull during segment
load.
- **Shared helper**: new `pkg/util/externalspec` parsing package +
paramtable entries (100% test coverage).
- **Arrow codecs**: enable snappy/lz4 in Arrow build (fixes
[#48869](https://github.com/milvus-io/milvus/issues/48869)).

Related to [#45881](https://github.com/milvus-io/milvus/issues/45881)
(External Collection with Lakehouse Integration tracking).

## Why split this way

This PR intentionally excludes the refresh pipeline
(manager/checker/inspector/task, schema DDL updater, refresh task
update, e2e refresh tests) — those land in Part 2/4. Each PR stays on a
single theme for reviewability.

## Test plan

- [x] \`make milvus\` — clean build
- [x] \`go build -tags dynamic,test ./... && cd pkg && go build -tags
dynamic,test ./...\` — 0 errors
- [x] \`go test -tags dynamic,test ./internal/datanode/external/...
./internal/storagev2/packed/...\` — 66 PASS / 0 FAIL
- [x] \`go test -tags dynamic,test ./pkg/v2/util/externalspec/...\` — 15
PASS, 100% coverage
- [x] \`golangci-lint run --build-tags=dynamic,test\` on all changed
packages — 0 issues
- [ ] CI validation (ut-go / ut-cpp / integration-test / e2e)

Signed-off-by: Wei Liu <wei.liu@zilliz.com>
2026-04-20 10:25:43 +08:00
8bc1597ee9 enhance: increase L0 compaction max deltalog count to 1000 (#47214)
This change increases the default value of deltalogMaxNum from 30 to
1000 in L0 compaction force trigger settings. This allows more segments
to be included in a single L0 compaction operation.

The change is safe because:
- We already have a maxSize limiter
(dataCoord.compaction.levelzero.forceTrigger.maxSize) that caps the
total size at 64MB, preventing excessive memory usage
- This only affects the maximum count allowed, not the minimum force
trigger threshold (deltalogMinNum: 10)
- Systems will still respect the size limit even if many small segments
are present

Resolves #46650

Signed-off-by: yangxuan <xuan.yang@zilliz.com>
Co-authored-by: Warp <agent@warp.dev>
2026-04-16 19:31:32 +08:00
0fb4ce552f enhance: implement streaming node resource group support (#47315)
issue: #47314

1. **Streaming Node Resource Group Isolation** — Core feature:
`Balancer` interface returns `StreamingNodeInfoWithResourceGroup`;
`ReplicaManager` assigns SQNs per-RG when
`streaming.strictResourceGroupIsolation.enabled=true`;
`HandleAlterConfig` rewritten for atomic batch updates; new
`HandleReplicaLoadConfigCompliance` endpoint for ops compliance checks.
2. **RESTful GET config endpoint** — `GET
/management/config/get?keys=k1,k2,k3` returns structured ordered results
with `key`, `value`, `source`, and `error` fields.

---------

Signed-off-by: chyezh <chyezh@outlook.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-16 16:53:42 +08:00
wei liuandGitHub e87cc36e82 enhance: bind snapshot lifecycle to collection (#48143)
## Summary
- Refactor snapshot name uniqueness from global to per-collection scope
- Add cascade delete: DropCollection triggers DropSnapshotsByCollection
- Add orphan snapshot GC for deleted collections
- Add database-level filtering for ListSnapshots and
ListRestoreSnapshotJobs
- Distinguish source/target collection in RestoreSnapshot API
- Move snapshot privileges from Global level to Collection level
- Update client SDK and documentation for new API semantics

issue: #44358
issue: #47890
issue: #47883
issue: #47855

## Test plan
- [x] Unit tests for snapshot_meta (DropSnapshotsByCollection,
per-collection isolation, partial failure)
- [x] Unit tests for snapshot_manager (DropSnapshotsByCollection,
getDBCollectionIDs)
- [x] Unit tests for services (ListSnapshots/ListRestoreJobs with dbID,
RestoreSnapshot with source collectionID)
- [x] Unit tests for ddl_callbacks_snapshot (new
dropSnapshotsByCollection callback)
- [x] Unit tests for garbage_collector (orphan snapshot GC)
- [x] E2E tests for cross-database snapshot isolation
- [ ] CI validation

## Note on skipped Python E2E tests
All 18 snapshot test classes in
`tests/python_client/milvus_client/test_milvus_client_snapshot.py` are
temporarily skipped with `@pytest.mark.skip`. Reason: this PR changes
snapshot APIs (DropSnapshot, DescribeSnapshot, RestoreSnapshot) to
require `collection_name` as a mandatory parameter, but the pymilvus SDK
used in CI has not been updated to pass this parameter yet. The tests
will be re-enabled once pymilvus SDK is updated to match the new API
contract.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

design doc:
https://github.com/milvus-io/milvus-design-docs/blob/main/design_docs/20251114-snapshot_design.md

---------

Signed-off-by: Wei Liu <wei.liu@zilliz.com>
2026-04-16 15:45:43 +08:00
wei liuandGitHub 80af30b353 enhance: add compaction protection for snapshots (#48227)
## Summary
- Add `compaction_protection_seconds` parameter to snapshot creation
API, allowing users to protect referenced segments from compaction for a
specified duration
- Implement dual-layer compaction protection: collection-level
fail-closed blocking (during RefIndex loading) + segment-level
expiry-based protection (after RefIndex loads)
- Protect all compaction paths: single, clustering, force-merge,
storage-version, and compaction trigger candidates

issue: https://github.com/milvus-io/milvus/issues/44358
design doc:
https://github.com/milvus-io/milvus-design-docs/blob/main/design_docs/20251114-snapshot_design.md

## Test plan
- [x] Unit tests for `IsCollectionCompactionBlocked` (7 subtests
covering blocked/unblocked/expired/multi-collection scenarios)
- [x] Unit tests for `IsSegmentCompactionProtected` and segment
protection rebuild
- [x] Unit tests for `CreateSnapshot` with
`compaction_protection_seconds` parameter
- [x] Unit tests for proxy-side validation (negative values, exceeding
max 7 days)
- [x] DDL callback tests with compaction protection parameter
- [x] Build verification (`make milvus` passes)
- [x] Lint verification (`make lint-fix` passes)
- [ ] E2E: Create snapshot with compaction protection → verify segments
are not compacted during protection window
- [ ] E2E: Verify compaction resumes after protection expires

🤖 Generated with [Claude Code](https://claude.com/claude-code)

pr: https://github.com/milvus-io/milvus-proto/pull/574

---------

Signed-off-by: Wei Liu <wei.liu@zilliz.com>
2026-04-14 20:13:42 +08:00
8652cbdf1a enhance: add requery policy parameter for regular search (#48925)
## Summary
- Add `common.requery.searchPolicy` config parameter to control when
regular search performs requery
- Symmetric to existing `common.requery.hybridSearchPolicy` for hybrid
search
- Supports three policies: `always`, `outputvector` (default),
`outputfields`
- Default `outputvector` preserves existing behavior — fully backward
compatible

issue: https://github.com/milvus-io/milvus/issues/48924

## Test plan
- [x] Unit tests: 11 test cases covering all policy branches,
functionScore interaction, case insensitivity
- [x] Changed code coverage: 100%
- [x] Build: passes on macOS arm64
- [x] Lint: passes golangci-lint

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Signed-off-by: Wei Liu <wei.liu@zilliz.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 18:25:41 +08:00
sparknackandGitHub e537d292a1 fix: await background load futures during cancellation and fix loadingTimeoutMs default (#48855)
## Summary
- Await background load futures in `GroupChunkTranslator` and
`ManifestGroupTranslator` cancellation cleanup paths to prevent
use-after-free / dangling futures
- Add `CheckCancellation` calls in `LoadCellBatchAsync` loop for prompt
cancellation
- Fix `tieredStorage.loadingTimeoutMs` default from `0` (immediate
failure) to `-1` (no timeout)

issue: #48854

## Test plan
- [x] Added unit test `CancellationStopsMidBatchPush` verifying
mid-batch cancellation stops loading and raises `FollyCancel`
- [ ] CI passes

---------

Signed-off-by: Shawn Wang <shawn.wang@zilliz.com>
2026-04-13 16:39:40 +08:00
ab87a3f825 fix: buffer cm.Reader in BM25 streamOneFile to reduce IO syscalls (#48845)
## Summary
- Wraps `cm.Reader` (S3/MinIO HTTP body) with `bufio.NewReader` in
`streamOneFile` before creating the TeeReader
- `DeserializeFromReader` calls `binary.Read` which reads 4/8 bytes per
call; without buffering, each small read hits the remote reader
directly, causing excessive IO operations during preload parsing
- With `bufio.Reader` (default 4KB buffer), small reads are served from
the buffer, reducing remote IO to ~1 per 4KB

## Test plan
- [x] Existing `TestIDFOracle` tests pass
- [x] Verified via profiling that IO syscall count drops significantly
during BM25 preload

issue: #46468

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Signed-off-by: aoiasd <zhicheng.yue@zilliz.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 10:37:40 +08:00
91cf2cce39 enhance: add visibilityFilterEnabled and bloomFilterEnabled toggles for querynode optimization (#48701)
## Summary
- Add `common.visibilityFilterEnabled` toggle to bypass row visibility
filtering (timestamp, delete, and TTL) on querynode. When disabled, all
rows are returned regardless of insert/delete timestamps, improving
performance for workloads that don't need timestamp consistency.
- Add `common.bloomFilterEnabled` toggle to skip bloom filter/PK stats
loading on querynode, reducing memory for workloads without delete or
search-by-id. Delete forwarding falls back to broadcast mode when
disabled.

issue: #48703

## Test plan
- [ ] Unit tests for bloom filter disabled path
(`TestLoadSegmentsWithoutBloomFilter`, `TestLoadWithoutBloomFilter`)
- [ ] Unit tests for nil candidate broadcast in delete forwarding
- [ ] Unit tests for visibility filter bypass with
`visibilityFilterEnabled=false`
- [ ] Verify no nil pointer panics when bloom filter is disabled
- [ ] Integration test with `bloomFilterEnabled=false` and
`visibilityFilterEnabled=false`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Signed-off-by: Shawn Wang <shawn.wang@zilliz.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 19:49:41 +08:00
1979c03e11 enhance: delegator-side segment pruning via PK predicate hints (#47805)
## Summary

Prune sealed segments at the shard delegator layer using primary-key
(PK) predicate hints before dispatching search/query sub-tasks to worker
nodes. The delegator evaluates a lightweight PK predicate IR against
per-segment bloom-filter candidates it maintains in memory (`pkoracle`),
removing segments that are provably non-matching before any worker RPC
is issued.

issue: #47804

---

## Background

When a search/query request carries a PK predicate (e.g. `id == 5`, `id
IN [1,2,3]`, `1 < id < 100`), the delegator currently fans out the
request to all workers that own sealed segments, even if a worker's
segments provably contain no matching PKs. This causes unnecessary C++
vector-search kernel invocations, wasting CPU, I/O, and network.

The delegator already holds a `pkoracle.Candidate` for every sealed
segment it manages. Each candidate contains a bloom filter and min/max
PK statistics — sufficient to definitively exclude non-matching segments
before any sub-task is dispatched.

---

## Design

### 1. Proxy: \`pk_filter\` hint field

A new \`pk_filter int32\` field on \`SearchRequest\` /
\`RetrieveRequest\` carries a proxy-set hint:

| Value | Constant | Meaning |
|-------|----------|---------|
| \`0\` | \`PkFilterNotChecked\` | Old proxy / not analysed — delegator
attempts compilation (backward compat) |
| \`1\` | \`PkFilterHasPkFilter\` | Proxy confirmed optimisable PK
predicate exists |
| \`2\` | \`PkFilterNoPkFilter\` | Proxy confirmed no PK predicate —
delegator skips plan deserialization |

\`HasOptimizablePkPredicate\` in
\`internal/util/exprutil/expr_checker.go\` walks the expression tree:
TermExpr / UnaryRangeExpr / BinaryRangeExpr on a PK column, or an AND of
those, are considered optimisable. OR requires both sides to carry a PK
predicate; NOT is not optimisable.

**Backward compatible:** \`pk_filter\` wire-default is \`0\`
(NotChecked). Old proxies require no changes.

### 2. Delegator: \`PruneSealedSegmentsByPKFilter\`

Called in \`delegator.Search\`, \`delegator.Query\`, and
\`delegator.QueryStream\` after the sealed snapshot is obtained but
before \`organizeSubTask\` dispatches sub-requests:

1. If \`pkFilter == NoPkFilter\`, return immediately (no
deserialization).
2. Unmarshal plan, compile \`PKFilterExpr\` IR.
3. For each \`SnapshotItem\`, collect \`entry.Candidate\` as
\`PKFilterTarget\` and call \`CheckPKFilter\`.
4. Remove non-matching \`SegmentEntry\` in-place.
5. \`organizeSubTask\` automatically skips workers whose segment list is
now empty.

Controlled by \`queryNode.enableSegmentFilter\` (default \`true\`,
hot-reloadable).

### 3. PK Filter IR (\`pk_filter.go\`)

Typed expression tree compiled once per request in the delegator
package:

| Node | Semantics |
|------|-----------|
| \`pkFilterTermExpr\` | \`pk IN [v1, v2, ...]\` |
| \`pkFilterUnaryRangeExpr\` | \`pk op value\` |
| \`pkFilterBinaryRangeExpr\` | \`lo (</<=) pk (</<=) hi\` |
| \`pkFilterLogicalExpr\` | \`AND / OR\` |
| \`pkFilterUnsupportedExpr\` | fallback — keeps all segments |

### 4. \`PKFilterTarget\` interface (\`pkoracle\`)

\`BloomFilterSet\` implements \`GetMinPk()\` / \`GetMaxPk()\` (global
min/max across all stat blobs) and satisfies the \`PKFilterTarget\`
interface used by the IR evaluator.

### 5. Metrics

| Metric | Description |
|--------|-------------|
| \`milvus_querynode_segment_filter_total_segment_num\` | Total segments
considered |
| \`milvus_querynode_segment_filter_skipped_segment_num\` | Segments
pruned |
| \`milvus_querynode_segment_filter_hit_segment_num\` | Segments that
passed the filter |

### 6. Incidental cleanup

- Remove stale \`SearchRequest.PkFilter()\` / \`SetPkFilter()\`
accessors (no callers).
- Remove \`SearchTask.plan\` field and its \`PreExecute\`
deserialization (\`Execute\` never reads it; segcore re-parses from raw
bytes internally).
- Fix stale comment in \`QueryTask\`.
- Add Apache license header to \`segment_filter_helper.go\`.

---

## Test Plan

- [x] \`TestCheckPKFilter\` — term / range / AND / OR all cases
- [x] \`TestBuildPKFilterExprFromSearchPlan\` — extract predicates from
search plan
- [x] \`TestHasOptimizablePkPredicate\` — all predicate types + logical
operators
- [x] \`TestCheckPKFilterEmptyTermExpr\` — empty IN [] edge case
- [ ] CI /ci-rerun-ut-go
- [ ] CI /ci-rerun-ut-integration

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Signed-off-by: xiaofanluan <xiaofan.luan@zilliz.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 02:59:41 +08:00
3475e2cd80 enhance: zero-copy search result passing between QueryNode and Proxy (#48648)
## Summary

- Add `PinnedRef[T]` smart pointer and `NewSharedPinnedRefs` for
ref-counted ownership across merged search tasks
- Add `PinnedResourceManager` (sync.Map registry) and `MsgPins` global
instance; `MsgPinnable` marker interface limits codec overhead to
`SearchResults` only
- Add `releaseCodec` (gRPC `CodecV2` wrapper) that frees pinned C memory
after marshaling
- Two-phase reduce in `SearchTask.Execute`: Phase 1 builds results with
full cleanup on error; Phase 2 pins blobs or releases C memory
immediately
- Gate entire zero-copy path with `QueryNodeCfg.EnableResultZeroCopy`
(default off)

issue: #48668

## Test plan

- [ ] `go test ./pkg/util/resource/...` — PinnedRef,
PinnedResourceManager, releaseCodec unit tests
- [ ] `go test ./internal/querynodev2/tasks/...` — SearchTask two-phase
reduce
- [ ] `go test ./internal/proxy/...` — delegator reduce path
- [ ] Enable `queryNode.enableResultZeroCopy: true` and run search
workload end-to-end

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Signed-off-by: xiaofanluan <xiaofan.luan@zilliz.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 02:41:36 +08:00
bc2132d7e1 enhance: streaming BM25 stats load with disk-first strategy (#48216)
relate: #41424

## Summary
- Stream BM25 stats directly to local disk via TeeReader/io.Copy,
avoiding full in-memory download and re-serialization
- Add caching layer resource tracking (Charge/Refund) for BM25 memory
and disk usage
- Add `queryNode.idfOracle.preload` to defer stats parsing to first
SyncDistribution

---------

Signed-off-by: aoiasd <zhicheng.yue@zilliz.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 16:13:42 +08:00
sparknackandGitHub 3e1d75af72 enhance: bump milvus-common to 5983a18 with warmup timeout and runtime config support (#48505)
issue: #48507

Update milvus-common to 5983a18 which adds warmup loading timeout,
runtime config hot-reload via TieredStorageConfig, and DList reservation
fixes. Wire through the new warmup_loading_timeout parameter and add
UpdateTieredStorageConfig CGO binding with config change callbacks for
runtime updates.

Signed-off-by: Shawn Wang <shawn.wang@zilliz.com>
2026-03-30 20:19:31 +08:00
6d38c7fd25 enhance: increase force merge memory safety factor from 1/3 to 1/4 (#48474)
## Summary
- Increase `forceMerge.dataNodeMemoryFactor` and
`forceMerge.queryNodeMemoryFactor` defaults from 3.0 to 4.0
- This reduces the max segment size produced by force merge compaction
(from 1/3 to 1/4 of node memory), preventing DataNode from producing
segments too large to index

Signed-off-by: yangxuan <xuan.yang@zilliz.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

Signed-off-by: yangxuan <xuan.yang@zilliz.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 14:53:32 +08:00
b0ec4a2dd8 fix: upgrade Go to 1.25.8 for CVE-2025-68121, CVE-2026-27142, CVE-2026-25679 (#48286)
issue: #48574

## Summary
- Upgrade Go from 1.24.12 to 1.25.8 across all go.mod files and
Dockerfiles
- Fixes CVE-2025-68121 (CRITICAL), CVE-2026-27142 (HIGH), CVE-2026-25679
(HIGH) in Go stdlib
- All three CVEs affect the Go standard library and are resolved by
upgrading to Go 1.25.8

## Changes
- Updated `go` directive in go.mod files (root, pkg/, client/,
tests/go_client/, examples/)
- Updated Go download URLs in Dockerfiles (build/docker/builder/)
- Updated `toolchain` directives where present

issue: https://github.com/milvus-io/milvus/issues/TBD

## Test plan
- [x] `make milvus` builds successfully with Go 1.25.8
- [ ] CI passes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Signed-off-by: Li Liu <li.liu@zilliz.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 14:23:30 +08:00