mirror of
https://github.com/milvus-io/milvus.git
synced 2026-10-12 02:19:10 +00:00
master
2445
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
1e943dc23b |
test: Increase PyMilvus version to 3.1.0rc92 from master for master branch (#54068)
Automated bump from pymilvus master branch to milvus master branch. Updates tests/python_client/requirements.txt. Signed-off-by: pymilvus-bot <[email protected]> |
||
|
|
8cfeb14750 |
test: Enable hybrid rerank chain test (#54041)
issue: https://github.com/milvus-io/milvus/issues/46565 Signed-off-by: junjie.jiang <[email protected]> |
||
|
|
d1cb277f0c |
test: wait for compactable segments in struct partial-update lifecycle (#53964)
issue: #53962 The Struct Array partial-update lifecycle test can request manual compaction while its freshly flushed segments are still being sorted. DataCoord then returns the valid no-plan result `-1`, and the immediate positive-ID assertion fails before the compaction/reload checks run. Wait for vector-index readiness, then retry only `-1` against a monotonic 120-second deadline, passing the remaining budget to each compact RPC. Require an accepted compaction to complete and check the baseline both immediately afterward and after release/load. RPC failures, unexpected IDs, timeouts, and data mismatches remain failures. This follows the existing Struct nullable lifecycle test's approach from #52108. The observed failure is in [PR #53941's E2E run](https://jenkins-milvus-ci.milvus.io/job/MILVUS-CI-V2-PR-PIPELINES/job/milvus-e2e-pipeline-gcp/61102/console); this change does not modify server compaction behavior. Validation: - Ruff lint and format checks, Python syntax compilation, and `git diff --check`. - Executed the changed statements extracted from the actual file with simulated time/RPC responses: retry then success, persistent no-plan timeout, invalid IDs, RPC failure, index/compaction wait failures, and both post-compaction and post-reload data mismatches. - Live E2E has not been run against this fix locally; CI validation is pending. The separately requested rerun of #53941 uses its original head and does not validate this patch. Signed-off-by: xiaofanluan <[email protected]> Co-authored-by: xiaofanluan <[email protected]> |
||
|
|
15fcd798cf |
test: add continuous streaming data integrity draft (#53307) (#53868)
issue: #53307 ## What changed - Add a Phase 2 draft continuous-streaming DataIntegrity L3 workload with concurrent MutationIngress and ImportIngress lanes, no manual flush, and no manual compaction during streaming. - Extend the Phase 1 framework through opt-in sequence, level, and filtered-verification helpers while keeping existing cases unchanged. - Add the Phase 2 design contract and include the draft workload in the existing dedicated serial DataIntegrity job. - After automatic coverage and final ingress verification pass, request one post-ingress compaction and require Phase 1 lineage/serving checkpoints, fenced full-data verification, and release/load verification; this does not establish per-Delete L0 attribution. - Keep fixed epochs without producer/validator coordination; missing suffix progress fails with explicit coverage diagnostics for CI failure-rate measurement. ## Validation - Related DataIntegrity unit tests: 202 passed. - Ruff, format checks, and scoped git diff checks passed. - This review update was verified in medium mode; the new post-ingress compaction phase has not yet been rerun against a live cluster. Signed-off-by: MrPresent-Han <[email protected]> Co-authored-by: MrPresent-Han <[email protected]> Co-authored-by: GPT-5 <[email protected]> |
||
|
|
734acf93f0 |
test: expand import and snapshot restore data integrity coverage (#53820)
## Summary - Add Python client import coverage for nullable values, defaults, row identity, scalar boundaries, vector encodings, dynamic fields, BM25, geometry, and timestamps across supported file formats. - Cover multi-file progress, empty-file commit/abort, malformed input, and preservation of existing data after failed imports. - Correct legacy import fixtures and assertions, including JSON field NULLs and the distinction between non-finite and null array elements. - Verify packed Storage V2 binlog restore after adding nullable dense/sparse vectors. Native Storage V3 uses the snapshot export/restore path instead. - Strengthen the REST v2 L0 snapshot lifecycle test with per-row and schema comparisons, NULL filtering, vector search, restore after dropping the source snapshot and collection, reload checks, and exported-object cleanup. ## Validation Tested against Milvus commit `1ae8642b8b1` using `milvus-dev-cli` E2E runners. - REST v2 snapshot lifecycle: passed on Storage V2 (76.93s) and Storage V3 (77.97s). - Packed Storage V2 binlog restore: 2 passed (dense and sparse nullable vectors). - Nullable timestamp defaults: 3 passed (JSON, CSV, and Parquet). - Targeted import and legacy bulk-insert runs covered nullable values, defaults, partition keys, malformed files, vector encodings, scalar boundaries, dynamic fields, BM25, and invalid array elements. - Python import testcase collection after renaming: 60 cases collected. - Changed snapshot testcase: Ruff formatting/lint, Python compilation, and pytest collection passed. Renamed import testcase: Ruff lint, Python compilation, and pytest collection passed. Validation used targeted runs during development; the complete final branch test selection has not been rerun as one suite. Snapshot validation used serial REST runs. The default CI storage configuration is not changed by this PR. ## Scope Test-only changes. No production behavior changes. --------- Signed-off-by: zhuwenxing <[email protected]> |
||
|
|
ad4887b38c |
fix: support vector null predicates (#52442)
issue: #52239 ## Summary - Support IS NULL and IS NOT NULL predicates for ordinary vector fields. - Read logical-row validity through vector-index HasValidData/IsRowValid when raw field data is unavailable, remaining compatible with #50524's Knowhere IdMap ownership. - Rebase onto current master while preserving master's broader search-by-PK result reordering and tests. ## Test Plan - [x] Rebase onto master `38c4699891` with exactly two commits and no merge commit. - [x] `git range-diff` confirms both patches are unchanged by the rebase. - [x] `git diff --check origin/master...HEAD` - [x] `go test ./internal/parser/planparserv2` - [x] `go test -c -o /tmp/milvus-pr-52442-rebased-testcases.test ./testcases` (from `tests/go_client`) - [x] C++ clang-format, Rust format, and Go format checks. - [x] `bash scripts/check_segcore_error_boundaries.sh` - [x] `ruff check` for the four changed Python test files. - [x] `python3 -m py_compile` for the four changed Python test files. - [x] Pre-rebase private Release+ASan integration build at `d839d36b`; the rebased commits are patch-equivalent. - [ ] CI on rebased head `a9e9d31ff2`. --------- Signed-off-by: marcelo-cjl <[email protected]> |
||
|
|
215c79e293 |
test: wait for indexes in external table source override (#53883)
The external-table add-field source-override test can load a refreshed snapshot before its embedding index is ready. Use a FLAT/L2 index for this data/schema test and wait for `pending_index_rows == 0` before loading each refreshed snapshot. Validation: Python syntax parsing, helper-signature review, clang-format 15, and `git diff --check` pass. The Milvus/MinIO E2E case was not run locally. `make lint-fix` ran Go formatting, then stopped at unrelated native type-check errors in `internal/storagev2` (missing Loon filesystem metrics APIs). Signed-off-by: sunby <[email protected]> |
||
|
|
ca8c70ba6f |
build(deps): bump deepdiff from 8.6.1 to 8.6.2 in /tests/python_client (#53674)
Bumps [deepdiff](https://github.com/qlustered/deepdiff) from 8.6.1 to 8.6.2. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/qlustered/deepdiff/releases">deepdiff's releases</a>.</em></p> <blockquote> <p>8.6.2 - Fix (CVE-2025-58367)</p> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/qlustered/deepdiff/commit/0d07ec21d12b46ef4e489383b363eadc22d990fb"><code>0d07ec2</code></a> Merge commit from fork</li> <li><a href="https://github.com/qlustered/deepdiff/commit/791f5aac51b2da7f90375ab204256ef6a6b40206"><code>791f5aa</code></a> updating CVE number</li> <li><a href="https://github.com/qlustered/deepdiff/commit/a6aafea3ba5498aab6f9c77047c54949e7e968ae"><code>a6aafea</code></a> updating docs</li> <li><a href="https://github.com/qlustered/deepdiff/commit/a0950abbe6263298bc4bdbc3ebb57edc1af079b4"><code>a0950ab</code></a> Bump version: 8.6.1 → 8.6.2</li> <li><a href="https://github.com/qlustered/deepdiff/commit/887128abe5e510341cc4a82f6914a82d5ff1b6a7"><code>887128a</code></a> Fix (CVE-2025-58367)</li> <li>See full diff in <a href="https://github.com/qlustered/deepdiff/compare/8.6.1...8.6.2">compare view</a></li> </ul> </details> <br /> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/milvus-io/milvus/network/alerts). </details> Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
dde236e5f9 |
test: decouple external add-field type matrix from E2E (#53777)
## What changed
- Move the proto and PyMilvus DataType matrix check into a separate test
so enum changes cannot prevent the external add-field E2E from reaching
Milvus.
- Classify the new proto-only UUID type and check that DataType
categories are disjoint and cover both proto and SDK enums.
- Verify each added field's type, external field mapping, and nullable
setting before refresh and index creation.
## Verification
- Ruff check and format check passed.
- The standalone DataType matrix test passed with PyMilvus 3.1.0rc89.
- The targeted external add-field E2E passed against Milvus master
commit
|
||
|
|
06ba9d2298 |
enhance: refactor asynchronous WAL recovery and summary persistence (#53595)
issue: #40451 - WAL recovery: replace the legacy flusher with asynchronous VChannel/Segment persistence, retained-message completion, and owner-fenced snapshots before a single global checkpoint. Publish schemas before VChannel base metadata and use the base checkpoint to filter incomplete schema publication during recovery; delegate task concurrency to the shared NodeScheduler. Preserve transaction state through RecoveryBarrier with one scanner, reconcile legacy segment state during migration, and mark the WAL unavailable if background checkpoint persistence terminates unexpectedly. - WALSummary and idempotency: keep summaries and keyed-write deduplication always available; persist chunks/manifests independently, restore deduplication windows, provide bounded Delete reads, and manage WAL coverage, retention, and bootstrap replay boundaries. Seal on staged size or WAL tail pressure, report terminal Summary failures to the WAL owner, and perform physical GC outside reader/publication locks. Remove obsolete idempotency retention settings. - Data persistence: materialize missing function outputs before growing persistence, publish growing L1 data to DataCoord before completing Inserts, and track commits with DataVersion. Retire empty L1 segments explicitly through DataCoord without generating a manifest or publishing DataView; install the SN tombstone without a DataVersion only after retirement is confirmed, allowing ManualFlush to complete. Materialize retained Deletes into L0 using size, age, recovery pressure, or explicit WAL boundaries; retain the Summary-based materializer for future QueryView integration. Report complete recovery positions and poison work after WAL ownership loss. - Lifecycle completion: synchronize ManualFlush, FlushAll, and snapshot creation through consuming-side L1/L0 completion and broadcast acknowledgements. Let Broadcaster add CChannel centrally while callers supply the required collection VChannels. Rename the import ID-range update message to UpdateImport while preserving its payload and behavior. Preserve coordinator-owned Import visibility and legacy CommitImport completion during upgrades, and flush surviving partitions on DropPartition. Fence dropped objects in memory, publish durable tombstones only after asynchronous dependencies finish, and retire metadata and historical schemas through checkpoint- and Summary-gated GC. Cancel stale QueryCoord orphan-segment cleanup when a loaded collection reassigns the node to a replica. --------- Signed-off-by: chyezh <[email protected]> Co-authored-by: Claude Opus 4.6 <[email protected]> |
||
|
|
38c4699891 |
fix: Repair Spark backfill toolbox build dependencies (#53770)
The Spark backfill toolbox init container fails when the pinned Avro recipe downloads the unavailable 1.12.1 archive from Apache's current mirror. The source build also needs additional Rust prerequisites, and the clean Spark runtime cannot load JNI unless libaio is included in the artifacts. This change: - Builds Avro C++ 1.12.2 from its official archive with a pinned SHA256. Reuses only the existing pinned recipe's build instructions, exports a distinct local recipe, and forces the storage dependency graph to that exact revision. - Installs pkg-config, libssl-dev, libclang-dev, and protobuf-compiler for the Rust bridge. - Bundles libaio.so.1 alongside the Conan runtime libraries. - Records the Avro recipe reference in build evidence and documents the prerequisites. issue: #52130 ### Validation - Shell syntax, embedded Python syntax, and git diff --check pass. - Verified Conan source download/checksum and repeatable recipe export; the resolved storage graph uses Avro 1.12.2. - Completed a Kubernetes toolbox build with Spark 4.0.1 / Java 21 on Linux AMD64, using spark-milvus commit 37d2217fe64c352048db71e4c928068b8cdaada6. - Verified artifact hashes, all JNI shared-library dependencies (including Avro 1.12.2), Python imports, BackfillApp class loading, and JNI loading in the Spark JVM. - A local Spark/Parquet round trip returned 100 rows with ID sum 4950. The build completed using caches preserved across retries. The final libaio packaging step was tested separately against the built artifacts, followed by the clean-runtime checks above; a fresh full build was not repeated after that packaging-only change. Milvus/S3 backfill was not exercised. Assembly emitted warnings about skipped Java 21/22 multi-release entries; assembly and the listed runtime checks passed. Signed-off-by: Eric Hou <[email protected]> Co-authored-by: Eric Hou <[email protected]> |
||
|
|
2dfd51b8d7 |
test: add external table reload checker (#53784)
issue: #53778 ## Changes - Add `ExternalTableLoadChecker` to repeatedly release and load a fixed external collection, then verify its row count without refreshing the source. - Register `external_table_load` as a chaos operation. ## Verification - `ruff check tests/python_client/chaos/checker.py` - Python 3.12 compile and import checks for the checker and operation enum. Signed-off-by: zhuwenxing <[email protected]> |
||
|
|
8c317d2ce1 |
test: fix topology-dependent FunctionChain tests (#53743)
Remove three Python E2E cases that assume L1 rerank runs on globally merged candidates. L1 pagination and GroupBy candidate selection depend on how segments are distributed across workers. Add QueryNode regression tests for worker-local L1 pagination and GroupBy candidate selection before L1 rerank. issue: #53737 Signed-off-by: junjie.jiang <[email protected]> |
||
|
|
5ddad821c9 |
test: add V2 projection data-integrity case (#53307) (#53631)
issue: #53307 ## Summary - Add an independent L3 Storage V2 vector-projection workload: persist deterministic PK-bound narrow and wide vectors, verify the full dataset, drop the binary-vector field with schema bump disabled, and require an adopted MixCompaction rewrite before checking every retained cell. - Reuse the existing exclusive configuration fixture, lineage/serving checkpoints, full-retrieve fences, canonical byte comparisons, and cleanup; leave ordinary workloads, server code, and shared CI runners unchanged. - Pin both PyMilvus requirement entries to `3.1.0rc89`, whose published wheel includes `list_segments`, `list_compaction_tasks`, `list_loaded_segments`, and the required public enums. - Check dropped-index absence by field ownership (`list_indexes(..., field_name=dropped_field)`), with regression coverage for same-name and custom-name stale indexes and an unrelated index sharing the dropped field's name. - Cover deterministic payloads, row-preserving vector corruption, verification ordering, and configuration restoration across success and failure paths in the explicitly collected helper unit-test module; unequal field widths are adversarial inputs, not proof of a particular native reader refill. ## Verification - Isolated published `pymilvus==3.1.0rc89`, not the local editable SDK: 163 helper/oracle unit tests and 50 configuration/reporting/runner tests passed. - All 8 dedicated L3 workloads collect successfully; server-backed E2E was not rerun for this medium-mode update. - Negative control: restoring the old name-only assertion in memory causes 6 expected unit-test failures. - Scoped Ruff checks, Ruff format checks, and `git diff --check` passed. Signed-off-by: MrPresent-Han <[email protected]> Co-authored-by: MrPresent-Han <[email protected]> Co-authored-by: Codex <[email protected]> |
||
|
|
3cd8755ee2 |
test: update snapshot restore alias conflict expectation (#53682)
After #53547, restoring a snapshot to an existing alias is rejected during restore admission with code 1100 and an "already exists in database" message. The alias-conflict test still expected the later CreateCollection error. Update `test_restore_target_name_equals_existing_alias_fails` to match the admission error, explicitly assert code 1100, and correct its path documentation. Preserve the snapshot check and subsequent restore to a fresh target. Validation: - Reproduced the original assertion failure against Milvus commit `09d3618c818` with PyMilvus `3.1.0rc83`. - Targeted E2E on the same instance: 3 passed (alias target, existing collection target, and failed-restore resource cleanup). - Ruff lint/format, Python compilation, and `git diff --check` passed. Signed-off-by: zhuwenxing <[email protected]> |
||
|
|
eb7e63ebcf |
test: add Spark-Milvus backfill E2E coverage (#52155)
## What this PR does Adds dedicated Spark-Milvus Backfill E2E coverage and the runtime tooling needed to execute it against real Storage V3 and Storage V2 segments. - Adds opt-in, serial-only pytest coverage for Backfill modes, null semantics, snapshot boundaries, schema fencing, manifest versions, compaction, and invalid inputs. - Adds Kubernetes Job and reusable Spark Toolbox runners with credential redaction, RBAC validation, evidence collection, and cleanup. - Builds `zilliztech/spark-milvus` in the toolbox pod and runs Spark locally through the validated wrapper and native-library runtime. - Separates Storage V3 and Storage V2 execution through pytest markers and independent Milvus deployments. - Uses the dedicated `SparkBackfill` tag, so the normal `L0 L1 L2 ClusterOnly` nightly selection does not include this suite. - Documents manual toolbox deployment and dedicated-suite execution. Fixes #52130 ## Pipeline isolation The suite is ignored during ordinary Python client collection unless `--run-spark-backfill` is explicitly provided. The dedicated pipeline additionally selects `--tags SparkBackfill`; existing PR, nightly, and weekly tag sets therefore select zero Spark Backfill cases. V3 and V2 remain separate marker selections because they require different Milvus storage configurations and must run serially without pytest-xdist. ## Test plan - [x] Dedicated Spark Backfill pipeline completed successfully. - [x] Storage V3: 30 cases collected; 26 passed and 4 strict xfails track the known schema-fencing gap in #51318. - [x] Dedicated `SparkBackfill` tag collects 31 cases: 30 V3 and 1 V2. - [x] Normal nightly tags `L0 L1 L2 ClusterOnly` select 0 Spark Backfill cases, even when the opt-in collection gate is opened. - [x] `ruff check tests/python_client/common/common_type.py tests/python_client/conftest.py tests/python_client/spark_backfill` - [x] `git diff upstream/master...HEAD --check` ## Operational notes - Spark execution uses `spark-submit --master local[2]` in one toolbox pod. - The toolbox is discovered by `app=spark-milvus-toolbox` and is managed outside pytest. - V3 and V2 must use independent Milvus deployments. --------- Signed-off-by: Eric Hou <[email protected]> Co-authored-by: Eric Hou <[email protected]> Co-authored-by: Claude Opus 4.6 <[email protected]> |
||
|
|
fda7d59e39 |
test: fix missing primary key expectation for AutoID partition upsert (#53611)
AutoID collections support Upsert, but callers must supply a primary key for lookup. `test_partition_upsert_with_auto_id` omits that key, so PyMilvus rejects the request before sending an Upsert RPC. The expectation restored in #53158 incorrectly matched the server-side error. Expect SDK error code `1` and the missing-primary-key message, preserving the existing negative test. Validation: - Ruff lint/format, Python compilation, and pytest collection passed. - Targeted E2E passed with PyMilvus `3.1.0rc83` and Milvus commit `09d3618c818`: the corrected missing-key test passed; two diagnostic cases confirmed Int64/VarChar AutoID Upsert preserves existing IDs, allocates IDs for missing lookup keys, and supports partial updates. Diagnostic cases are not included in this PR. Signed-off-by: zhuwenxing <[email protected]> |
||
|
|
ed7c7ff0d6 |
fix: initialize Docker bind mount ownership (#53549)
issue: #51221 related: #49775 ## What this changes - Add a one-shot volume initializer to the CPU and GPU standalone Compose files. - Resolve the numeric UID/GID from the same Milvus image and migrate `/var/lib/milvus` before the non-root server starts. - Write a UID/GID-specific marker only after a successful recursive migration, so large existing volumes are not scanned on every start and interrupted migrations remain retryable. - Prepare the bind mount in `standalone_embed.sh`, including when a previously created container is stopped after a permission failure. - Teach Docker deployment health checks to exclude one-shot services. - Document the ownership and restore contract. The initializer has no network, uses a read-only root filesystem, and mounts only the Milvus data directory. The Milvus server continues to run as `milvus:milvus`. This fixes both fresh rootful-Docker installations, where Docker creates the bind source as `root:root`, and upgrades from root-running images with root-owned data or cache files. It avoids the ineffective image-layer `chmod` approach from #51226 because a bind mount hides image-layer ownership and mode. ## Compatibility - The recursive ownership migration runs once for each image UID/GID. - A failed or interrupted migration does not create the marker and is retried. - Root-running older images can still read and write the migrated files on rollback. - After restoring files owned by another user, remove `.milvus-volume-owner-*` before starting Milvus to rerun migration. ## Validation - `git diff --check` - `bash -n scripts/standalone_embed.sh tests/python_client/deploy/utils.sh tests/python_client/deploy/check_healthy.sh` - `docker compose -f deployments/docker/standalone/docker-compose.yml config --quiet` - `docker compose -f deployments/docker/gpu/standalone/docker-compose.yml config --quiet` - Verified the deployment health-count expressions return the three long-running services. - Simulated the existing release bump regexes and confirmed both init/server image references and `MILVUS_IMAGE` are updated. Container-level startup was not run locally because the Docker daemon is unavailable; the Linux deployment CI must exercise the fresh-install and root-owned upgrade paths. --------- Signed-off-by: Zhikun Yao <[email protected]> |
||
|
|
33d4d826f3 |
enhance: expose compaction lifecycle observability (#53308)
issue: #53307 Protocol dependency: milvus-io/milvus-proto#668 (merged). ## What changed - Reuse the existing RPCs to expose retained segment lifecycle metadata and direct compaction sources; retain the existing sealed/loaded segment reporting contract without adding Growing segments to GetQuerySegmentInfo. - Expose collection-scoped retained compaction tasks, with complete task identity, public type/state enums, source/target sets, and failure reasons, while preserving manual job-ID lookup. - Preserve failure reasons across worker cleanup without changing task cleanup or metadata GC semantics. - Add seven **L3-only** data-integrity workloads: fixed V2/V3 Insert, fixed V2/V3 Import, V2 add/drop-field evolution through MixCompaction with schema bump disabled, V3 schema evolution, and V2-to-V3-to-V2 storage transitions. - Validate deterministic full-row/full-field data against an independent oracle, fenced persistence/serving checkpoints, and actual lineage transitions, allowing either automatic or manual compaction. - Provide `tests/scripts/ci_compaction_integrity.sh` as a dedicated, single-invocation, serial entry; leave the shared `tests/scripts/ci_e2e.sh` unchanged from the PR base. - Retain successful audit records only for the dedicated workload marker, preserving ordinary tests' JSON, HTML, and worker-report formats. ## Compatibility and execution boundary - Omitted segment states preserve the existing persistent-state behavior; task and dropped-segment history are subject to existing retention/GC, not a fixed response-size or record-count limit. - These workloads are not added to per-PR E2E or ordinary Nightly pipelines. - The dedicated job must own the deployment/config namespace exclusively, install a compatible PyMilvus build, and provide connection options plus a unique `CI_LOG_PATH`. - The entry enforces `-n 0`, the L3 workload marker, and explicit opt-in, while forwarding connection options, filters, and pytest's exit status. - Insert/Import workloads use three rounds by default; insert load units are batches, not a promise of a physical segment count, and dense vector dimensions are 16. ## Observability semantics and follow-ups - **Segment listing is not an atomic snapshot.** The Proxy first calls `GetSegmentsByStates`, then `GetSegmentInfo`; returned details are filtered again against the requested states (or the legacy default: Flushing, Flushed, Sealed). A segment whose fetched state no longer matches is omitted, and a segment becoming eligible after ID enumeration may be absent. Consumers must not treat a single response as a consistent lifecycle snapshot. - **Existing lookup errors are preserved.** `IncludeUnHealthy` is enabled only when Dropped is explicitly requested. In the default healthy-only path, a selected source becoming Dropped before detail lookup still returns `SegmentNotFound`, as before; that error is not converted into a successful partial list. A history segment being GC'd between the two RPCs can also fail the lookup. - **Aggregate `Completed` means no running tasks, not universal success.** This preserves the existing aggregation semantics: all-failed/all-timeout retained tasks, or an empty task set, can report Completed. Inspect each task's `state` and `failure_reason` for its outcome; proving an actual data transition additionally requires lineage, active-set adoption, and serving-set evidence. This PR does not redefine task retry or cleanup behavior. - **History capacity is a follow-up.** Dropped-segment queries enumerate the retained history and fetch its details, while collection-scoped compaction queries return retained tasks across triggers. Neither path currently provides pagination or a fixed count/size cap, so scan, copy, and response costs grow with the retained record count despite retention/GC. Pagination and capacity controls for both paths are deferred; they must preserve the ability to enumerate complete retained history rather than silently truncate lineage or task evidence. ## Previously recorded verification The results below are earlier recorded runs, including the original six-workload suite before the V2 DDL workload was added; the documentation/review-response update did not rerun tests. - 22 server-independent CI boundary tests passed, covering ordinary/special audit output, worker report merging, scoped execution guards, and the dedicated entry's argument/exit-code behavior. - 20 differential checks against the PR-base logging plugin produced byte-identical ordinary worker JSON, report JSON, and HTML across all five result outcomes. - 14 existing DataIntegrity and etcd-helper unit tests passed. - The three original L1 DataIntegrity parameter instances passed with `-n 2 --dist loadgroup` in 59.39 seconds; their merged successful JSON records retained the original metadata-only shape. - Ruff lint/format, shell syntax, and scoped PR-base whitespace checks passed; the shared runner is byte-identical to the PR base. - The new dedicated entry ran all six workloads serially against the existing local cluster: **6 passed in 3373.52 seconds**, with three rounds for each Insert/Import workload and the storage-transition workload, plus five DDL checkpoints over 25,000 rows. - All six successful reports retained their audit evidence (403 structured events), including every expected round/DDL checkpoint, full segment/task snapshots, serving frontiers, and matching expected/retrieved PK digests. ## Design and job entry - [Data-integrity design contract](https://github.com/MrPresent-Han/milvus/blob/codex/compaction-e2e-observability/docs/design-docs/design_docs/compaction_data_integrity_e2e_design.md) - [Dedicated serial entry](https://github.com/MrPresent-Han/milvus/blob/codex/compaction-e2e-observability/tests/scripts/ci_compaction_integrity.sh) Signed-off-by: MrPresent-Han <[email protected]> Co-authored-by: MrPresent-Han <[email protected]> |
||
|
|
bf02c32d35 |
enhance: chain supports dynamic field (#53493)
https://github.com/milvus-io/milvus/issues/46565 Signed-off-by: junjie.jiang <[email protected]> |
||
|
|
f887463b25 |
fix: Serialize snapshot restores targeting the same collection (#53547)
issue: #53513 Concurrent internal restores can both pass Phase 0 and reuse the same target collection through idempotent CreateCollection, producing duplicate copy jobs. Share the existing per-target external restore lock with internal restores and validate target absence under the Phase 0 DDL lock before pinning the source. Hold the target lock through collection creation, job submission and synchronous cleanup, while releasing the DDL lock before nested DDL calls. Normalize an empty database name to `default` so both spellings share the same lock. An existing restore target is now rejected during admission, before the source snapshot is pinned. Its error message changes from "create duplicate collection with different parameters" to "target collection ... already exists in database ..."; the error code remains 1100. Update both existing Python rejection tests to check the new message and explicitly assert the code, since the shared error checker only validates message substrings. Add regression tests for internal/external contention, independent targets, admission failures, rollback retry and registered-broadcast ACK timeouts. Add an L2 Python e2e that starts two restores to the same target and requires one success, one already-exists error, one completed job and matching restored data. ### Validation - Targeted restore Go tests passed with `-tags dynamic,test`, `-gcflags="all=-N -l"` and `-race`. Changed restore functions have 100% statement coverage; this is not whole-package coverage. - `TestMilvusClientSnapshotConcurrency::test_concurrent_restore_same_target` passed with `--count=3`: 3 passed in 33.08s. Each run checks all 256 primary keys, scalar fields and vectors. Test collections were cleaned up. - After rebuilding Go on base `f5475123f2`, the two existing-target rejection tests (`test_snapshot_restore_collection_exist` and `test_snapshot_restore_failure_no_resource_leak`) and the concurrent-target regression passed together: 3 passed in 35.42s. The existing-target tests explicitly verify error code 1100 as well as the admission error message. Independent cleanup verification found no remaining collections. - Ruff lint/format checks and `git diff --check` passed. - Live testing used this worktree's binary in isolated standalone mode with embedded etcd, RocksMQ and local storage. Mixed internal/external contention is unit-tested; the original cluster/S3 topology was not exercised. The lock serializes restore requests within the snapshot manager. It does not add fencing against unrelated CreateCollection/DropCollection operations or coordinator failover. --------- Signed-off-by: Wei Liu <[email protected]> |
||
|
|
2cbfc53b81 |
feat: preserve primary keys in full AutoID upsert (#53158)
issue: #53157 ## What changed - Full AutoID Upsert shares preparation with Partial Upsert and classifies supplied lookup keys with one PK-only Strong Retrieve using standard Query visibility and TTL handling. It adds no Full-specific fixed MVCC or guarantee-timestamp mechanism. - Existing rows preserve their primary keys, so their delete and insert route to the same VChannel transaction. - Missing rows always receive allocator-owned IDs. No Delete is emitted for a missing lookup key. No insert-on-not-found configuration or new not-found error code is introduced. - Partial Upsert retains master's Strong Query and actual per-channel CAS snapshots. AutoID Partial preserves existing keys and allocates new IDs for missing rows with complete insert fields, retaining them across internal CAS retries. Full Upsert does not collect or bind CAS proofs. - The Go row client retains AutoID lookup keys for Upsert, and the response returns final IDs in request order. - Shared `prepareUpsert` performs Retrieve, PK classification and missing AutoID allocation. Full Upsert returns before Partial-only field merging and CAS processing, preserving the complete request payload and row order. - Missing business PKs are allocated during preparation; internal RowIDs remain initialized in `insertPreExecute`. One PK helper validates keys and rewrites only missing positions in a copy of the PK field. Response IDs also drive Insert routing, without separate routing state. ## Compatibility and scope This preserves the historical create-on-not-found outcome while fixing identity replacement for existing rows. Full AutoID Upsert now depends on the standard Query/load-state path. Retrying a missing lookup key after an ambiguous outcome may create another generated identity; this is not an idempotency mechanism or a cross-VChannel request transaction. No RootCoord behavior, collection property, public protobuf, WAL format, or replication protocol is added. Deployments must use homogeneous Proxy versions during the semantic transition, as described in the design. Design: [Preserve Primary Keys in Full AutoID Upsert](https://github.com/weiliu1031/milvus/blob/refine-autoid-upsert/docs/design-docs/design_docs/20260803-autoid-upsert-primary-key-preservation.md) ## Validation Latest publication (`24e2ae1974`, 2026-09-15): - Rebased onto master `fee4ed4316` without conflicts. Both branch-only commits are equivalent in range-diff; the aggregate patch ID and changed paths are unchanged. - Post-rebase `SKIP_3RDPARTY=1 make milvus` passed in the designated worktree, rebuilding Milvus C++ and Go code while reusing third-party dependencies already built there by the preceding full `make milvus`. - 82 targeted Proxy tests passed after rebase with `-tags dynamic,test`, `-gcflags='all=-N -l'`, `-count=1` and local macOS linker options. Coverage includes shared Full/Partial preparation, PK validation, missing-ID allocation, CAS retries, routing and Query visibility. These mocked tests required no shared-service reset. - Full Proxy golangci-lint 2.11.3 passed with 0 issues. `gofmt` checks and `git diff --check` passed; the worktree was clean before publication. - At the user's direction, full-suite tests, the 99% coverage gate and repository-wide verifiers were skipped. No live E2E or fresh coverage result is claimed for this HEAD. New-head CI remains required. Previous publication (`e6000d8b67`, 2026-09-15; historical): - Rebased onto master `423b8e483d`. Resolved query/upsert conflicts by preserving master's Partial Strong-read/CAS protocol and AutoID fallback, while keeping Full classification on its ordinary visibility path. - The mmap counter collision fix is already upstream and was dropped as a duplicate. No new feature paths were added; the design and tests were aligned with the authorized Partial behavior. - `make build-cpp` passed in the designated worktree. - 56 targeted Proxy tests passed with `-tags dynamic,test`, `-gcflags='all=-N -l'`, `-count=1` and local macOS linker options, covering Full/Partial AutoID, CAS retries, snapshot binding, routing and Query visibility. These mocked tests required no shared-service reset. - Full Proxy golangci-lint 2.11.3 passed with 0 issues; formatter and `git diff --check` passed. - Full-suite tests, coverage and live E2E were not rerun. New-head CI remains required; earlier-head green results do not validate this head. Previous publication (`ffa01a4d1d`, 2026-09-10; historical): - Rebased onto master `13cd0e99f9` without conflicts. All seven commits are equivalent in range-diff; aggregate patch ID and paths are unchanged. - Full merr package tests and the Proxy paramtable subtest passed. - Formatter and git diff checks passed. - Post-rebase Proxy tests and full Proxy lint were attempted but blocked by stale local C++ headers missing master's new initcore C interfaces. Rebuilding this worktree with `make build-cpp` then failed at `LoadAdmissionController.cpp:87,91,131`: returning `future` calls the deleted `folly::coro::Future<LoadAdmissionLease>` copy constructor. That source file is identical to master and is not changed by this PR. No unrelated C++ repair was included. Post-rebase integration package compilation was not reached; Proxy validation remains incomplete. - Mock tests did not require starting or resetting shared services. - Full-suite tests, coverage and live E2E were not run for this publication. New-head CI must still validate the complete branch. Historical validation, not fresh evidence for this HEAD: - Before rebase, the switch-removal candidate passed 19 targeted Proxy tests, full merr tests, the Proxy paramtable subtest, full Proxy lint 2.11.3, formatter checks and HelloMilvus integration package compilation. - Earlier revisions ran targeted CAS/retry/routing tests, Go SDK `TestUpsertAutoIDRows` and `TestUpsertAutoIDMixedBatch`, REST v2 `test_upsert_vector_pk_auto_id` for Int64/VarChar, builds and Python syntax checks. - The prior QueryNode `TestFillOutputFieldsOrdered_NoCMemoryLeak` CI failure was not repaired by this change; its implementation and thresholds remain untouched. New-head CI is needed to establish status. --------- Signed-off-by: Wei Liu <[email protected]> |
||
|
|
c24624e280 |
feat: HybridSearch support l0/l1/l2 rerank chains (#52884)
https://github.com/milvus-io/milvus/issues/46565 doc: docs/design-docs/design_docs/20260818-hybrid-search-function-chain.md Signed-off-by: junjie.jiang <[email protected]> |
||
|
|
10beedd721 |
enhance: Avoid TimeTick waits in partial update reads (#53336)
issue: #53335 Serial partial updates currently use a fixed MVCC read that can wait for the next TimeTick. Use a fresh Strong query for the first attempt and each safe CAS retry, then bind QueryNode's actual per-channel snapshots to the CAS proof. StreamingNode rejects proofs older than its current WAL tracking lifecycle, including a reopened WAL with the same channel term. Require a nonzero snapshot for every write channel before merging or writing. Existing conflict, retention, and incomplete-transaction guards remain active. All participating Proxy, QueryNode, and StreamingNode instances must implement this protocol; mixed-version rollout is outside this change. Design: [Partial Update Optimistic Lock](docs/design-docs/design_docs/20260601-partial-update-optimistic-lock-design.md). AutoID partial updates now preserve existing PKs and allocate a new AutoID for each missing row with complete insert fields. Each attempt resolves all possible destination terms before one Strong query, then selects the final write channels from its actual snapshots after allocation. Freshly allocated IDs are not queried again. Destination IDs remain stable within internal CAS retries; original fields stay immutable and returned IDs retain input order. Missing source PKs generate no Delete, and successful results return destination IDs in input order. Cross-vchannel transactions remain independent, and this does not add cross-request deduplication. Missing-PK insert failures name the PK and missing required field, without a row index, while retaining the non-retriable parameter error. The design and Python e2e error assertions are synchronized. Earlier validation (before the latest refactor): - Targeted Proxy query/upsert regression tests, QueryNode executed-snapshot tests, and StreamingNode lifecycle-history tests passed locally. - Earlier Strong-read Release build and serial A/B/B/A benchmark (before the AutoID fallback update): batch 16 / 128 / 512 mean latency changed from 199.771 / 199.774 / 199.731 ms to 1.293 / 1.838 / 4.658 ms. Each version/batch has 300 measured requests; 2,160 total requests including warmups succeeded, with full scalar-field and sampled vector-preservation checks. - Benchmark scope: Apple M5, Standalone, RocksMQ, 2 shards, 8,192 rows, 128-dimensional vectors, scalar REPLACE. Both versions used identical local native libraries, including a separate local compiler compatibility adjustment. This is not a distributed or concurrent-load benchmark. - `git diff --check` passed. Distributed WAL failover/fault injection and the full repository test suite were not run. - AutoID fallback: targeted Proxy tests cover Int64/VarChar IDs, absent/existing rows, real message packing with mocked mixed-channel success/CAS failure, stable retry IDs, result order, and missing-field error classification. QueryNode snapshot and StreamingNode lifecycle tests were also rerun on this branch. - Python error assertions were updated and syntax-checked; Python e2e and distributed fault injection were not run for this update. Latest refactor validation: - Updated the design and tests for one query per attempt, stable AutoIDs, and shared PK handling. Added RPC-to-CAS packing cases for distinct channel snapshots, empty destinations, missing/zero snapshots, and fixed namespace routing. - Formatting and diff checks passed. No tests or local builds were run for this update, as requested; earlier test and benchmark results do not validate this refactor. --------- Signed-off-by: Wei Liu <[email protected]> |
||
|
|
2ad9913d41 |
fix: align XGBoost corrupted model assertion with segcore diagnostics (#53401)
issue: #53398 ## Summary The corrupted-XGBoost-UBJ e2e test asserted that `segcoreCode=` never appears in the error message. That contradicts the current error contract: `merr` keeps the original segcore code in the diagnostic, and the code travels the wire directly. Update the assertion to require `segcoreCode=2042` instead of rejecting the decoration. The test still verifies the explicit parse failure, wire code 2042, input-error classification, non-retriable behavior, and successful reranking with the valid model. ## Test Plan - `python3 -m py_compile tests/python_client/milvus_client/test_milvus_client_function_chain.py` - `ruff check --config tests/ruff.toml tests/python_client/milvus_client/test_milvus_client_function_chain.py` - CI on this PR: `ci-v2/e2e-default`, `ci-v2/go-sdk`, and `Ruff (changed files only)` pass. Fixes #53398 Signed-off-by: lorenzozanee <[email protected]> |
||
|
|
82bcce8867 |
enhance: classify segcore errors across producers and enforce classification end-to-end (#50768)
## What Consume the producer-owned error classification at the segcore boundary and make the whole C++→Go classification drift-proof, so a segcore error is classified as **input** (caller's fault, non-retriable), **transient** (retriable) or **permanent** (non-retriable) instead of flattening to `UnexpectedError(2001)` or carrying the wrong retry default. Design + tracking: #50903. ## Changes - **T1** — register the storage fallback pair in `pkg/util/merr/segcore.go`: `StorageError(2044)` non-retriable, `StorageTransientError(2045)` retriable. - **T2** — `KnowhereStatusToErrorCode` → a switch with **no `default` + `-Werror=switch`** over the full `knowhere::Status`; add build-path variant `KnowhereBuildStatusToErrorCode` so a build-time OOM / disk read stays **retriable** instead of collapsing into a permanent `IndexBuildError`. - **T3/T4** — `ArrowStatusToErrorCode` delegates to the producer's `milvus_storage::ToSegcoreError` (retires milvus's duplicate mapper); audited and routed **25 storage arrow-status sites** that were collapsing to `2001` through the single mapper (extracted to `storage/StatusToErrorCode.h`), always preserving the arrow sub-code in the message. - **T5** — unmapped-code observability: `UnmappedSegcoreCodeTotal{code}` counter + rate-limited WARN via an observer hook (merr is a leaf package); registered on QueryNode and DataNode. Unknown code degrades to non-retriable, never panics. - **T6** — codegen + compile-time enforcement: a generated `SegcoreCode` type (from milvus-common's `EasyAssert.h`) + an exhaustive `classForCode` switch marked `//exhaustive:enforce`, with the `exhaustive` golangci-lint enabled opt-in — a new C++ code that is not classified fails lint (the C++→Go analog of `-Werror=switch`). - **§3 B-tier** — classify `marisa` and `simdjson` errors (build/load/parse) instead of collapsing to `2001`, sub-code in the message; simdjson optional-access (`NO_SUCH_FIELD`/`INCORRECT_TYPE`) stays a benign skip; the `loon_ffi` FFI boundary is untouched. - **Boundary hardening (adversarial self-review of this PR's own diff)** — closed the escapes that would defeat the mapping above: a `throw e;` slicing rethrow in `LoadWithStrategy` that destroyed the very codes the columnar-read mapping attaches (bare `throw;` now), the same slice in `MinioChunkManager::PreCheck`; `GetCoreMetrics` / `EstimateLoadIndexResource` / init-and-config entry points that could let an exception cross the C ABI and terminate the process; and every remaining extern-C entry that caught only `std::exception` now ends in `catch(...)` via the shared `CGoCatch.h` macros. - **Pin + semantics** — bump `milvus-storage_VERSION` to `11f8a36` (the milvus-io/milvus-storage#574 merge, which also contains #575) and align the no-detail `IOError` expectation with the settled semantics: the producer tags every known-transient failure with a retryable `ExtendStatusDetail`, so a bare `IOError` with no detail is unclassified and deliberately falls back to permanent `StorageError(2044)` — a stripped-detail NotFound now degrades to non-retriable (safe) instead of retriable (retry storm on a permanent 404). - **Wire pass-through (client-visible)** — a segcore error now reaches the client with its ORIGINAL code (2009 stays 2009, 2024 stays 2024) instead of collapsing to the `ErrSegcore(2000)` umbrella with the real code buried in the message. Family identity for `errors.Is` is preserved via inner/Unwrap; input/system/retriable classification unchanged. Guardrails: only in-band (2000-2099) codes pass through (garbage still collapses to 2000); cross-family mappings (2046 → wire 110) keep their sentinel's code. `ErrSegcoreUnsupported`/`ErrSegcorePretendFinished` move to the C++ values they represent (2001→2003, 2002→2033) — their old numbers squatted on C++ UnexpectedError/NotImplemented and would false-match under code-based `errors.Is`. Verified end-to-end on a live standalone (ef<k reaches the client as 2042, unsupported tokenizer as 2001); the three e2e assertions pinning the old 2000 updated. - **Remaining code-destroying sites** — the three classes that still swallowed a producer's classification before the cgo boundary are now gone from `internal/core/src` and `internal/core/thirdparty`: status-consuming `AssertInfo` (104 → 0, incl. ~47 arrow builder paths whose commonest failure is OOM, now retriable `MemAllocateFailed` instead of a permanent 2001), bare `throw std::runtime_error/logic_error/bad_alloc` (68 → 0 — these were not `SegcoreError`, so they collapsed to 2001 *and* falsely fired the untyped-exception observer), and `throw fmt::format(...)` (12 → 0 — it throws a `std::string`, which `catch (std::exception&)` cannot see at all). tantivy's 73 `AssertInfo(res.result_->success, ...)` (plus 10 raw-`RustResult` stragglers found later) now classify the rust error — originally by its Display prefix, since replaced by a proper `#[repr(i32)]` discriminant carried in `RustResult.error_code` (see the Aug-10 update below). Typed `ThrowInfo` sites: 894 → 1081. The ~1500 genuine invariant asserts are untouched — 2001 is correct for them. The long-standing FIXME about `err_code` not surviving the nested LOON FFI boundary is also resolved, delegating to `milvus_storage::ToSegcoreErrorCode` rather than duplicating its table. ## Verification **Verified in this PR:** - **Mapping correctness (unit-tested, in-process):** `test_knowhere_status_mapping.cpp` / `test_storage_error_code.cpp` / `test_exec.cpp` cover every mapper branch (knowhere Status incl. the build variant, arrow/extend status incl. `AwsErrorNotFound→ObjectNotExist(2017)`, permanent-S3 vs transient), plus `FailureCStatus` code preservation and both observer hooks firing. - **Code projection to Go (one hop, unit-tested):** `segcore_test.go` pins `classForCode` for every generated code and asserts `merr.Status(err).GetRetriable()` for transient codes; the T6 generator is idempotent and the `exhaustive` lint fails on an unclassified code. - **Full C++ suite:** 8213/8223 unit tests pass locally (10 skipped; Azure connectivity tests excluded), 8648 in CI, rebased on current master (one pre-existing, unrelated concurrency test excluded: `GrowingConcurrentReopenTest` deadlocks deterministically on current master with or without this PR — rwlock writer starvation in growing-segment reopen code this PR does not touch; reported separately). - **Static audit (grep-verifiable):** every storage arrow-status consumption site on the read path routes through `ArrowStatusToErrorCode`, and every extern-C boundary ends in a `catch(...)` tail. **Explicitly NOT verified here (follow-up):** - **Runtime fault injection.** No S3 throttle / 404 / OOM / corrupt-file failure has been triggered end-to-end in a running cluster. Transient codes reach Go with `retriable=true` (unit-tested projection), but the downstream consumption — `lb_policy` replica reroute on `merr.IsRetryableErr`, index/analyze scheduler retry — is pre-existing logic from #50221 and has **not** been driven by a real segcore transient error in this PR. This PR preserves classification for observability and correct retry defaults; the retry behavior itself is exercised only by its own pre-existing tests. ## Dependencies - ~~milvus-common `StorageTransientError(2045)` — zilliztech/milvus-common#102~~ **merged**. - ~~milvus-storage `ToSegcoreError` / packed `ExtendStatusCode` — milvus-io/milvus-storage#575 + #574~~ **merged; pin bumped in-tree to `11f8a36`**. - ~~knowhere three-way classification — zilliztech/knowhere#1704~~ **merged** (the milvus-side `KnowhereStatusToErrorCode` → thin delegate to knowhere's own `ToSegcoreErrorCode` is a follow-up, gated on a knowhere version bump). - ~~milvus-common untyped-cgo-exception observer — zilliztech/milvus-common#112~~ **merged and released as `1.0.0-1fd1160`; the pin now points at the published package.** All dependencies are in. ## Update (Aug 10) — full-population audit, LOON path, runtime observability The originally deferred FFI/LOON path is now **done on the milvus side**, and the audit was extended from the three grep-able classes to the *entire* 2001-producing population: - **Every remaining 2001 site read.** All 1,517 `AssertInfo` (four sweeps: errno fingerprint, failure-keyword messages, condition morphology, and finally **data provenance** — does the guarded value come from disk/network?) and all 198 explicit `ThrowInfo(UnexpectedError)` sites. ~290 were externally-triggerable and now carry typed codes: file/remote IO -> `FileOpen/Create/Read/WriteFailed` (retriable), mmap/allocation -> `MmapError`/`MemAllocateFailed` (retriable), persisted-format damage (CRC/magic/parquet meta/index-meta keys) -> `DataFormatBroken`, deployment config -> `ConfigInvalid`, request content -> `InvalidParameter`, a cancel-race -> `FollyCancel`. The ~1,400 kept sites are genuine invariants or cgo contracts where 2001 is the correct report. - **Two infinite-retry bugs.** Statically-impossible conditions (index_type x metric blacklist, per-type metric allowlists, json/geometry index gates) threw 2001 -> generic retry -> the build task spun forever; they now throw `Unsupported`, which `getStateFromError` maps to a terminal `JobStateFailed`. Missing `index_type`/`metric_type`/`min_gram`/`max_gram` keys in persisted index meta had the same loop on the load path; they are `DataFormatBroken` now. - **knowhere `expected<>` bypasses closed** (8 sites in `QueryResult.h`/`CachedSearchIterator`): iterator failures went through `AssertInfo` and discarded the Status knowhere had already classified; they now route through `KnowhereStatusToErrorCode`, so an OOM/disk failure during search iteration stays retriable. Preflight rewraps in `segment_c`/`boost_score` similarly preserved the original `SegcoreError` code instead of flattening to 2001+string. - **tantivy discriminant over the FFI.** `RustResult` now carries `error_code` (`#[repr(i32)] TantivyBindingErrorCode`, cbindgen-exported); the C++ mapper switches on the enum instead of parsing the Display text, and the inner `tantivy::TantivyError` is discriminated too (`IoError/Open*Error` -> Io/retriable, `DataCorruption/IncompatibleIndex` -> DataCorruption). Wording changes on the rust side can no longer silently degrade classification. - **LOON / FFI path (the deferred item), milvus side complete.** The Go funnel `HandleLoonFFIResult` dropped `err_code` entirely and wrapped every failure as `ErrLoonTransient` — a 404/access-denied/corrupt-data retried as transient. It now classifies by the producer's own `loon_ffi_is_retryable_errcode`; permanent failures carry the new `ErrLoonPermanent` and terminate retry loops (`pack_writer_v3` via `retry.Unrecoverable`; the external-refresh manager guard extended so behavior does not invert). On the C++ side `LoonErrCodeToErrorCode` is the single classification entry (low band -> hand table, extend band -> producer's `ToSegcoreErrorCode`, unknown -> producer's retryable probe), unifying the two previously-divergent `ThrowIfFFIError` helpers — `LOON_FILE_NOT_FOUND(12)` now converges to `ObjectNotExist(2017)` on both integration paths. Remaining LOON items (e.g. promoting FileNotFound into `ExtendStatusCode`) live in the milvus-storage repo. - **Regression guards.** `scripts/check_segcore_error_boundaries.sh` wired into `make static-check`: every `throw` in `internal/core/src` must carry a milvus ErrorCode (zero-tolerance; currently 0 violations); vendored `fmindex::` is confined to its boundary files; knowhere/arrow/milvus_storage/tantivy are ratcheted by a checked-in file-set baseline (new consumer files fail the check; shrinking is free). - **Runtime observability for what is left.** `milvus_cgo_unexpected_segcore_origin_total{origin="<file>:<line>"}` counts every 2001 crossing the cgo boundary by its C++ source location (parsed from the ` at file:line` suffix `AssertInfo` already emits, build paths collapsed to repo-relative). A site that fires in production names itself — reclassification becomes evidence-driven instead of re-reading ~1,400 asserts. Site count for the 2001 family: 1,955 on master -> 1,525 on this branch; the delta is reclassification into actionable codes, not deletion of checks. ## Deferred - milvus-storage-side LOON improvements: promote `LOON_FILE_NOT_FOUND` into `ExtendStatusCode`, category byte (design §4.7) — tracked in the storage repo. - knowhere-side: thin-delegate `KnowhereStatusToErrorCode` to knowhere's own `ToSegcoreErrorCode`, gated on a knowhere version bump. issue: #50903 --------- Signed-off-by: Zack <[email protected]> Co-authored-by: Zack <[email protected]> Co-authored-by: Claude Fable 5 <[email protected]> Co-authored-by: xiaofanluan <[email protected]> |
||
|
|
48a5f578c0 |
test: update client cases for storage and sdk changes (#53305)
issue: #51544 Reopens #51755, whose author has left the project. The branch is rebased onto current master and the conflicts are resolved. ## What changed - Derive the default Python client test namespace from `MILVUS_NS` or `MILVUS_HELM_NAMESPACE` before falling back to `chaos-testing`. - Add an optional external-source MinIO endpoint override (`MILVUS_EXTERNAL_SOURCE_MINIO_HOST`) for external table tests, so the client upload endpoint and the server-side `external_source` endpoint can be configured independently. - Resolve the bulk insert MinIO endpoint from the existing `minio_host` / `minio_bucket` fixtures instead of looking up the MinIO pod IP through the k8s API, so these cases no longer require in-cluster access. - Extend TEXT LOB layout validation to read Vortex segment data files in addition to the existing parquet layout. The Vortex files are decoded with `vortex-data`; when the installed reader cannot decode Milvus StorageV3's custom encoding the case skips rather than asserting on synthesized references. ## Dropped from the original PR Two changes from #51755 have since landed on master independently and are not included here: - The multi-primary-key invalid schema assertion — master already validates at `add_field` time, via the framework's `CheckTasks.err_res` helper rather than `pytest.raises`. - The `Date` / `Time` / `Decimal` entries in the external table add-field matrix. ## Verification - `test_text_lob_bulk_import_json_csv_parquet` - `test_text_lob_inline_vs_lob_object_layout` - `test_milvus_client_external_table_add_all_supported_field_types` - `test_milvus_client_xgboost_supports_all_numeric_feature_types` Signed-off-by: zhenshan.cao <[email protected]> Co-authored-by: nico <[email protected]> Co-authored-by: Claude Opus 5 (1M context) <[email protected]> |
||
|
|
dd75544f37 |
test: fix external refresh and oversized insert expectations (#53148)
issue: #53133 issue: #52648 ## What was changed - Handle both valid outcomes of two back-to-back external collection refresh requests: - reject or reuse the request while the first job is active; - allow a new job only after the first job reaches a terminal state. - Update the oversized insert test to verify the current application-level `maxInsertSize` rejection. - Assert error code `1102` and the stable `exceeds maxInsertSize` message instead of the obsolete gRPC `message larger than max` error. ## Why The external refresh test assumed that the first job would always remain active until the second request arrived. On faster environments, the first job can complete before the second request, making a new refresh job valid. The oversized insert test assumed a 64 MiB gRPC receive limit. The Proxy receive limit is now 128 MiB, while oversized materialized inserts are rejected by the 64 MiB `quotaAndLimits.limits.maxInsertSize` guard. ## Verification - `ruff check` passed for both changed files. - `ruff format --check` passed for both changed files. - Python compilation checks passed. - External refresh regression E2E: passed. - Oversized insert regression E2E: passed with error code `1102`. --------- Signed-off-by: zhuwenxing <[email protected]> |
||
|
|
3067e2542d |
test: add Go, PyMilvus, and REST e2e for FMINDEX and membership_match (#52629)
## Summary Add end-to-end coverage for FMINDEX and the unified `membership_match` expression across the Go SDK, PyMilvus, and RESTful v2. Related issues: #51375, #52778, #53036 ## Coverage ### FMINDEX - Build parameter defaults, boundaries, combined parameters, and invalid types or ranges. - VARCHAR-only validation, including JSON, scalar, and struct-array sub-fields. - Prefix, infix, suffix, general LIKE recheck, regex fallback, escaped wildcards, NULL, and UTF-8 behavior. - Long-text low-hit fixtures and sealed segments above `minSegmentNumRowsToEnableIndex`, preventing fake-finished index coverage. - Exact indexed-field versus unindexed twin-field PK comparison. - Growing plus sealed visibility, mutation, upsert, named-index drop, and rebuild lifecycle checks. - Query and Search coverage with exact projected fields, distance ordering, index identity, type, and row-progress assertions. - VARCHAR AUTOINDEX resolution is verified against the configured scalar-index policy without hard-coding a specific index type. ### membership_match - Bloom and Roaring wire compatibility through a shared static manifest while each SDK keeps independent collection setup. - Bloom zero-false-negative checks plus a statistically bounded false-positive check tied to the configured FPR; Roaring uses exact PK ground truth. - Query and Search must return the same complete Bloom-filtered PK set when topK covers the fixture. - Integer widths, negative values, INT64 boundaries, VARCHAR, JSON strict typing, nested paths, dynamic fields, NULL semantics, and unsupported top-level BOOL/FLOAT fields. - Positive, negated, empty, malformed, domain-mismatch, delete, growing plus sealed, and struct-array rejection cases. - Explicit `STL_SORT`, `INVERTED`, `BITMAP`, and `TRIE` scalar-index paths. - Internal-only `HYBRID` paths are exercised through the supported `AUTOINDEX` request and verified against DataCoord's resolved build parameters for primitive and JSON-path indexes. - Mutation tests use isolated collections; shared read-only fixtures register cleanup before setup begins. ### RESTful v2 - FMINDEX anchored LIKE Query and Search compared with exact PK ground truth and an unindexed twin field. - Index identity, type, persisted parameters, row progress, completion, and collection load state are verified before assertions. - Search validates exact projected values by primary key. - JSON string and missing membership template parameters are verified as server-side validation failures. - Python `bytes` are verified to fail local JSON serialization before HTTP. A positive REST binary-template case remains blocked by #53036. ## Validation - `go test -tags dynamic,test -gcflags='all=-N -l' -c ./testcases` - `go vet -tags dynamic,test ./testcases` - `go test ./membership/sbbf -count=1` - Ruff check and format check for all changed Python and REST files - Python byte-compilation for all changed Python and REST files - Pytest collection: 68 PyMilvus/FMINDEX tests and 7 REST tests - Cross-SDK membership wire-manifest verification - `git diff --check` The Proxy parameter-resolution unit test and Bloom integration package cannot execute on the host because it lacks the native `milvus_core`, `rdkafka`, and `rocksdb` pkg-config packages. A targeted PyMilvus FMINDEX run reached index creation but timed out after 120 seconds before assertions; its temporary collection was cleaned up. Full server-backed E2E was not completed. Signed-off-by: Yanliang Qiao <[email protected]> |
||
|
|
87058e5dc7 |
test: stabilize TTL E2E cases under slow CI (#53175)
issue: #53171 ## What this PR does - Preserve collection TTL expiration coverage while measuring from before the first write with a monotonic deadline. - Verify newly inserted rows remain visible under the original short collection TTL before extending it for slower multi-RPC checks. - Replace setup-sensitive TTL windows in timezone-offset and partition cases with explicit expired and unexpired timestamps. - Preserve real-time entity expiration after release and reload by starting the short TTL window after reload completes. - Use monotonic polling with attempt and elapsed-time diagnostics. ## How was it tested? - Ruff check and format check passed. - Python compilation check passed. - The complete TTL test file passed with pytest-xdist using 6 workers and load-group scheduling: 37 passed. --------- Signed-off-by: zhuwenxing <[email protected]> |
||
|
|
32b08caeb5 |
fix: fail invalid milvus-table refresh requests (#52304)
issue: #52294 ## Summary - add PyMilvus E2E coverage for using Milvus snapshots as milvus-table external sources - classify invalid snapshot metadata paths as input errors so refresh jobs fail terminally instead of remaining retryable - verify real and virtual primary keys, deletes, refreshes, schema alignment, mixed data types, and failure atomicity - mark the target-owned BM25 output case as a strict xfail pending #52303 ## Design document docs/design-docs/design_docs/20260526-milvus-table-external-source.md ## Test plan - [x] python3 -m compileall -q milvus_client/test_milvus_client_snapshot_external.py - [x] python3 -m ruff check milvus_client/test_milvus_client_snapshot_external.py - [x] targeted BM25 E2E reports XFAIL with the #52303 reason - [x] pytest collection discovers all 17 test variants - [ ] targeted Go unit tests were not runnable locally because milvus_core, milvus-storage, and RocksDB pkg-config dependencies are unavailable; CI will run them --------- Signed-off-by: Eric Hou <[email protected]> Co-authored-by: Eric Hou <[email protected]> Co-authored-by: Claude Opus 4.6 <[email protected]> |
||
|
|
2736a1ee33 |
test: align boost-ranker invalid-filter assertion with server wording (#53101)
`test_search_boost_ranker_invalid_filter` asserts that the error message for an invalid boost-ranker filter contains `parse expr failed`. That wording no longer exists anywhere in the server, so the case fails deterministically on master. #52778 ( |
||
|
|
06a86d47c9 |
test: Add search-by-PK input order regression test (#53091)
## Summary - Add Python Client E2E regression coverage for search-by-PK requests with non-ascending IDs. - Compare each search-by-PK top-1 result block with an equivalent ordinary vector search to verify positional correspondence. - Use an independent FLAT/L2 collection with strong consistency and deterministic orthogonal vectors. issue: #52862 ## Test Plan - [x] Run the new case against `harbor.milvus.io/milvusdb/milvus:3.0-20260901-eb4e2a97` (1 passed). - [x] Repeat the new case three times against the same deployment (3 passed). - [x] `python -m py_compile tests/python_client/milvus_client/test_milvus_client_search_by_pk.py` - [x] `git diff --check origin/master...HEAD` Signed-off-by: Yanliang Qiao <[email protected]> |
||
|
|
c30447158d |
test: retry CDC topology restore in force-promote teardown (#52993)
## Problem The CDC force-promote failover tests kill containers with chaos-mesh and restore the A→B topology in teardown. `wait_for_pods_ready` returns as soon as the Pod reports Ready, but the proxy can still refuse connections for a few seconds after that, so the single-shot switchover loses the race — and the teardown swallowed the failure as a warning, letting the test pass with the topology left broken for every later test. Observed in `milvus_cdc_failover_test` #55: - `03:08:23` `wait pods mcf-s-55: rc=0` (pods reported Ready) - `03:08:24` teardown starts restoring A→B - `03:08:25` `Fail connecting to server on <upstream>:19530` → logged as a warning, test still PASSED - next test then failed with `create collection ... sync failed after 30.11s timeout`, and its cleanup reported `cluster is not primary, cannot do any DDL/DCL` One root cause, a misleading failure in a different test. ## Changes **`tests/python_client/cdc/conftest.py`** - `switchover_helper` retries for up to 180s while a cluster is still refusing connections, rebuilding and closing its clients on each attempt. This covers every caller, including `test_switchover.py`. **`tests/python_client/cdc/testcases/test_force_promote.py`** - The six teardowns record a restore failure, still run `cleanup_resources()`, then re-raise it instead of warning — a broken topology can no longer silently poison later tests. ## Test Plan Injected connection failures into the shipped `do_switchover` path: - [x] transient refusals (the #55 scenario): retries, restores the topology, sends the config once - [x] cluster never recovers: raises after the deadline instead of continuing silently - [x] healthy cluster: succeeds on the first attempt, both clients closed, behavior unchanged - [x] `ruff check` with the repo's `tests/ruff.toml` passes Not exercised against a live cluster; the retry window (180s) is a first estimate based on the ~1s gap seen in #55 plus headroom. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Signed-off-by: bigsheeper <[email protected]> Co-authored-by: Claude Fable 5 <[email protected]> |
||
|
|
81be5438a5 |
test: run growing segment snapshot regression in CI (#53038)
issue: #52989 ## What changed Promote `test_snapshot_growing_segment_without_flush` from L2 to L0 so the regression test runs in CI. ## Why This test directly covers the snapshot restore regression reported in #52989. Running it in CI helps prevent the issue from recurring. ## Validation - `ruff check tests/python_client/milvus_client/test_milvus_client_snapshot.py` - Python syntax compilation passed - L0 collection check: 1 test collected - Targeted Python SDK E2E: 1 passed Signed-off-by: zhuwenxing <[email protected]> |
||
|
|
9adaf280f6 |
test: update outdated Python client expectations (#52997)
### What this PR does
Update two outdated Python SDK E2E expectations:
- Classify the newly added protobuf-only `Date`, `Time`, and `Decimal`
data types as unsupported for external table add-field operations.
- Validate duplicate primary keys during schema construction, where
current PyMilvus raises the error, instead of waiting for collection
creation.
Without the first classification, the external-table case fails with:
`external add-field proto DataType matrix is stale;
unclassified={28,29,30}`
### Verification
- Ruff checks passed.
- Python compilation passed.
- Both affected pytest nodes were collected successfully.
- Both affected Python SDK E2E cases passed against a master build:
-
`TestMilvusClientExternalTableAddField::test_milvus_client_external_table_add_all_supported_field_types`
-
`TestMilvusClientCollectionInvalid::test_milvus_client_collection_invalid_schema_multi_pk`
---------
Signed-off-by: zhuwenxing <[email protected]>
|
||
|
|
9c7f7329a6 |
test: cover embedding list indexes with trailing empty arrays (#52935)
## What this PR does Add Python SDK E2E coverage for Embedding List indexes whose sealed data ends with empty arrays. The test: - inserts non-empty Embedding Lists followed by trailing empty arrays; - builds and loads an HNSW index; - verifies filtered search over the indexed data; - retrieves the final non-empty row and the last two empty rows; - checks that trailing empty rows remain present and return empty arrays. ## Verification - Reproduction commit `b0d70ae`: failed with `failed to get emb list, invalid args`. - Current master-based image: passed. - `ruff check`: passed. - Python compilation check: passed. --------- Signed-off-by: zhuwenxing <[email protected]> Co-authored-by: Codex <[email protected]> |
||
|
|
3dfae89e93 |
feat: route general LIKE through FMINDEX with candidate recheck (#52697)
General LIKE with interior `%` or `_` was declined by FMINDEX even though PrefixMatch, PostfixMatch, and InnerMatch already use it. This routes VARCHAR Match through `ShouldUseOp`: split the pattern on wildcards, take candidates from the rarest literal fragment, then recheck those rows on sealed VARCHAR with `LikePatternMatcher` via `ProcessDataByOffsets`. FMINDEX load no longer materializes ISA. Match phase 2 rechecks candidate rows on sealed VARCHAR via ProcessDataByOffsets. The Match guard is locate-only again, the same occ times sa_sample_rate bound as Prefix, Inner, and Postfix. Empty-fragment patterns still decline. RegexMatch, equality, IN, TEXT, JSON, ARRAY, and growing segments are unchanged. FMINDEX Match is never served as unrechecked PatternMatch candidates through the ScalarIndex path. Design: `docs/design-docs/design_docs/20260708-fm_index_scalar_index.md` issue: #52683 ## How to test `LOCAL_STORAGE_SIZE=10` is required on this host. Without the VARCHAR recheck (product from `47f5cf5791`, tests kept): 5 FAILED (`ShouldUseOp(Match)` still prices Extract, so `%RARE%` / `%ZEBRA%` stay declined). With `7a3e274a36`: ``` source scripts/setenv.sh export DYLD_LIBRARY_PATH="$PWD/cmake_build/src:$DYLD_LIBRARY_PATH" LOCAL_STORAGE_SIZE=10 cmake_build/unittest/all_tests --gtest_filter='FMIndex.*' [==========] 23 tests from 1 test suite ran. [ PASSED ] 23 tests. ``` Includes `FMIndex.ExecutorPathMatchRechecksVarchar` and `FMIndex.MatchOracleEqualsBruteForce`. Whole C++ module (three Darwin crashers excluded): ``` export LOCAL_STORAGE_SIZE=10 internal/core/output/unittest/all_tests --gtest_filter='-JsonIndexTest.LargeInt64LiteralDoesNotAliasInDoublePathIndex:JsonFlatIndexExprTest.PreservesLargeInt64LiteralPrecision:SortBufferTest.*' [==========] Running 8326 tests from 473 test suites. [ PASSED ] 8167 tests. ``` None of the 138 failures are `FMIndex.*`. Reverse deps: Ngram 10/10, scalar/hybrid/inverted 26/26, json_stats_test 79/79, LikeConjunctExpr 1/1. /cc @xiaofan-luan --------- Signed-off-by: David Dallakyan <[email protected]> Signed-off-by: xiaofanluan <[email protected]> Co-authored-by: xiaofanluan <[email protected]> |
||
|
|
4461a40a2d |
test: stabilize chaos checker lifecycle and snapshot restore validation (#52901)
## What this PR does - bound and stagger expensive chaos checker operations - stop checker threads as a coordinated group and fail fast when they stall - isolate snapshot restore validation in a dedicated collection - verify restored row counts and sampled primary keys - avoid rebuilding indexes unnecessarily during chaos recovery - add structured checker observability and focused unit coverage - document entity-level TTL behavior ## Why Concurrent heavy checker operations can accumulate after fault recovery, delay snapshot restoration, and cause the validation stage to exceed its timeout. This change bounds checker lifecycle work, improves cleanup and recovery behavior, and makes stalled operations easier to diagnose. ## Validation - `ruff check` passed for all changed Python files - `git diff --check upstream/master...HEAD` - chaos checker unit tests: 27 passed - `test_concurrent_operation.py`: passed in 1005.20s - snapshot restore jobs: 8/8 completed - `test_single_request_operation.py`: passed in 1649.80s - snapshot restore jobs: 4/4 completed - standalone + Woodpecker validation against Milvus commit `f5eef7da8ab` - all 12 restore jobs completed in 2.6–22.0 seconds without restore timeout ## Notes The end-to-end validation covered the concurrent baseline without active chaos injection. Fault-injection recovery remains covered by the scheduled chaos pipelines. --------- Signed-off-by: zhuwenxing <[email protected]> |
||
|
|
b50db3004e |
test: e2e for schema-bump backfill over added-field function input and TEXT LOB (#52662)
### What problem master e2e never covers two schema-bump additive intersections: (1) an `add_function_field` whose input VARCHAR was itself added via `add_collection_field` after the data was sealed (the exact crash shape of issue #52159); (2) an `add_function_field` bump triggered while the collection already holds a TEXT LOB column. Today `test_add_function_field_feature.py` uses only create-time VARCHAR inputs (no `add_collection_field`), and `test_milvus_client_text_lob.py` has no `add_function_field` at all — the two concerns never meet. ### What this does Add two pymilvus e2e cases into the existing files (reusing their helpers, no new file): - `test_add_bm25_function_field_on_backfilled_varchar_input`: seal rows without the varchar, `add_collection_field(VARCHAR)`, then `add_function_field` BM25 whose input is that added field. Asserts: old rows read back null; sibling columns (code/vec) are byte-exact per row against the inserted values; schema_version increments across both bumps; null-input rows are never matched by BM25. - `test_text_lob_add_function_field_bump_preserves_lob`: sealed TEXT LOB rows in four states (external/inline/empty/null) plus an `add_function_field` BM25 bump. Asserts: every `content` payload is preserved byte-exact; sibling columns (tag/vector) stay intact per row; a post-bump insert is still exact. Add base helper `wait_for_schema_version_consistency`: gate bump completion on the DataCoord-emitted `schema_version_consistent_segments == schema_version_total_segments` stats (via `get_collection_stats`) instead of a fixed sleep; combined with a `describe_collection` schema_version increment assertion so the gate cannot pass on the pre-bump state. ### Dependency / notes - Depends on the master fix landing first: `pr: #52484` (issue #52159). Until it merges, `test_add_bm25_function_field_on_backfilled_varchar_input` reproduces a `panic: no such field` on the datanode (exactly the regression this test guards), so CI is expected RED — this is intended. - Validated locally with a with-fix / without-fix two-arm comparison: the without-fix binary reproduces the panic (RED), the with-fix binary passes both tests (GREEN). External LOB goes through the `.vx` ref and the bump uses REUSE_ALL (LOB path unchanged), both confirmed against on-disk storage. - Requires `dataCoord.compaction.bumpSchemaVersion.enabled: true` (already set in the three e2e helm values). - Related enhancement tracking: #51649. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Also folds in a one-line repair of a stale L2 assertion (issue: #52878): #52219 intentionally dropped the computed expected dim from the minhash dim-mismatch message (overflow-safe division check), so the assertion no longer expects the literal `512`. Signed-off-by: MrPresent-Han <[email protected]> Co-authored-by: MrPresent-Han <[email protected]> Co-authored-by: Claude Opus 4.8 <[email protected]> |
||
|
|
b277503c9b |
test: stop pinning the knowhere codec list in test_sparse_index_rejects_invalid_codec (#52758)
<!-- team2-testfix:52645 --> fix: #52645 ## What Test-only change. `test_sparse_index_rejects_invalid_codec` asserted the full server error message, including the `supported: [...]` list that knowhere generates. That list legitimately grows when knowhere is upgraded (it gained `block_adaptive`), so the assertion breaks on a correct server. The expectation is narrowed to the part that does not drift: ``` "inverted_index_codec invalid_codec not found or not supported" ``` The check is a substring match (`assert error_dict[err_msg] in res.message`), so the shortened expectation still verifies that the invalid codec is rejected, and the error-code assertion (1100) is unchanged. Sibling negative cases in the same file (`inverted_index_algo`, `quant_type`) already use this short-prefix form; this makes the codec case consistent with them. No product code is touched. ## Why this is not a server bug - `grep -rn "block_streamvbyte\|block_maskedvbyte\|block_adaptive"` over the repository matches only this test file. The parameter name and the `supported: [...]` list come from the knowhere binary; Milvus passes the parameters through `ValidateIndexParams` (cgo). - The error code is 1100 on both sides and the rejection path executes correctly — only the set of supported codecs grew. - There is no upstream fix to backport: the hardcoded string was introduced in `0bbe4d02a8` (#50775) and has not been touched since. - No cross-repo change is involved: pymilvus only relays the server's error message; the proto is unchanged. ## Evidence The single failing case was run against one running Milvus instance, alternating unpatched/patched twice each (`milvus_client/test_milvus_client_sparse_inverted_index.py::TestSparseInvertedIndexV3Negative::test_sparse_index_rejects_invalid_codec`): | run | unpatched | patched | |---|---|---| | 1 | fails with the reported assertion | passes | | 2 | fails with the reported assertion | passes | --- _Automated draft from the team2 pipeline. Not auto-merged; please review._ Signed-off-by: zhenshan.cao <[email protected]> |
||
|
|
cfa24c7488 |
enhance: refactor merge operator for declarative construction (#52665)
- construct merge operators from representations with runtime search metrics - validate multi-input layouts and preserve native row and element identities - round-trip element indices through DataFrame conversion - remove synthetic hybrid element keys and the select operator - add design documents and regression coverage issue: #https://github.com/milvus-io/milvus/issues/52319 Signed-off-by: junjie.jiang <[email protected]> |
||
|
|
82edd6b254 |
test: reduce e2e setup cost via shared collections (T2 geometry/minhash + reranker dedup) (#52765)
## Goal pytest E2E runtime is dominated by setup (create + insert + index); search/query is negligible. This PR adopts the "one setup, many verification points" pattern (shared collections / wide tables) to cut redundant setup **without reducing any coverage** (all parametrized cases and assertions are preserved, no values trimmed). ## Changes (4 commits) ### 1. Geometry shared collections (pilot, measured −20% wall-clock) - `TestMilvusClientGeometryInsertShared`: 14 insert-family cases share 1 collection (ids partitioned per WKT type), collapsing 14 setups → 1. - `TestMilvusClientGeometrySpatialShared`: 14 spatial-operator cases share 1 dataset provisioned in 2 collections (RTREE / no geo index), collapsing 14 setups → 2. - Template: `@pytest.mark.xdist_group` + module-scoped fixture + `force_teardown=False` + `request.addfinalizer`. - Measured against a test cluster: 123 passed / 3 skipped unchanged, **137.2s → 110.4s**. ### 2. search.py stale reranker dedup - `test_milvus_client_search_with_reranker` (288 combos, in-body setup) is a duplicate of `search_reranker.py::TestMilvusClientSearchDecayRerankShared` (identical schema/parametrization/assertions). Removed the stale copy (−288 setups/PR); coverage kept by the shared version. ### 3. minhash default-schema shared collection - `TestMilvusClientMinHashDefaultShared`: 3 read tests (search_basic / search_with_filter / query_by_id) share 1 collection. Results identical to baseline (the file was already fast, so the gain is marginal). ### 4. Review fixes - Replaced module-level globals with class attributes; cached client across the class; added clarifying comments (RTREE-on-empty, geo-index semantic change); extra dedup of `test_milvus_client_search_with_reranker_default_offset_decay` (shared version is a strict superset). All commits carry `Signed-off-by`. ## Verification - geometry + minhash run against a test cluster: 196 passed; the 2 `TestMinHashBulkImport` failures are pre-existing environment issues (also fail on master, need MinIO config). - `ruff check` / `ruff format` pass. - No parametrized values changed — zero coverage loss. ## Background First batch of the e2e runtime optimization (T2: one-setup-many-queries). Follow-ups planned per schema clustering (struct_array_element_search, external_table, search.py remaining, restful tag audit). --------- Signed-off-by: Yanliang Qiao <[email protected]> |
||
|
|
8f3de28158 |
test: tolerate rerank score drift when comparing rerank results (#52742)
## What this PR does / why we need it Fixes #52737. `test_milvus_client_single_vector_search_with_model_rerank` compares Milvus rerank results against a fresh ground-truth `/rerank` call with **exact list equality**. The reranker service is not bit-reproducible run to run on GPU (nondeterministic reduction order + float16 amplifies it into ~1e-3 relative score movement), so the assertion fails on near-ties — two neighbouring candidates whose scores differ by less than the service's own reproducibility error swap places. ## Changes In both `compare_milvus_rerank_with_origin_rerank` implementations (`test_milvus_client_search.py` and `test_milvus_client_search_reranker.py`): - Compare the reranked document **set** exactly (`sorted(actual) == sorted(gt)`). - Enforce **ordering only between documents whose ground-truth scores differ beyond a tolerance** (`rel_tol=0.05`, `abs_tol=1e-6`); near-ties are allowed to swap. ## Why this doesn't mask real bugs - CPU backends are bit-identical, so the tolerance never loosens a deterministic run. - A genuine ordering/pairing bug moves a score by far more than the tolerance, so the epsilon-guarded order check (and the set check) still catch it. ## Verification - Ran `[True-tei]` / `[False-tei]` single-vector rerank and `[tei]` hybrid rerank in both files against a standalone Milvus + TEI reranker (CPU float32) — all passed. - Standalone check with the failing run's data: near-tie swap is tolerated, far-apart swap and wrong-set are still caught. Signed-off-by: Yanliang Qiao <[email protected]> |
||
|
|
e6f4533744 |
feat: Support L1 rerank (#52376)
doc: docs/design-docs/design_docs/20260624-function-chain-api.md #52319 Signed-off-by: junjie.jiang <[email protected]> |
||
|
|
f744f11e82 |
test: avoid float-int collision in json_contains_any test data (#52616)
## Related Issue Fixes #52594 ## What type of PR is this? - [x] test ## What this PR does Fixes a flaky test `test_milvus_client_query_expr_all_datatype_json_contains_any` that intermittently fails with `1501 == 1500`. ## Root cause The JSON field's `listMix` float element was built as `i * 1.1`. Under IEEE 754 double arithmetic, some products round exactly to an integer (e.g. `1190 * 1.1 == 1309.0`). When the random `_id` lands on such a value, segcore's `json_contains_any` (intentionally) matches the JSON double `1309.0` against the int64 query element, so an extra even row satisfies the predicate and the hardcoded `default_nb // 2` assertion fails. This is a test-data defect, not a product bug — the server result is correct for the inserted data. ## Changes Replace `i * 1.1` with `i + 0.5` (which can never equal an integer) in the three affected spots in `tests/python_client/milvus_client/test_milvus_client_query.py`: - `listMix` in `test_milvus_client_query_expr_list_all_datatype_json_contains_all` - `listMix` in `test_milvus_client_query_expr_all_datatype_json_contains_any` (the flaky test) - `mix_data` in `test_milvus_client_query_expr_list_all_datatype_json_contains_any` ## Verification - Reproduced before the fix: `json_contains_any(listMix, [1309, True])` returned 1501 rows (extra even row `int64=1190`). - After the fix, forcing the previously-colliding `_id=1309` returns exactly 1500 rows. - `test_milvus_client_query_expr_all_datatype_json_contains_any` passed 5 consecutive rounds (10 parametrized runs). - The other two touched tests passed as well (2 + 4 parametrized runs). Signed-off-by: Yanliang Qiao <[email protected]> |
||
|
|
9b6f05b0cb |
test: fix external table drop-function e2e to use drop_function_field (#52674)
## What type of PR is this? - [x] test ## What this PR does / why we need it Fixes `test_milvus_client_external_table_drop_function_rejected`, which asserted the old external-collection rejection message. The `DropCollectionFunction` RPC is deprecated and the proxy now rejects it earlier (impl.go:1409) with a different message, before the external-collection schema check runs, so the test failed on message comparison. Switch the test from `drop_collection_function` to `drop_function_field`, which routes through `AlterCollectionSchema` and still exercises the external-collection schema protection, producing the expected `alter collection schema operation is not supported for external collection` rejection. ## Which issues does this PR resolve? Fixes #52646 ## Test evidence - Reproduced the failure against master + pymilvus 3.1.0rc80, then verified the fixed test passes: `pytest milvus_client/test_milvus_client_external_table.py -k test_milvus_client_external_table_drop_function_rejected` → 1 passed Signed-off-by: Yanliang Qiao <[email protected]> |
||
|
|
9672073f7a |
test: add e2e for query order by with vector output (#52574)
## Summary Add E2E regression test OB-063 for #52463: scalar Query ORDER BY combined with a dense vector in `output_fields` used to fail with `unsupported data type VECTOR_FLOAT` (segcoreCode=2001) because the vector was materialized in the pre-TopK ProjectNode (single-project mode). Fixed by #52498, which defers vector outputs to late materialization after TopK. issue: #52463 ### Test design - All-fixed-width schema (`id` / `rank` / `vec`, no variable-width field), so the pre-fix planner takes the single-project path that triggers the bug - Sort key `rank = (i*7)%10` is a coprime permutation of 0..9: unique keys, deterministic total order, and a real row permutation, so the deferred post-TopK vector fetch must actually reorder rows (an `id:asc` sort would be an identity permutation and could mask a reordering bug) - Covers both explicit (`["id","rank","vec"]`) and wildcard (`["*"]`) output_fields - Asserts ascending rank order and verifies each returned vector's payload against its row id (`vec[0] == id`) ### Test plan - [x] Fails on pre-fix build `3.0-20260814-566ace73` with the exact issue error: `unsupported data type VECTOR_FLOAT at Utils.cpp:1712`, code=2000 - [x] Passes on post-fix build `master-20260817-c2a92a8a` (contains #52498), cluster mode, both via LB endpoint and port-forward Signed-off-by: lyyyuna <[email protected]> |
||
|
|
e2a193598b |
test: add REST ordering, aggregation, and schema evolution coverage (#52170)
## Summary - Add REST v2 query and search coverage for `orderByFields`, query aggregation, and `searchAggregation`. - Add REST v2 schema-evolution coverage for drop field and atomic add/drop function-field operations. - Extend the REST test client with `add_function_field` and `drop_function_field` helpers. - Keep schema-evolution cases focused on REST request parameters and resulting metadata, without duplicating segment lifecycle or multi-replica coverage. ## Coverage - Query/search ordering with filters, pagination, nullable fields, deterministic member assertions, and deliberately distinct ANN/scalar/PK ordering. - Query/search aggregation with exact metrics and hit-score oracles, nullable group keys, composite/nested groups, `searchSize`, `topHits`, and multi-query ownership. - Drop field invalid identifier combinations, protected or unknown fields, repeated drops, and complete before/after schema-index snapshots. - Add function field required objects, field-name binding, default AutoIndex behavior, output-field/function/index metadata, and rejected-request atomicity. - Drop function field selective cascade across two bindings, invalid or repeated drops, and field dependency validation. Related changes: #52071, #51360, #51411 ## Test Plan - `python3 -m pytest testcases/test_query_order_by.py testcases/test_search_order_by.py testcases/test_query_aggregation.py testcases/test_search_aggregation.py testcases/test_drop_field_operations.py testcases/test_function_field_operations.py --endpoint http://127.0.0.1:19530 --token root:Milvus --minio_host 127.0.0.1 -q -s` - 66 passed - `python3 -m pytest milvus_client/test_milvus_client_search_aggregation.py --host 127.0.0.1 --port 19530 --user root --password Milvus --token root:Milvus -q -s` - 51 passed, 1 existing xfailed - `ruff check` on all seven changed test files - `ruff format --check` on all seven changed test files - `git diff --check` --------- Signed-off-by: lyyyuna <[email protected]> Co-authored-by: Claude Opus 4.6 <[email protected]> |
||
|
|
abe869648e |
test: strengthen add function field search readiness coverage (#52131)
## Summary - Align add-function-field search polling with the schema-evolution readiness policy. - Record transient search errors and empty-result timing, then require a 2-second post-hit wait followed by five successful fixed verification rounds. - Require exact ordered topK IDs for whole-result comparisons and fail immediately on non-empty unexpected results. - Add regression coverage for the #51366 path with a post-created base index and 512 total rows. Related: #51366 ## Test Plan - `git diff --check` - `ruff check tests/python_client/milvus_client/test_add_function_field_feature.py` - `ruff format --check tests/python_client/milvus_client/test_add_function_field_feature.py` - `python -m py_compile tests/python_client/milvus_client/test_add_function_field_feature.py` - Targeted E2E on `schema-evolution-v3-latest` using `3.0-20260810-e2820e27`: 3 passed in 320.79s - Full `test_add_function_field_feature.py` run after the 2-second wait change on `schema-evolution-v3-latest`: 23 passed in 900.08s --------- Signed-off-by: lyyyuna <[email protected]> Co-authored-by: Claude Opus 4.6 <[email protected]> |