go.temporal.io/server@v1.23.0/common/persistence/sql/common.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  	"encoding/binary"
    32  	"encoding/gob"
    33  	"fmt"
    34  
    35  	"go.temporal.io/api/serviceerror"
    36  
    37  	"go.temporal.io/server/common/log"
    38  	"go.temporal.io/server/common/log/tag"
    39  	"go.temporal.io/server/common/persistence"
    40  	"go.temporal.io/server/common/persistence/sql/sqlplugin"
    41  )
    42  
    43  // TODO: Rename all SQL Managers to Stores
    44  type SqlStore struct {
    45  	Db     sqlplugin.DB
    46  	logger log.Logger
    47  }
    48  
    49  func NewSqlStore(db sqlplugin.DB, logger log.Logger) SqlStore {
    50  	return SqlStore{
    51  		Db:     db,
    52  		logger: logger,
    53  	}
    54  }
    55  
    56  func (m *SqlStore) GetName() string {
    57  	return m.Db.PluginName()
    58  }
    59  
    60  func (m *SqlStore) GetDbName() string {
    61  	return m.Db.DbName()
    62  }
    63  
    64  func (m *SqlStore) Close() {
    65  	if m.Db != nil {
    66  		err := m.Db.Close()
    67  		if err != nil {
    68  			m.logger.Error("Error closing SQL database", tag.Error(err))
    69  		}
    70  	}
    71  }
    72  
    73  func (m *SqlStore) txExecute(ctx context.Context, operation string, f func(tx sqlplugin.Tx) error) error {
    74  	tx, err := m.Db.BeginTx(ctx)
    75  	if err != nil {
    76  		return serviceerror.NewUnavailable(fmt.Sprintf("%s failed. Failed to start transaction. Error: %v", operation, err))
    77  	}
    78  	err = f(tx)
    79  	if err != nil {
    80  		rollBackErr := tx.Rollback()
    81  		if rollBackErr != nil {
    82  			m.logger.Error("transaction rollback error", tag.Error(rollBackErr))
    83  		}
    84  
    85  		switch err.(type) {
    86  		case *persistence.ConditionFailedError,
    87  			*persistence.CurrentWorkflowConditionFailedError,
    88  			*persistence.WorkflowConditionFailedError,
    89  			*serviceerror.NamespaceAlreadyExists,
    90  			*persistence.ShardOwnershipLostError,
    91  			*serviceerror.Unavailable,
    92  			*serviceerror.NotFound:
    93  			return err
    94  		default:
    95  			return serviceerror.NewUnavailable(fmt.Sprintf("%v: %v", operation, err))
    96  		}
    97  	}
    98  	if err := tx.Commit(); err != nil {
    99  		return serviceerror.NewUnavailable(fmt.Sprintf("%s operation failed. Failed to commit transaction. Error: %v", operation, err))
   100  	}
   101  	return nil
   102  }
   103  
   104  func gobSerialize(x interface{}) ([]byte, error) {
   105  	b := bytes.Buffer{}
   106  	e := gob.NewEncoder(&b)
   107  	err := e.Encode(x)
   108  	if err != nil {
   109  		return nil, serviceerror.NewInternal(fmt.Sprintf("Error in serialization: %v", err))
   110  	}
   111  	return b.Bytes(), nil
   112  }
   113  
   114  func gobDeserialize(a []byte, x interface{}) error {
   115  	b := bytes.NewBuffer(a)
   116  	d := gob.NewDecoder(b)
   117  	err := d.Decode(x)
   118  	if err != nil {
   119  		return serviceerror.NewInternal(fmt.Sprintf("Error in deserialization: %v", err))
   120  	}
   121  	return nil
   122  }
   123  
   124  func serializePageToken(offset int64) []byte {
   125  	b := make([]byte, 8)
   126  	binary.LittleEndian.PutUint64(b, uint64(offset))
   127  	return b
   128  }
   129  
   130  func deserializePageToken(payload []byte) (int64, error) {
   131  	if len(payload) != 8 {
   132  		return 0, fmt.Errorf("invalid token of %v length", len(payload))
   133  	}
   134  	return int64(binary.LittleEndian.Uint64(payload)), nil
   135  }
   136  
   137  func convertCommonErrors(
   138  	operation string,
   139  	err error,
   140  ) error {
   141  	if err == sql.ErrNoRows {
   142  		return serviceerror.NewNotFound(fmt.Sprintf("%v failed. Error: %v ", operation, err))
   143  	}
   144  
   145  	return serviceerror.NewUnavailable(fmt.Sprintf("%v operation failed. Error: %v", operation, err))
   146  }