fix: resolve data race in indexMeta (#46763)

issue: #46762

Copy the fieldIndexes map while holding the read lock to prevent data
race. The original code released the lock before iterating over the map,
which could cause concurrent access issues.

Affected methods:
- GetSegmentIndexState
- GetIndexedSegments
- IsUnIndexedSegment
- GetSegmentIndexedFields

Signed-off-by: Wei Liu <wei.liu@zilliz.com>
This commit is contained in:
wei liu 2026-01-07 10:33:25 +08:00 committed by GitHub
parent 4719cb80ca
commit 3242895999
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -519,12 +519,17 @@ func (m *indexMeta) GetSegmentIndexState(collID, segmentID UniqueID, indexID Uni
}
m.fieldIndexLock.RLock()
fieldIndexes, ok := m.indexes[collID]
fieldIndexesMap, ok := m.indexes[collID]
if !ok {
state.FailReason = fmt.Sprintf("collection not exist with ID: %d", collID)
m.fieldIndexLock.RUnlock()
return state
}
// Copy the map to avoid data race after releasing the lock
fieldIndexes := make(map[UniqueID]*model.Index, len(fieldIndexesMap))
for id, index := range fieldIndexesMap {
fieldIndexes[id] = index
}
m.fieldIndexLock.RUnlock()
indexes, ok := m.segmentIndexes.Get(segmentID)
@ -551,11 +556,16 @@ func (m *indexMeta) GetSegmentIndexState(collID, segmentID UniqueID, indexID Uni
func (m *indexMeta) GetIndexedSegments(collectionID int64, segmentIDs, fieldIDs []UniqueID) []int64 {
m.fieldIndexLock.RLock()
fieldIndexes, ok := m.indexes[collectionID]
fieldIndexesMap, ok := m.indexes[collectionID]
if !ok {
m.fieldIndexLock.RUnlock()
return nil
}
// Copy the map to avoid data race after releasing the lock
fieldIndexes := make(map[UniqueID]*model.Index, len(fieldIndexesMap))
for id, index := range fieldIndexesMap {
fieldIndexes[id] = index
}
m.fieldIndexLock.RUnlock()
fieldIDSet := typeutil.NewUniqueSet(fieldIDs...)
@ -684,11 +694,16 @@ func (m *indexMeta) MarkIndexAsDeleted(ctx context.Context, collID UniqueID, ind
func (m *indexMeta) IsUnIndexedSegment(collectionID UniqueID, segID UniqueID) bool {
m.fieldIndexLock.RLock()
fieldIndexes, ok := m.indexes[collectionID]
fieldIndexesMap, ok := m.indexes[collectionID]
if !ok {
m.fieldIndexLock.RUnlock()
return false
}
// Copy the map to avoid data race after releasing the lock
fieldIndexes := make(map[UniqueID]*model.Index, len(fieldIndexesMap))
for id, index := range fieldIndexesMap {
fieldIndexes[id] = index
}
m.fieldIndexLock.RUnlock()
// the segment should be unindexed status if the fieldIndexes is not nil
@ -1189,12 +1204,17 @@ func (m *indexMeta) GetIndexJSON(collectionID int64) string {
func (m *indexMeta) GetSegmentIndexedFields(collectionID UniqueID, segmentID UniqueID) (bool, []*metricsinfo.IndexedField) {
m.fieldIndexLock.RLock()
fieldIndexes, ok := m.indexes[collectionID]
fieldIndexesMap, ok := m.indexes[collectionID]
if !ok {
// the segment should be unindexed status if the collection has no indexes
m.fieldIndexLock.RUnlock()
return false, []*metricsinfo.IndexedField{}
}
// Copy the map to avoid data race after releasing the lock
fieldIndexes := make(map[UniqueID]*model.Index, len(fieldIndexesMap))
for id, index := range fieldIndexesMap {
fieldIndexes[id] = index
}
m.fieldIndexLock.RUnlock()
// the segment should be unindexed status if the segment indexes is not found