2021-10-27 17:44:48 +08:00
|
|
|
// Licensed to the LF AI & Data foundation under one
|
|
|
|
// or more contributor license agreements. See the NOTICE file
|
|
|
|
// distributed with this work for additional information
|
|
|
|
// regarding copyright ownership. The ASF licenses this file
|
|
|
|
// to you under the Apache License, Version 2.0 (the
|
|
|
|
// "License"); you may not use this file except in compliance
|
2021-04-19 13:50:12 +08:00
|
|
|
// with the License. You may obtain a copy of the License at
|
|
|
|
//
|
2021-10-27 17:44:48 +08:00
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
2021-04-19 13:50:12 +08:00
|
|
|
//
|
2021-10-27 17:44:48 +08:00
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
2021-04-19 13:50:12 +08:00
|
|
|
|
2021-06-21 17:28:03 +08:00
|
|
|
package indexcoord
|
2021-01-26 09:38:40 +08:00
|
|
|
|
|
|
|
import (
|
|
|
|
"container/heap"
|
|
|
|
"sync"
|
2021-12-09 14:19:40 +08:00
|
|
|
|
|
|
|
"github.com/milvus-io/milvus/internal/proto/commonpb"
|
2021-01-26 09:38:40 +08:00
|
|
|
)
|
|
|
|
|
2021-09-30 11:06:04 +08:00
|
|
|
// PQItem is something we manage in a priority queue.
|
2021-01-26 09:38:40 +08:00
|
|
|
type PQItem struct {
|
2021-07-14 14:15:55 +08:00
|
|
|
key UniqueID
|
2021-05-27 22:24:29 +08:00
|
|
|
|
2021-01-26 09:38:40 +08:00
|
|
|
priority int // The priority of the item in the queue.
|
|
|
|
// The index is needed by update and is maintained by the heap.Interface methods.
|
2021-11-01 17:16:05 +08:00
|
|
|
weight int // The weight of the item in the queue.
|
|
|
|
// When the priority is the same, a smaller weight is more preferred.
|
2021-01-26 09:38:40 +08:00
|
|
|
index int // The index of the item in the heap.
|
2021-12-09 14:19:40 +08:00
|
|
|
|
|
|
|
totalMem uint64 // The total memory of the IndexNode.
|
2021-01-26 09:38:40 +08:00
|
|
|
}
|
|
|
|
|
2021-09-30 11:06:04 +08:00
|
|
|
// PriorityQueue implements heap.Interface and holds Items.
|
2021-01-26 09:38:40 +08:00
|
|
|
type PriorityQueue struct {
|
2021-12-09 14:19:40 +08:00
|
|
|
items []*PQItem
|
|
|
|
lock sync.RWMutex
|
|
|
|
policy PeekClientPolicy
|
2021-01-26 09:38:40 +08:00
|
|
|
}
|
|
|
|
|
2021-09-30 11:06:04 +08:00
|
|
|
// Len is the length of the priority queue.
|
2021-01-26 09:38:40 +08:00
|
|
|
func (pq *PriorityQueue) Len() int {
|
|
|
|
return len(pq.items)
|
|
|
|
}
|
|
|
|
|
2021-09-30 11:06:04 +08:00
|
|
|
// Less reports whether the element with index i
|
|
|
|
// must sort before the element with index j.
|
2021-01-26 09:38:40 +08:00
|
|
|
func (pq *PriorityQueue) Less(i, j int) bool {
|
|
|
|
// We want Pop to give us the highest, not lowest, priority so we use greater than here.
|
2021-11-01 17:16:05 +08:00
|
|
|
return (pq.items[i].priority < pq.items[j].priority) ||
|
|
|
|
(pq.items[i].priority == pq.items[j].priority && pq.items[i].weight < pq.items[j].weight)
|
2021-01-26 09:38:40 +08:00
|
|
|
}
|
|
|
|
|
2021-09-30 11:06:04 +08:00
|
|
|
// Swap swaps the elements with indexes i and j.
|
2021-01-26 09:38:40 +08:00
|
|
|
func (pq *PriorityQueue) Swap(i, j int) {
|
|
|
|
pq.items[i], pq.items[j] = pq.items[j], pq.items[i]
|
|
|
|
pq.items[i].index = i
|
|
|
|
pq.items[j].index = j
|
|
|
|
}
|
|
|
|
|
2021-09-30 11:06:04 +08:00
|
|
|
// Push adds an element to the priority.
|
2021-01-26 09:38:40 +08:00
|
|
|
func (pq *PriorityQueue) Push(x interface{}) {
|
|
|
|
pq.lock.Lock()
|
|
|
|
defer pq.lock.Unlock()
|
|
|
|
n := (*pq).Len()
|
|
|
|
item := x.(*PQItem)
|
|
|
|
item.index = n
|
|
|
|
pq.items = append(pq.items, item)
|
|
|
|
}
|
|
|
|
|
2021-05-31 10:32:30 +08:00
|
|
|
// Pop do not call this directly.
|
2021-01-26 09:38:40 +08:00
|
|
|
func (pq *PriorityQueue) Pop() interface{} {
|
|
|
|
old := pq.items
|
|
|
|
n := len(old)
|
|
|
|
item := old[n-1]
|
|
|
|
item.index = -1 // for safety
|
|
|
|
pq.items = old[0 : n-1]
|
|
|
|
return item
|
|
|
|
}
|
|
|
|
|
2021-09-30 11:06:04 +08:00
|
|
|
// CheckExist checks whether the nodeID is already in the priority.
|
2021-07-14 14:15:55 +08:00
|
|
|
func (pq *PriorityQueue) CheckExist(nodeID UniqueID) bool {
|
2021-01-26 09:38:40 +08:00
|
|
|
pq.lock.RLock()
|
|
|
|
defer pq.lock.RUnlock()
|
|
|
|
|
|
|
|
for _, item := range pq.items {
|
2021-07-14 14:15:55 +08:00
|
|
|
if nodeID == item.key {
|
2021-01-26 09:38:40 +08:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func (pq *PriorityQueue) getItemByKey(key UniqueID) interface{} {
|
|
|
|
var ret interface{} = nil
|
|
|
|
for _, item := range pq.items {
|
|
|
|
if item.key == key {
|
|
|
|
ret = item
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
2021-05-31 10:32:30 +08:00
|
|
|
// IncPriority update modifies the priority and value of an Item in the queue.
|
2021-01-26 09:38:40 +08:00
|
|
|
func (pq *PriorityQueue) IncPriority(key UniqueID, priority int) {
|
|
|
|
pq.lock.Lock()
|
|
|
|
defer pq.lock.Unlock()
|
|
|
|
item := pq.getItemByKey(key)
|
|
|
|
if item != nil {
|
|
|
|
item.(*PQItem).priority += priority
|
2021-11-01 17:16:05 +08:00
|
|
|
if priority > 0 {
|
|
|
|
item.(*PQItem).weight += priority
|
|
|
|
}
|
2021-01-26 09:38:40 +08:00
|
|
|
heap.Fix(pq, item.(*PQItem).index)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-31 10:32:30 +08:00
|
|
|
// UpdatePriority update modifies the priority and value of an Item in the queue.
|
2021-01-26 09:38:40 +08:00
|
|
|
func (pq *PriorityQueue) UpdatePriority(key UniqueID, priority int) {
|
|
|
|
pq.lock.Lock()
|
|
|
|
defer pq.lock.Unlock()
|
|
|
|
item := pq.getItemByKey(key)
|
|
|
|
if item != nil {
|
|
|
|
item.(*PQItem).priority = priority
|
2021-11-01 17:16:05 +08:00
|
|
|
item.(*PQItem).weight = priority
|
2021-01-26 09:38:40 +08:00
|
|
|
heap.Fix(pq, item.(*PQItem).index)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-30 11:06:04 +08:00
|
|
|
// Remove deletes the corresponding item according to the key.
|
2021-01-26 09:38:40 +08:00
|
|
|
func (pq *PriorityQueue) Remove(key UniqueID) {
|
|
|
|
pq.lock.Lock()
|
|
|
|
defer pq.lock.Unlock()
|
|
|
|
item := pq.getItemByKey(key)
|
|
|
|
if item != nil {
|
|
|
|
heap.Remove(pq, item.(*PQItem).index)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-03 10:13:55 +08:00
|
|
|
// Peek picks an key with the lowest load.
|
2021-12-09 14:19:40 +08:00
|
|
|
func (pq *PriorityQueue) Peek(memorySize uint64, indexParams []*commonpb.KeyValuePair, typeParams []*commonpb.KeyValuePair) UniqueID {
|
2021-01-26 09:38:40 +08:00
|
|
|
pq.lock.RLock()
|
|
|
|
defer pq.lock.RUnlock()
|
|
|
|
|
2021-07-14 14:15:55 +08:00
|
|
|
if pq.Len() == 0 {
|
|
|
|
return UniqueID(-1)
|
2021-01-26 09:38:40 +08:00
|
|
|
}
|
2021-12-09 14:19:40 +08:00
|
|
|
return pq.policy(memorySize, indexParams, typeParams, pq)
|
2021-01-26 09:38:40 +08:00
|
|
|
}
|
2021-02-23 11:57:18 +08:00
|
|
|
|
2021-09-30 11:06:04 +08:00
|
|
|
// PeekAll return the key of all the items.
|
2021-07-14 14:15:55 +08:00
|
|
|
func (pq *PriorityQueue) PeekAll() []UniqueID {
|
2021-02-23 11:57:18 +08:00
|
|
|
pq.lock.RLock()
|
|
|
|
defer pq.lock.RUnlock()
|
|
|
|
|
2021-07-14 14:15:55 +08:00
|
|
|
var ret []UniqueID
|
2021-02-23 11:57:18 +08:00
|
|
|
for _, item := range pq.items {
|
2021-07-14 14:15:55 +08:00
|
|
|
ret = append(ret, item.key)
|
2021-02-23 11:57:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret
|
|
|
|
}
|