go.temporal.io/server@v1.23.0/common/persistence/sql/execution_util.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 sql 26 27 import ( 28 "bytes" 29 "context" 30 "database/sql" 31 "fmt" 32 33 commonpb "go.temporal.io/api/common/v1" 34 enumspb "go.temporal.io/api/enums/v1" 35 "go.temporal.io/api/serviceerror" 36 37 enumsspb "go.temporal.io/server/api/enums/v1" 38 persistencespb "go.temporal.io/server/api/persistence/v1" 39 p "go.temporal.io/server/common/persistence" 40 "go.temporal.io/server/common/persistence/serialization" 41 "go.temporal.io/server/common/persistence/sql/sqlplugin" 42 "go.temporal.io/server/common/primitives" 43 "go.temporal.io/server/service/history/tasks" 44 ) 45 46 func applyWorkflowMutationTx( 47 ctx context.Context, 48 tx sqlplugin.Tx, 49 shardID int32, 50 workflowMutation *p.InternalWorkflowMutation, 51 ) error { 52 lastWriteVersion := workflowMutation.LastWriteVersion 53 namespaceID := workflowMutation.NamespaceID 54 workflowID := workflowMutation.WorkflowID 55 runID := workflowMutation.ExecutionState.RunId 56 57 namespaceIDBytes, err := primitives.ParseUUID(namespaceID) 58 if err != nil { 59 return serviceerror.NewInternal(fmt.Sprintf("uuid parse failed. Error: %v", err)) 60 } 61 62 runIDBytes, err := primitives.ParseUUID(runID) 63 if err != nil { 64 return serviceerror.NewInternal(fmt.Sprintf("uuid parse failed. Error: %v", err)) 65 } 66 67 // TODO Remove me if UPDATE holds the lock to the end of a transaction 68 if err := lockAndCheckExecution(ctx, 69 tx, 70 shardID, 71 namespaceIDBytes, 72 workflowID, 73 runIDBytes, 74 workflowMutation.Condition, 75 workflowMutation.DBRecordVersion, 76 ); err != nil { 77 switch err.(type) { 78 case *p.WorkflowConditionFailedError, *p.ConditionFailedError: 79 return err 80 default: 81 return serviceerror.NewUnavailable(fmt.Sprintf("applyWorkflowMutationTx failed. Failed to lock executions row. Error: %v", err)) 82 } 83 } 84 85 if err := updateExecution(ctx, 86 tx, 87 namespaceID, 88 workflowID, 89 workflowMutation.ExecutionInfoBlob, 90 workflowMutation.ExecutionState, 91 workflowMutation.NextEventID, 92 lastWriteVersion, 93 workflowMutation.DBRecordVersion, 94 shardID, 95 ); err != nil { 96 return serviceerror.NewUnavailable(fmt.Sprintf("applyWorkflowMutationTx failed. Failed to update executions row. Erorr: %v", err)) 97 } 98 99 if err := applyTasks(ctx, 100 tx, 101 shardID, 102 workflowMutation.Tasks, 103 ); err != nil { 104 return err 105 } 106 107 if err := updateActivityInfos(ctx, 108 tx, 109 workflowMutation.UpsertActivityInfos, 110 workflowMutation.DeleteActivityInfos, 111 shardID, 112 namespaceIDBytes, 113 workflowID, 114 runIDBytes, 115 ); err != nil { 116 return serviceerror.NewUnavailable(fmt.Sprintf("applyWorkflowMutationTx failed. Error: %v", err)) 117 } 118 119 if err := updateTimerInfos(ctx, 120 tx, 121 workflowMutation.UpsertTimerInfos, 122 workflowMutation.DeleteTimerInfos, 123 shardID, 124 namespaceIDBytes, 125 workflowID, 126 runIDBytes, 127 ); err != nil { 128 return serviceerror.NewUnavailable(fmt.Sprintf("applyWorkflowMutationTx failed. Error: %v", err)) 129 } 130 131 if err := updateChildExecutionInfos(ctx, 132 tx, 133 workflowMutation.UpsertChildExecutionInfos, 134 workflowMutation.DeleteChildExecutionInfos, 135 shardID, 136 namespaceIDBytes, 137 workflowID, 138 runIDBytes, 139 ); err != nil { 140 return serviceerror.NewUnavailable(fmt.Sprintf("applyWorkflowMutationTx failed. Error: %v", err)) 141 } 142 143 if err := updateRequestCancelInfos(ctx, 144 tx, 145 workflowMutation.UpsertRequestCancelInfos, 146 workflowMutation.DeleteRequestCancelInfos, 147 shardID, 148 namespaceIDBytes, 149 workflowID, 150 runIDBytes, 151 ); err != nil { 152 return serviceerror.NewUnavailable(fmt.Sprintf("applyWorkflowMutationTx failed. Error: %v", err)) 153 } 154 155 if err := updateSignalInfos(ctx, 156 tx, 157 workflowMutation.UpsertSignalInfos, 158 workflowMutation.DeleteSignalInfos, 159 shardID, 160 namespaceIDBytes, 161 workflowID, 162 runIDBytes, 163 ); err != nil { 164 return serviceerror.NewUnavailable(fmt.Sprintf("applyWorkflowMutationTx failed. Error: %v", err)) 165 } 166 167 if err := updateSignalsRequested(ctx, 168 tx, 169 workflowMutation.UpsertSignalRequestedIDs, 170 workflowMutation.DeleteSignalRequestedIDs, 171 shardID, 172 namespaceIDBytes, 173 workflowID, 174 runIDBytes); err != nil { 175 return serviceerror.NewUnavailable(fmt.Sprintf("applyWorkflowMutationTx failed. Error: %v", err)) 176 } 177 178 if workflowMutation.ClearBufferedEvents { 179 if err := deleteBufferedEvents(ctx, 180 tx, 181 shardID, 182 namespaceIDBytes, 183 workflowID, 184 runIDBytes, 185 ); err != nil { 186 return serviceerror.NewUnavailable(fmt.Sprintf("applyWorkflowMutationTx failed. Error: %v", err)) 187 } 188 } 189 190 if err := updateBufferedEvents(ctx, 191 tx, 192 workflowMutation.NewBufferedEvents, 193 shardID, 194 namespaceIDBytes, 195 workflowID, 196 runIDBytes, 197 ); err != nil { 198 return serviceerror.NewUnavailable(fmt.Sprintf("applyWorkflowMutationTx failed. Error: %v", err)) 199 } 200 return nil 201 } 202 203 func applyWorkflowSnapshotTxAsReset( 204 ctx context.Context, 205 tx sqlplugin.Tx, 206 shardID int32, 207 workflowSnapshot *p.InternalWorkflowSnapshot, 208 ) error { 209 210 lastWriteVersion := workflowSnapshot.LastWriteVersion 211 workflowID := workflowSnapshot.WorkflowID 212 namespaceID := workflowSnapshot.NamespaceID 213 runID := workflowSnapshot.ExecutionState.RunId 214 namespaceIDBytes, err := primitives.ParseUUID(namespaceID) 215 if err != nil { 216 return err 217 } 218 runIDBytes, err := primitives.ParseUUID(runID) 219 if err != nil { 220 return err 221 } 222 223 // TODO Is there a way to modify the various map tables without fear of other people adding rows after we delete, without locking the executions row? 224 if err := lockAndCheckExecution(ctx, 225 tx, 226 shardID, 227 namespaceIDBytes, 228 workflowID, 229 runIDBytes, 230 workflowSnapshot.Condition, 231 workflowSnapshot.DBRecordVersion, 232 ); err != nil { 233 switch err.(type) { 234 case *p.WorkflowConditionFailedError, *p.ConditionFailedError: 235 return err 236 default: 237 return serviceerror.NewUnavailable(fmt.Sprintf("applyWorkflowSnapshotTxAsReset failed. Failed to lock executions row. Error: %v", err)) 238 } 239 } 240 241 if err := updateExecution(ctx, 242 tx, 243 namespaceID, 244 workflowID, 245 workflowSnapshot.ExecutionInfoBlob, 246 workflowSnapshot.ExecutionState, 247 workflowSnapshot.NextEventID, 248 lastWriteVersion, 249 workflowSnapshot.DBRecordVersion, 250 shardID, 251 ); err != nil { 252 return serviceerror.NewUnavailable(fmt.Sprintf("applyWorkflowSnapshotTxAsReset failed. Failed to update executions row. Erorr: %v", err)) 253 } 254 255 if err := applyTasks(ctx, 256 tx, 257 shardID, 258 workflowSnapshot.Tasks, 259 ); err != nil { 260 return err 261 } 262 263 if err := deleteActivityInfoMap(ctx, 264 tx, 265 shardID, 266 namespaceIDBytes, 267 workflowID, 268 runIDBytes, 269 ); err != nil { 270 return serviceerror.NewUnavailable(fmt.Sprintf("applyWorkflowSnapshotTxAsReset failed. Failed to clear activity info map. Error: %v", err)) 271 } 272 273 if err := updateActivityInfos(ctx, 274 tx, 275 workflowSnapshot.ActivityInfos, 276 nil, 277 shardID, 278 namespaceIDBytes, 279 workflowID, 280 runIDBytes, 281 ); err != nil { 282 return serviceerror.NewUnavailable(fmt.Sprintf("applyWorkflowSnapshotTxAsReset failed. Failed to insert into activity info map after clearing. Error: %v", err)) 283 } 284 285 if err := deleteTimerInfoMap(ctx, 286 tx, 287 shardID, 288 namespaceIDBytes, 289 workflowID, 290 runIDBytes, 291 ); err != nil { 292 return serviceerror.NewUnavailable(fmt.Sprintf("applyWorkflowSnapshotTxAsReset failed. Failed to clear timer info map. Error: %v", err)) 293 } 294 295 if err := updateTimerInfos(ctx, 296 tx, 297 workflowSnapshot.TimerInfos, 298 nil, 299 shardID, 300 namespaceIDBytes, 301 workflowID, 302 runIDBytes, 303 ); err != nil { 304 return serviceerror.NewUnavailable(fmt.Sprintf("applyWorkflowSnapshotTxAsReset failed. Failed to insert into timer info map after clearing. Error: %v", err)) 305 } 306 307 if err := deleteChildExecutionInfoMap(ctx, 308 tx, 309 shardID, 310 namespaceIDBytes, 311 workflowID, 312 runIDBytes, 313 ); err != nil { 314 return serviceerror.NewUnavailable(fmt.Sprintf("applyWorkflowSnapshotTxAsReset failed. Failed to clear child execution info map. Error: %v", err)) 315 } 316 317 if err := updateChildExecutionInfos(ctx, 318 tx, 319 workflowSnapshot.ChildExecutionInfos, 320 nil, 321 shardID, 322 namespaceIDBytes, 323 workflowID, 324 runIDBytes, 325 ); err != nil { 326 return serviceerror.NewUnavailable(fmt.Sprintf("applyWorkflowSnapshotTxAsReset failed. Failed to insert into activity info map after clearing. Error: %v", err)) 327 } 328 329 if err := deleteRequestCancelInfoMap(ctx, 330 tx, 331 shardID, 332 namespaceIDBytes, 333 workflowID, 334 runIDBytes, 335 ); err != nil { 336 return serviceerror.NewUnavailable(fmt.Sprintf("applyWorkflowSnapshotTxAsReset failed. Failed to clear request cancel info map. Error: %v", err)) 337 } 338 339 if err := updateRequestCancelInfos(ctx, 340 tx, 341 workflowSnapshot.RequestCancelInfos, 342 nil, 343 shardID, 344 namespaceIDBytes, 345 workflowID, 346 runIDBytes, 347 ); err != nil { 348 return serviceerror.NewUnavailable(fmt.Sprintf("applyWorkflowSnapshotTxAsReset failed. Failed to insert into request cancel info map after clearing. Error: %v", err)) 349 } 350 351 if err := deleteSignalInfoMap(ctx, 352 tx, 353 shardID, 354 namespaceIDBytes, 355 workflowID, 356 runIDBytes, 357 ); err != nil { 358 return serviceerror.NewUnavailable(fmt.Sprintf("applyWorkflowSnapshotTxAsReset failed. Failed to clear signal info map. Error: %v", err)) 359 } 360 361 if err := updateSignalInfos(ctx, 362 tx, 363 workflowSnapshot.SignalInfos, 364 nil, 365 shardID, 366 namespaceIDBytes, 367 workflowID, 368 runIDBytes, 369 ); err != nil { 370 return serviceerror.NewUnavailable(fmt.Sprintf("applyWorkflowSnapshotTxAsReset failed. Failed to insert into signal info map after clearing. Error: %v", err)) 371 } 372 373 if err := deleteSignalsRequestedSet(ctx, 374 tx, 375 shardID, 376 namespaceIDBytes, 377 workflowID, 378 runIDBytes); err != nil { 379 return serviceerror.NewUnavailable(fmt.Sprintf("applyWorkflowSnapshotTxAsReset failed. Failed to clear signals requested set. Error: %v", err)) 380 } 381 382 if err := updateSignalsRequested(ctx, 383 tx, 384 workflowSnapshot.SignalRequestedIDs, 385 nil, 386 shardID, 387 namespaceIDBytes, 388 workflowID, 389 runIDBytes, 390 ); err != nil { 391 return serviceerror.NewUnavailable(fmt.Sprintf("applyWorkflowSnapshotTxAsReset failed. Failed to insert into signals requested set after clearing. Error: %v", err)) 392 } 393 394 if err := deleteBufferedEvents(ctx, 395 tx, 396 shardID, 397 namespaceIDBytes, 398 workflowID, 399 runIDBytes, 400 ); err != nil { 401 return serviceerror.NewUnavailable(fmt.Sprintf("applyWorkflowSnapshotTxAsReset failed. Failed to clear buffered events. Error: %v", err)) 402 } 403 return nil 404 } 405 406 func (m *sqlExecutionStore) applyWorkflowSnapshotTxAsNew( 407 ctx context.Context, 408 tx sqlplugin.Tx, 409 shardID int32, 410 workflowSnapshot *p.InternalWorkflowSnapshot, 411 ) error { 412 413 lastWriteVersion := workflowSnapshot.LastWriteVersion 414 workflowID := workflowSnapshot.WorkflowID 415 namespaceID := workflowSnapshot.NamespaceID 416 runID := workflowSnapshot.ExecutionState.RunId 417 namespaceIDBytes, err := primitives.ParseUUID(namespaceID) 418 if err != nil { 419 return err 420 } 421 runIDBytes, err := primitives.ParseUUID(runID) 422 if err != nil { 423 return err 424 } 425 426 if err := m.createExecution(ctx, 427 tx, 428 namespaceID, 429 workflowID, 430 workflowSnapshot.ExecutionInfoBlob, 431 workflowSnapshot.ExecutionState, 432 workflowSnapshot.NextEventID, 433 lastWriteVersion, 434 workflowSnapshot.DBRecordVersion, 435 shardID, 436 ); err != nil { 437 return err 438 } 439 440 if err := applyTasks(ctx, 441 tx, 442 shardID, 443 workflowSnapshot.Tasks, 444 ); err != nil { 445 return err 446 } 447 448 if err := updateActivityInfos(ctx, 449 tx, 450 workflowSnapshot.ActivityInfos, 451 nil, 452 shardID, 453 namespaceIDBytes, 454 workflowID, 455 runIDBytes, 456 ); err != nil { 457 return serviceerror.NewUnavailable(fmt.Sprintf("applyWorkflowSnapshotTxAsNew failed. Failed to insert into activity info map after clearing. Error: %v", err)) 458 } 459 460 if err := updateTimerInfos(ctx, 461 tx, 462 workflowSnapshot.TimerInfos, 463 nil, 464 shardID, 465 namespaceIDBytes, 466 workflowID, 467 runIDBytes, 468 ); err != nil { 469 return serviceerror.NewUnavailable(fmt.Sprintf("applyWorkflowSnapshotTxAsNew failed. Failed to insert into timer info map after clearing. Error: %v", err)) 470 } 471 472 if err := updateChildExecutionInfos(ctx, 473 tx, 474 workflowSnapshot.ChildExecutionInfos, 475 nil, 476 shardID, 477 namespaceIDBytes, 478 workflowID, 479 runIDBytes, 480 ); err != nil { 481 return serviceerror.NewUnavailable(fmt.Sprintf("applyWorkflowSnapshotTxAsNew failed. Failed to insert into activity info map after clearing. Error: %v", err)) 482 } 483 484 if err := updateRequestCancelInfos(ctx, 485 tx, 486 workflowSnapshot.RequestCancelInfos, 487 nil, 488 shardID, 489 namespaceIDBytes, 490 workflowID, 491 runIDBytes, 492 ); err != nil { 493 return serviceerror.NewUnavailable(fmt.Sprintf("applyWorkflowSnapshotTxAsNew failed. Failed to insert into request cancel info map after clearing. Error: %v", err)) 494 } 495 496 if err := updateSignalInfos(ctx, 497 tx, 498 workflowSnapshot.SignalInfos, 499 nil, 500 shardID, 501 namespaceIDBytes, 502 workflowID, 503 runIDBytes, 504 ); err != nil { 505 return serviceerror.NewUnavailable(fmt.Sprintf("applyWorkflowSnapshotTxAsNew failed. Failed to insert into signal info map after clearing. Error: %v", err)) 506 } 507 508 if err := updateSignalsRequested(ctx, 509 tx, 510 workflowSnapshot.SignalRequestedIDs, 511 nil, 512 shardID, 513 namespaceIDBytes, 514 workflowID, 515 runIDBytes, 516 ); err != nil { 517 return serviceerror.NewUnavailable(fmt.Sprintf("applyWorkflowSnapshotTxAsNew failed. Failed to insert into signals requested set after clearing. Error: %v", err)) 518 } 519 520 return nil 521 } 522 523 func applyTasks( 524 ctx context.Context, 525 tx sqlplugin.Tx, 526 shardID int32, 527 insertTasks map[tasks.Category][]p.InternalHistoryTask, 528 ) error { 529 530 var err error 531 for category, tasksByCategory := range insertTasks { 532 switch category.Type() { 533 case tasks.CategoryTypeImmediate: 534 err = createImmediateTasks(ctx, tx, shardID, category.ID(), tasksByCategory) 535 case tasks.CategoryTypeScheduled: 536 err = createScheduledTasks(ctx, tx, shardID, category.ID(), tasksByCategory) 537 default: 538 err = serviceerror.NewInternal(fmt.Sprintf("Unknown task category type: %v", category)) 539 } 540 541 if err != nil { 542 return err 543 } 544 } 545 546 return nil 547 } 548 549 // lockCurrentExecutionIfExists returns current execution or nil if none is found for the workflowID 550 // locking it in the DB 551 func lockCurrentExecutionIfExists( 552 ctx context.Context, 553 tx sqlplugin.Tx, 554 shardID int32, 555 namespaceID primitives.UUID, 556 workflowID string, 557 ) (*sqlplugin.CurrentExecutionsRow, error) { 558 rows, err := tx.LockCurrentExecutionsJoinExecutions(ctx, sqlplugin.CurrentExecutionsFilter{ 559 ShardID: shardID, NamespaceID: namespaceID, WorkflowID: workflowID, 560 }) 561 if err != nil { 562 if err != sql.ErrNoRows { 563 return nil, serviceerror.NewUnavailable(fmt.Sprintf("lockCurrentExecutionIfExists failed. Failed to get current_executions row for (shard,namespace,workflow) = (%v, %v, %v). Error: %v", shardID, namespaceID, workflowID, err)) 564 } 565 } 566 size := len(rows) 567 if size > 1 { 568 return nil, serviceerror.NewUnavailable(fmt.Sprintf("lockCurrentExecutionIfExists failed. Multiple current_executions rows for (shard,namespace,workflow) = (%v, %v, %v).", shardID, namespaceID, workflowID)) 569 } 570 if size == 0 { 571 return nil, nil 572 } 573 return &rows[0], nil 574 } 575 576 func createOrUpdateCurrentExecution( 577 ctx context.Context, 578 tx sqlplugin.Tx, 579 createMode p.CreateWorkflowMode, 580 shardID int32, 581 namespaceID primitives.UUID, 582 workflowID string, 583 runID primitives.UUID, 584 state enumsspb.WorkflowExecutionState, 585 status enumspb.WorkflowExecutionStatus, 586 createRequestID string, 587 lastWriteVersion int64, 588 ) error { 589 590 row := sqlplugin.CurrentExecutionsRow{ 591 ShardID: shardID, 592 NamespaceID: namespaceID, 593 WorkflowID: workflowID, 594 RunID: runID, 595 CreateRequestID: createRequestID, 596 State: state, 597 Status: status, 598 LastWriteVersion: lastWriteVersion, 599 } 600 601 switch createMode { 602 case p.CreateWorkflowModeUpdateCurrent: 603 if err := updateCurrentExecution(ctx, 604 tx, 605 shardID, 606 namespaceID, 607 workflowID, 608 runID, 609 createRequestID, 610 state, 611 status, 612 row.LastWriteVersion, 613 ); err != nil { 614 return serviceerror.NewUnavailable(fmt.Sprintf("createOrUpdateCurrentExecution failed. Failed to reuse workflow ID. Error: %v", err)) 615 } 616 case p.CreateWorkflowModeBrandNew: 617 if _, err := tx.InsertIntoCurrentExecutions(ctx, &row); err != nil { 618 return serviceerror.NewUnavailable(fmt.Sprintf("createOrUpdateCurrentExecution failed. Failed to insert into current_executions table. Error: %v", err)) 619 } 620 case p.CreateWorkflowModeBypassCurrent: 621 // noop 622 default: 623 return fmt.Errorf("createOrUpdateCurrentExecution failed. Unknown workflow creation mode: %v", createMode) 624 } 625 626 return nil 627 } 628 629 func lockAndCheckExecution( 630 ctx context.Context, 631 tx sqlplugin.Tx, 632 shardID int32, 633 namespaceID primitives.UUID, 634 workflowID string, 635 runID primitives.UUID, 636 condition int64, 637 dbRecordVersion int64, 638 ) error { 639 640 version, nextEventID, err := lockExecution(ctx, tx, shardID, namespaceID, workflowID, runID) 641 if err != nil { 642 return err 643 } 644 645 if dbRecordVersion == 0 { 646 if nextEventID != condition { 647 return &p.WorkflowConditionFailedError{ 648 Msg: fmt.Sprintf("lockAndCheckExecution failed. Next_event_id was %v when it should have been %v.", nextEventID, condition), 649 NextEventID: nextEventID, 650 DBRecordVersion: version, 651 } 652 } 653 } else { 654 dbRecordVersion -= 1 655 if version != dbRecordVersion { 656 return &p.WorkflowConditionFailedError{ 657 Msg: fmt.Sprintf("lockAndCheckExecution failed. DBRecordVersion expected: %v, actually %v.", dbRecordVersion, version), 658 NextEventID: nextEventID, 659 DBRecordVersion: version, 660 } 661 } 662 } 663 664 return nil 665 } 666 667 func lockExecution( 668 ctx context.Context, 669 tx sqlplugin.Tx, 670 shardID int32, 671 namespaceID primitives.UUID, 672 workflowID string, 673 runID primitives.UUID, 674 ) (int64, int64, error) { 675 676 dbRecordVersion, nextEventID, err := tx.WriteLockExecutions(ctx, sqlplugin.ExecutionsFilter{ 677 ShardID: shardID, 678 NamespaceID: namespaceID, 679 WorkflowID: workflowID, 680 RunID: runID, 681 }) 682 if err != nil { 683 if err == sql.ErrNoRows { 684 return 0, 0, &p.ConditionFailedError{ 685 Msg: fmt.Sprintf("WriteLockExecutions failed. Unable to lock (shard, namespace, workflow, run) = (%v,%v,%v,%v) which does not exist.", 686 shardID, 687 namespaceID, 688 workflowID, 689 runID), 690 } 691 } 692 return 0, 0, serviceerror.NewUnavailable(fmt.Sprintf("lockNextEventID failed. Error: %v", err)) 693 } 694 return dbRecordVersion, nextEventID, nil 695 } 696 697 func createImmediateTasks( 698 ctx context.Context, 699 tx sqlplugin.Tx, 700 shardID int32, 701 categoryID int, 702 immedidateTasks []p.InternalHistoryTask, 703 ) error { 704 // This is for backward compatiblity. 705 // These task categories exist before the general history_immediate_tasks table is created, 706 // so they have their own tables. 707 switch categoryID { 708 case tasks.CategoryIDTransfer: 709 return createTransferTasks(ctx, tx, shardID, immedidateTasks) 710 case tasks.CategoryIDVisibility: 711 return createVisibilityTasks(ctx, tx, shardID, immedidateTasks) 712 case tasks.CategoryIDReplication: 713 return createReplicationTasks(ctx, tx, shardID, immedidateTasks) 714 } 715 716 if len(immedidateTasks) == 0 { 717 return nil 718 } 719 720 immediateTasksRows := make([]sqlplugin.HistoryImmediateTasksRow, 0, len(immedidateTasks)) 721 for _, task := range immedidateTasks { 722 immediateTasksRows = append(immediateTasksRows, sqlplugin.HistoryImmediateTasksRow{ 723 ShardID: shardID, 724 CategoryID: int32(categoryID), 725 TaskID: task.Key.TaskID, 726 Data: task.Blob.Data, 727 DataEncoding: task.Blob.EncodingType.String(), 728 }) 729 } 730 731 result, err := tx.InsertIntoHistoryImmediateTasks(ctx, immediateTasksRows) 732 if err != nil { 733 return serviceerror.NewUnavailable(fmt.Sprintf("createImmediateTasks failed. Error: %v", err)) 734 } 735 736 rowsAffected, err := result.RowsAffected() 737 if err != nil { 738 return serviceerror.NewUnavailable(fmt.Sprintf("createImmediateTasks failed. Could not verify number of rows inserted. Error: %v", err)) 739 } 740 741 if int(rowsAffected) != len(immediateTasksRows) { 742 return serviceerror.NewUnavailable(fmt.Sprintf("createImmediateTasks failed. Inserted %v instead of %v rows into history_immediate_tasks. Error: %v", rowsAffected, len(immediateTasksRows), err)) 743 } 744 return nil 745 } 746 747 func createScheduledTasks( 748 ctx context.Context, 749 tx sqlplugin.Tx, 750 shardID int32, 751 categoryID int, 752 scheduledTasks []p.InternalHistoryTask, 753 ) error { 754 // This is for backward compatiblity. 755 // These task categories exists before the general history_scheduled_tasks table is created, 756 // so they have their own tables. 757 if categoryID == tasks.CategoryIDTimer { 758 return createTimerTasks(ctx, tx, shardID, scheduledTasks) 759 } 760 761 if len(scheduledTasks) == 0 { 762 return nil 763 } 764 765 scheduledTasksRows := make([]sqlplugin.HistoryScheduledTasksRow, 0, len(scheduledTasks)) 766 for _, task := range scheduledTasks { 767 scheduledTasksRows = append(scheduledTasksRows, sqlplugin.HistoryScheduledTasksRow{ 768 ShardID: shardID, 769 CategoryID: int32(categoryID), 770 VisibilityTimestamp: task.Key.FireTime, 771 TaskID: task.Key.TaskID, 772 Data: task.Blob.Data, 773 DataEncoding: task.Blob.EncodingType.String(), 774 }) 775 } 776 777 result, err := tx.InsertIntoHistoryScheduledTasks(ctx, scheduledTasksRows) 778 if err != nil { 779 return serviceerror.NewUnavailable(fmt.Sprintf("createScheduledTasks failed. Error: %v", err)) 780 } 781 rowsAffected, err := result.RowsAffected() 782 if err != nil { 783 return serviceerror.NewUnavailable(fmt.Sprintf("createScheduledTasks failed. Could not verify number of rows inserted. Error: %v", err)) 784 } 785 786 if int(rowsAffected) != len(scheduledTasks) { 787 return serviceerror.NewUnavailable(fmt.Sprintf("createScheduledTasks failed. Inserted %v instead of %v rows into history_scheduled_tasks. Error: %v", rowsAffected, len(scheduledTasks), err)) 788 } 789 return nil 790 } 791 792 func createTransferTasks( 793 ctx context.Context, 794 tx sqlplugin.Tx, 795 shardID int32, 796 transferTasks []p.InternalHistoryTask, 797 ) error { 798 799 if len(transferTasks) == 0 { 800 return nil 801 } 802 803 transferTasksRows := make([]sqlplugin.TransferTasksRow, 0, len(transferTasks)) 804 for _, task := range transferTasks { 805 transferTasksRows = append(transferTasksRows, sqlplugin.TransferTasksRow{ 806 ShardID: shardID, 807 TaskID: task.Key.TaskID, 808 Data: task.Blob.Data, 809 DataEncoding: task.Blob.EncodingType.String(), 810 }) 811 } 812 813 result, err := tx.InsertIntoTransferTasks(ctx, transferTasksRows) 814 if err != nil { 815 return serviceerror.NewUnavailable(fmt.Sprintf("createTransferTasks failed. Error: %v", err)) 816 } 817 818 rowsAffected, err := result.RowsAffected() 819 if err != nil { 820 return serviceerror.NewUnavailable(fmt.Sprintf("createTransferTasks failed. Could not verify number of rows inserted. Error: %v", err)) 821 } 822 823 if int(rowsAffected) != len(transferTasks) { 824 return serviceerror.NewUnavailable(fmt.Sprintf("createTransferTasks failed. Inserted %v instead of %v rows into transfer_tasks. Error: %v", rowsAffected, len(transferTasks), err)) 825 } 826 return nil 827 } 828 829 func createTimerTasks( 830 ctx context.Context, 831 tx sqlplugin.Tx, 832 shardID int32, 833 timerTasks []p.InternalHistoryTask, 834 ) error { 835 836 if len(timerTasks) == 0 { 837 return nil 838 } 839 840 timerTasksRows := make([]sqlplugin.TimerTasksRow, 0, len(timerTasks)) 841 for _, task := range timerTasks { 842 timerTasksRows = append(timerTasksRows, sqlplugin.TimerTasksRow{ 843 ShardID: shardID, 844 VisibilityTimestamp: task.Key.FireTime, 845 TaskID: task.Key.TaskID, 846 Data: task.Blob.Data, 847 DataEncoding: task.Blob.EncodingType.String(), 848 }) 849 } 850 851 result, err := tx.InsertIntoTimerTasks(ctx, timerTasksRows) 852 if err != nil { 853 return serviceerror.NewUnavailable(fmt.Sprintf("createTimerTasks failed. Error: %v", err)) 854 } 855 rowsAffected, err := result.RowsAffected() 856 if err != nil { 857 return serviceerror.NewUnavailable(fmt.Sprintf("createTimerTasks failed. Could not verify number of rows inserted. Error: %v", err)) 858 } 859 860 if int(rowsAffected) != len(timerTasks) { 861 return serviceerror.NewUnavailable(fmt.Sprintf("createTimerTasks failed. Inserted %v instead of %v rows into timer_tasks. Error: %v", rowsAffected, len(timerTasks), err)) 862 } 863 return nil 864 } 865 866 func createReplicationTasks( 867 ctx context.Context, 868 tx sqlplugin.Tx, 869 shardID int32, 870 replicationTasks []p.InternalHistoryTask, 871 ) error { 872 873 if len(replicationTasks) == 0 { 874 return nil 875 } 876 877 replicationTasksRows := make([]sqlplugin.ReplicationTasksRow, 0, len(replicationTasks)) 878 for _, task := range replicationTasks { 879 replicationTasksRows = append(replicationTasksRows, sqlplugin.ReplicationTasksRow{ 880 ShardID: shardID, 881 TaskID: task.Key.TaskID, 882 Data: task.Blob.Data, 883 DataEncoding: task.Blob.EncodingType.String(), 884 }) 885 } 886 887 result, err := tx.InsertIntoReplicationTasks(ctx, replicationTasksRows) 888 if err != nil { 889 return serviceerror.NewUnavailable(fmt.Sprintf("createReplicationTasks failed. Error: %v", err)) 890 } 891 892 rowsAffected, err := result.RowsAffected() 893 if err != nil { 894 return serviceerror.NewUnavailable(fmt.Sprintf("createReplicationTasks failed. Could not verify number of rows inserted. Error: %v", err)) 895 } 896 897 if int(rowsAffected) != len(replicationTasks) { 898 return serviceerror.NewUnavailable(fmt.Sprintf("createReplicationTasks failed. Inserted %v instead of %v rows into transfer_tasks. Error: %v", rowsAffected, len(replicationTasks), err)) 899 } 900 return nil 901 } 902 903 func createVisibilityTasks( 904 ctx context.Context, 905 tx sqlplugin.Tx, 906 shardID int32, 907 visibilityTasks []p.InternalHistoryTask, 908 ) error { 909 910 if len(visibilityTasks) == 0 { 911 return nil 912 } 913 914 visibilityTasksRows := make([]sqlplugin.VisibilityTasksRow, 0, len(visibilityTasks)) 915 for _, task := range visibilityTasks { 916 visibilityTasksRows = append(visibilityTasksRows, sqlplugin.VisibilityTasksRow{ 917 ShardID: shardID, 918 TaskID: task.Key.TaskID, 919 Data: task.Blob.Data, 920 DataEncoding: task.Blob.EncodingType.String(), 921 }) 922 } 923 924 result, err := tx.InsertIntoVisibilityTasks(ctx, visibilityTasksRows) 925 if err != nil { 926 return serviceerror.NewUnavailable(fmt.Sprintf("createTransferTasks failed. Error: %v", err)) 927 } 928 929 rowsAffected, err := result.RowsAffected() 930 if err != nil { 931 return serviceerror.NewUnavailable(fmt.Sprintf("createTransferTasks failed. Could not verify number of rows inserted. Error: %v", err)) 932 } 933 934 if int(rowsAffected) != len(visibilityTasksRows) { 935 return serviceerror.NewUnavailable(fmt.Sprintf("createTransferTasks failed. Inserted %v instead of %v rows into transfer_tasks. Error: %v", rowsAffected, len(visibilityTasksRows), err)) 936 } 937 return nil 938 } 939 940 func assertNotCurrentExecution( 941 ctx context.Context, 942 tx sqlplugin.Tx, 943 shardID int32, 944 namespaceID primitives.UUID, 945 workflowID string, 946 runID primitives.UUID, 947 ) error { 948 currentRow, err := tx.LockCurrentExecutions(ctx, sqlplugin.CurrentExecutionsFilter{ 949 ShardID: shardID, 950 NamespaceID: namespaceID, 951 WorkflowID: workflowID, 952 }) 953 if err != nil { 954 if err == sql.ErrNoRows { 955 // allow bypassing no current record 956 return nil 957 } 958 return serviceerror.NewUnavailable(fmt.Sprintf("assertCurrentExecution failed. Unable to load current record. Error: %v", err)) 959 } 960 return assertRunIDMismatch(runID, currentRow) 961 } 962 963 func assertRunIDAndUpdateCurrentExecution( 964 ctx context.Context, 965 tx sqlplugin.Tx, 966 shardID int32, 967 namespaceID primitives.UUID, 968 workflowID string, 969 newRunID primitives.UUID, 970 previousRunID primitives.UUID, 971 createRequestID string, 972 state enumsspb.WorkflowExecutionState, 973 status enumspb.WorkflowExecutionStatus, 974 lastWriteVersion int64, 975 ) error { 976 977 assertFn := func(currentRow *sqlplugin.CurrentExecutionsRow) error { 978 if !bytes.Equal(currentRow.RunID, previousRunID) { 979 return &p.CurrentWorkflowConditionFailedError{ 980 Msg: fmt.Sprintf( 981 "assertRunIDAndUpdateCurrentExecution failed. current run ID: %v, request run ID: %v", 982 currentRow.RunID, 983 previousRunID, 984 ), 985 RequestID: currentRow.CreateRequestID, 986 RunID: currentRow.RunID.String(), 987 State: currentRow.State, 988 Status: currentRow.Status, 989 LastWriteVersion: currentRow.LastWriteVersion, 990 } 991 } 992 return nil 993 } 994 if err := assertCurrentExecution(ctx, 995 tx, 996 shardID, 997 namespaceID, 998 workflowID, 999 assertFn, 1000 ); err != nil { 1001 return err 1002 } 1003 1004 return updateCurrentExecution(ctx, 1005 tx, 1006 shardID, 1007 namespaceID, 1008 workflowID, 1009 newRunID, 1010 createRequestID, 1011 state, 1012 status, 1013 lastWriteVersion, 1014 ) 1015 } 1016 1017 func assertCurrentExecution( 1018 ctx context.Context, 1019 tx sqlplugin.Tx, 1020 shardID int32, 1021 namespaceID primitives.UUID, 1022 workflowID string, 1023 assertFn func(currentRow *sqlplugin.CurrentExecutionsRow) error, 1024 ) error { 1025 1026 currentRow, err := tx.LockCurrentExecutions(ctx, sqlplugin.CurrentExecutionsFilter{ 1027 ShardID: shardID, 1028 NamespaceID: namespaceID, 1029 WorkflowID: workflowID, 1030 }) 1031 if err != nil { 1032 return serviceerror.NewUnavailable(fmt.Sprintf("assertCurrentExecution failed. Unable to load current record. Error: %v", err)) 1033 } 1034 return assertFn(currentRow) 1035 } 1036 1037 func assertRunIDMismatch(requestRunID primitives.UUID, currentRow *sqlplugin.CurrentExecutionsRow) error { 1038 // zombie workflow creation with existence of current record, this is a noop 1039 if currentRow == nil { 1040 return nil 1041 } 1042 if bytes.Equal(currentRow.RunID, requestRunID) { 1043 return extractCurrentWorkflowConflictError( 1044 currentRow, 1045 fmt.Sprintf( 1046 "assertRunIDMismatch failed. request run ID: %v, current run ID: %v", 1047 requestRunID, 1048 currentRow.RunID.String(), 1049 ), 1050 ) 1051 } 1052 return nil 1053 } 1054 1055 func updateCurrentExecution( 1056 ctx context.Context, 1057 tx sqlplugin.Tx, 1058 shardID int32, 1059 namespaceID primitives.UUID, 1060 workflowID string, 1061 runID primitives.UUID, 1062 createRequestID string, 1063 state enumsspb.WorkflowExecutionState, 1064 status enumspb.WorkflowExecutionStatus, 1065 lastWriteVersion int64, 1066 ) error { 1067 1068 result, err := tx.UpdateCurrentExecutions(ctx, &sqlplugin.CurrentExecutionsRow{ 1069 ShardID: shardID, 1070 NamespaceID: namespaceID, 1071 WorkflowID: workflowID, 1072 RunID: runID, 1073 CreateRequestID: createRequestID, 1074 State: state, 1075 Status: status, 1076 LastWriteVersion: lastWriteVersion, 1077 }) 1078 if err != nil { 1079 return serviceerror.NewUnavailable(fmt.Sprintf("updateCurrentExecution failed. Error: %v", err)) 1080 } 1081 rowsAffected, err := result.RowsAffected() 1082 if err != nil { 1083 return serviceerror.NewUnavailable(fmt.Sprintf("updateCurrentExecution failed. Failed to check number of rows updated in current_executions table. Error: %v", err)) 1084 } 1085 if rowsAffected != 1 { 1086 return serviceerror.NewUnavailable(fmt.Sprintf("updateCurrentExecution failed. %v rows of current_executions updated instead of 1.", rowsAffected)) 1087 } 1088 return nil 1089 } 1090 1091 func buildExecutionRow( 1092 namespaceID string, 1093 workflowID string, 1094 executionInfo *commonpb.DataBlob, 1095 executionState *persistencespb.WorkflowExecutionState, 1096 nextEventID int64, 1097 lastWriteVersion int64, 1098 dbRecordVersion int64, 1099 shardID int32, 1100 ) (row *sqlplugin.ExecutionsRow, err error) { 1101 1102 stateBlob, err := serialization.WorkflowExecutionStateToBlob(executionState) 1103 if err != nil { 1104 return nil, err 1105 } 1106 1107 nsBytes, err := primitives.ParseUUID(namespaceID) 1108 if err != nil { 1109 return nil, err 1110 } 1111 1112 ridBytes, err := primitives.ParseUUID(executionState.RunId) 1113 if err != nil { 1114 return nil, err 1115 } 1116 1117 return &sqlplugin.ExecutionsRow{ 1118 ShardID: shardID, 1119 NamespaceID: nsBytes, 1120 WorkflowID: workflowID, 1121 RunID: ridBytes, 1122 NextEventID: nextEventID, 1123 LastWriteVersion: lastWriteVersion, 1124 Data: executionInfo.Data, 1125 DataEncoding: executionInfo.EncodingType.String(), 1126 State: stateBlob.Data, 1127 StateEncoding: stateBlob.EncodingType.String(), 1128 DBRecordVersion: dbRecordVersion, 1129 }, nil 1130 } 1131 1132 func (m *sqlExecutionStore) createExecution( 1133 ctx context.Context, 1134 tx sqlplugin.Tx, 1135 namespaceID string, 1136 workflowID string, 1137 executionInfo *commonpb.DataBlob, 1138 executionState *persistencespb.WorkflowExecutionState, 1139 nextEventID int64, 1140 lastWriteVersion int64, 1141 dbRecordVersion int64, 1142 shardID int32, 1143 ) error { 1144 1145 row, err := buildExecutionRow( 1146 namespaceID, 1147 workflowID, 1148 executionInfo, 1149 executionState, 1150 nextEventID, 1151 lastWriteVersion, 1152 dbRecordVersion, 1153 shardID, 1154 ) 1155 if err != nil { 1156 return err 1157 } 1158 result, err := tx.InsertIntoExecutions(ctx, row) 1159 if err != nil { 1160 if m.Db.IsDupEntryError(err) { 1161 return &p.WorkflowConditionFailedError{ 1162 Msg: fmt.Sprintf("Workflow execution already running. WorkflowId: %v", workflowID), 1163 NextEventID: 0, 1164 DBRecordVersion: 0, 1165 } 1166 } 1167 return serviceerror.NewUnavailable(fmt.Sprintf("createExecution failed. Erorr: %v", err)) 1168 } 1169 rowsAffected, err := result.RowsAffected() 1170 if err != nil { 1171 return serviceerror.NewUnavailable(fmt.Sprintf("createExecution failed. Failed to verify number of rows affected. Erorr: %v", err)) 1172 } 1173 if rowsAffected != 1 { 1174 return serviceerror.NewNotFound(fmt.Sprintf("createExecution failed. Affected %v rows updated instead of 1.", rowsAffected)) 1175 } 1176 1177 return nil 1178 } 1179 1180 func updateExecution( 1181 ctx context.Context, 1182 tx sqlplugin.Tx, 1183 namespaceID string, 1184 workflowID string, 1185 executionInfo *commonpb.DataBlob, 1186 executionState *persistencespb.WorkflowExecutionState, 1187 nextEventID int64, 1188 lastWriteVersion int64, 1189 dbRecordVersion int64, 1190 shardID int32, 1191 ) error { 1192 row, err := buildExecutionRow( 1193 namespaceID, 1194 workflowID, 1195 executionInfo, 1196 executionState, 1197 nextEventID, 1198 lastWriteVersion, 1199 dbRecordVersion, 1200 shardID, 1201 ) 1202 if err != nil { 1203 return err 1204 } 1205 result, err := tx.UpdateExecutions(ctx, row) 1206 if err != nil { 1207 return serviceerror.NewUnavailable(fmt.Sprintf("updateExecution failed. Erorr: %v", err)) 1208 } 1209 rowsAffected, err := result.RowsAffected() 1210 if err != nil { 1211 return serviceerror.NewUnavailable(fmt.Sprintf("updateExecution failed. Failed to verify number of rows affected. Erorr: %v", err)) 1212 } 1213 if rowsAffected != 1 { 1214 return serviceerror.NewNotFound(fmt.Sprintf("updateExecution failed. Affected %v rows updated instead of 1.", rowsAffected)) 1215 } 1216 1217 return nil 1218 }