go.temporal.io/server@v1.23.0/common/persistence/cassandra/mutable_state_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 31 commonpb "go.temporal.io/api/common/v1" 32 enumspb "go.temporal.io/api/enums/v1" 33 "go.temporal.io/api/serviceerror" 34 35 enumsspb "go.temporal.io/server/api/enums/v1" 36 persistencespb "go.temporal.io/server/api/persistence/v1" 37 "go.temporal.io/server/common/log" 38 p "go.temporal.io/server/common/persistence" 39 "go.temporal.io/server/common/persistence/nosql/nosqlplugin/cassandra/gocql" 40 "go.temporal.io/server/common/persistence/serialization" 41 ) 42 43 const ( 44 templateUpdateLeaseQuery = `UPDATE executions ` + 45 `SET range_id = ? ` + 46 `WHERE shard_id = ? ` + 47 `and type = ? ` + 48 `and namespace_id = ? ` + 49 `and workflow_id = ? ` + 50 `and run_id = ? ` + 51 `and visibility_ts = ? ` + 52 `and task_id = ? ` + 53 `IF range_id = ?` 54 55 templateUpdateCurrentWorkflowExecutionQuery = `UPDATE executions USING TTL 0 ` + 56 `SET current_run_id = ?, execution_state = ?, execution_state_encoding = ?, workflow_last_write_version = ?, workflow_state = ? ` + 57 `WHERE shard_id = ? ` + 58 `and type = ? ` + 59 `and namespace_id = ? ` + 60 `and workflow_id = ? ` + 61 `and run_id = ? ` + 62 `and visibility_ts = ? ` + 63 `and task_id = ? ` + 64 `IF current_run_id = ? ` 65 66 templateUpdateCurrentWorkflowExecutionForNewQuery = templateUpdateCurrentWorkflowExecutionQuery + 67 `and workflow_last_write_version = ? ` + 68 `and workflow_state = ? ` 69 70 templateCreateCurrentWorkflowExecutionQuery = `INSERT INTO executions (` + 71 `shard_id, type, namespace_id, workflow_id, run_id, ` + 72 `visibility_ts, task_id, current_run_id, execution_state, execution_state_encoding, ` + 73 `workflow_last_write_version, workflow_state) ` + 74 `VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) IF NOT EXISTS USING TTL 0 ` 75 76 templateCreateWorkflowExecutionQuery = `INSERT INTO executions (` + 77 `shard_id, namespace_id, workflow_id, run_id, type, ` + 78 `execution, execution_encoding, execution_state, execution_state_encoding, next_event_id, db_record_version, ` + 79 `visibility_ts, task_id, checksum, checksum_encoding) ` + 80 `VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) IF NOT EXISTS ` 81 82 templateGetWorkflowExecutionQuery = `SELECT execution, execution_encoding, execution_state, execution_state_encoding, next_event_id, activity_map, activity_map_encoding, timer_map, timer_map_encoding, ` + 83 `child_executions_map, child_executions_map_encoding, request_cancel_map, request_cancel_map_encoding, signal_map, signal_map_encoding, signal_requested, buffered_events_list, ` + 84 `checksum, checksum_encoding, db_record_version ` + 85 `FROM executions ` + 86 `WHERE shard_id = ? ` + 87 `and type = ? ` + 88 `and namespace_id = ? ` + 89 `and workflow_id = ? ` + 90 `and run_id = ? ` + 91 `and visibility_ts = ? ` + 92 `and task_id = ?` 93 94 templateGetCurrentExecutionQuery = `SELECT current_run_id, execution, execution_encoding, execution_state, execution_state_encoding, workflow_last_write_version ` + 95 `FROM executions ` + 96 `WHERE shard_id = ? ` + 97 `and type = ? ` + 98 `and namespace_id = ? ` + 99 `and workflow_id = ? ` + 100 `and run_id = ? ` + 101 `and visibility_ts = ? ` + 102 `and task_id = ?` 103 104 templateListWorkflowExecutionQuery = `SELECT run_id, execution, execution_encoding, execution_state, execution_state_encoding, next_event_id ` + 105 `FROM executions ` + 106 `WHERE shard_id = ? ` + 107 `and type = ?` 108 109 // TODO deprecate templateUpdateWorkflowExecutionQueryDeprecated in favor of templateUpdateWorkflowExecutionQuery 110 // Deprecated. 111 templateUpdateWorkflowExecutionQueryDeprecated = `UPDATE executions ` + 112 `SET execution = ? ` + 113 `, execution_encoding = ? ` + 114 `, execution_state = ? ` + 115 `, execution_state_encoding = ? ` + 116 `, next_event_id = ? ` + 117 `, db_record_version = ? ` + 118 `, checksum = ? ` + 119 `, checksum_encoding = ? ` + 120 `WHERE shard_id = ? ` + 121 `and type = ? ` + 122 `and namespace_id = ? ` + 123 `and workflow_id = ? ` + 124 `and run_id = ? ` + 125 `and visibility_ts = ? ` + 126 `and task_id = ? ` + 127 `IF next_event_id = ? ` 128 templateUpdateWorkflowExecutionQuery = `UPDATE executions ` + 129 `SET execution = ? ` + 130 `, execution_encoding = ? ` + 131 `, execution_state = ? ` + 132 `, execution_state_encoding = ? ` + 133 `, next_event_id = ? ` + 134 `, db_record_version = ? ` + 135 `, checksum = ? ` + 136 `, checksum_encoding = ? ` + 137 `WHERE shard_id = ? ` + 138 `and type = ? ` + 139 `and namespace_id = ? ` + 140 `and workflow_id = ? ` + 141 `and run_id = ? ` + 142 `and visibility_ts = ? ` + 143 `and task_id = ? ` + 144 `IF db_record_version = ? ` 145 146 templateUpdateActivityInfoQuery = `UPDATE executions ` + 147 `SET activity_map[ ? ] = ?, activity_map_encoding = ? ` + 148 `WHERE shard_id = ? ` + 149 `and type = ? ` + 150 `and namespace_id = ? ` + 151 `and workflow_id = ? ` + 152 `and run_id = ? ` + 153 `and visibility_ts = ? ` + 154 `and task_id = ? ` 155 156 templateResetActivityInfoQuery = `UPDATE executions ` + 157 `SET activity_map = ?, activity_map_encoding = ? ` + 158 `WHERE shard_id = ? ` + 159 `and type = ? ` + 160 `and namespace_id = ? ` + 161 `and workflow_id = ? ` + 162 `and run_id = ? ` + 163 `and visibility_ts = ? ` + 164 `and task_id = ? ` 165 166 templateUpdateTimerInfoQuery = `UPDATE executions ` + 167 `SET timer_map[ ? ] = ?, timer_map_encoding = ? ` + 168 `WHERE shard_id = ? ` + 169 `and type = ? ` + 170 `and namespace_id = ? ` + 171 `and workflow_id = ? ` + 172 `and run_id = ? ` + 173 `and visibility_ts = ? ` + 174 `and task_id = ? ` 175 176 templateResetTimerInfoQuery = `UPDATE executions ` + 177 `SET timer_map = ?, timer_map_encoding = ? ` + 178 `WHERE shard_id = ? ` + 179 `and type = ? ` + 180 `and namespace_id = ? ` + 181 `and workflow_id = ? ` + 182 `and run_id = ? ` + 183 `and visibility_ts = ? ` + 184 `and task_id = ? ` 185 186 templateUpdateChildExecutionInfoQuery = `UPDATE executions ` + 187 `SET child_executions_map[ ? ] = ?, child_executions_map_encoding = ? ` + 188 `WHERE shard_id = ? ` + 189 `and type = ? ` + 190 `and namespace_id = ? ` + 191 `and workflow_id = ? ` + 192 `and run_id = ? ` + 193 `and visibility_ts = ? ` + 194 `and task_id = ? ` 195 196 templateResetChildExecutionInfoQuery = `UPDATE executions ` + 197 `SET child_executions_map = ?, child_executions_map_encoding = ? ` + 198 `WHERE shard_id = ? ` + 199 `and type = ? ` + 200 `and namespace_id = ? ` + 201 `and workflow_id = ? ` + 202 `and run_id = ? ` + 203 `and visibility_ts = ? ` + 204 `and task_id = ? ` 205 206 templateUpdateRequestCancelInfoQuery = `UPDATE executions ` + 207 `SET request_cancel_map[ ? ] = ?, request_cancel_map_encoding = ? ` + 208 `WHERE shard_id = ? ` + 209 `and type = ? ` + 210 `and namespace_id = ? ` + 211 `and workflow_id = ? ` + 212 `and run_id = ? ` + 213 `and visibility_ts = ? ` + 214 `and task_id = ? ` 215 216 templateResetRequestCancelInfoQuery = `UPDATE executions ` + 217 `SET request_cancel_map = ?, request_cancel_map_encoding = ? ` + 218 `WHERE shard_id = ? ` + 219 `and type = ? ` + 220 `and namespace_id = ? ` + 221 `and workflow_id = ? ` + 222 `and run_id = ? ` + 223 `and visibility_ts = ? ` + 224 `and task_id = ? ` 225 226 templateUpdateSignalInfoQuery = `UPDATE executions ` + 227 `SET signal_map[ ? ] = ?, signal_map_encoding = ? ` + 228 `WHERE shard_id = ? ` + 229 `and type = ? ` + 230 `and namespace_id = ? ` + 231 `and workflow_id = ? ` + 232 `and run_id = ? ` + 233 `and visibility_ts = ? ` + 234 `and task_id = ? ` 235 236 templateResetSignalInfoQuery = `UPDATE executions ` + 237 `SET signal_map = ?, signal_map_encoding = ? ` + 238 `WHERE shard_id = ? ` + 239 `and type = ? ` + 240 `and namespace_id = ? ` + 241 `and workflow_id = ? ` + 242 `and run_id = ? ` + 243 `and visibility_ts = ? ` + 244 `and task_id = ? ` 245 246 templateUpdateSignalRequestedQuery = `UPDATE executions ` + 247 `SET signal_requested = signal_requested + ? ` + 248 `WHERE shard_id = ? ` + 249 `and type = ? ` + 250 `and namespace_id = ? ` + 251 `and workflow_id = ? ` + 252 `and run_id = ? ` + 253 `and visibility_ts = ? ` + 254 `and task_id = ? ` 255 256 templateResetSignalRequestedQuery = `UPDATE executions ` + 257 `SET signal_requested = ?` + 258 `WHERE shard_id = ? ` + 259 `and type = ? ` + 260 `and namespace_id = ? ` + 261 `and workflow_id = ? ` + 262 `and run_id = ? ` + 263 `and visibility_ts = ? ` + 264 `and task_id = ? ` 265 266 templateAppendBufferedEventsQuery = `UPDATE executions ` + 267 `SET buffered_events_list = buffered_events_list + ? ` + 268 `WHERE shard_id = ? ` + 269 `and type = ? ` + 270 `and namespace_id = ? ` + 271 `and workflow_id = ? ` + 272 `and run_id = ? ` + 273 `and visibility_ts = ? ` + 274 `and task_id = ? ` 275 276 templateDeleteBufferedEventsQuery = `UPDATE executions ` + 277 `SET buffered_events_list = [] ` + 278 `WHERE shard_id = ? ` + 279 `and type = ? ` + 280 `and namespace_id = ? ` + 281 `and workflow_id = ? ` + 282 `and run_id = ? ` + 283 `and visibility_ts = ? ` + 284 `and task_id = ? ` 285 286 templateDeleteActivityInfoQuery = `DELETE activity_map[ ? ] ` + 287 `FROM executions ` + 288 `WHERE shard_id = ? ` + 289 `and type = ? ` + 290 `and namespace_id = ? ` + 291 `and workflow_id = ? ` + 292 `and run_id = ? ` + 293 `and visibility_ts = ? ` + 294 `and task_id = ? ` 295 296 templateDeleteTimerInfoQuery = `DELETE timer_map[ ? ] ` + 297 `FROM executions ` + 298 `WHERE shard_id = ? ` + 299 `and type = ? ` + 300 `and namespace_id = ? ` + 301 `and workflow_id = ? ` + 302 `and run_id = ? ` + 303 `and visibility_ts = ? ` + 304 `and task_id = ? ` 305 306 templateDeleteChildExecutionInfoQuery = `DELETE child_executions_map[ ? ] ` + 307 `FROM executions ` + 308 `WHERE shard_id = ? ` + 309 `and type = ? ` + 310 `and namespace_id = ? ` + 311 `and workflow_id = ? ` + 312 `and run_id = ? ` + 313 `and visibility_ts = ? ` + 314 `and task_id = ? ` 315 316 templateDeleteRequestCancelInfoQuery = `DELETE request_cancel_map[ ? ] ` + 317 `FROM executions ` + 318 `WHERE shard_id = ? ` + 319 `and type = ? ` + 320 `and namespace_id = ? ` + 321 `and workflow_id = ? ` + 322 `and run_id = ? ` + 323 `and visibility_ts = ? ` + 324 `and task_id = ? ` 325 326 templateDeleteSignalInfoQuery = `DELETE signal_map[ ? ] ` + 327 `FROM executions ` + 328 `WHERE shard_id = ? ` + 329 `and type = ? ` + 330 `and namespace_id = ? ` + 331 `and workflow_id = ? ` + 332 `and run_id = ? ` + 333 `and visibility_ts = ? ` + 334 `and task_id = ? ` 335 336 templateDeleteWorkflowExecutionMutableStateQuery = `DELETE FROM executions ` + 337 `WHERE shard_id = ? ` + 338 `and type = ? ` + 339 `and namespace_id = ? ` + 340 `and workflow_id = ? ` + 341 `and run_id = ? ` + 342 `and visibility_ts = ? ` + 343 `and task_id = ? ` 344 345 templateDeleteWorkflowExecutionCurrentRowQuery = templateDeleteWorkflowExecutionMutableStateQuery + " if current_run_id = ? " 346 347 templateDeleteWorkflowExecutionSignalRequestedQuery = `UPDATE executions ` + 348 `SET signal_requested = signal_requested - ? ` + 349 `WHERE shard_id = ? ` + 350 `and type = ? ` + 351 `and namespace_id = ? ` + 352 `and workflow_id = ? ` + 353 `and run_id = ? ` + 354 `and visibility_ts = ? ` + 355 `and task_id = ? ` 356 ) 357 358 type ( 359 MutableStateStore struct { 360 Session gocql.Session 361 Logger log.Logger 362 } 363 ) 364 365 func NewMutableStateStore( 366 session gocql.Session, 367 logger log.Logger, 368 ) *MutableStateStore { 369 return &MutableStateStore{ 370 Session: session, 371 Logger: logger, 372 } 373 } 374 375 func (d *MutableStateStore) CreateWorkflowExecution( 376 ctx context.Context, 377 request *p.InternalCreateWorkflowExecutionRequest, 378 ) (*p.InternalCreateWorkflowExecutionResponse, error) { 379 batch := d.Session.NewBatch(gocql.LoggedBatch).WithContext(ctx) 380 381 shardID := request.ShardID 382 newWorkflow := request.NewWorkflowSnapshot 383 lastWriteVersion := newWorkflow.LastWriteVersion 384 namespaceID := newWorkflow.NamespaceID 385 workflowID := newWorkflow.WorkflowID 386 runID := newWorkflow.RunID 387 388 var requestCurrentRunID string 389 390 switch request.Mode { 391 case p.CreateWorkflowModeBypassCurrent: 392 // noop 393 394 case p.CreateWorkflowModeUpdateCurrent: 395 batch.Query(templateUpdateCurrentWorkflowExecutionForNewQuery, 396 runID, 397 newWorkflow.ExecutionStateBlob.Data, 398 newWorkflow.ExecutionStateBlob.EncodingType.String(), 399 lastWriteVersion, 400 newWorkflow.ExecutionState.State, 401 shardID, 402 rowTypeExecution, 403 namespaceID, 404 workflowID, 405 permanentRunID, 406 defaultVisibilityTimestamp, 407 rowTypeExecutionTaskID, 408 request.PreviousRunID, 409 request.PreviousLastWriteVersion, 410 enumsspb.WORKFLOW_EXECUTION_STATE_COMPLETED, 411 ) 412 413 requestCurrentRunID = request.PreviousRunID 414 415 case p.CreateWorkflowModeBrandNew: 416 batch.Query(templateCreateCurrentWorkflowExecutionQuery, 417 shardID, 418 rowTypeExecution, 419 namespaceID, 420 workflowID, 421 permanentRunID, 422 defaultVisibilityTimestamp, 423 rowTypeExecutionTaskID, 424 runID, 425 newWorkflow.ExecutionStateBlob.Data, 426 newWorkflow.ExecutionStateBlob.EncodingType.String(), 427 lastWriteVersion, 428 newWorkflow.ExecutionState.State, 429 ) 430 431 requestCurrentRunID = "" 432 433 default: 434 return nil, serviceerror.NewInternal(fmt.Sprintf("CreateWorkflowExecution: unknown mode: %v", request.Mode)) 435 } 436 437 if err := applyWorkflowSnapshotBatchAsNew(batch, 438 request.ShardID, 439 &newWorkflow, 440 ); err != nil { 441 return nil, err 442 } 443 444 batch.Query(templateUpdateLeaseQuery, 445 request.RangeID, 446 request.ShardID, 447 rowTypeShard, 448 rowTypeShardNamespaceID, 449 rowTypeShardWorkflowID, 450 rowTypeShardRunID, 451 defaultVisibilityTimestamp, 452 rowTypeShardTaskID, 453 request.RangeID, 454 ) 455 456 conflictRecord := newConflictRecord() 457 applied, conflictIter, err := d.Session.MapExecuteBatchCAS(batch, conflictRecord) 458 if err != nil { 459 return nil, gocql.ConvertError("CreateWorkflowExecution", err) 460 } 461 defer func() { 462 _ = conflictIter.Close() 463 }() 464 465 if !applied { 466 return nil, convertErrors( 467 conflictRecord, 468 conflictIter, 469 shardID, 470 request.RangeID, 471 requestCurrentRunID, 472 []executionCASCondition{{ 473 runID: newWorkflow.ExecutionState.RunId, 474 // dbVersion is for CAS, so the db record version will be set to `updateWorkflow.DBRecordVersion` 475 // while CAS on `updateWorkflow.DBRecordVersion - 1` 476 dbVersion: newWorkflow.DBRecordVersion - 1, 477 nextEventID: newWorkflow.Condition, 478 }}, 479 ) 480 } 481 482 return &p.InternalCreateWorkflowExecutionResponse{}, nil 483 } 484 485 func (d *MutableStateStore) GetWorkflowExecution( 486 ctx context.Context, 487 request *p.GetWorkflowExecutionRequest, 488 ) (*p.InternalGetWorkflowExecutionResponse, error) { 489 query := d.Session.Query(templateGetWorkflowExecutionQuery, 490 request.ShardID, 491 rowTypeExecution, 492 request.NamespaceID, 493 request.WorkflowID, 494 request.RunID, 495 defaultVisibilityTimestamp, 496 rowTypeExecutionTaskID, 497 ).WithContext(ctx) 498 499 result := make(map[string]interface{}) 500 if err := query.MapScan(result); err != nil { 501 return nil, gocql.ConvertError("GetWorkflowExecution", err) 502 } 503 504 state, err := mutableStateFromRow(result) 505 if err != nil { 506 return nil, serviceerror.NewUnavailable(fmt.Sprintf("GetWorkflowExecution operation failed. Error: %v", err)) 507 } 508 509 activityInfos := make(map[int64]*commonpb.DataBlob) 510 aMap := result["activity_map"].(map[int64][]byte) 511 aMapEncoding := result["activity_map_encoding"].(string) 512 for key, value := range aMap { 513 activityInfos[key] = p.NewDataBlob(value, aMapEncoding) 514 } 515 state.ActivityInfos = activityInfos 516 517 timerInfos := make(map[string]*commonpb.DataBlob) 518 tMapEncoding := result["timer_map_encoding"].(string) 519 tMap := result["timer_map"].(map[string][]byte) 520 for key, value := range tMap { 521 timerInfos[key] = p.NewDataBlob(value, tMapEncoding) 522 } 523 state.TimerInfos = timerInfos 524 525 childExecutionInfos := make(map[int64]*commonpb.DataBlob) 526 cMap := result["child_executions_map"].(map[int64][]byte) 527 cMapEncoding := result["child_executions_map_encoding"].(string) 528 for key, value := range cMap { 529 childExecutionInfos[key] = p.NewDataBlob(value, cMapEncoding) 530 } 531 state.ChildExecutionInfos = childExecutionInfos 532 533 requestCancelInfos := make(map[int64]*commonpb.DataBlob) 534 rMapEncoding := result["request_cancel_map_encoding"].(string) 535 rMap := result["request_cancel_map"].(map[int64][]byte) 536 for key, value := range rMap { 537 requestCancelInfos[key] = p.NewDataBlob(value, rMapEncoding) 538 } 539 state.RequestCancelInfos = requestCancelInfos 540 541 signalInfos := make(map[int64]*commonpb.DataBlob) 542 sMapEncoding := result["signal_map_encoding"].(string) 543 sMap := result["signal_map"].(map[int64][]byte) 544 for key, value := range sMap { 545 signalInfos[key] = p.NewDataBlob(value, sMapEncoding) 546 } 547 state.SignalInfos = signalInfos 548 state.SignalRequestedIDs = gocql.UUIDsToStringSlice(result["signal_requested"]) 549 550 eList := result["buffered_events_list"].([]map[string]interface{}) 551 bufferedEventsBlobs := make([]*commonpb.DataBlob, 0, len(eList)) 552 for _, v := range eList { 553 blob := createHistoryEventBatchBlob(v) 554 bufferedEventsBlobs = append(bufferedEventsBlobs, blob) 555 } 556 state.BufferedEvents = bufferedEventsBlobs 557 558 state.Checksum = p.NewDataBlob(result["checksum"].([]byte), result["checksum_encoding"].(string)) 559 560 dbVersion := int64(0) 561 if dbRecordVersion, ok := result["db_record_version"]; ok { 562 dbVersion = dbRecordVersion.(int64) 563 } else { 564 dbVersion = 0 565 } 566 567 return &p.InternalGetWorkflowExecutionResponse{ 568 State: state, 569 DBRecordVersion: dbVersion, 570 }, nil 571 } 572 573 func (d *MutableStateStore) UpdateWorkflowExecution( 574 ctx context.Context, 575 request *p.InternalUpdateWorkflowExecutionRequest, 576 ) error { 577 batch := d.Session.NewBatch(gocql.LoggedBatch).WithContext(ctx) 578 579 updateWorkflow := request.UpdateWorkflowMutation 580 newWorkflow := request.NewWorkflowSnapshot 581 582 namespaceID := updateWorkflow.NamespaceID 583 workflowID := updateWorkflow.WorkflowID 584 runID := updateWorkflow.RunID 585 shardID := request.ShardID 586 587 switch request.Mode { 588 case p.UpdateWorkflowModeBypassCurrent: 589 if err := d.assertNotCurrentExecution( 590 ctx, 591 request.ShardID, 592 namespaceID, 593 workflowID, 594 runID, 595 ); err != nil { 596 return err 597 } 598 599 case p.UpdateWorkflowModeUpdateCurrent: 600 if newWorkflow != nil { 601 newLastWriteVersion := newWorkflow.LastWriteVersion 602 newNamespaceID := newWorkflow.NamespaceID 603 newWorkflowID := newWorkflow.WorkflowID 604 newRunID := newWorkflow.RunID 605 606 if namespaceID != newNamespaceID { 607 return serviceerror.NewInternal("UpdateWorkflowExecution: cannot continue as new to another namespace") 608 } 609 610 batch.Query(templateUpdateCurrentWorkflowExecutionQuery, 611 newRunID, 612 newWorkflow.ExecutionStateBlob.Data, 613 newWorkflow.ExecutionStateBlob.EncodingType.String(), 614 newLastWriteVersion, 615 newWorkflow.ExecutionState.State, 616 shardID, 617 rowTypeExecution, 618 newNamespaceID, 619 newWorkflowID, 620 permanentRunID, 621 defaultVisibilityTimestamp, 622 rowTypeExecutionTaskID, 623 runID, 624 ) 625 626 } else { 627 lastWriteVersion := updateWorkflow.LastWriteVersion 628 629 executionStateDatablob, err := serialization.WorkflowExecutionStateToBlob(updateWorkflow.ExecutionState) 630 if err != nil { 631 return err 632 } 633 634 batch.Query(templateUpdateCurrentWorkflowExecutionQuery, 635 runID, 636 executionStateDatablob.Data, 637 executionStateDatablob.EncodingType.String(), 638 lastWriteVersion, 639 updateWorkflow.ExecutionState.State, 640 request.ShardID, 641 rowTypeExecution, 642 namespaceID, 643 workflowID, 644 permanentRunID, 645 defaultVisibilityTimestamp, 646 rowTypeExecutionTaskID, 647 runID, 648 ) 649 } 650 651 default: 652 return serviceerror.NewInternal(fmt.Sprintf("UpdateWorkflowExecution: unknown mode: %v", request.Mode)) 653 } 654 655 if err := applyWorkflowMutationBatch(batch, shardID, &updateWorkflow); err != nil { 656 return err 657 } 658 if newWorkflow != nil { 659 if err := applyWorkflowSnapshotBatchAsNew(batch, 660 request.ShardID, 661 newWorkflow, 662 ); err != nil { 663 return err 664 } 665 } 666 667 // Verifies that the RangeID has not changed 668 batch.Query(templateUpdateLeaseQuery, 669 request.RangeID, 670 request.ShardID, 671 rowTypeShard, 672 rowTypeShardNamespaceID, 673 rowTypeShardWorkflowID, 674 rowTypeShardRunID, 675 defaultVisibilityTimestamp, 676 rowTypeShardTaskID, 677 request.RangeID, 678 ) 679 680 conflictRecord := newConflictRecord() 681 applied, conflictIter, err := d.Session.MapExecuteBatchCAS(batch, conflictRecord) 682 if err != nil { 683 return gocql.ConvertError("UpdateWorkflowExecution", err) 684 } 685 defer func() { 686 _ = conflictIter.Close() 687 }() 688 689 if !applied { 690 return convertErrors( 691 conflictRecord, 692 conflictIter, 693 request.ShardID, 694 request.RangeID, 695 updateWorkflow.ExecutionState.RunId, 696 []executionCASCondition{{ 697 runID: updateWorkflow.ExecutionState.RunId, 698 // dbVersion is for CAS, so the db record version will be set to `updateWorkflow.DBRecordVersion` 699 // while CAS on `updateWorkflow.DBRecordVersion - 1` 700 dbVersion: updateWorkflow.DBRecordVersion - 1, 701 nextEventID: updateWorkflow.Condition, 702 }}, 703 ) 704 } 705 return nil 706 } 707 708 func (d *MutableStateStore) ConflictResolveWorkflowExecution( 709 ctx context.Context, 710 request *p.InternalConflictResolveWorkflowExecutionRequest, 711 ) error { 712 batch := d.Session.NewBatch(gocql.LoggedBatch).WithContext(ctx) 713 714 currentWorkflow := request.CurrentWorkflowMutation 715 resetWorkflow := request.ResetWorkflowSnapshot 716 newWorkflow := request.NewWorkflowSnapshot 717 718 shardID := request.ShardID 719 720 namespaceID := resetWorkflow.NamespaceID 721 workflowID := resetWorkflow.WorkflowID 722 723 var currentRunID string 724 725 switch request.Mode { 726 case p.ConflictResolveWorkflowModeBypassCurrent: 727 if err := d.assertNotCurrentExecution( 728 ctx, 729 shardID, 730 namespaceID, 731 workflowID, 732 resetWorkflow.ExecutionState.RunId, 733 ); err != nil { 734 return err 735 } 736 737 case p.ConflictResolveWorkflowModeUpdateCurrent: 738 executionState := resetWorkflow.ExecutionState 739 lastWriteVersion := resetWorkflow.LastWriteVersion 740 if newWorkflow != nil { 741 lastWriteVersion = newWorkflow.LastWriteVersion 742 executionState = newWorkflow.ExecutionState 743 } 744 runID := executionState.RunId 745 createRequestID := executionState.CreateRequestId 746 state := executionState.State 747 status := executionState.Status 748 749 executionStateDatablob, err := serialization.WorkflowExecutionStateToBlob(&persistencespb.WorkflowExecutionState{ 750 RunId: runID, 751 CreateRequestId: createRequestID, 752 State: state, 753 Status: status, 754 }) 755 if err != nil { 756 return serviceerror.NewUnavailable(fmt.Sprintf("ConflictResolveWorkflowExecution operation failed. Error: %v", err)) 757 } 758 759 if currentWorkflow != nil { 760 currentRunID = currentWorkflow.ExecutionState.RunId 761 762 batch.Query(templateUpdateCurrentWorkflowExecutionQuery, 763 runID, 764 executionStateDatablob.Data, 765 executionStateDatablob.EncodingType.String(), 766 lastWriteVersion, 767 state, 768 shardID, 769 rowTypeExecution, 770 namespaceID, 771 workflowID, 772 permanentRunID, 773 defaultVisibilityTimestamp, 774 rowTypeExecutionTaskID, 775 currentRunID, 776 ) 777 778 } else { 779 // reset workflow is current 780 currentRunID = resetWorkflow.ExecutionState.RunId 781 782 batch.Query(templateUpdateCurrentWorkflowExecutionQuery, 783 runID, 784 executionStateDatablob.Data, 785 executionStateDatablob.EncodingType.String(), 786 lastWriteVersion, 787 state, 788 shardID, 789 rowTypeExecution, 790 namespaceID, 791 workflowID, 792 permanentRunID, 793 defaultVisibilityTimestamp, 794 rowTypeExecutionTaskID, 795 currentRunID, 796 ) 797 } 798 799 default: 800 return serviceerror.NewInternal(fmt.Sprintf("ConflictResolveWorkflowExecution: unknown mode: %v", request.Mode)) 801 } 802 803 if err := applyWorkflowSnapshotBatchAsReset(batch, shardID, &resetWorkflow); err != nil { 804 return err 805 } 806 807 if currentWorkflow != nil { 808 if err := applyWorkflowMutationBatch(batch, shardID, currentWorkflow); err != nil { 809 return err 810 } 811 } 812 if newWorkflow != nil { 813 if err := applyWorkflowSnapshotBatchAsNew(batch, shardID, newWorkflow); err != nil { 814 return err 815 } 816 } 817 818 // Verifies that the RangeID has not changed 819 batch.Query(templateUpdateLeaseQuery, 820 request.RangeID, 821 request.ShardID, 822 rowTypeShard, 823 rowTypeShardNamespaceID, 824 rowTypeShardWorkflowID, 825 rowTypeShardRunID, 826 defaultVisibilityTimestamp, 827 rowTypeShardTaskID, 828 request.RangeID, 829 ) 830 831 conflictRecord := newConflictRecord() 832 applied, conflictIter, err := d.Session.MapExecuteBatchCAS(batch, conflictRecord) 833 if err != nil { 834 return gocql.ConvertError("ConflictResolveWorkflowExecution", err) 835 } 836 defer func() { 837 _ = conflictIter.Close() 838 }() 839 840 if !applied { 841 executionCASConditions := []executionCASCondition{{ 842 runID: resetWorkflow.RunID, 843 // dbVersion is for CAS, so the db record version will be set to `resetWorkflow.DBRecordVersion` 844 // while CAS on `resetWorkflow.DBRecordVersion - 1` 845 dbVersion: resetWorkflow.DBRecordVersion - 1, 846 nextEventID: resetWorkflow.Condition, 847 }} 848 if currentWorkflow != nil { 849 executionCASConditions = append(executionCASConditions, executionCASCondition{ 850 runID: currentWorkflow.RunID, 851 // dbVersion is for CAS, so the db record version will be set to `currentWorkflow.DBRecordVersion` 852 // while CAS on `currentWorkflow.DBRecordVersion - 1` 853 dbVersion: currentWorkflow.DBRecordVersion - 1, 854 nextEventID: currentWorkflow.Condition, 855 }) 856 } 857 return convertErrors( 858 conflictRecord, 859 conflictIter, 860 request.ShardID, 861 request.RangeID, 862 currentRunID, 863 executionCASConditions, 864 ) 865 } 866 return nil 867 } 868 869 func (d *MutableStateStore) assertNotCurrentExecution( 870 ctx context.Context, 871 shardID int32, 872 namespaceID string, 873 workflowID string, 874 runID string, 875 ) error { 876 877 if resp, err := d.GetCurrentExecution(ctx, &p.GetCurrentExecutionRequest{ 878 ShardID: shardID, 879 NamespaceID: namespaceID, 880 WorkflowID: workflowID, 881 }); err != nil { 882 if _, isNotFound := err.(*serviceerror.NotFound); isNotFound { 883 // allow bypassing no current record 884 return nil 885 } 886 return err 887 } else if resp.RunID == runID { 888 return &p.CurrentWorkflowConditionFailedError{ 889 Msg: fmt.Sprintf("Assertion on current record failed. Current run ID is not expected: %v", resp.RunID), 890 RequestID: "", 891 RunID: "", 892 State: enumsspb.WORKFLOW_EXECUTION_STATE_UNSPECIFIED, 893 Status: enumspb.WORKFLOW_EXECUTION_STATUS_UNSPECIFIED, 894 LastWriteVersion: 0, 895 } 896 } 897 898 return nil 899 } 900 901 func (d *MutableStateStore) DeleteWorkflowExecution( 902 ctx context.Context, 903 request *p.DeleteWorkflowExecutionRequest, 904 ) error { 905 query := d.Session.Query(templateDeleteWorkflowExecutionMutableStateQuery, 906 request.ShardID, 907 rowTypeExecution, 908 request.NamespaceID, 909 request.WorkflowID, 910 request.RunID, 911 defaultVisibilityTimestamp, 912 rowTypeExecutionTaskID, 913 ).WithContext(ctx) 914 915 err := query.Exec() 916 return gocql.ConvertError("DeleteWorkflowExecution", err) 917 } 918 919 func (d *MutableStateStore) DeleteCurrentWorkflowExecution( 920 ctx context.Context, 921 request *p.DeleteCurrentWorkflowExecutionRequest, 922 ) error { 923 query := d.Session.Query(templateDeleteWorkflowExecutionCurrentRowQuery, 924 request.ShardID, 925 rowTypeExecution, 926 request.NamespaceID, 927 request.WorkflowID, 928 permanentRunID, 929 defaultVisibilityTimestamp, 930 rowTypeExecutionTaskID, 931 request.RunID, 932 ).WithContext(ctx) 933 934 err := query.Exec() 935 return gocql.ConvertError("DeleteWorkflowCurrentRow", err) 936 } 937 938 func (d *MutableStateStore) GetCurrentExecution( 939 ctx context.Context, 940 request *p.GetCurrentExecutionRequest, 941 ) (*p.InternalGetCurrentExecutionResponse, error) { 942 query := d.Session.Query(templateGetCurrentExecutionQuery, 943 request.ShardID, 944 rowTypeExecution, 945 request.NamespaceID, 946 request.WorkflowID, 947 permanentRunID, 948 defaultVisibilityTimestamp, 949 rowTypeExecutionTaskID, 950 ).WithContext(ctx) 951 952 result := make(map[string]interface{}) 953 if err := query.MapScan(result); err != nil { 954 return nil, gocql.ConvertError("GetCurrentExecution", err) 955 } 956 957 currentRunID := gocql.UUIDToString(result["current_run_id"]) 958 executionStateBlob, err := executionStateBlobFromRow(result) 959 if err != nil { 960 return nil, serviceerror.NewUnavailable(fmt.Sprintf("GetCurrentExecution operation failed. Error: %v", err)) 961 } 962 963 // TODO: fix blob ExecutionState in storage should not be a blob. 964 executionState, err := serialization.WorkflowExecutionStateFromBlob(executionStateBlob.Data, executionStateBlob.EncodingType.String()) 965 if err != nil { 966 return nil, err 967 } 968 969 return &p.InternalGetCurrentExecutionResponse{ 970 RunID: currentRunID, 971 ExecutionState: executionState, 972 }, nil 973 } 974 975 func (d *MutableStateStore) SetWorkflowExecution( 976 ctx context.Context, 977 request *p.InternalSetWorkflowExecutionRequest, 978 ) error { 979 batch := d.Session.NewBatch(gocql.LoggedBatch).WithContext(ctx) 980 981 shardID := request.ShardID 982 setSnapshot := request.SetWorkflowSnapshot 983 984 if err := applyWorkflowSnapshotBatchAsReset(batch, shardID, &setSnapshot); err != nil { 985 return err 986 } 987 988 // Verifies that the RangeID has not changed 989 batch.Query(templateUpdateLeaseQuery, 990 request.RangeID, 991 request.ShardID, 992 rowTypeShard, 993 rowTypeShardNamespaceID, 994 rowTypeShardWorkflowID, 995 rowTypeShardRunID, 996 defaultVisibilityTimestamp, 997 rowTypeShardTaskID, 998 request.RangeID, 999 ) 1000 1001 conflictRecord := newConflictRecord() 1002 applied, conflictIter, err := d.Session.MapExecuteBatchCAS(batch, conflictRecord) 1003 if err != nil { 1004 return gocql.ConvertError("SetWorkflowExecution", err) 1005 } 1006 defer func() { 1007 _ = conflictIter.Close() 1008 }() 1009 1010 if !applied { 1011 executionCASConditions := []executionCASCondition{{ 1012 runID: setSnapshot.RunID, 1013 // dbVersion is for CAS, so the db record version will be set to `setSnapshot.DBRecordVersion` 1014 // while CAS on `setSnapshot.DBRecordVersion - 1` 1015 dbVersion: setSnapshot.DBRecordVersion - 1, 1016 nextEventID: setSnapshot.Condition, 1017 }} 1018 return convertErrors( 1019 conflictRecord, 1020 conflictIter, 1021 request.ShardID, 1022 request.RangeID, 1023 "", 1024 executionCASConditions, 1025 ) 1026 } 1027 return nil 1028 } 1029 1030 func (d *MutableStateStore) ListConcreteExecutions( 1031 ctx context.Context, 1032 request *p.ListConcreteExecutionsRequest, 1033 ) (*p.InternalListConcreteExecutionsResponse, error) { 1034 query := d.Session.Query( 1035 templateListWorkflowExecutionQuery, 1036 request.ShardID, 1037 rowTypeExecution, 1038 ).WithContext(ctx) 1039 iter := query.PageSize(request.PageSize).PageState(request.PageToken).Iter() 1040 1041 response := &p.InternalListConcreteExecutionsResponse{} 1042 result := make(map[string]interface{}) 1043 for iter.MapScan(result) { 1044 runID := gocql.UUIDToString(result["run_id"]) 1045 if runID == permanentRunID { 1046 result = make(map[string]interface{}) 1047 continue 1048 } 1049 if _, ok := result["execution"]; ok { 1050 state, err := mutableStateFromRow(result) 1051 if err != nil { 1052 return nil, err 1053 } 1054 response.States = append(response.States, state) 1055 } 1056 result = make(map[string]interface{}) 1057 } 1058 if len(iter.PageState()) > 0 { 1059 response.NextPageToken = iter.PageState() 1060 } 1061 return response, nil 1062 } 1063 1064 func mutableStateFromRow( 1065 result map[string]interface{}, 1066 ) (*p.InternalWorkflowMutableState, error) { 1067 eiBytes, ok := result["execution"].([]byte) 1068 if !ok { 1069 return nil, newPersistedTypeMismatchError("execution", "", eiBytes, result) 1070 } 1071 1072 eiEncoding, ok := result["execution_encoding"].(string) 1073 if !ok { 1074 return nil, newPersistedTypeMismatchError("execution_encoding", "", eiEncoding, result) 1075 } 1076 1077 nextEventID, ok := result["next_event_id"].(int64) 1078 if !ok { 1079 return nil, newPersistedTypeMismatchError("next_event_id", "", nextEventID, result) 1080 } 1081 1082 protoState, err := executionStateBlobFromRow(result) 1083 if err != nil { 1084 return nil, err 1085 } 1086 1087 mutableState := &p.InternalWorkflowMutableState{ 1088 ExecutionInfo: p.NewDataBlob(eiBytes, eiEncoding), 1089 ExecutionState: protoState, 1090 NextEventID: nextEventID, 1091 } 1092 return mutableState, nil 1093 } 1094 1095 func executionStateBlobFromRow( 1096 result map[string]interface{}, 1097 ) (*commonpb.DataBlob, error) { 1098 state, ok := result["execution_state"].([]byte) 1099 if !ok { 1100 return nil, newPersistedTypeMismatchError("execution_state", "", state, result) 1101 } 1102 1103 stateEncoding, ok := result["execution_state_encoding"].(string) 1104 if !ok { 1105 return nil, newPersistedTypeMismatchError("execution_state_encoding", "", stateEncoding, result) 1106 } 1107 1108 return p.NewDataBlob(state, stateEncoding), nil 1109 }