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 }