github.com/matrixorigin/matrixone@v1.2.0/pkg/taskservice/mem_task_storage.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 taskservice
    16  
    17  import (
    18  	"context"
    19  	"sort"
    20  	"sync"
    21  
    22  	"github.com/matrixorigin/matrixone/pkg/pb/task"
    23  	"github.com/mohae/deepcopy"
    24  )
    25  
    26  // used for testing
    27  type memTaskStorage struct {
    28  	sync.RWMutex
    29  
    30  	id                uint64
    31  	asyncTasks        map[uint64]task.AsyncTask
    32  	asyncTaskIndexes  map[string]uint64
    33  	cronTasks         map[uint64]task.CronTask
    34  	cronTaskIndexes   map[string]uint64
    35  	daemonTasks       map[uint64]task.DaemonTask
    36  	daemonTaskIndexes map[string]uint64
    37  
    38  	// Used for testing. Make some changes to the data before updating.
    39  	preUpdate     func()
    40  	preUpdateCron func() error
    41  }
    42  
    43  func NewMemTaskStorage() TaskStorage {
    44  	return &memTaskStorage{
    45  		asyncTasks:        make(map[uint64]task.AsyncTask),
    46  		asyncTaskIndexes:  make(map[string]uint64),
    47  		cronTasks:         make(map[uint64]task.CronTask),
    48  		cronTaskIndexes:   make(map[string]uint64),
    49  		daemonTasks:       make(map[uint64]task.DaemonTask),
    50  		daemonTaskIndexes: make(map[string]uint64),
    51  		preUpdateCron:     func() error { return nil },
    52  		preUpdate:         func() {},
    53  	}
    54  }
    55  
    56  func (s *memTaskStorage) Close() error {
    57  	return nil
    58  }
    59  
    60  func (s *memTaskStorage) AddAsyncTask(ctx context.Context, tasks ...task.AsyncTask) (int, error) {
    61  	s.Lock()
    62  	defer s.Unlock()
    63  
    64  	n := 0
    65  	for _, v := range tasks {
    66  		if _, ok := s.asyncTaskIndexes[v.Metadata.ID]; ok {
    67  			continue
    68  		}
    69  
    70  		v.ID = s.nextIDLocked()
    71  		s.asyncTasks[v.ID] = v
    72  		s.asyncTaskIndexes[v.Metadata.ID] = v.ID
    73  		n++
    74  	}
    75  	return n, nil
    76  }
    77  
    78  func (s *memTaskStorage) UpdateAsyncTask(ctx context.Context, tasks []task.AsyncTask, conds ...Condition) (int, error) {
    79  	if s.preUpdate != nil {
    80  		s.preUpdate()
    81  	}
    82  
    83  	c := newConditions(conds...)
    84  	s.Lock()
    85  	defer s.Unlock()
    86  
    87  	n := 0
    88  	for _, task := range tasks {
    89  		if v, ok := s.asyncTasks[task.ID]; ok && s.filterAsyncTask(c, v) {
    90  			n++
    91  			s.asyncTasks[task.ID] = task
    92  		}
    93  	}
    94  	return n, nil
    95  }
    96  
    97  func (s *memTaskStorage) DeleteAsyncTask(ctx context.Context, conds ...Condition) (int, error) {
    98  	c := newConditions(conds...)
    99  
   100  	s.Lock()
   101  	defer s.Unlock()
   102  
   103  	var removeTasks []task.AsyncTask
   104  	for _, task := range s.asyncTasks {
   105  		if v, ok := s.asyncTasks[task.ID]; ok && s.filterAsyncTask(c, v) {
   106  			removeTasks = append(removeTasks, task)
   107  		}
   108  	}
   109  
   110  	for _, task := range removeTasks {
   111  		delete(s.asyncTasks, task.ID)
   112  		delete(s.asyncTaskIndexes, task.Metadata.ID)
   113  	}
   114  	return len(removeTasks), nil
   115  }
   116  
   117  func (s *memTaskStorage) QueryAsyncTask(ctx context.Context, conds ...Condition) ([]task.AsyncTask, error) {
   118  	s.RLock()
   119  	defer s.RUnlock()
   120  
   121  	c := newConditions(conds...)
   122  
   123  	sortedTasks := make([]task.AsyncTask, 0, len(s.asyncTasks))
   124  	for _, task := range s.asyncTasks {
   125  		sortedTasks = append(sortedTasks, task)
   126  	}
   127  	sort.Slice(sortedTasks, func(i, j int) bool { return sortedTasks[i].ID < sortedTasks[j].ID })
   128  
   129  	var result []task.AsyncTask
   130  	for _, task := range sortedTasks {
   131  		if s.filterAsyncTask(c, task) {
   132  			result = append(result, task)
   133  		}
   134  		if cond, e := (*c)[CondLimit]; e && cond.eval(len(result)) {
   135  			break
   136  		}
   137  	}
   138  	return result, nil
   139  }
   140  
   141  func (s *memTaskStorage) AddCronTask(ctx context.Context, tasks ...task.CronTask) (int, error) {
   142  	s.Lock()
   143  	defer s.Unlock()
   144  
   145  	n := 0
   146  	for _, v := range tasks {
   147  		if _, ok := s.cronTaskIndexes[v.Metadata.ID]; ok {
   148  			continue
   149  		}
   150  
   151  		v.ID = s.nextIDLocked()
   152  		s.cronTasks[v.ID] = v
   153  		s.cronTaskIndexes[v.Metadata.ID] = v.ID
   154  		n++
   155  	}
   156  	return n, nil
   157  }
   158  
   159  func (s *memTaskStorage) QueryCronTask(context.Context, ...Condition) ([]task.CronTask, error) {
   160  	s.Lock()
   161  	defer s.Unlock()
   162  
   163  	tasks := make([]task.CronTask, 0, len(s.cronTasks))
   164  	for _, v := range s.cronTasks {
   165  		tasks = append(tasks, v)
   166  	}
   167  	sort.Slice(tasks, func(i, j int) bool { return tasks[i].ID < tasks[j].ID })
   168  	return tasks, nil
   169  }
   170  
   171  func (s *memTaskStorage) UpdateCronTask(ctx context.Context, cron task.CronTask, value task.AsyncTask) (int, error) {
   172  	s.Lock()
   173  	defer s.Unlock()
   174  
   175  	if err := s.preUpdateCron(); err != nil {
   176  		return 0, err
   177  	}
   178  
   179  	if _, ok := s.asyncTaskIndexes[value.Metadata.ID]; ok {
   180  		return 0, nil
   181  	}
   182  	if v, ok := s.cronTasks[cron.ID]; !ok || v.TriggerTimes != cron.TriggerTimes-1 {
   183  		return 0, nil
   184  	}
   185  
   186  	value.ID = s.nextIDLocked()
   187  	s.asyncTasks[value.ID] = value
   188  	s.asyncTaskIndexes[value.Metadata.ID] = value.ID
   189  	s.cronTasks[cron.ID] = cron
   190  	return 2, nil
   191  }
   192  
   193  func (s *memTaskStorage) AddDaemonTask(ctx context.Context, tasks ...task.DaemonTask) (int, error) {
   194  	s.Lock()
   195  	defer s.Unlock()
   196  
   197  	n := 0
   198  	for _, v := range tasks {
   199  		if _, ok := s.daemonTaskIndexes[v.Metadata.ID]; ok {
   200  			continue
   201  		}
   202  
   203  		s.daemonTasks[v.ID] = v
   204  		s.daemonTaskIndexes[v.Metadata.ID] = v.ID
   205  		n++
   206  	}
   207  	return n, nil
   208  }
   209  
   210  func (s *memTaskStorage) UpdateDaemonTask(ctx context.Context, tasks []task.DaemonTask, conds ...Condition) (int, error) {
   211  	if s.preUpdate != nil {
   212  		s.preUpdate()
   213  	}
   214  
   215  	c := newConditions(conds...)
   216  
   217  	s.Lock()
   218  	defer s.Unlock()
   219  
   220  	n := 0
   221  	for _, t := range tasks {
   222  		if v, ok := s.daemonTasks[t.ID]; ok && s.filterDaemonTask(c, v) {
   223  			n++
   224  			s.daemonTasks[t.ID] = t
   225  		}
   226  	}
   227  	return n, nil
   228  }
   229  
   230  func (s *memTaskStorage) DeleteDaemonTask(ctx context.Context, conds ...Condition) (int, error) {
   231  	c := newConditions(conds...)
   232  
   233  	s.Lock()
   234  	defer s.Unlock()
   235  
   236  	var removeTasks []task.DaemonTask
   237  	for _, task := range s.daemonTasks {
   238  		if v, ok := s.daemonTasks[task.ID]; ok && s.filterDaemonTask(c, v) {
   239  			removeTasks = append(removeTasks, task)
   240  		}
   241  	}
   242  
   243  	for _, task := range removeTasks {
   244  		delete(s.daemonTasks, task.ID)
   245  		delete(s.daemonTaskIndexes, task.Metadata.ID)
   246  	}
   247  	return len(removeTasks), nil
   248  }
   249  
   250  func (s *memTaskStorage) QueryDaemonTask(ctx context.Context, conds ...Condition) ([]task.DaemonTask, error) {
   251  	s.RLock()
   252  	defer s.RUnlock()
   253  
   254  	c := newConditions(conds...)
   255  
   256  	sortedTasks := make([]task.DaemonTask, 0, len(s.daemonTasks))
   257  	for _, t := range s.daemonTasks {
   258  		sortedTasks = append(sortedTasks, deepcopy.Copy(t).(task.DaemonTask))
   259  	}
   260  	sort.Slice(sortedTasks, func(i, j int) bool { return sortedTasks[i].ID < sortedTasks[j].ID })
   261  
   262  	var result []task.DaemonTask
   263  	for _, task := range sortedTasks {
   264  		if s.filterDaemonTask(c, task) {
   265  			result = append(result, task)
   266  		}
   267  		if cond, e := (*c)[CondLimit]; e && cond.eval(len(result)) {
   268  			break
   269  		}
   270  	}
   271  	return result, nil
   272  }
   273  
   274  func (s *memTaskStorage) HeartbeatDaemonTask(ctx context.Context, tasks []task.DaemonTask) (int, error) {
   275  	if s.preUpdate != nil {
   276  		s.preUpdate()
   277  	}
   278  
   279  	s.Lock()
   280  	defer s.Unlock()
   281  
   282  	n := 0
   283  	for _, t := range tasks {
   284  		if _, ok := s.daemonTasks[t.ID]; ok {
   285  			n++
   286  			s.daemonTasks[t.ID] = t
   287  		}
   288  	}
   289  	return n, nil
   290  }
   291  
   292  func (s *memTaskStorage) nextIDLocked() uint64 {
   293  	s.id++
   294  	return s.id
   295  }
   296  
   297  func (s *memTaskStorage) filterAsyncTask(c *conditions, task task.AsyncTask) bool {
   298  	ok := true
   299  
   300  	if cond, e := (*c)[CondTaskID]; e {
   301  		ok = cond.eval(task.ID)
   302  	}
   303  	if !ok {
   304  		return false
   305  	}
   306  
   307  	if cond, e := (*c)[CondTaskRunner]; e {
   308  		ok = cond.eval(task.TaskRunner)
   309  	}
   310  	if !ok {
   311  		return false
   312  	}
   313  
   314  	if cond, e := (*c)[CondTaskStatus]; e {
   315  		ok = cond.eval(task.Status)
   316  	}
   317  	if !ok {
   318  		return false
   319  	}
   320  
   321  	if cond, e := (*c)[CondTaskEpoch]; e {
   322  		ok = cond.eval(task.Epoch)
   323  	}
   324  	if !ok {
   325  		return false
   326  	}
   327  
   328  	if cond, e := (*c)[CondTaskParentTaskID]; e {
   329  		ok = cond.eval(task.ParentTaskID)
   330  	}
   331  	return ok
   332  }
   333  
   334  func (s *memTaskStorage) filterDaemonTask(c *conditions, task task.DaemonTask) bool {
   335  	ok := true
   336  
   337  	if cond, e := (*c)[CondTaskID]; e {
   338  		ok = cond.eval(task.ID)
   339  	}
   340  	if !ok {
   341  		return false
   342  	}
   343  
   344  	if cond, e := (*c)[CondTaskRunner]; e {
   345  		ok = cond.eval(task.TaskRunner)
   346  	}
   347  	if !ok {
   348  		return false
   349  	}
   350  
   351  	if cond, e := (*c)[CondTaskStatus]; e {
   352  		ok = cond.eval(task.TaskStatus)
   353  	}
   354  	if !ok {
   355  		return false
   356  	}
   357  
   358  	if cond, e := (*c)[CondTaskType]; e {
   359  		ok = cond.eval(task.TaskType)
   360  	}
   361  
   362  	if cond, e := (*c)[CondAccountID]; e {
   363  		ok = cond.eval(task.AccountID)
   364  	}
   365  
   366  	if cond, e := (*c)[CondAccount]; e {
   367  		ok = cond.eval(task.Account)
   368  	}
   369  
   370  	if cond, e := (*c)[CondLastHeartbeat]; e {
   371  		ok = cond.eval(task.LastHeartbeat.UnixNano())
   372  	}
   373  	return ok
   374  }