github.com/matrixorigin/matrixone@v0.7.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  )
    24  
    25  // used for testing
    26  type memTaskStorage struct {
    27  	sync.RWMutex
    28  
    29  	id              uint64
    30  	tasks           map[uint64]task.Task
    31  	taskIndexes     map[string]uint64
    32  	cronTasks       map[uint64]task.CronTask
    33  	cronTaskIndexes map[string]uint64
    34  
    35  	// Used for testing. Make some changes to the data before updating.
    36  	preUpdate     func()
    37  	preUpdateCron func() error
    38  }
    39  
    40  func NewMemTaskStorage() TaskStorage {
    41  	return &memTaskStorage{
    42  		tasks:           make(map[uint64]task.Task),
    43  		taskIndexes:     make(map[string]uint64),
    44  		cronTasks:       make(map[uint64]task.CronTask),
    45  		cronTaskIndexes: make(map[string]uint64),
    46  		preUpdateCron:   func() error { return nil },
    47  		preUpdate:       func() {},
    48  	}
    49  }
    50  
    51  func (s *memTaskStorage) Close() error {
    52  	return nil
    53  }
    54  
    55  func (s *memTaskStorage) Add(ctx context.Context, tasks ...task.Task) (int, error) {
    56  	s.Lock()
    57  	defer s.Unlock()
    58  
    59  	n := 0
    60  	for _, v := range tasks {
    61  		if _, ok := s.taskIndexes[v.Metadata.ID]; ok {
    62  			continue
    63  		}
    64  
    65  		v.ID = s.nextIDLocked()
    66  		s.tasks[v.ID] = v
    67  		s.taskIndexes[v.Metadata.ID] = v.ID
    68  		n++
    69  	}
    70  	return n, nil
    71  }
    72  
    73  func (s *memTaskStorage) Update(ctx context.Context, tasks []task.Task, conds ...Condition) (int, error) {
    74  	if s.preUpdate != nil {
    75  		s.preUpdate()
    76  	}
    77  
    78  	c := conditions{}
    79  	for _, cond := range conds {
    80  		cond(&c)
    81  	}
    82  
    83  	s.Lock()
    84  	defer s.Unlock()
    85  
    86  	n := 0
    87  	for _, task := range tasks {
    88  		if v, ok := s.tasks[task.ID]; ok && s.filter(c, v) {
    89  			n++
    90  			s.tasks[task.ID] = task
    91  		}
    92  	}
    93  	return n, nil
    94  }
    95  
    96  func (s *memTaskStorage) Delete(ctx context.Context, conds ...Condition) (int, error) {
    97  	c := conditions{}
    98  	for _, cond := range conds {
    99  		cond(&c)
   100  	}
   101  
   102  	s.Lock()
   103  	defer s.Unlock()
   104  
   105  	var removeTasks []task.Task
   106  	for _, task := range s.tasks {
   107  		if v, ok := s.tasks[task.ID]; ok && s.filter(c, v) {
   108  			removeTasks = append(removeTasks, task)
   109  		}
   110  	}
   111  
   112  	for _, task := range removeTasks {
   113  		delete(s.tasks, task.ID)
   114  		delete(s.taskIndexes, task.Metadata.ID)
   115  	}
   116  	return len(removeTasks), nil
   117  }
   118  
   119  func (s *memTaskStorage) Query(ctx context.Context, conds ...Condition) ([]task.Task, error) {
   120  	s.RLock()
   121  	defer s.RUnlock()
   122  
   123  	c := conditions{}
   124  	for _, cond := range conds {
   125  		cond(&c)
   126  	}
   127  
   128  	sortedTasks := make([]task.Task, 0, len(s.tasks))
   129  	for _, task := range s.tasks {
   130  		sortedTasks = append(sortedTasks, task)
   131  	}
   132  	sort.Slice(sortedTasks, func(i, j int) bool { return sortedTasks[i].ID < sortedTasks[j].ID })
   133  
   134  	var result []task.Task
   135  	for _, task := range sortedTasks {
   136  		if s.filter(c, task) {
   137  			result = append(result, task)
   138  		}
   139  		if c.limit > 0 && c.limit <= len(result) {
   140  			break
   141  		}
   142  	}
   143  	return result, nil
   144  }
   145  
   146  func (s *memTaskStorage) AddCronTask(ctx context.Context, tasks ...task.CronTask) (int, error) {
   147  	s.Lock()
   148  	defer s.Unlock()
   149  
   150  	n := 0
   151  	for _, v := range tasks {
   152  		if _, ok := s.cronTaskIndexes[v.Metadata.ID]; ok {
   153  			continue
   154  		}
   155  
   156  		v.ID = s.nextIDLocked()
   157  		s.cronTasks[v.ID] = v
   158  		s.cronTaskIndexes[v.Metadata.ID] = v.ID
   159  		n++
   160  	}
   161  	return n, nil
   162  }
   163  
   164  func (s *memTaskStorage) QueryCronTask(context.Context) ([]task.CronTask, error) {
   165  	s.Lock()
   166  	defer s.Unlock()
   167  
   168  	tasks := make([]task.CronTask, 0, len(s.cronTasks))
   169  	for _, v := range s.cronTasks {
   170  		tasks = append(tasks, v)
   171  	}
   172  	sort.Slice(tasks, func(i, j int) bool { return tasks[i].ID < tasks[j].ID })
   173  	return tasks, nil
   174  }
   175  
   176  func (s *memTaskStorage) UpdateCronTask(ctx context.Context, cron task.CronTask, value task.Task) (int, error) {
   177  	s.Lock()
   178  	defer s.Unlock()
   179  
   180  	if err := s.preUpdateCron(); err != nil {
   181  		return 0, err
   182  	}
   183  
   184  	if _, ok := s.taskIndexes[value.Metadata.ID]; ok {
   185  		return 0, nil
   186  	}
   187  	if v, ok := s.cronTasks[cron.ID]; !ok || v.TriggerTimes != cron.TriggerTimes-1 {
   188  		return 0, nil
   189  	}
   190  
   191  	value.ID = s.nextIDLocked()
   192  	s.tasks[value.ID] = value
   193  	s.taskIndexes[value.Metadata.ID] = value.ID
   194  	s.cronTasks[cron.ID] = cron
   195  	return 2, nil
   196  }
   197  
   198  func (s *memTaskStorage) nextIDLocked() uint64 {
   199  	s.id++
   200  	return s.id
   201  }
   202  
   203  func (s *memTaskStorage) filter(c conditions, task task.Task) bool {
   204  	ok := true
   205  
   206  	if c.hasTaskIDCond {
   207  		switch c.taskIDOp {
   208  		case EQ:
   209  			ok = task.ID == c.taskID
   210  		case GT:
   211  			ok = task.ID > c.taskID
   212  		case GE:
   213  			ok = task.ID >= c.taskID
   214  		case LE:
   215  			ok = task.ID <= c.taskID
   216  		case LT:
   217  			ok = task.ID < c.taskID
   218  		}
   219  	}
   220  
   221  	if ok && c.hasTaskRunnerCond {
   222  		switch c.taskRunnerOp {
   223  		case EQ:
   224  			ok = task.TaskRunner == c.taskRunner
   225  		}
   226  	}
   227  
   228  	if ok && c.hasTaskStatusCond {
   229  		switch c.taskStatusOp {
   230  		case EQ:
   231  			ok = task.Status == c.taskStatus
   232  		case GT:
   233  			ok = task.Status > c.taskStatus
   234  		case GE:
   235  			ok = task.Status >= c.taskStatus
   236  		case LE:
   237  			ok = task.Status <= c.taskStatus
   238  		case LT:
   239  			ok = task.Status < c.taskStatus
   240  		}
   241  	}
   242  
   243  	if ok && c.hasTaskEpochCond {
   244  		switch c.taskEpochOp {
   245  		case EQ:
   246  			ok = task.Epoch == c.taskEpoch
   247  		case GT:
   248  			ok = task.Epoch > c.taskEpoch
   249  		case GE:
   250  			ok = task.Epoch >= c.taskEpoch
   251  		case LE:
   252  			ok = task.Epoch <= c.taskEpoch
   253  		case LT:
   254  			ok = task.Epoch < c.taskEpoch
   255  		}
   256  	}
   257  
   258  	if ok && c.hasTaskParentIDCond {
   259  		switch c.taskParentTaskIDOp {
   260  		case EQ:
   261  			ok = task.ParentTaskID == c.taskParentTaskID
   262  		}
   263  	}
   264  	return ok
   265  }