go.temporal.io/server@v1.23.0/common/persistence/sql/sqlplugin/mysql/events.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 mysql 26 27 import ( 28 "context" 29 "database/sql" 30 31 "go.temporal.io/server/common/persistence/sql/sqlplugin" 32 ) 33 34 const ( 35 // below are templates for history_node table 36 addHistoryNodesQuery = `INSERT INTO history_node (` + 37 `shard_id, tree_id, branch_id, node_id, prev_txn_id, txn_id, data, data_encoding) ` + 38 `VALUES (:shard_id, :tree_id, :branch_id, :node_id, :prev_txn_id, :txn_id, :data, :data_encoding) ` + 39 `ON DUPLICATE KEY UPDATE prev_txn_id=:prev_txn_id, data=:data, data_encoding=:data_encoding ` 40 41 getHistoryNodesQuery = `SELECT node_id, prev_txn_id, txn_id, data, data_encoding FROM history_node ` + 42 `WHERE shard_id = ? AND tree_id = ? AND branch_id = ? AND ((node_id = ? AND txn_id > ?) OR node_id > ?) AND node_id < ? ` + 43 `ORDER BY shard_id, tree_id, branch_id, node_id, txn_id LIMIT ? ` 44 45 getHistoryNodesReverseQuery = `SELECT node_id, prev_txn_id, txn_id, data, data_encoding FROM history_node ` + 46 `WHERE shard_id = ? AND tree_id = ? AND branch_id = ? AND node_id >= ? AND ((node_id = ? AND txn_id < ?) OR node_id < ?) ` + 47 `ORDER BY shard_id, tree_id, branch_id DESC, node_id DESC, txn_id DESC LIMIT ? ` 48 49 getHistoryNodeMetadataQuery = `SELECT node_id, prev_txn_id, txn_id FROM history_node ` + 50 `WHERE shard_id = ? AND tree_id = ? AND branch_id = ? AND ((node_id = ? AND txn_id > ?) OR node_id > ?) AND node_id < ? ` + 51 `ORDER BY shard_id, tree_id, branch_id, node_id, txn_id LIMIT ? ` 52 53 deleteHistoryNodeQuery = `DELETE FROM history_node WHERE shard_id = ? AND tree_id = ? AND branch_id = ? AND node_id = ? AND txn_id = ? ` 54 55 deleteHistoryNodesQuery = `DELETE FROM history_node WHERE shard_id = ? AND tree_id = ? AND branch_id = ? AND node_id >= ? ` 56 57 // below are templates for history_tree table 58 addHistoryTreeQuery = `INSERT INTO history_tree (` + 59 `shard_id, tree_id, branch_id, data, data_encoding) ` + 60 `VALUES (:shard_id, :tree_id, :branch_id, :data, :data_encoding) ` + 61 `ON DUPLICATE KEY UPDATE data=VALUES(data), data_encoding=VALUES(data_encoding)` 62 63 getHistoryTreeQuery = `SELECT branch_id, data, data_encoding FROM history_tree WHERE shard_id = ? AND tree_id = ? ` 64 65 // conceptually this query is WHERE (shard_id, tree_id, branch_id) > (?, ?, ?) 66 // but mysql doesn't execute it efficiently unless it's spelled out like this 67 paginateBranchesQuery = `SELECT shard_id, tree_id, branch_id, data, data_encoding 68 FROM history_tree 69 WHERE (shard_id = ? AND ((tree_id = ? AND branch_id > ?) OR tree_id > ?)) OR shard_id > ? 70 ORDER BY shard_id, tree_id, branch_id 71 LIMIT ?` 72 73 deleteHistoryTreeQuery = `DELETE FROM history_tree WHERE shard_id = ? AND tree_id = ? AND branch_id = ? ` 74 ) 75 76 // For history_node table: 77 78 // InsertIntoHistoryNode inserts a row into history_node table 79 func (mdb *db) InsertIntoHistoryNode( 80 ctx context.Context, 81 row *sqlplugin.HistoryNodeRow, 82 ) (sql.Result, error) { 83 // NOTE: txn_id is *= -1 within DB 84 row.TxnID = -row.TxnID 85 return mdb.conn.NamedExecContext(ctx, 86 addHistoryNodesQuery, 87 row, 88 ) 89 } 90 91 // DeleteFromHistoryNode delete a row from history_node table 92 func (mdb *db) DeleteFromHistoryNode( 93 ctx context.Context, 94 row *sqlplugin.HistoryNodeRow, 95 ) (sql.Result, error) { 96 // NOTE: txn_id is *= -1 within DB 97 row.TxnID = -row.TxnID 98 return mdb.conn.ExecContext(ctx, 99 deleteHistoryNodeQuery, 100 row.ShardID, 101 row.TreeID, 102 row.BranchID, 103 row.NodeID, 104 row.TxnID, 105 ) 106 } 107 108 // SelectFromHistoryNode reads one or more rows from history_node table 109 func (mdb *db) RangeSelectFromHistoryNode( 110 ctx context.Context, 111 filter sqlplugin.HistoryNodeSelectFilter, 112 ) ([]sqlplugin.HistoryNodeRow, error) { 113 var query string 114 if filter.MetadataOnly { 115 query = getHistoryNodeMetadataQuery 116 } else if filter.ReverseOrder { 117 query = getHistoryNodesReverseQuery 118 } else { 119 query = getHistoryNodesQuery 120 } 121 122 var args []interface{} 123 if filter.ReverseOrder { 124 args = []interface{}{ 125 filter.ShardID, 126 filter.TreeID, 127 filter.BranchID, 128 filter.MinNodeID, 129 filter.MaxTxnID, 130 -filter.MaxTxnID, 131 filter.MaxNodeID, 132 filter.PageSize, 133 } 134 } else { 135 args = []interface{}{ 136 filter.ShardID, 137 filter.TreeID, 138 filter.BranchID, 139 filter.MinNodeID, 140 -filter.MinTxnID, // NOTE: transaction ID is *= -1 when stored 141 filter.MinNodeID, 142 filter.MaxNodeID, 143 filter.PageSize, 144 } 145 } 146 147 var rows []sqlplugin.HistoryNodeRow 148 if err := mdb.conn.SelectContext(ctx, &rows, query, args...); err != nil { 149 return nil, err 150 } 151 152 // NOTE: since we let txn_id multiple by -1 when inserting, we have to revert it back here 153 for index := range rows { 154 rows[index].TxnID = -rows[index].TxnID 155 } 156 return rows, nil 157 } 158 159 // DeleteFromHistoryNode deletes one or more rows from history_node table 160 func (mdb *db) RangeDeleteFromHistoryNode( 161 ctx context.Context, 162 filter sqlplugin.HistoryNodeDeleteFilter, 163 ) (sql.Result, error) { 164 return mdb.conn.ExecContext(ctx, 165 deleteHistoryNodesQuery, 166 filter.ShardID, 167 filter.TreeID, 168 filter.BranchID, 169 filter.MinNodeID, 170 ) 171 } 172 173 // For history_tree table: 174 175 // InsertIntoHistoryTree inserts a row into history_tree table 176 func (mdb *db) InsertIntoHistoryTree( 177 ctx context.Context, 178 row *sqlplugin.HistoryTreeRow, 179 ) (sql.Result, error) { 180 return mdb.conn.NamedExecContext(ctx, 181 addHistoryTreeQuery, 182 row, 183 ) 184 } 185 186 // SelectFromHistoryTree reads one or more rows from history_tree table 187 func (mdb *db) SelectFromHistoryTree( 188 ctx context.Context, 189 filter sqlplugin.HistoryTreeSelectFilter, 190 ) ([]sqlplugin.HistoryTreeRow, error) { 191 var rows []sqlplugin.HistoryTreeRow 192 err := mdb.conn.SelectContext(ctx, 193 &rows, 194 getHistoryTreeQuery, 195 filter.ShardID, 196 filter.TreeID, 197 ) 198 return rows, err 199 } 200 201 // PaginateBranchesFromHistoryTree reads up to page.Limit rows from the history_tree table sorted by their primary key, 202 // while skipping the first page.Offset rows. 203 func (mdb *db) PaginateBranchesFromHistoryTree( 204 ctx context.Context, 205 page sqlplugin.HistoryTreeBranchPage, 206 ) ([]sqlplugin.HistoryTreeRow, error) { 207 var rows []sqlplugin.HistoryTreeRow 208 err := mdb.conn.SelectContext( 209 ctx, 210 &rows, 211 paginateBranchesQuery, 212 page.ShardID, 213 page.TreeID, 214 page.BranchID, 215 page.TreeID, 216 page.ShardID, 217 page.Limit, 218 ) 219 return rows, err 220 } 221 222 // DeleteFromHistoryTree deletes one or more rows from history_tree table 223 func (mdb *db) DeleteFromHistoryTree( 224 ctx context.Context, 225 filter sqlplugin.HistoryTreeDeleteFilter, 226 ) (sql.Result, error) { 227 return mdb.conn.ExecContext(ctx, 228 deleteHistoryTreeQuery, 229 filter.ShardID, 230 filter.TreeID, 231 filter.BranchID, 232 ) 233 }