321 lines
7.7 KiB
Go
321 lines
7.7 KiB
Go
// Copyright 2017 The Kubernetes Authors.
|
|
// Copyright 2024 PingCAP, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// 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.
|
|
// Modifications:
|
|
// 1. Use "github.com/stretchr/testify/require" to do assertions.
|
|
// 2. Test max heap instead of min heap.
|
|
// 3. Add a test for the peak API.
|
|
// 4. Add a test for the IsEmpty API.
|
|
// 5. Remove concurrency and thread-safety tests.
|
|
// 6. Add a test for the Len API.
|
|
// 7. Remove the BulkAdd related tests.
|
|
|
|
package priorityqueue
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/pingcap/tidb/pkg/sessionctx"
|
|
"github.com/pingcap/tidb/pkg/sessionctx/sysproctrack"
|
|
statstypes "github.com/pingcap/tidb/pkg/statistics/handle/types"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
type testHeapObject struct {
|
|
tableID int64
|
|
val float64
|
|
}
|
|
|
|
func (t testHeapObject) ValidateAndPrepare(sctx sessionctx.Context) (bool, string) {
|
|
panic("implement me")
|
|
}
|
|
func (t testHeapObject) Analyze(statsHandle statstypes.StatsHandle, sysProcTracker sysproctrack.Tracker) error {
|
|
panic("implement me")
|
|
}
|
|
func (t testHeapObject) SetWeight(weight float64) {
|
|
panic("implement me")
|
|
}
|
|
func (t testHeapObject) GetWeight() float64 {
|
|
return t.val
|
|
}
|
|
func (t testHeapObject) HasNewlyAddedIndex() bool {
|
|
panic("implement me")
|
|
}
|
|
func (t testHeapObject) GetIndicators() Indicators {
|
|
panic("implement me")
|
|
}
|
|
func (t testHeapObject) SetIndicators(indicators Indicators) {
|
|
panic("implement me")
|
|
}
|
|
func (t testHeapObject) GetTableID() int64 {
|
|
return t.tableID
|
|
}
|
|
func (t testHeapObject) RegisterSuccessHook(hook SuccessJobHook) {
|
|
panic("implement me")
|
|
}
|
|
func (t testHeapObject) RegisterFailureHook(hook FailureJobHook) {
|
|
panic("implement me")
|
|
}
|
|
func (t testHeapObject) AsJSON() statstypes.AnalysisJobJSON {
|
|
panic("implement me")
|
|
}
|
|
func (t testHeapObject) String() string {
|
|
panic("implement me")
|
|
}
|
|
func mkHeapObj(
|
|
tableID int64,
|
|
val float64,
|
|
) testHeapObject {
|
|
return testHeapObject{
|
|
tableID: tableID,
|
|
val: val,
|
|
}
|
|
}
|
|
|
|
func TestHeap_AddOrUpdate(t *testing.T) {
|
|
h := newHeap()
|
|
err := h.addOrUpdate(mkHeapObj(1, 10))
|
|
require.NoError(t, err)
|
|
err = h.addOrUpdate(mkHeapObj(2, 1))
|
|
require.NoError(t, err)
|
|
err = h.addOrUpdate(mkHeapObj(3, 11))
|
|
require.NoError(t, err)
|
|
err = h.addOrUpdate(mkHeapObj(4, 30))
|
|
require.NoError(t, err)
|
|
err = h.addOrUpdate(mkHeapObj(1, 13)) // This updates object with tableID 1.
|
|
require.NoError(t, err)
|
|
|
|
item, err := h.pop()
|
|
require.NoError(t, err)
|
|
require.Equal(t, int64(4), item.GetTableID())
|
|
|
|
item, err = h.pop()
|
|
require.NoError(t, err)
|
|
require.Equal(t, int64(1), item.GetTableID())
|
|
|
|
err = h.delete(mkHeapObj(3, 11)) // Deletes object with tableID 3.
|
|
require.NoError(t, err)
|
|
err = h.addOrUpdate(mkHeapObj(1, 14)) // Updates object with tableID 1.
|
|
require.NoError(t, err)
|
|
|
|
item, err = h.pop()
|
|
require.NoError(t, err)
|
|
require.Equal(t, int64(1), item.GetTableID())
|
|
|
|
item, err = h.pop()
|
|
require.NoError(t, err)
|
|
require.Equal(t, int64(2), item.GetTableID())
|
|
}
|
|
|
|
func TestHeapEmptyPop(t *testing.T) {
|
|
h := newHeap()
|
|
_, err := h.pop()
|
|
require.EqualError(t, err, "heap is empty")
|
|
}
|
|
|
|
func TestHeap_Delete(t *testing.T) {
|
|
h := newHeap()
|
|
err := h.addOrUpdate(mkHeapObj(1, 10))
|
|
require.NoError(t, err)
|
|
err = h.addOrUpdate(mkHeapObj(2, 1))
|
|
require.NoError(t, err)
|
|
err = h.addOrUpdate(mkHeapObj(3, 31))
|
|
require.NoError(t, err)
|
|
err = h.addOrUpdate(mkHeapObj(4, 11))
|
|
require.NoError(t, err)
|
|
|
|
err = h.delete(mkHeapObj(3, 31))
|
|
require.NoError(t, err)
|
|
|
|
item, err := h.pop()
|
|
require.NoError(t, err)
|
|
require.Equal(t, int64(4), item.GetTableID())
|
|
|
|
err = h.addOrUpdate(mkHeapObj(5, 30))
|
|
require.NoError(t, err)
|
|
|
|
err = h.delete(mkHeapObj(2, 1))
|
|
require.NoError(t, err)
|
|
|
|
item, err = h.pop()
|
|
require.NoError(t, err)
|
|
require.Equal(t, int64(5), item.GetTableID())
|
|
|
|
item, err = h.pop()
|
|
require.NoError(t, err)
|
|
require.Equal(t, int64(1), item.GetTableID())
|
|
|
|
require.Equal(t, 0, h.len())
|
|
}
|
|
|
|
func TestHeap_Update(t *testing.T) {
|
|
h := newHeap()
|
|
err := h.addOrUpdate(mkHeapObj(1, 10))
|
|
require.NoError(t, err)
|
|
err = h.addOrUpdate(mkHeapObj(2, 1))
|
|
require.NoError(t, err)
|
|
err = h.addOrUpdate(mkHeapObj(3, 31))
|
|
require.NoError(t, err)
|
|
err = h.addOrUpdate(mkHeapObj(4, 11))
|
|
require.NoError(t, err)
|
|
|
|
err = h.update(mkHeapObj(4, 50))
|
|
require.NoError(t, err)
|
|
require.Equal(t, int64(4), h.data.queue[0])
|
|
|
|
item, err := h.pop()
|
|
require.NoError(t, err)
|
|
require.Equal(t, int64(4), item.GetTableID())
|
|
|
|
err = h.update(mkHeapObj(2, 100))
|
|
require.NoError(t, err)
|
|
require.Equal(t, int64(2), h.data.queue[0])
|
|
}
|
|
|
|
func TestHeap_Get(t *testing.T) {
|
|
h := newHeap()
|
|
err := h.addOrUpdate(mkHeapObj(1, 10))
|
|
require.NoError(t, err)
|
|
err = h.addOrUpdate(mkHeapObj(2, 1))
|
|
require.NoError(t, err)
|
|
err = h.addOrUpdate(mkHeapObj(3, 31))
|
|
require.NoError(t, err)
|
|
err = h.addOrUpdate(mkHeapObj(4, 11))
|
|
require.NoError(t, err)
|
|
|
|
obj, exists, err := h.Get(mkHeapObj(4, 0))
|
|
require.NoError(t, err)
|
|
require.True(t, exists)
|
|
require.Equal(t, int64(4), obj.GetTableID())
|
|
|
|
_, exists, err = h.Get(mkHeapObj(5, 0))
|
|
require.NoError(t, err)
|
|
require.False(t, exists)
|
|
}
|
|
|
|
func TestHeap_GetByKey(t *testing.T) {
|
|
h := newHeap()
|
|
err := h.addOrUpdate(mkHeapObj(1, 10))
|
|
require.NoError(t, err)
|
|
err = h.addOrUpdate(mkHeapObj(2, 1))
|
|
require.NoError(t, err)
|
|
err = h.addOrUpdate(mkHeapObj(3, 31))
|
|
require.NoError(t, err)
|
|
err = h.addOrUpdate(mkHeapObj(4, 11))
|
|
require.NoError(t, err)
|
|
|
|
obj, exists, err := h.getByKey(4)
|
|
require.NoError(t, err)
|
|
require.True(t, exists)
|
|
require.Equal(t, int64(4), obj.GetTableID())
|
|
|
|
_, exists, err = h.getByKey(5)
|
|
require.NoError(t, err)
|
|
require.False(t, exists)
|
|
}
|
|
|
|
func TestHeap_List(t *testing.T) {
|
|
h := newHeap()
|
|
list := h.list()
|
|
require.Empty(t, list)
|
|
|
|
items := map[int64]float64{
|
|
1: 10,
|
|
2: 1,
|
|
3: 30,
|
|
4: 11,
|
|
5: 30,
|
|
}
|
|
for k, v := range items {
|
|
h.addOrUpdate(mkHeapObj(k, v))
|
|
}
|
|
list = h.list()
|
|
require.Len(t, list, len(items))
|
|
for _, obj := range list {
|
|
require.Equal(t, items[obj.GetTableID()], obj.GetWeight())
|
|
}
|
|
}
|
|
|
|
func TestHeap_ListKeys(t *testing.T) {
|
|
h := newHeap()
|
|
list := h.ListKeys()
|
|
require.Empty(t, list)
|
|
|
|
items := map[int64]float64{
|
|
1: 10,
|
|
2: 1,
|
|
3: 30,
|
|
4: 11,
|
|
5: 30,
|
|
}
|
|
for k, v := range items {
|
|
h.addOrUpdate(mkHeapObj(k, v))
|
|
}
|
|
list = h.ListKeys()
|
|
require.Len(t, list, len(items))
|
|
for _, key := range list {
|
|
_, ok := items[key]
|
|
require.True(t, ok)
|
|
}
|
|
}
|
|
|
|
func TestHeap_Peek(t *testing.T) {
|
|
h := newHeap()
|
|
_, err := h.peek()
|
|
require.EqualError(t, err, "heap is empty")
|
|
|
|
err = h.addOrUpdate(mkHeapObj(1, 10))
|
|
require.NoError(t, err)
|
|
err = h.addOrUpdate(mkHeapObj(2, 1))
|
|
require.NoError(t, err)
|
|
err = h.addOrUpdate(mkHeapObj(3, 31))
|
|
require.NoError(t, err)
|
|
err = h.addOrUpdate(mkHeapObj(4, 11))
|
|
require.NoError(t, err)
|
|
|
|
item, err := h.peek()
|
|
require.NoError(t, err)
|
|
require.Equal(t, int64(3), item.GetTableID())
|
|
|
|
item, err = h.pop()
|
|
require.NoError(t, err)
|
|
require.Equal(t, int64(3), item.GetTableID())
|
|
}
|
|
|
|
func TestHeap_IsEmpty(t *testing.T) {
|
|
h := newHeap()
|
|
require.True(t, h.isEmpty())
|
|
|
|
err := h.addOrUpdate(mkHeapObj(1, 10))
|
|
require.NoError(t, err)
|
|
require.False(t, h.isEmpty())
|
|
|
|
_, err = h.pop()
|
|
require.NoError(t, err)
|
|
require.True(t, h.isEmpty())
|
|
}
|
|
|
|
func TestHeap_Len(t *testing.T) {
|
|
h := newHeap()
|
|
require.Zero(t, h.len())
|
|
|
|
err := h.addOrUpdate(mkHeapObj(1, 10))
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, h.len())
|
|
|
|
_, err = h.pop()
|
|
require.NoError(t, err)
|
|
require.Zero(t, h.len())
|
|
}
|