github.com/matrixorigin/matrixone@v0.7.0/pkg/hakeeper/task/task_scheduler_test.go (about)

     1  // Copyright 2022 Matrix Origin
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package task
    16  
    17  import (
    18  	"context"
    19  	"testing"
    20  
    21  	"github.com/matrixorigin/matrixone/pkg/common/runtime"
    22  	"github.com/matrixorigin/matrixone/pkg/hakeeper"
    23  	"github.com/matrixorigin/matrixone/pkg/logutil"
    24  	pb "github.com/matrixorigin/matrixone/pkg/pb/logservice"
    25  	"github.com/matrixorigin/matrixone/pkg/pb/metadata"
    26  	"github.com/matrixorigin/matrixone/pkg/pb/task"
    27  	"github.com/matrixorigin/matrixone/pkg/taskservice"
    28  	"github.com/stretchr/testify/assert"
    29  )
    30  
    31  func TestMain(m *testing.M) {
    32  	logutil.SetupMOLogger(&logutil.LogConfig{
    33  		Level:  "debug",
    34  		Format: "console",
    35  	})
    36  
    37  	runtime.SetupProcessLevelRuntime(runtime.NewRuntime(metadata.ServiceType_LOG, "test", logutil.GetGlobalLogger()))
    38  	m.Run()
    39  }
    40  
    41  func TestGetExpiredTasks(t *testing.T) {
    42  	cases := []struct {
    43  		tasks     []task.Task
    44  		expiredCN []string
    45  
    46  		expected []task.Task
    47  	}{
    48  		{
    49  			tasks:     nil,
    50  			expiredCN: nil,
    51  
    52  			expected: nil,
    53  		},
    54  		{
    55  			tasks:     []task.Task{{TaskRunner: "a"}, {TaskRunner: "b"}},
    56  			expiredCN: []string{"a"},
    57  
    58  			expected: []task.Task{{TaskRunner: "a"}},
    59  		},
    60  	}
    61  
    62  	for _, c := range cases {
    63  		results := getExpiredTasks(c.tasks, c.expiredCN)
    64  		assert.Equal(t, c.expected, results)
    65  	}
    66  }
    67  
    68  func TestGetCNOrderedMap(t *testing.T) {
    69  	cases := []struct {
    70  		tasks     []task.Task
    71  		workingCN []string
    72  
    73  		expected *cnMap
    74  	}{
    75  		{
    76  			tasks:     nil,
    77  			workingCN: nil,
    78  
    79  			expected: newOrderedMap(nil),
    80  		},
    81  		{
    82  			tasks:     []task.Task{{TaskRunner: "a"}, {TaskRunner: "b"}, {TaskRunner: "b"}},
    83  			workingCN: []string{"a", "b"},
    84  
    85  			expected: &cnMap{
    86  				m:           map[string]uint32{"a": 1, "b": 2},
    87  				orderedKeys: []string{"a", "b"},
    88  			},
    89  		},
    90  		{
    91  			tasks:     []task.Task{{TaskRunner: "a"}, {TaskRunner: "b"}, {TaskRunner: "a"}, {TaskRunner: "a"}},
    92  			workingCN: []string{"a", "b"},
    93  
    94  			expected: &cnMap{
    95  				m:           map[string]uint32{"a": 3, "b": 1},
    96  				orderedKeys: []string{"b", "a"},
    97  			},
    98  		},
    99  	}
   100  
   101  	for _, c := range cases {
   102  		results := getCNOrdered(c.tasks, c.workingCN)
   103  		assert.Equal(t, c.expected, results)
   104  	}
   105  }
   106  
   107  func TestScheduleCreatedTasks(t *testing.T) {
   108  	service := taskservice.NewTaskService(runtime.DefaultRuntime(), taskservice.NewMemTaskStorage())
   109  	scheduler := NewScheduler(func() taskservice.TaskService { return service }, hakeeper.Config{})
   110  	cnState := pb.CNState{Stores: map[string]pb.CNStoreInfo{"a": {}}}
   111  	currentTick := uint64(0)
   112  
   113  	// Schedule empty task
   114  	scheduler.Schedule(cnState, currentTick)
   115  
   116  	// Create Task 1
   117  	assert.NoError(t, service.Create(context.Background(), task.TaskMetadata{ID: "1"}))
   118  	query, err := service.QueryTask(context.Background())
   119  	assert.NoError(t, err)
   120  	assert.Equal(t, task.TaskStatus_Created, query[0].Status)
   121  
   122  	// Schedule Task 1
   123  	scheduler.Schedule(cnState, currentTick)
   124  
   125  	query, err = service.QueryTask(context.Background())
   126  	assert.NoError(t, err)
   127  	assert.Equal(t, "a", query[0].TaskRunner)
   128  	assert.Equal(t, task.TaskStatus_Running, query[0].Status)
   129  
   130  	// Create Task 2
   131  	assert.NoError(t, service.Create(context.Background(), task.TaskMetadata{ID: "2"}))
   132  	query, err = service.QueryTask(context.Background(),
   133  		taskservice.WithTaskStatusCond(taskservice.EQ, task.TaskStatus_Created))
   134  	assert.NoError(t, err)
   135  	assert.Equal(t, 1, len(query))
   136  	assert.NotNil(t, query[0].Status)
   137  
   138  	// Add CNStore "b"
   139  	cnState = pb.CNState{Stores: map[string]pb.CNStoreInfo{"a": {}, "b": {}}}
   140  
   141  	// Schedule Task 2
   142  	scheduler.Schedule(cnState, currentTick)
   143  
   144  	query, err = service.QueryTask(context.Background(), taskservice.WithTaskRunnerCond(taskservice.EQ, "b"))
   145  	assert.NoError(t, err)
   146  	assert.NotNil(t, query)
   147  	assert.Equal(t, task.TaskStatus_Running, query[0].Status)
   148  }
   149  
   150  func TestReallocateExpiredTasks(t *testing.T) {
   151  	service := taskservice.NewTaskService(runtime.DefaultRuntime(), taskservice.NewMemTaskStorage())
   152  	scheduler := NewScheduler(func() taskservice.TaskService { return service }, hakeeper.Config{})
   153  	cnState := pb.CNState{Stores: map[string]pb.CNStoreInfo{"a": {}}}
   154  	currentTick := expiredTick - 1
   155  
   156  	// Create Task 1
   157  	assert.NoError(t, service.Create(context.Background(), task.TaskMetadata{ID: "1"}))
   158  	query, err := service.QueryTask(context.Background())
   159  	assert.NoError(t, err)
   160  	assert.Equal(t, task.TaskStatus_Created, query[0].Status)
   161  
   162  	// Schedule Task 1 on "a"
   163  	scheduler.Schedule(cnState, currentTick)
   164  
   165  	query, err = service.QueryTask(context.Background())
   166  	assert.NoError(t, err)
   167  	assert.Equal(t, 1, len(query))
   168  	assert.Equal(t, "a", query[0].TaskRunner)
   169  	assert.Equal(t, task.TaskStatus_Running, query[0].Status)
   170  
   171  	// Make CNStore "a" expired
   172  	cnState = pb.CNState{Stores: map[string]pb.CNStoreInfo{"a": {}}}
   173  	currentTick = expiredTick + 1
   174  
   175  	// Re-schedule Task 1
   176  	// Since no other CN available, task 1 remains on CN "a"
   177  	scheduler.Schedule(cnState, currentTick)
   178  
   179  	query, err = service.QueryTask(context.Background())
   180  	assert.NoError(t, err)
   181  	assert.Equal(t, 1, len(query))
   182  	assert.Equal(t, "a", query[0].TaskRunner)
   183  	assert.Equal(t, task.TaskStatus_Running, query[0].Status)
   184  
   185  	// Add CNStore "b"
   186  	cnState = pb.CNState{Stores: map[string]pb.CNStoreInfo{"a": {}, "b": {Tick: expiredTick}}}
   187  
   188  	// Re-schedule Task 1
   189  	// "b" available
   190  	scheduler.Schedule(cnState, currentTick)
   191  
   192  	query, err = service.QueryTask(context.Background())
   193  	assert.NoError(t, err)
   194  	assert.Equal(t, 1, len(query))
   195  	assert.Equal(t, "b", query[0].TaskRunner)
   196  	assert.Equal(t, task.TaskStatus_Running, query[0].Status)
   197  }
   198  
   199  func TestSchedulerCreateTasks(t *testing.T) {
   200  	service := taskservice.NewTaskService(runtime.DefaultRuntime(), taskservice.NewMemTaskStorage())
   201  	scheduler := NewScheduler(func() taskservice.TaskService { return service }, hakeeper.Config{})
   202  	cnState := pb.CNState{Stores: map[string]pb.CNStoreInfo{"a": {}}}
   203  	currentTick := uint64(0)
   204  
   205  	assert.NoError(t, scheduler.Create(context.Background(),
   206  		[]task.TaskMetadata{{ID: "1"}}))
   207  
   208  	// Schedule empty task
   209  	scheduler.Schedule(cnState, currentTick)
   210  }