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 }