From c0029b788dfdcea56e27ca83c1787e3464f39ad3 Mon Sep 17 00:00:00 2001 From: Spade A <71589810+SpadeA-Tang@users.noreply.github.com> Date: Tue, 4 Nov 2025 20:19:33 +0800 Subject: [PATCH] fix: alter collection failed with MMAP setting for STRUCT (#45173) issue: https://github.com/milvus-io/milvus/issues/45001 ref: https://github.com/milvus-io/milvus/issues/42148 --------- Signed-off-by: SpadeA Signed-off-by: aoiasd Signed-off-by: SpadeA-Tang Co-authored-by: aoiasd --- internal/metastore/model/struct_field.go | 10 ++++++- internal/querycoordv2/task/utils.go | 30 +++++++++++++++++++-- internal/rootcoord/alter_collection_task.go | 11 ++++---- pkg/common/common.go | 22 +++++++++++++++ 4 files changed, 65 insertions(+), 8 deletions(-) diff --git a/internal/metastore/model/struct_field.go b/internal/metastore/model/struct_field.go index a5c91fa395..27292d2b0c 100644 --- a/internal/metastore/model/struct_field.go +++ b/internal/metastore/model/struct_field.go @@ -1,7 +1,9 @@ package model import ( + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" "github.com/milvus-io/milvus-proto/go-api/v2/schemapb" + "github.com/milvus-io/milvus/pkg/v2/common" ) type StructArrayField struct { @@ -9,6 +11,7 @@ type StructArrayField struct { Name string Description string Fields []*Field + TypeParams []*commonpb.KeyValuePair } func (s *StructArrayField) Clone() *StructArrayField { @@ -17,6 +20,7 @@ func (s *StructArrayField) Clone() *StructArrayField { Name: s.Name, Description: s.Description, Fields: CloneFields(s.Fields), + TypeParams: common.CloneKeyValuePairs(s.TypeParams), } } @@ -29,10 +33,12 @@ func CloneStructArrayFields(structArrayFields []*StructArrayField) []*StructArra } func (s *StructArrayField) Equal(other StructArrayField) bool { + var paramsA common.KeyValuePairs = s.TypeParams return s.FieldID == other.FieldID && s.Name == other.Name && s.Description == other.Description && - CheckFieldsEqual(s.Fields, other.Fields) + CheckFieldsEqual(s.Fields, other.Fields) && + paramsA.Equal(other.TypeParams) } func CheckStructArrayFieldsEqual(structArrayFieldsA, structArrayFieldsB []*StructArrayField) bool { @@ -63,6 +69,7 @@ func MarshalStructArrayFieldModel(structArrayField *StructArrayField) *schemapb. Name: structArrayField.Name, Description: structArrayField.Description, Fields: MarshalFieldModels(structArrayField.Fields), + TypeParams: structArrayField.TypeParams, } } @@ -88,6 +95,7 @@ func UnmarshalStructArrayFieldModel(fieldSchema *schemapb.StructArrayFieldSchema Name: fieldSchema.Name, Description: fieldSchema.Description, Fields: UnmarshalFieldModels(fieldSchema.Fields), + TypeParams: fieldSchema.TypeParams, } } diff --git a/internal/querycoordv2/task/utils.go b/internal/querycoordv2/task/utils.go index 62307ad3a8..cb91967dcc 100644 --- a/internal/querycoordv2/task/utils.go +++ b/internal/querycoordv2/task/utils.go @@ -285,9 +285,35 @@ func applyCollectionMmapSetting(schema *schemapb.CollectionSchema, } } for _, structField := range schema.GetStructArrayFields() { + structTypeParams := structField.GetTypeParams() + structMmapEnabled, structExist := common.IsMmapDataEnabled(structTypeParams...) + + // If struct field itself doesn't have mmap setting, inherit from collection + if !structExist && exist && + !common.FieldHasMmapKey(schema, structField.GetFieldID()) { + structField.TypeParams = append(structField.TypeParams, &commonpb.KeyValuePair{ + Key: common.MmapEnabledKey, + Value: strconv.FormatBool(collectionMmapEnabled), + }) + // Update struct's mmap state since we just set it + structMmapEnabled = collectionMmapEnabled + structExist = true + } + + // Apply mmap setting to fields inside struct for _, field := range structField.GetFields() { - if exist && - !common.FieldHasMmapKey(schema, field.GetFieldID()) { + // Skip if field already has mmap setting + if common.FieldHasMmapKey(schema, field.GetFieldID()) { + continue + } + + // Priority: struct field setting > collection setting + if structExist { + field.TypeParams = append(field.TypeParams, &commonpb.KeyValuePair{ + Key: common.MmapEnabledKey, + Value: strconv.FormatBool(structMmapEnabled), + }) + } else if exist { field.TypeParams = append(field.TypeParams, &commonpb.KeyValuePair{ Key: common.MmapEnabledKey, Value: strconv.FormatBool(collectionMmapEnabled), diff --git a/internal/rootcoord/alter_collection_task.go b/internal/rootcoord/alter_collection_task.go index b90b614437..d263ecd192 100644 --- a/internal/rootcoord/alter_collection_task.go +++ b/internal/rootcoord/alter_collection_task.go @@ -91,13 +91,14 @@ func ResetFieldProperties(coll *model.Collection, fieldName string, newProps []* return nil } } - for _, structField := range coll.StructArrayFields { + for i, structField := range coll.StructArrayFields { if structField.Name == fieldName { - return merr.WrapErrParameterInvalidMsg("struct field has no properties to alter", fieldName) + coll.StructArrayFields[i].TypeParams = newProps + return nil } - for i, field := range structField.Fields { + for j, field := range structField.Fields { if field.Name == fieldName { - structField.Fields[i].TypeParams = newProps + coll.StructArrayFields[i].Fields[j].TypeParams = newProps return nil } } @@ -113,7 +114,7 @@ func GetFieldProperties(coll *model.Collection, fieldName string) ([]*commonpb.K } for _, structField := range coll.StructArrayFields { if structField.Name == fieldName { - return nil, merr.WrapErrParameterInvalidMsg("struct field has no properties", fieldName) + return structField.TypeParams, nil } for _, field := range structField.Fields { if field.Name == fieldName { diff --git a/pkg/common/common.go b/pkg/common/common.go index b051491e8f..3b0db81c96 100644 --- a/pkg/common/common.go +++ b/pkg/common/common.go @@ -316,6 +316,28 @@ func FieldHasMmapKey(schema *schemapb.CollectionSchema, fieldID int64) bool { return false } } + // Check struct array fields + for _, structField := range schema.GetStructArrayFields() { + if structField.GetFieldID() == fieldID { + for _, kv := range structField.GetTypeParams() { + if kv.Key == MmapEnabledKey { + return true + } + } + return false + } + // Check fields inside struct + for _, field := range structField.GetFields() { + if field.GetFieldID() == fieldID { + for _, kv := range field.GetTypeParams() { + if kv.Key == MmapEnabledKey { + return true + } + } + return false + } + } + } return false }