go.temporal.io/server@v1.23.0/common/persistence/sql/execution_tasks.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  	"context"
    29  	"database/sql"
    30  	"encoding/json"
    31  	"errors"
    32  	"fmt"
    33  	"math"
    34  	"time"
    35  
    36  	"go.temporal.io/api/serviceerror"
    37  
    38  	p "go.temporal.io/server/common/persistence"
    39  	"go.temporal.io/server/common/persistence/serialization"
    40  	"go.temporal.io/server/common/persistence/sql/sqlplugin"
    41  	"go.temporal.io/server/service/history/tasks"
    42  )
    43  
    44  func (m *sqlExecutionStore) RegisterHistoryTaskReader(
    45  	_ context.Context,
    46  	_ *p.RegisterHistoryTaskReaderRequest,
    47  ) error {
    48  	// no-op
    49  	return nil
    50  }
    51  
    52  func (m *sqlExecutionStore) UnregisterHistoryTaskReader(
    53  	_ context.Context,
    54  	_ *p.UnregisterHistoryTaskReaderRequest,
    55  ) {
    56  	// no-op
    57  }
    58  
    59  func (m *sqlExecutionStore) UpdateHistoryTaskReaderProgress(
    60  	_ context.Context,
    61  	_ *p.UpdateHistoryTaskReaderProgressRequest,
    62  ) {
    63  	// no-op
    64  }
    65  
    66  func (m *sqlExecutionStore) AddHistoryTasks(
    67  	ctx context.Context,
    68  	request *p.InternalAddHistoryTasksRequest,
    69  ) error {
    70  	return m.txExecuteShardLocked(ctx,
    71  		"AddHistoryTasks",
    72  		request.ShardID,
    73  		request.RangeID,
    74  		func(tx sqlplugin.Tx) error {
    75  			return applyTasks(ctx,
    76  				tx,
    77  				request.ShardID,
    78  				request.Tasks,
    79  			)
    80  		})
    81  }
    82  
    83  func (m *sqlExecutionStore) GetHistoryTasks(
    84  	ctx context.Context,
    85  	request *p.GetHistoryTasksRequest,
    86  ) (*p.InternalGetHistoryTasksResponse, error) {
    87  	switch request.TaskCategory.Type() {
    88  	case tasks.CategoryTypeImmediate:
    89  		return m.getHistoryImmediateTasks(ctx, request)
    90  	case tasks.CategoryTypeScheduled:
    91  		return m.getHistoryScheduledTasks(ctx, request)
    92  	default:
    93  		return nil, serviceerror.NewInternal(fmt.Sprintf("Unknown task category type: %v", request.TaskCategory))
    94  	}
    95  }
    96  
    97  func (m *sqlExecutionStore) CompleteHistoryTask(
    98  	ctx context.Context,
    99  	request *p.CompleteHistoryTaskRequest,
   100  ) error {
   101  	switch request.TaskCategory.Type() {
   102  	case tasks.CategoryTypeImmediate:
   103  		return m.completeHistoryImmediateTask(ctx, request)
   104  	case tasks.CategoryTypeScheduled:
   105  		return m.completeHistoryScheduledTask(ctx, request)
   106  	default:
   107  		return serviceerror.NewInternal(fmt.Sprintf("Unknown task category type: %v", request.TaskCategory))
   108  	}
   109  }
   110  
   111  func (m *sqlExecutionStore) RangeCompleteHistoryTasks(
   112  	ctx context.Context,
   113  	request *p.RangeCompleteHistoryTasksRequest,
   114  ) error {
   115  	switch request.TaskCategory.Type() {
   116  	case tasks.CategoryTypeImmediate:
   117  		return m.rangeCompleteHistoryImmediateTasks(ctx, request)
   118  	case tasks.CategoryTypeScheduled:
   119  		return m.rangeCompleteHistoryScheduledTasks(ctx, request)
   120  	default:
   121  		return serviceerror.NewInternal(fmt.Sprintf("Unknown task category type: %v", request.TaskCategory))
   122  	}
   123  }
   124  
   125  func (m *sqlExecutionStore) getHistoryImmediateTasks(
   126  	ctx context.Context,
   127  	request *p.GetHistoryTasksRequest,
   128  ) (*p.InternalGetHistoryTasksResponse, error) {
   129  	// This is for backward compatiblity.
   130  	// These task categories exist before the general history_immediate_tasks table is created,
   131  	// so they have their own tables.
   132  	categoryID := request.TaskCategory.ID()
   133  	switch categoryID {
   134  	case tasks.CategoryIDTransfer:
   135  		return m.getTransferTasks(ctx, request)
   136  	case tasks.CategoryIDVisibility:
   137  		return m.getVisibilityTasks(ctx, request)
   138  	case tasks.CategoryIDReplication:
   139  		return m.getReplicationTasks(ctx, request)
   140  	}
   141  
   142  	inclusiveMinTaskID, exclusiveMaxTaskID, err := getImmediateTaskReadRange(request)
   143  	if err != nil {
   144  		return nil, err
   145  	}
   146  
   147  	rows, err := m.Db.RangeSelectFromHistoryImmediateTasks(ctx, sqlplugin.HistoryImmediateTasksRangeFilter{
   148  		ShardID:            request.ShardID,
   149  		CategoryID:         int32(categoryID),
   150  		InclusiveMinTaskID: inclusiveMinTaskID,
   151  		ExclusiveMaxTaskID: exclusiveMaxTaskID,
   152  		PageSize:           request.BatchSize,
   153  	})
   154  	if err != nil {
   155  		if err != sql.ErrNoRows {
   156  			return nil, serviceerror.NewUnavailable(
   157  				fmt.Sprintf("GetHistoryTasks operation failed. Select failed. CategoryID: %v. Error: %v", categoryID, err),
   158  			)
   159  		}
   160  	}
   161  	resp := &p.InternalGetHistoryTasksResponse{
   162  		Tasks: make([]p.InternalHistoryTask, len(rows)),
   163  	}
   164  	if len(rows) == 0 {
   165  		return resp, nil
   166  	}
   167  
   168  	for i, row := range rows {
   169  		resp.Tasks[i] = p.InternalHistoryTask{
   170  			Key:  tasks.NewImmediateKey(row.TaskID),
   171  			Blob: p.NewDataBlob(row.Data, row.DataEncoding),
   172  		}
   173  	}
   174  	if len(rows) == request.BatchSize {
   175  		resp.NextPageToken = getImmediateTaskNextPageToken(
   176  			rows[len(rows)-1].TaskID,
   177  			exclusiveMaxTaskID,
   178  		)
   179  	}
   180  
   181  	return resp, nil
   182  }
   183  
   184  func (m *sqlExecutionStore) completeHistoryImmediateTask(
   185  	ctx context.Context,
   186  	request *p.CompleteHistoryTaskRequest,
   187  ) error {
   188  	// This is for backward compatiblity.
   189  	// These task categories exist before the general history_immediate_tasks table is created,
   190  	// so they have their own tables.
   191  	categoryID := request.TaskCategory.ID()
   192  	switch categoryID {
   193  	case tasks.CategoryIDTransfer:
   194  		return m.completeTransferTask(ctx, request)
   195  	case tasks.CategoryIDVisibility:
   196  		return m.completeVisibilityTask(ctx, request)
   197  	case tasks.CategoryIDReplication:
   198  		return m.completeReplicationTask(ctx, request)
   199  	}
   200  
   201  	if _, err := m.Db.DeleteFromHistoryImmediateTasks(ctx, sqlplugin.HistoryImmediateTasksFilter{
   202  		ShardID:    request.ShardID,
   203  		CategoryID: int32(categoryID),
   204  		TaskID:     request.TaskKey.TaskID,
   205  	}); err != nil {
   206  		return serviceerror.NewUnavailable(
   207  			fmt.Sprintf("CompleteHistoryTask operation failed. CategoryID: %v. Error: %v", categoryID, err),
   208  		)
   209  	}
   210  	return nil
   211  }
   212  
   213  func (m *sqlExecutionStore) rangeCompleteHistoryImmediateTasks(
   214  	ctx context.Context,
   215  	request *p.RangeCompleteHistoryTasksRequest,
   216  ) error {
   217  	// This is for backward compatiblity.
   218  	// These task categories exist before the general history_immediate_tasks table is created,
   219  	// so they have their own tables.
   220  	categoryID := request.TaskCategory.ID()
   221  	switch categoryID {
   222  	case tasks.CategoryIDTransfer:
   223  		return m.rangeCompleteTransferTasks(ctx, request)
   224  	case tasks.CategoryIDVisibility:
   225  		return m.rangeCompleteVisibilityTasks(ctx, request)
   226  	case tasks.CategoryIDReplication:
   227  		return m.rangeCompleteReplicationTasks(ctx, request)
   228  	}
   229  
   230  	if _, err := m.Db.RangeDeleteFromHistoryImmediateTasks(ctx, sqlplugin.HistoryImmediateTasksRangeFilter{
   231  		ShardID:            request.ShardID,
   232  		CategoryID:         int32(categoryID),
   233  		InclusiveMinTaskID: request.InclusiveMinTaskKey.TaskID,
   234  		ExclusiveMaxTaskID: request.ExclusiveMaxTaskKey.TaskID,
   235  	}); err != nil {
   236  		return serviceerror.NewUnavailable(
   237  			fmt.Sprintf("RangeCompleteTransferTask operation failed. CategoryID: %v. Error: %v", categoryID, err),
   238  		)
   239  	}
   240  	return nil
   241  }
   242  
   243  func (m *sqlExecutionStore) getHistoryScheduledTasks(
   244  	ctx context.Context,
   245  	request *p.GetHistoryTasksRequest,
   246  ) (*p.InternalGetHistoryTasksResponse, error) {
   247  	// This is for backward compatiblity.
   248  	// These task categories exist before the general history_scheduled_tasks table is created,
   249  	// so they have their own tables.
   250  	categoryID := request.TaskCategory.ID()
   251  	if categoryID == tasks.CategoryIDTimer {
   252  		return m.getTimerTasks(ctx, request)
   253  	}
   254  
   255  	pageToken := &scheduledTaskPageToken{TaskID: math.MinInt64, Timestamp: request.InclusiveMinTaskKey.FireTime}
   256  	if len(request.NextPageToken) > 0 {
   257  		if err := pageToken.deserialize(request.NextPageToken); err != nil {
   258  			return nil, serviceerror.NewInternal(
   259  				fmt.Sprintf("categoryID: %v. error deserializing scheduledTaskPageToken: %v", categoryID, err),
   260  			)
   261  		}
   262  	}
   263  
   264  	rows, err := m.Db.RangeSelectFromHistoryScheduledTasks(ctx, sqlplugin.HistoryScheduledTasksRangeFilter{
   265  		ShardID:                         request.ShardID,
   266  		CategoryID:                      int32(categoryID),
   267  		InclusiveMinVisibilityTimestamp: pageToken.Timestamp,
   268  		InclusiveMinTaskID:              pageToken.TaskID,
   269  		ExclusiveMaxVisibilityTimestamp: request.ExclusiveMaxTaskKey.FireTime,
   270  		PageSize:                        request.BatchSize,
   271  	})
   272  
   273  	if err != nil && err != sql.ErrNoRows {
   274  		return nil, serviceerror.NewUnavailable(
   275  			fmt.Sprintf("GetHistoryTasks operation failed. Select failed. CategoryID: %v. Error: %v", categoryID, err),
   276  		)
   277  	}
   278  
   279  	resp := &p.InternalGetHistoryTasksResponse{Tasks: make([]p.InternalHistoryTask, 0, len(rows))}
   280  	for _, row := range rows {
   281  		resp.Tasks = append(resp.Tasks, p.InternalHistoryTask{
   282  			Key:  tasks.NewKey(row.VisibilityTimestamp, row.TaskID),
   283  			Blob: p.NewDataBlob(row.Data, row.DataEncoding),
   284  		})
   285  	}
   286  
   287  	if len(resp.Tasks) == request.BatchSize {
   288  		pageToken = &scheduledTaskPageToken{
   289  			TaskID:    rows[request.BatchSize-1].TaskID + 1,
   290  			Timestamp: rows[request.BatchSize-1].VisibilityTimestamp,
   291  		}
   292  		nextToken, err := pageToken.serialize()
   293  		if err != nil {
   294  			return nil, serviceerror.NewInternal(fmt.Sprintf("GetHistoryTasks: error serializing page token: %v", err))
   295  		}
   296  		resp.NextPageToken = nextToken
   297  	}
   298  
   299  	return resp, nil
   300  }
   301  
   302  func (m *sqlExecutionStore) completeHistoryScheduledTask(
   303  	ctx context.Context,
   304  	request *p.CompleteHistoryTaskRequest,
   305  ) error {
   306  	// This is for backward compatiblity.
   307  	// These task categories exist before the general history_scheduled_tasks table is created,
   308  	// so they have their own tables.
   309  	categoryID := request.TaskCategory.ID()
   310  	if categoryID == tasks.CategoryIDTimer {
   311  		return m.completeTimerTask(ctx, request)
   312  	}
   313  
   314  	if _, err := m.Db.DeleteFromHistoryScheduledTasks(ctx, sqlplugin.HistoryScheduledTasksFilter{
   315  		ShardID:             request.ShardID,
   316  		CategoryID:          int32(categoryID),
   317  		VisibilityTimestamp: request.TaskKey.FireTime,
   318  		TaskID:              request.TaskKey.TaskID,
   319  	}); err != nil {
   320  		return serviceerror.NewUnavailable(fmt.Sprintf("CompleteHistoryTask operation failed. CategoryID: %v. Error: %v", categoryID, err))
   321  	}
   322  	return nil
   323  }
   324  
   325  func (m *sqlExecutionStore) rangeCompleteHistoryScheduledTasks(
   326  	ctx context.Context,
   327  	request *p.RangeCompleteHistoryTasksRequest,
   328  ) error {
   329  	// This is for backward compatiblity.
   330  	// These task categories exist before the general history_scheduled_tasks table is created,
   331  	// so they have their own tables.
   332  	categoryID := request.TaskCategory.ID()
   333  	if categoryID == tasks.CategoryIDTimer {
   334  		return m.rangeCompleteTimerTasks(ctx, request)
   335  	}
   336  
   337  	start := request.InclusiveMinTaskKey.FireTime
   338  	end := request.ExclusiveMaxTaskKey.FireTime
   339  	if _, err := m.Db.RangeDeleteFromHistoryScheduledTasks(ctx, sqlplugin.HistoryScheduledTasksRangeFilter{
   340  		ShardID:                         request.ShardID,
   341  		CategoryID:                      int32(categoryID),
   342  		InclusiveMinVisibilityTimestamp: start,
   343  		ExclusiveMaxVisibilityTimestamp: end,
   344  	}); err != nil {
   345  		return serviceerror.NewUnavailable(fmt.Sprintf("RangeCompleteHistoryTask operation failed. CategoryID: %v. Error: %v", categoryID, err))
   346  	}
   347  	return nil
   348  }
   349  
   350  func (m *sqlExecutionStore) getTransferTasks(
   351  	ctx context.Context,
   352  	request *p.GetHistoryTasksRequest,
   353  ) (*p.InternalGetHistoryTasksResponse, error) {
   354  	inclusiveMinTaskID, exclusiveMaxTaskID, err := getImmediateTaskReadRange(request)
   355  	if err != nil {
   356  		return nil, err
   357  	}
   358  
   359  	rows, err := m.Db.RangeSelectFromTransferTasks(ctx, sqlplugin.TransferTasksRangeFilter{
   360  		ShardID:            request.ShardID,
   361  		InclusiveMinTaskID: inclusiveMinTaskID,
   362  		ExclusiveMaxTaskID: exclusiveMaxTaskID,
   363  		PageSize:           request.BatchSize,
   364  	})
   365  	if err != nil {
   366  		if err != sql.ErrNoRows {
   367  			return nil, serviceerror.NewUnavailable(fmt.Sprintf("GetTransferTasks operation failed. Select failed. Error: %v", err))
   368  		}
   369  	}
   370  	resp := &p.InternalGetHistoryTasksResponse{
   371  		Tasks: make([]p.InternalHistoryTask, len(rows)),
   372  	}
   373  	if len(rows) == 0 {
   374  		return resp, nil
   375  	}
   376  
   377  	for i, row := range rows {
   378  		resp.Tasks[i] = p.InternalHistoryTask{
   379  			Key:  tasks.NewImmediateKey(row.TaskID),
   380  			Blob: p.NewDataBlob(row.Data, row.DataEncoding),
   381  		}
   382  	}
   383  	if len(rows) == request.BatchSize {
   384  		resp.NextPageToken = getImmediateTaskNextPageToken(
   385  			rows[len(rows)-1].TaskID,
   386  			exclusiveMaxTaskID,
   387  		)
   388  	}
   389  
   390  	return resp, nil
   391  }
   392  
   393  func (m *sqlExecutionStore) completeTransferTask(
   394  	ctx context.Context,
   395  	request *p.CompleteHistoryTaskRequest,
   396  ) error {
   397  	if _, err := m.Db.DeleteFromTransferTasks(ctx, sqlplugin.TransferTasksFilter{
   398  		ShardID: request.ShardID,
   399  		TaskID:  request.TaskKey.TaskID,
   400  	}); err != nil {
   401  		return serviceerror.NewUnavailable(fmt.Sprintf("CompleteTransferTask operation failed. Error: %v", err))
   402  	}
   403  	return nil
   404  }
   405  
   406  func (m *sqlExecutionStore) rangeCompleteTransferTasks(
   407  	ctx context.Context,
   408  	request *p.RangeCompleteHistoryTasksRequest,
   409  ) error {
   410  	if _, err := m.Db.RangeDeleteFromTransferTasks(ctx, sqlplugin.TransferTasksRangeFilter{
   411  		ShardID:            request.ShardID,
   412  		InclusiveMinTaskID: request.InclusiveMinTaskKey.TaskID,
   413  		ExclusiveMaxTaskID: request.ExclusiveMaxTaskKey.TaskID,
   414  	}); err != nil {
   415  		return serviceerror.NewUnavailable(fmt.Sprintf("RangeCompleteTransferTask operation failed. Error: %v", err))
   416  	}
   417  	return nil
   418  }
   419  
   420  func (m *sqlExecutionStore) getTimerTasks(
   421  	ctx context.Context,
   422  	request *p.GetHistoryTasksRequest,
   423  ) (*p.InternalGetHistoryTasksResponse, error) {
   424  	pageToken := &scheduledTaskPageToken{TaskID: math.MinInt64, Timestamp: request.InclusiveMinTaskKey.FireTime}
   425  	if len(request.NextPageToken) > 0 {
   426  		if err := pageToken.deserialize(request.NextPageToken); err != nil {
   427  			return nil, serviceerror.NewInternal(fmt.Sprintf("error deserializing timerTaskPageToken: %v", err))
   428  		}
   429  	}
   430  
   431  	rows, err := m.Db.RangeSelectFromTimerTasks(ctx, sqlplugin.TimerTasksRangeFilter{
   432  		ShardID:                         request.ShardID,
   433  		InclusiveMinVisibilityTimestamp: pageToken.Timestamp,
   434  		InclusiveMinTaskID:              pageToken.TaskID,
   435  		ExclusiveMaxVisibilityTimestamp: request.ExclusiveMaxTaskKey.FireTime,
   436  		PageSize:                        request.BatchSize,
   437  	})
   438  
   439  	if err != nil && err != sql.ErrNoRows {
   440  		return nil, serviceerror.NewUnavailable(fmt.Sprintf("GetTimerTasks operation failed. Select failed. Error: %v", err))
   441  	}
   442  
   443  	resp := &p.InternalGetHistoryTasksResponse{Tasks: make([]p.InternalHistoryTask, 0, len(rows))}
   444  	for _, row := range rows {
   445  		resp.Tasks = append(resp.Tasks, p.InternalHistoryTask{
   446  			Key:  tasks.NewKey(row.VisibilityTimestamp, row.TaskID),
   447  			Blob: p.NewDataBlob(row.Data, row.DataEncoding),
   448  		})
   449  	}
   450  
   451  	if len(resp.Tasks) == request.BatchSize {
   452  		pageToken = &scheduledTaskPageToken{
   453  			TaskID:    rows[request.BatchSize-1].TaskID + 1,
   454  			Timestamp: rows[request.BatchSize-1].VisibilityTimestamp,
   455  		}
   456  		nextToken, err := pageToken.serialize()
   457  		if err != nil {
   458  			return nil, serviceerror.NewInternal(fmt.Sprintf("GetTimerTasks: error serializing page token: %v", err))
   459  		}
   460  		resp.NextPageToken = nextToken
   461  	}
   462  
   463  	return resp, nil
   464  }
   465  
   466  func (m *sqlExecutionStore) completeTimerTask(
   467  	ctx context.Context,
   468  	request *p.CompleteHistoryTaskRequest,
   469  ) error {
   470  	if _, err := m.Db.DeleteFromTimerTasks(ctx, sqlplugin.TimerTasksFilter{
   471  		ShardID:             request.ShardID,
   472  		VisibilityTimestamp: request.TaskKey.FireTime,
   473  		TaskID:              request.TaskKey.TaskID,
   474  	}); err != nil {
   475  		return serviceerror.NewUnavailable(fmt.Sprintf("CompleteTimerTask operation failed. Error: %v", err))
   476  	}
   477  	return nil
   478  }
   479  
   480  func (m *sqlExecutionStore) rangeCompleteTimerTasks(
   481  	ctx context.Context,
   482  	request *p.RangeCompleteHistoryTasksRequest,
   483  ) error {
   484  	start := request.InclusiveMinTaskKey.FireTime
   485  	end := request.ExclusiveMaxTaskKey.FireTime
   486  	if _, err := m.Db.RangeDeleteFromTimerTasks(ctx, sqlplugin.TimerTasksRangeFilter{
   487  		ShardID:                         request.ShardID,
   488  		InclusiveMinVisibilityTimestamp: start,
   489  		ExclusiveMaxVisibilityTimestamp: end,
   490  	}); err != nil {
   491  		return serviceerror.NewUnavailable(fmt.Sprintf("RangeCompleteTimerTask operation failed. Error: %v", err))
   492  	}
   493  	return nil
   494  }
   495  
   496  func (m *sqlExecutionStore) getReplicationTasks(
   497  	ctx context.Context,
   498  	request *p.GetHistoryTasksRequest,
   499  ) (*p.InternalGetHistoryTasksResponse, error) {
   500  	inclusiveMinTaskID, exclusiveMaxTaskID, err := getImmediateTaskReadRange(request)
   501  	if err != nil {
   502  		return nil, err
   503  	}
   504  
   505  	rows, err := m.Db.RangeSelectFromReplicationTasks(ctx, sqlplugin.ReplicationTasksRangeFilter{
   506  		ShardID:            request.ShardID,
   507  		InclusiveMinTaskID: inclusiveMinTaskID,
   508  		ExclusiveMaxTaskID: exclusiveMaxTaskID,
   509  		PageSize:           request.BatchSize,
   510  	})
   511  
   512  	switch err {
   513  	case nil:
   514  		return m.populateGetReplicationTasksResponse(rows, request.ExclusiveMaxTaskKey.TaskID, request.BatchSize)
   515  	case sql.ErrNoRows:
   516  		return &p.InternalGetHistoryTasksResponse{}, nil
   517  	default:
   518  		return nil, serviceerror.NewUnavailable(fmt.Sprintf("GetReplicationTasks operation failed. Select failed: %v", err))
   519  	}
   520  }
   521  
   522  func getImmediateTaskReadRange(
   523  	request *p.GetHistoryTasksRequest,
   524  ) (inclusiveMinTaskID int64, exclusiveMaxTaskID int64, err error) {
   525  	inclusiveMinTaskID = request.InclusiveMinTaskKey.TaskID
   526  	if len(request.NextPageToken) > 0 {
   527  		inclusiveMinTaskID, err = deserializePageToken(request.NextPageToken)
   528  		if err != nil {
   529  			return 0, 0, err
   530  		}
   531  	}
   532  
   533  	return inclusiveMinTaskID, request.ExclusiveMaxTaskKey.TaskID, nil
   534  }
   535  
   536  func getImmediateTaskNextPageToken(
   537  	lastTaskID int64,
   538  	exclusiveMaxTaskID int64,
   539  ) []byte {
   540  	nextTaskID := lastTaskID + 1
   541  	if nextTaskID < exclusiveMaxTaskID {
   542  		return serializePageToken(nextTaskID)
   543  	}
   544  	return nil
   545  }
   546  
   547  func (m *sqlExecutionStore) populateGetReplicationTasksResponse(
   548  	rows []sqlplugin.ReplicationTasksRow,
   549  	exclusiveMaxTaskID int64,
   550  	batchSize int,
   551  ) (*p.InternalGetHistoryTasksResponse, error) {
   552  	if len(rows) == 0 {
   553  		return &p.InternalGetHistoryTasksResponse{}, nil
   554  	}
   555  
   556  	var replicationTasks = make([]p.InternalHistoryTask, len(rows))
   557  	for i, row := range rows {
   558  		replicationTasks[i] = p.InternalHistoryTask{
   559  			Key:  tasks.NewImmediateKey(row.TaskID),
   560  			Blob: p.NewDataBlob(row.Data, row.DataEncoding),
   561  		}
   562  	}
   563  	var nextPageToken []byte
   564  	if len(rows) == batchSize {
   565  		nextPageToken = getImmediateTaskNextPageToken(
   566  			rows[len(rows)-1].TaskID,
   567  			exclusiveMaxTaskID,
   568  		)
   569  	}
   570  	return &p.InternalGetHistoryTasksResponse{
   571  		Tasks:         replicationTasks,
   572  		NextPageToken: nextPageToken,
   573  	}, nil
   574  }
   575  
   576  func (m *sqlExecutionStore) populateGetReplicationDLQTasksResponse(
   577  	rows []sqlplugin.ReplicationDLQTasksRow,
   578  	exclusiveMaxTaskID int64,
   579  	batchSize int,
   580  ) (*p.InternalGetHistoryTasksResponse, error) {
   581  	if len(rows) == 0 {
   582  		return &p.InternalGetHistoryTasksResponse{}, nil
   583  	}
   584  
   585  	var dlqTasks = make([]p.InternalHistoryTask, len(rows))
   586  	for i, row := range rows {
   587  		dlqTasks[i] = p.InternalHistoryTask{
   588  			Key:  tasks.NewImmediateKey(row.TaskID),
   589  			Blob: p.NewDataBlob(row.Data, row.DataEncoding),
   590  		}
   591  	}
   592  	var nextPageToken []byte
   593  	if len(rows) == batchSize {
   594  		nextPageToken = getImmediateTaskNextPageToken(
   595  			rows[len(rows)-1].TaskID,
   596  			exclusiveMaxTaskID,
   597  		)
   598  	}
   599  	return &p.InternalGetHistoryTasksResponse{
   600  		Tasks:         dlqTasks,
   601  		NextPageToken: nextPageToken,
   602  	}, nil
   603  }
   604  
   605  func (m *sqlExecutionStore) completeReplicationTask(
   606  	ctx context.Context,
   607  	request *p.CompleteHistoryTaskRequest,
   608  ) error {
   609  	if _, err := m.Db.DeleteFromReplicationTasks(ctx, sqlplugin.ReplicationTasksFilter{
   610  		ShardID: request.ShardID,
   611  		TaskID:  request.TaskKey.TaskID,
   612  	}); err != nil {
   613  		return serviceerror.NewUnavailable(fmt.Sprintf("CompleteReplicationTask operation failed. Error: %v", err))
   614  	}
   615  	return nil
   616  }
   617  
   618  func (m *sqlExecutionStore) rangeCompleteReplicationTasks(
   619  	ctx context.Context,
   620  	request *p.RangeCompleteHistoryTasksRequest,
   621  ) error {
   622  	if _, err := m.Db.RangeDeleteFromReplicationTasks(ctx, sqlplugin.ReplicationTasksRangeFilter{
   623  		ShardID:            request.ShardID,
   624  		InclusiveMinTaskID: request.InclusiveMinTaskKey.TaskID,
   625  		ExclusiveMaxTaskID: request.ExclusiveMaxTaskKey.TaskID,
   626  	}); err != nil {
   627  		return serviceerror.NewUnavailable(fmt.Sprintf("RangeCompleteReplicationTask operation failed. Error: %v", err))
   628  	}
   629  	return nil
   630  }
   631  
   632  func (m *sqlExecutionStore) PutReplicationTaskToDLQ(
   633  	ctx context.Context,
   634  	request *p.PutReplicationTaskToDLQRequest,
   635  ) error {
   636  	replicationTask := request.TaskInfo
   637  	blob, err := serialization.ReplicationTaskInfoToBlob(replicationTask)
   638  
   639  	if err != nil {
   640  		return err
   641  	}
   642  
   643  	_, err = m.Db.InsertIntoReplicationDLQTasks(ctx, []sqlplugin.ReplicationDLQTasksRow{{
   644  		SourceClusterName: request.SourceClusterName,
   645  		ShardID:           request.ShardID,
   646  		TaskID:            replicationTask.GetTaskId(),
   647  		Data:              blob.Data,
   648  		DataEncoding:      blob.EncodingType.String(),
   649  	}})
   650  
   651  	// Tasks are immutable. So it's fine if we already persisted it before.
   652  	// This can happen when tasks are retried (ack and cleanup can have lag on source side).
   653  	if err != nil && !m.Db.IsDupEntryError(err) {
   654  		return serviceerror.NewUnavailable(fmt.Sprintf("Failed to create replication tasks. Error: %v", err))
   655  	}
   656  
   657  	return nil
   658  }
   659  
   660  func (m *sqlExecutionStore) GetReplicationTasksFromDLQ(
   661  	ctx context.Context,
   662  	request *p.GetReplicationTasksFromDLQRequest,
   663  ) (*p.InternalGetHistoryTasksResponse, error) {
   664  	inclusiveMinTaskID, exclusiveMaxTaskID, err := getImmediateTaskReadRange(&request.GetHistoryTasksRequest)
   665  	if err != nil {
   666  		return nil, err
   667  	}
   668  
   669  	rows, err := m.Db.RangeSelectFromReplicationDLQTasks(ctx, sqlplugin.ReplicationDLQTasksRangeFilter{
   670  		ShardID:            request.ShardID,
   671  		InclusiveMinTaskID: inclusiveMinTaskID,
   672  		ExclusiveMaxTaskID: exclusiveMaxTaskID,
   673  		PageSize:           request.BatchSize,
   674  		SourceClusterName:  request.SourceClusterName,
   675  	})
   676  
   677  	switch err {
   678  	case nil:
   679  		return m.populateGetReplicationDLQTasksResponse(rows, request.ExclusiveMaxTaskKey.TaskID, request.BatchSize)
   680  	case sql.ErrNoRows:
   681  		return &p.InternalGetHistoryTasksResponse{}, nil
   682  	default:
   683  		return nil, serviceerror.NewUnavailable(fmt.Sprintf("GetReplicationTasks operation failed. Select failed: %v", err))
   684  	}
   685  }
   686  
   687  func (m *sqlExecutionStore) DeleteReplicationTaskFromDLQ(
   688  	ctx context.Context,
   689  	request *p.DeleteReplicationTaskFromDLQRequest,
   690  ) error {
   691  	if _, err := m.Db.DeleteFromReplicationDLQTasks(ctx, sqlplugin.ReplicationDLQTasksFilter{
   692  		ShardID:           request.ShardID,
   693  		TaskID:            request.TaskKey.TaskID,
   694  		SourceClusterName: request.SourceClusterName,
   695  	}); err != nil {
   696  		return err
   697  	}
   698  	return nil
   699  }
   700  
   701  func (m *sqlExecutionStore) RangeDeleteReplicationTaskFromDLQ(
   702  	ctx context.Context,
   703  	request *p.RangeDeleteReplicationTaskFromDLQRequest,
   704  ) error {
   705  	if _, err := m.Db.RangeDeleteFromReplicationDLQTasks(ctx, sqlplugin.ReplicationDLQTasksRangeFilter{
   706  		ShardID:            request.ShardID,
   707  		SourceClusterName:  request.SourceClusterName,
   708  		InclusiveMinTaskID: request.InclusiveMinTaskKey.TaskID,
   709  		ExclusiveMaxTaskID: request.ExclusiveMaxTaskKey.TaskID,
   710  	}); err != nil {
   711  		return err
   712  	}
   713  	return nil
   714  }
   715  
   716  func (m *sqlExecutionStore) IsReplicationDLQEmpty(
   717  	ctx context.Context,
   718  	request *p.GetReplicationTasksFromDLQRequest,
   719  ) (bool, error) {
   720  	res, err := m.Db.RangeSelectFromReplicationDLQTasks(ctx, sqlplugin.ReplicationDLQTasksRangeFilter{
   721  		ShardID:            request.ShardID,
   722  		SourceClusterName:  request.SourceClusterName,
   723  		InclusiveMinTaskID: request.InclusiveMinTaskKey.TaskID,
   724  		ExclusiveMaxTaskID: math.MaxInt64,
   725  		PageSize:           1,
   726  	})
   727  	if err != nil {
   728  		if errors.Is(err, sql.ErrNoRows) {
   729  			// The queue is empty
   730  			return true, nil
   731  		}
   732  		return false, err
   733  	}
   734  	return len(res) == 0, nil
   735  }
   736  
   737  func (m *sqlExecutionStore) getVisibilityTasks(
   738  	ctx context.Context,
   739  	request *p.GetHistoryTasksRequest,
   740  ) (*p.InternalGetHistoryTasksResponse, error) {
   741  	inclusiveMinTaskID, exclusiveMaxTaskID, err := getImmediateTaskReadRange(request)
   742  	if err != nil {
   743  		return nil, err
   744  	}
   745  
   746  	rows, err := m.Db.RangeSelectFromVisibilityTasks(ctx, sqlplugin.VisibilityTasksRangeFilter{
   747  		ShardID:            request.ShardID,
   748  		InclusiveMinTaskID: inclusiveMinTaskID,
   749  		ExclusiveMaxTaskID: exclusiveMaxTaskID,
   750  		PageSize:           request.BatchSize,
   751  	})
   752  	if err != nil {
   753  		if err != sql.ErrNoRows {
   754  			return nil, serviceerror.NewUnavailable(fmt.Sprintf("GetVisibilityTasks operation failed. Select failed. Error: %v", err))
   755  		}
   756  	}
   757  	resp := &p.InternalGetHistoryTasksResponse{
   758  		Tasks: make([]p.InternalHistoryTask, len(rows)),
   759  	}
   760  	if len(rows) == 0 {
   761  		return resp, nil
   762  	}
   763  
   764  	for i, row := range rows {
   765  		resp.Tasks[i] = p.InternalHistoryTask{
   766  			Key:  tasks.NewImmediateKey(row.TaskID),
   767  			Blob: p.NewDataBlob(row.Data, row.DataEncoding),
   768  		}
   769  	}
   770  	if len(rows) == request.BatchSize {
   771  		resp.NextPageToken = getImmediateTaskNextPageToken(
   772  			rows[len(rows)-1].TaskID,
   773  			exclusiveMaxTaskID,
   774  		)
   775  	}
   776  
   777  	return resp, nil
   778  }
   779  
   780  func (m *sqlExecutionStore) completeVisibilityTask(
   781  	ctx context.Context,
   782  	request *p.CompleteHistoryTaskRequest,
   783  ) error {
   784  	if _, err := m.Db.DeleteFromVisibilityTasks(ctx, sqlplugin.VisibilityTasksFilter{
   785  		ShardID: request.ShardID,
   786  		TaskID:  request.TaskKey.TaskID,
   787  	}); err != nil {
   788  		return serviceerror.NewUnavailable(fmt.Sprintf("CompleteVisibilityTask operation failed. Error: %v", err))
   789  	}
   790  	return nil
   791  }
   792  
   793  func (m *sqlExecutionStore) rangeCompleteVisibilityTasks(
   794  	ctx context.Context,
   795  	request *p.RangeCompleteHistoryTasksRequest,
   796  ) error {
   797  	if _, err := m.Db.RangeDeleteFromVisibilityTasks(ctx, sqlplugin.VisibilityTasksRangeFilter{
   798  		ShardID:            request.ShardID,
   799  		InclusiveMinTaskID: request.InclusiveMinTaskKey.TaskID,
   800  		ExclusiveMaxTaskID: request.ExclusiveMaxTaskKey.TaskID,
   801  	}); err != nil {
   802  		return serviceerror.NewUnavailable(fmt.Sprintf("RangeCompleteVisibilityTask operation failed. Error: %v", err))
   803  	}
   804  	return nil
   805  }
   806  
   807  type scheduledTaskPageToken struct {
   808  	TaskID    int64
   809  	Timestamp time.Time
   810  }
   811  
   812  func (t *scheduledTaskPageToken) serialize() ([]byte, error) {
   813  	return json.Marshal(t)
   814  }
   815  
   816  func (t *scheduledTaskPageToken) deserialize(payload []byte) error {
   817  	return json.Unmarshal(payload, t)
   818  }