go.temporal.io/server@v1.23.0/common/persistence/sql/sqlplugin/mysql/queue.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" 32 "go.temporal.io/server/common/persistence/sql/sqlplugin" 33 ) 34 35 const ( 36 templateEnqueueMessageQuery = `INSERT INTO queue (queue_type, message_id, message_payload, message_encoding) VALUES(:queue_type, :message_id, :message_payload, :message_encoding)` 37 templateGetMessageQuery = `SELECT message_id, message_payload, message_encoding FROM queue WHERE queue_type = ? and message_id = ?` 38 templateGetMessagesQuery = `SELECT message_id, message_payload, message_encoding FROM queue WHERE queue_type = ? and message_id > ? and message_id <= ? ORDER BY message_id ASC LIMIT ?` 39 templateDeleteMessageQuery = `DELETE FROM queue WHERE queue_type = ? and message_id = ?` 40 templateRangeDeleteMessagesQuery = `DELETE FROM queue WHERE queue_type = ? and message_id > ? and message_id <= ?` 41 42 // Note that even though this query takes a range lock that serializes all writes, it will return multiple rows 43 // whenever more than one enqueue-er blocks. This is why we max(). 44 templateGetLastMessageIDQuery = `SELECT MAX(message_id) FROM queue WHERE message_id >= (SELECT message_id FROM queue WHERE queue_type=? ORDER BY message_id DESC LIMIT 1) FOR UPDATE` 45 46 templateCreateQueueMetadataQuery = `INSERT INTO queue_metadata (queue_type, data, data_encoding, version) VALUES(:queue_type, :data, :data_encoding, :version)` 47 templateUpdateQueueMetadataQuery = `UPDATE queue_metadata SET data = :data, data_encoding = :data_encoding, version= :version+1 WHERE queue_type = :queue_type and version = :version` 48 templateGetQueueMetadataQuery = `SELECT data, data_encoding, version from queue_metadata WHERE queue_type = ?` 49 templateLockQueueMetadataQuery = templateGetQueueMetadataQuery + " FOR UPDATE" 50 ) 51 52 // InsertIntoMessages inserts a new row into queue table 53 func (mdb *db) InsertIntoMessages( 54 ctx context.Context, 55 row []sqlplugin.QueueMessageRow, 56 ) (sql.Result, error) { 57 return mdb.conn.NamedExecContext(ctx, 58 templateEnqueueMessageQuery, 59 row, 60 ) 61 } 62 63 func (mdb *db) SelectFromMessages( 64 ctx context.Context, 65 filter sqlplugin.QueueMessagesFilter, 66 ) ([]sqlplugin.QueueMessageRow, error) { 67 var rows []sqlplugin.QueueMessageRow 68 err := mdb.conn.SelectContext(ctx, 69 &rows, 70 templateGetMessageQuery, 71 filter.QueueType, 72 filter.MessageID, 73 ) 74 return rows, err 75 } 76 77 func (mdb *db) RangeSelectFromMessages( 78 ctx context.Context, 79 filter sqlplugin.QueueMessagesRangeFilter, 80 ) ([]sqlplugin.QueueMessageRow, error) { 81 var rows []sqlplugin.QueueMessageRow 82 err := mdb.conn.SelectContext(ctx, 83 &rows, 84 templateGetMessagesQuery, 85 filter.QueueType, 86 filter.MinMessageID, 87 filter.MaxMessageID, 88 filter.PageSize, 89 ) 90 return rows, err 91 } 92 93 // DeleteFromMessages deletes message with a messageID from the queue 94 func (mdb *db) DeleteFromMessages( 95 ctx context.Context, 96 filter sqlplugin.QueueMessagesFilter, 97 ) (sql.Result, error) { 98 return mdb.conn.ExecContext(ctx, 99 templateDeleteMessageQuery, 100 filter.QueueType, 101 filter.MessageID, 102 ) 103 } 104 105 // RangeDeleteFromMessages deletes messages before messageID from the queue 106 func (mdb *db) RangeDeleteFromMessages( 107 ctx context.Context, 108 filter sqlplugin.QueueMessagesRangeFilter, 109 ) (sql.Result, error) { 110 return mdb.conn.ExecContext(ctx, 111 templateRangeDeleteMessagesQuery, 112 filter.QueueType, 113 filter.MinMessageID, 114 filter.MaxMessageID, 115 ) 116 } 117 118 // GetLastEnqueuedMessageIDForUpdate returns the last enqueued message ID 119 func (mdb *db) GetLastEnqueuedMessageIDForUpdate( 120 ctx context.Context, 121 queueType persistence.QueueType, 122 ) (int64, error) { 123 var lastMessageID *int64 124 err := mdb.conn.GetContext(ctx, 125 &lastMessageID, 126 templateGetLastMessageIDQuery, 127 queueType, 128 ) 129 if lastMessageID == nil { 130 // The layer of code above us expects ErrNoRows when the queue is empty. MAX() yields 131 // null when the queue is empty, so we need to turn that into the correct error. 132 return 0, sql.ErrNoRows 133 } else { 134 return *lastMessageID, err 135 } 136 } 137 138 func (mdb *db) InsertIntoQueueMetadata( 139 ctx context.Context, 140 row *sqlplugin.QueueMetadataRow, 141 ) (sql.Result, error) { 142 return mdb.conn.NamedExecContext(ctx, 143 templateCreateQueueMetadataQuery, 144 row, 145 ) 146 } 147 148 func (mdb *db) UpdateQueueMetadata( 149 ctx context.Context, 150 row *sqlplugin.QueueMetadataRow, 151 ) (sql.Result, error) { 152 return mdb.conn.NamedExecContext(ctx, 153 templateUpdateQueueMetadataQuery, 154 row, 155 ) 156 } 157 158 func (mdb *db) SelectFromQueueMetadata( 159 ctx context.Context, 160 filter sqlplugin.QueueMetadataFilter, 161 ) (*sqlplugin.QueueMetadataRow, error) { 162 var row sqlplugin.QueueMetadataRow 163 err := mdb.conn.GetContext(ctx, 164 &row, 165 templateGetQueueMetadataQuery, 166 filter.QueueType, 167 ) 168 if err != nil { 169 return nil, err 170 } 171 return &row, nil 172 } 173 174 func (mdb *db) LockQueueMetadata( 175 ctx context.Context, 176 filter sqlplugin.QueueMetadataFilter, 177 ) (*sqlplugin.QueueMetadataRow, error) { 178 var row sqlplugin.QueueMetadataRow 179 err := mdb.conn.GetContext(ctx, 180 &row, 181 templateLockQueueMetadataQuery, 182 filter.QueueType, 183 ) 184 if err != nil { 185 return nil, err 186 } 187 return &row, nil 188 }