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 }