go.temporal.io/server@v1.23.0/common/persistence/cassandra/matching_task_store.go (about) 1 // The MIT License 2 // 3 // Copyright (c) 2020 Temporal Technologies Inc. All rights reserved. 4 // 5 // Copyright (c) 2020 Uber Technologies, Inc. 6 // 7 // Permission is hereby granted, free of charge, to any person obtaining a copy 8 // of this software and associated documentation files (the "Software"), to deal 9 // in the Software without restriction, including without limitation the rights 10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 // copies of the Software, and to permit persons to whom the Software is 12 // furnished to do so, subject to the following conditions: 13 // 14 // The above copyright notice and this permission notice shall be included in 15 // all copies or substantial portions of the Software. 16 // 17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 // THE SOFTWARE. 24 25 package cassandra 26 27 import ( 28 "context" 29 "fmt" 30 "strings" 31 "time" 32 33 enumspb "go.temporal.io/api/enums/v1" 34 "go.temporal.io/api/serviceerror" 35 "google.golang.org/protobuf/types/known/timestamppb" 36 37 "go.temporal.io/server/common/convert" 38 "go.temporal.io/server/common/log" 39 p "go.temporal.io/server/common/persistence" 40 "go.temporal.io/server/common/persistence/nosql/nosqlplugin/cassandra/gocql" 41 "go.temporal.io/server/common/primitives/timestamp" 42 ) 43 44 const ( 45 templateCreateTaskQuery = `INSERT INTO tasks (` + 46 `namespace_id, task_queue_name, task_queue_type, type, task_id, task, task_encoding) ` + 47 `VALUES(?, ?, ?, ?, ?, ?, ?)` 48 49 templateCreateTaskWithTTLQuery = `INSERT INTO tasks (` + 50 `namespace_id, task_queue_name, task_queue_type, type, task_id, task, task_encoding) ` + 51 `VALUES(?, ?, ?, ?, ?, ?, ?) USING TTL ?` 52 53 templateGetTasksQuery = `SELECT task_id, task, task_encoding ` + 54 `FROM tasks ` + 55 `WHERE namespace_id = ? ` + 56 `and task_queue_name = ? ` + 57 `and task_queue_type = ? ` + 58 `and type = ? ` + 59 `and task_id >= ? ` + 60 `and task_id < ?` 61 62 templateCompleteTaskQuery = `DELETE FROM tasks ` + 63 `WHERE namespace_id = ? ` + 64 `and task_queue_name = ? ` + 65 `and task_queue_type = ? ` + 66 `and type = ? ` + 67 `and task_id = ?` 68 69 templateCompleteTasksLessThanQuery = `DELETE FROM tasks ` + 70 `WHERE namespace_id = ? ` + 71 `AND task_queue_name = ? ` + 72 `AND task_queue_type = ? ` + 73 `AND type = ? ` + 74 `AND task_id < ? ` 75 76 templateGetTaskQueueQuery = `SELECT ` + 77 `range_id, ` + 78 `task_queue, ` + 79 `task_queue_encoding ` + 80 `FROM tasks ` + 81 `WHERE namespace_id = ? ` + 82 `and task_queue_name = ? ` + 83 `and task_queue_type = ? ` + 84 `and type = ? ` + 85 `and task_id = ?` 86 87 templateInsertTaskQueueQuery = `INSERT INTO tasks (` + 88 `namespace_id, ` + 89 `task_queue_name, ` + 90 `task_queue_type, ` + 91 `type, ` + 92 `task_id, ` + 93 `range_id, ` + 94 `task_queue, ` + 95 `task_queue_encoding ` + 96 `) VALUES (?, ?, ?, ?, ?, ?, ?, ?) IF NOT EXISTS` 97 98 templateUpdateTaskQueueQuery = `UPDATE tasks SET ` + 99 `range_id = ?, ` + 100 `task_queue = ?, ` + 101 `task_queue_encoding = ? ` + 102 `WHERE namespace_id = ? ` + 103 `and task_queue_name = ? ` + 104 `and task_queue_type = ? ` + 105 `and type = ? ` + 106 `and task_id = ? ` + 107 `IF range_id = ?` 108 109 templateUpdateTaskQueueQueryWithTTLPart1 = `INSERT INTO tasks (` + 110 `namespace_id, ` + 111 `task_queue_name, ` + 112 `task_queue_type, ` + 113 `type, ` + 114 `task_id ` + 115 `) VALUES (?, ?, ?, ?, ?) USING TTL ?` 116 117 templateUpdateTaskQueueQueryWithTTLPart2 = `UPDATE tasks USING TTL ? SET ` + 118 `range_id = ?, ` + 119 `task_queue = ?, ` + 120 `task_queue_encoding = ? ` + 121 `WHERE namespace_id = ? ` + 122 `and task_queue_name = ? ` + 123 `and task_queue_type = ? ` + 124 `and type = ? ` + 125 `and task_id = ? ` + 126 `IF range_id = ?` 127 128 templateDeleteTaskQueueQuery = `DELETE FROM tasks ` + 129 `WHERE namespace_id = ? ` + 130 `AND task_queue_name = ? ` + 131 `AND task_queue_type = ? ` + 132 `AND type = ? ` + 133 `AND task_id = ? ` + 134 `IF range_id = ?` 135 136 templateGetTaskQueueUserDataQuery = `SELECT data, data_encoding, version 137 FROM task_queue_user_data 138 WHERE namespace_id = ? AND build_id = '' 139 AND task_queue_name = ?` 140 141 templateUpdateTaskQueueUserDataQuery = `UPDATE task_queue_user_data SET 142 data = ?, 143 data_encoding = ?, 144 version = ? 145 WHERE namespace_id = ? 146 AND build_id = '' 147 AND task_queue_name = ? 148 IF version = ?` 149 150 templateInsertTaskQueueUserDataQuery = `INSERT INTO task_queue_user_data 151 (namespace_id, build_id, task_queue_name, data, data_encoding, version) VALUES 152 (? , '' , ? , ? , ? , 1 ) IF NOT EXISTS` 153 154 templateInsertBuildIdTaskQueueMappingQuery = `INSERT INTO task_queue_user_data 155 (namespace_id, build_id, task_queue_name) VALUES 156 (? , ? , ?)` 157 templateDeleteBuildIdTaskQueueMappingQuery = `DELETE FROM task_queue_user_data 158 WHERE namespace_id = ? AND build_id = ? AND task_queue_name = ?` 159 templateListTaskQueueUserDataQuery = `SELECT task_queue_name, data, data_encoding, version FROM task_queue_user_data WHERE namespace_id = ? AND build_id = ''` 160 templateListTaskQueueNamesByBuildIdQuery = `SELECT task_queue_name FROM task_queue_user_data WHERE namespace_id = ? AND build_id = ?` 161 templateCountTaskQueueByBuildIdQuery = `SELECT COUNT(*) FROM task_queue_user_data WHERE namespace_id = ? AND build_id = ?` 162 163 // Not much of a need to make this configurable, we're just reading some strings 164 listTaskQueueNamesByBuildIdPageSize = 100 165 ) 166 167 type ( 168 MatchingTaskStore struct { 169 Session gocql.Session 170 Logger log.Logger 171 } 172 ) 173 174 func NewMatchingTaskStore( 175 session gocql.Session, 176 logger log.Logger, 177 ) *MatchingTaskStore { 178 return &MatchingTaskStore{ 179 Session: session, 180 Logger: logger, 181 } 182 } 183 184 func (d *MatchingTaskStore) CreateTaskQueue( 185 ctx context.Context, 186 request *p.InternalCreateTaskQueueRequest, 187 ) error { 188 query := d.Session.Query(templateInsertTaskQueueQuery, 189 request.NamespaceID, 190 request.TaskQueue, 191 request.TaskType, 192 rowTypeTaskQueue, 193 taskQueueTaskID, 194 request.RangeID, 195 request.TaskQueueInfo.Data, 196 request.TaskQueueInfo.EncodingType.String(), 197 ).WithContext(ctx) 198 199 previous := make(map[string]interface{}) 200 applied, err := query.MapScanCAS(previous) 201 if err != nil { 202 return gocql.ConvertError("CreateTaskQueue", err) 203 } 204 205 if !applied { 206 previousRangeID := previous["range_id"] 207 return &p.ConditionFailedError{ 208 Msg: fmt.Sprintf("CreateTaskQueue: TaskQueue:%v, TaskQueueType:%v, PreviousRangeID:%v", 209 request.TaskQueue, request.TaskType, previousRangeID), 210 } 211 } 212 213 return nil 214 } 215 216 func (d *MatchingTaskStore) GetTaskQueue( 217 ctx context.Context, 218 request *p.InternalGetTaskQueueRequest, 219 ) (*p.InternalGetTaskQueueResponse, error) { 220 query := d.Session.Query(templateGetTaskQueueQuery, 221 request.NamespaceID, 222 request.TaskQueue, 223 request.TaskType, 224 rowTypeTaskQueue, 225 taskQueueTaskID, 226 ).WithContext(ctx) 227 228 var rangeID int64 229 var tlBytes []byte 230 var tlEncoding string 231 if err := query.Scan(&rangeID, &tlBytes, &tlEncoding); err != nil { 232 return nil, gocql.ConvertError("GetTaskQueue", err) 233 } 234 235 return &p.InternalGetTaskQueueResponse{ 236 RangeID: rangeID, 237 TaskQueueInfo: p.NewDataBlob(tlBytes, tlEncoding), 238 }, nil 239 } 240 241 // UpdateTaskQueue update task queue 242 func (d *MatchingTaskStore) UpdateTaskQueue( 243 ctx context.Context, 244 request *p.InternalUpdateTaskQueueRequest, 245 ) (*p.UpdateTaskQueueResponse, error) { 246 var err error 247 var applied bool 248 previous := make(map[string]interface{}) 249 if request.TaskQueueKind == enumspb.TASK_QUEUE_KIND_STICKY { // if task_queue is sticky, then update with TTL 250 if request.ExpiryTime == nil { 251 return nil, serviceerror.NewInternal("ExpiryTime cannot be nil for sticky task queue") 252 } 253 expiryTTL := convert.Int64Ceil(time.Until(timestamp.TimeValue(request.ExpiryTime)).Seconds()) 254 if expiryTTL >= maxCassandraTTL { 255 expiryTTL = maxCassandraTTL 256 } 257 batch := d.Session.NewBatch(gocql.LoggedBatch).WithContext(ctx) 258 batch.Query(templateUpdateTaskQueueQueryWithTTLPart1, 259 request.NamespaceID, 260 request.TaskQueue, 261 request.TaskType, 262 rowTypeTaskQueue, 263 taskQueueTaskID, 264 expiryTTL, 265 ) 266 batch.Query(templateUpdateTaskQueueQueryWithTTLPart2, 267 expiryTTL, 268 request.RangeID, 269 request.TaskQueueInfo.Data, 270 request.TaskQueueInfo.EncodingType.String(), 271 request.NamespaceID, 272 request.TaskQueue, 273 request.TaskType, 274 rowTypeTaskQueue, 275 taskQueueTaskID, 276 request.PrevRangeID, 277 ) 278 applied, _, err = d.Session.MapExecuteBatchCAS(batch, previous) 279 } else { 280 query := d.Session.Query(templateUpdateTaskQueueQuery, 281 request.RangeID, 282 request.TaskQueueInfo.Data, 283 request.TaskQueueInfo.EncodingType.String(), 284 request.NamespaceID, 285 request.TaskQueue, 286 request.TaskType, 287 rowTypeTaskQueue, 288 taskQueueTaskID, 289 request.PrevRangeID, 290 ).WithContext(ctx) 291 applied, err = query.MapScanCAS(previous) 292 } 293 294 if err != nil { 295 return nil, gocql.ConvertError("UpdateTaskQueue", err) 296 } 297 298 if !applied { 299 var columns []string 300 for k, v := range previous { 301 columns = append(columns, fmt.Sprintf("%s=%v", k, v)) 302 } 303 304 return nil, &p.ConditionFailedError{ 305 Msg: fmt.Sprintf("Failed to update task queue. name: %v, type: %v, rangeID: %v, columns: (%v)", 306 request.TaskQueue, request.TaskType, request.RangeID, strings.Join(columns, ",")), 307 } 308 } 309 310 return &p.UpdateTaskQueueResponse{}, nil 311 } 312 313 func (d *MatchingTaskStore) ListTaskQueue( 314 _ context.Context, 315 _ *p.ListTaskQueueRequest, 316 ) (*p.InternalListTaskQueueResponse, error) { 317 return nil, serviceerror.NewUnavailable("unsupported operation") 318 } 319 320 func (d *MatchingTaskStore) DeleteTaskQueue( 321 ctx context.Context, 322 request *p.DeleteTaskQueueRequest, 323 ) error { 324 query := d.Session.Query( 325 templateDeleteTaskQueueQuery, 326 request.TaskQueue.NamespaceID, 327 request.TaskQueue.TaskQueueName, 328 request.TaskQueue.TaskQueueType, 329 rowTypeTaskQueue, 330 taskQueueTaskID, 331 request.RangeID, 332 ).WithContext(ctx) 333 previous := make(map[string]interface{}) 334 applied, err := query.MapScanCAS(previous) 335 if err != nil { 336 return gocql.ConvertError("DeleteTaskQueue", err) 337 } 338 if !applied { 339 return &p.ConditionFailedError{ 340 Msg: fmt.Sprintf("DeleteTaskQueue operation failed: expected_range_id=%v but found %+v", request.RangeID, previous), 341 } 342 } 343 return nil 344 } 345 346 // CreateTasks add tasks 347 func (d *MatchingTaskStore) CreateTasks( 348 ctx context.Context, 349 request *p.InternalCreateTasksRequest, 350 ) (*p.CreateTasksResponse, error) { 351 batch := d.Session.NewBatch(gocql.LoggedBatch).WithContext(ctx) 352 namespaceID := request.NamespaceID 353 taskQueue := request.TaskQueue 354 taskQueueType := request.TaskType 355 356 for _, task := range request.Tasks { 357 ttl := GetTaskTTL(task.ExpiryTime) 358 359 if ttl <= 0 || ttl > maxCassandraTTL { 360 batch.Query(templateCreateTaskQuery, 361 namespaceID, 362 taskQueue, 363 taskQueueType, 364 rowTypeTask, 365 task.TaskId, 366 task.Task.Data, 367 task.Task.EncodingType.String()) 368 } else { 369 batch.Query(templateCreateTaskWithTTLQuery, 370 namespaceID, 371 taskQueue, 372 taskQueueType, 373 rowTypeTask, 374 task.TaskId, 375 task.Task.Data, 376 task.Task.EncodingType.String(), 377 ttl) 378 } 379 } 380 381 // The following query is used to ensure that range_id didn't change 382 batch.Query(templateUpdateTaskQueueQuery, 383 request.RangeID, 384 request.TaskQueueInfo.Data, 385 request.TaskQueueInfo.EncodingType.String(), 386 namespaceID, 387 taskQueue, 388 taskQueueType, 389 rowTypeTaskQueue, 390 taskQueueTaskID, 391 request.RangeID, 392 ) 393 394 previous := make(map[string]interface{}) 395 applied, _, err := d.Session.MapExecuteBatchCAS(batch, previous) 396 if err != nil { 397 return nil, gocql.ConvertError("CreateTasks", err) 398 } 399 if !applied { 400 rangeID := previous["range_id"] 401 return nil, &p.ConditionFailedError{ 402 Msg: fmt.Sprintf("Failed to create task. TaskQueue: %v, taskQueueType: %v, rangeID: %v, db rangeID: %v", 403 taskQueue, taskQueueType, request.RangeID, rangeID), 404 } 405 } 406 407 return &p.CreateTasksResponse{}, nil 408 } 409 410 func GetTaskTTL(expireTime *timestamppb.Timestamp) int64 { 411 var ttl int64 = 0 412 if expireTime != nil && !expireTime.AsTime().IsZero() { 413 expiryTtl := convert.Int64Ceil(time.Until(expireTime.AsTime()).Seconds()) 414 415 // 0 means no ttl, we dont want that. 416 // Todo: Come back and correctly ignore expired in-memory tasks before persisting 417 if expiryTtl < 1 { 418 expiryTtl = 1 419 } 420 421 ttl = expiryTtl 422 } 423 return ttl 424 } 425 426 // GetTasks get a task 427 func (d *MatchingTaskStore) GetTasks( 428 ctx context.Context, 429 request *p.GetTasksRequest, 430 ) (*p.InternalGetTasksResponse, error) { 431 // Reading taskqueue tasks need to be quorum level consistent, otherwise we could lose tasks 432 query := d.Session.Query(templateGetTasksQuery, 433 request.NamespaceID, 434 request.TaskQueue, 435 request.TaskType, 436 rowTypeTask, 437 request.InclusiveMinTaskID, 438 request.ExclusiveMaxTaskID, 439 ).WithContext(ctx) 440 iter := query.PageSize(request.PageSize).PageState(request.NextPageToken).Iter() 441 442 response := &p.InternalGetTasksResponse{} 443 task := make(map[string]interface{}) 444 for iter.MapScan(task) { 445 _, ok := task["task_id"] 446 if !ok { // no tasks, but static column record returned 447 continue 448 } 449 450 rawTask, ok := task["task"] 451 if !ok { 452 return nil, newFieldNotFoundError("task", task) 453 } 454 taskVal, ok := rawTask.([]byte) 455 if !ok { 456 var byteSliceType []byte 457 return nil, newPersistedTypeMismatchError("task", byteSliceType, rawTask, task) 458 459 } 460 461 rawEncoding, ok := task["task_encoding"] 462 if !ok { 463 return nil, newFieldNotFoundError("task_encoding", task) 464 } 465 encodingVal, ok := rawEncoding.(string) 466 if !ok { 467 var byteSliceType []byte 468 return nil, newPersistedTypeMismatchError("task_encoding", byteSliceType, rawEncoding, task) 469 } 470 response.Tasks = append(response.Tasks, p.NewDataBlob(taskVal, encodingVal)) 471 472 task = make(map[string]interface{}) // Reinitialize map as initialized fails on unmarshalling 473 } 474 if len(iter.PageState()) > 0 { 475 response.NextPageToken = iter.PageState() 476 } 477 478 if err := iter.Close(); err != nil { 479 return nil, serviceerror.NewUnavailable(fmt.Sprintf("GetTasks operation failed. Error: %v", err)) 480 } 481 return response, nil 482 } 483 484 // CompleteTask delete a task 485 func (d *MatchingTaskStore) CompleteTask( 486 ctx context.Context, 487 request *p.CompleteTaskRequest, 488 ) error { 489 tli := request.TaskQueue 490 query := d.Session.Query(templateCompleteTaskQuery, 491 tli.NamespaceID, 492 tli.TaskQueueName, 493 tli.TaskQueueType, 494 rowTypeTask, 495 request.TaskID, 496 ).WithContext(ctx) 497 498 err := query.Exec() 499 if err != nil { 500 return gocql.ConvertError("CompleteTask", err) 501 } 502 503 return nil 504 } 505 506 // CompleteTasksLessThan deletes all tasks less than the given task id. This API ignores the 507 // Limit request parameter i.e. either all tasks leq the task_id will be deleted or an error will 508 // be returned to the caller 509 func (d *MatchingTaskStore) CompleteTasksLessThan( 510 ctx context.Context, 511 request *p.CompleteTasksLessThanRequest, 512 ) (int, error) { 513 query := d.Session.Query( 514 templateCompleteTasksLessThanQuery, 515 request.NamespaceID, 516 request.TaskQueueName, 517 request.TaskType, 518 rowTypeTask, 519 request.ExclusiveMaxTaskID, 520 ).WithContext(ctx) 521 err := query.Exec() 522 if err != nil { 523 return 0, gocql.ConvertError("CompleteTasksLessThan", err) 524 } 525 return p.UnknownNumRowsAffected, nil 526 } 527 528 func (d *MatchingTaskStore) GetTaskQueueUserData( 529 ctx context.Context, 530 request *p.GetTaskQueueUserDataRequest, 531 ) (*p.InternalGetTaskQueueUserDataResponse, error) { 532 query := d.Session.Query(templateGetTaskQueueUserDataQuery, 533 request.NamespaceID, 534 request.TaskQueue, 535 ).WithContext(ctx) 536 var version int64 537 var userDataBytes []byte 538 var encoding string 539 if err := query.Scan(&userDataBytes, &encoding, &version); err != nil { 540 return nil, gocql.ConvertError("GetTaskQueueData", err) 541 } 542 543 return &p.InternalGetTaskQueueUserDataResponse{ 544 Version: version, 545 UserData: p.NewDataBlob(userDataBytes, encoding), 546 }, nil 547 } 548 549 func (d *MatchingTaskStore) UpdateTaskQueueUserData( 550 ctx context.Context, 551 request *p.InternalUpdateTaskQueueUserDataRequest, 552 ) error { 553 batch := d.Session.NewBatch(gocql.UnloggedBatch).WithContext(ctx) 554 555 if request.Version == 0 { 556 batch.Query(templateInsertTaskQueueUserDataQuery, 557 request.NamespaceID, 558 request.TaskQueue, 559 request.UserData.Data, 560 request.UserData.EncodingType.String(), 561 ) 562 } else { 563 batch.Query(templateUpdateTaskQueueUserDataQuery, 564 request.UserData.Data, 565 request.UserData.EncodingType.String(), 566 request.Version+1, 567 request.NamespaceID, 568 request.TaskQueue, 569 request.Version, 570 ) 571 } 572 for _, buildId := range request.BuildIdsAdded { 573 batch.Query(templateInsertBuildIdTaskQueueMappingQuery, request.NamespaceID, buildId, request.TaskQueue) 574 } 575 for _, buildId := range request.BuildIdsRemoved { 576 batch.Query(templateDeleteBuildIdTaskQueueMappingQuery, request.NamespaceID, buildId, request.TaskQueue) 577 } 578 579 previous := make(map[string]interface{}) 580 applied, iter, err := d.Session.MapExecuteBatchCAS(batch, previous) 581 582 if err != nil { 583 return gocql.ConvertError("UpdateTaskQueueUserData", err) 584 } 585 586 // We only care about the conflict in the first query 587 err = iter.Close() 588 if err != nil { 589 return gocql.ConvertError("UpdateTaskQueueUserData", err) 590 } 591 592 if !applied { 593 var columns []string 594 for k, v := range previous { 595 columns = append(columns, fmt.Sprintf("%s=%v", k, v)) 596 } 597 598 return &p.ConditionFailedError{ 599 Msg: fmt.Sprintf("Failed to update task queue. name: %v, version: %v, columns: (%v)", 600 request.TaskQueue, request.Version, strings.Join(columns, ",")), 601 } 602 } 603 604 return nil 605 } 606 607 func (d *MatchingTaskStore) ListTaskQueueUserDataEntries(ctx context.Context, request *p.ListTaskQueueUserDataEntriesRequest) (*p.InternalListTaskQueueUserDataEntriesResponse, error) { 608 query := d.Session.Query(templateListTaskQueueUserDataQuery, request.NamespaceID).WithContext(ctx) 609 iter := query.PageSize(request.PageSize).PageState(request.NextPageToken).Iter() 610 611 response := &p.InternalListTaskQueueUserDataEntriesResponse{} 612 row := make(map[string]interface{}) 613 for iter.MapScan(row) { 614 taskQueueRaw, ok := row["task_queue_name"] 615 if !ok { 616 return nil, newFieldNotFoundError("task_queue_name", row) 617 } 618 taskQueue, ok := taskQueueRaw.(string) 619 if !ok { 620 return nil, newPersistedTypeMismatchError("task_queue_name", taskQueue, taskQueueRaw, row) 621 } 622 623 dataRaw, ok := row["data"] 624 if !ok { 625 return nil, newFieldNotFoundError("data", row) 626 } 627 data, ok := dataRaw.([]byte) 628 if !ok { 629 return nil, newPersistedTypeMismatchError("data", data, dataRaw, row) 630 } 631 632 dataEncodingRaw, ok := row["data_encoding"] 633 if !ok { 634 return nil, newFieldNotFoundError("data_encoding", row) 635 } 636 dataEncoding, ok := dataEncodingRaw.(string) 637 if !ok { 638 return nil, newPersistedTypeMismatchError("data_encoding", dataEncoding, dataEncodingRaw, row) 639 } 640 641 versionRaw, ok := row["version"] 642 if !ok { 643 return nil, newFieldNotFoundError("version", row) 644 } 645 version, ok := versionRaw.(int64) 646 if !ok { 647 return nil, newPersistedTypeMismatchError("version", version, versionRaw, row) 648 } 649 650 response.Entries = append(response.Entries, p.InternalTaskQueueUserDataEntry{TaskQueue: taskQueue, Data: p.NewDataBlob(data, dataEncoding), Version: version}) 651 652 row = make(map[string]interface{}) // Reinitialize map as initialized fails on unmarshalling 653 } 654 if len(iter.PageState()) > 0 { 655 response.NextPageToken = iter.PageState() 656 } 657 658 if err := iter.Close(); err != nil { 659 return nil, serviceerror.NewUnavailable(fmt.Sprintf("ListTaskQueueUserDataEntries operation failed. Error: %v", err)) 660 } 661 return response, nil 662 } 663 664 func (d *MatchingTaskStore) GetTaskQueuesByBuildId(ctx context.Context, request *p.GetTaskQueuesByBuildIdRequest) ([]string, error) { 665 query := d.Session.Query(templateListTaskQueueNamesByBuildIdQuery, request.NamespaceID, request.BuildID).WithContext(ctx) 666 iter := query.PageSize(listTaskQueueNamesByBuildIdPageSize).Iter() 667 668 var taskQueues []string 669 row := make(map[string]interface{}) 670 671 for { 672 for iter.MapScan(row) { 673 taskQueueRaw, ok := row["task_queue_name"] 674 if !ok { 675 return nil, newFieldNotFoundError("task_queue_name", row) 676 } 677 taskQueue, ok := taskQueueRaw.(string) 678 if !ok { 679 var stringType string 680 return nil, newPersistedTypeMismatchError("task_queue_name", stringType, taskQueueRaw, row) 681 } 682 683 taskQueues = append(taskQueues, taskQueue) 684 685 row = make(map[string]interface{}) // Reinitialize map as initialized fails on unmarshalling 686 } 687 if len(iter.PageState()) == 0 { 688 break 689 } 690 } 691 692 if err := iter.Close(); err != nil { 693 return nil, serviceerror.NewUnavailable(fmt.Sprintf("GetTaskQueuesByBuildId operation failed. Error: %v", err)) 694 } 695 return taskQueues, nil 696 } 697 698 func (d *MatchingTaskStore) CountTaskQueuesByBuildId(ctx context.Context, request *p.CountTaskQueuesByBuildIdRequest) (int, error) { 699 var count int 700 query := d.Session.Query(templateCountTaskQueueByBuildIdQuery, request.NamespaceID, request.BuildID).WithContext(ctx) 701 err := query.Scan(&count) 702 return count, err 703 } 704 705 func (d *MatchingTaskStore) GetName() string { 706 return cassandraPersistenceName 707 } 708 709 func (d *MatchingTaskStore) Close() { 710 if d.Session != nil { 711 d.Session.Close() 712 } 713 }