go.temporal.io/server@v1.23.0/common/persistence/queue_v2_util.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 persistence 26 27 import ( 28 "fmt" 29 30 "go.temporal.io/api/serviceerror" 31 32 persistencespb "go.temporal.io/server/api/persistence/v1" 33 ) 34 35 const ( 36 // pageTokenPrefixByte is the first byte of the serialized page token. It's used to ensure that the page token is 37 // not empty. Without this, if the last_read_message_id is 0, the serialized page token would be empty, and clients 38 // could erroneously assume that there are no more messages beyond the first page. This is purely used to ensure 39 // that tokens are non-empty; it is not used to verify that the token is valid like the magic byte in some other 40 // protocols. 41 pageTokenPrefixByte = 0 42 ) 43 44 func GetNextPageTokenForReadMessages(result []QueueV2Message) []byte { 45 if len(result) == 0 { 46 return nil 47 } 48 lastReadMessageID := result[len(result)-1].MetaData.ID 49 token := &persistencespb.ReadQueueMessagesNextPageToken{ 50 LastReadMessageId: lastReadMessageID, 51 } 52 // This can never fail if you inspect the implementation. 53 b, _ := token.Marshal() 54 55 // See the comment above pageTokenPrefixByte for why we want to do this. 56 return append([]byte{pageTokenPrefixByte}, b...) 57 } 58 59 func GetMinMessageIDToReadForQueueV2( 60 queueType QueueV2Type, 61 queueName string, 62 nextPageToken []byte, 63 queue *persistencespb.Queue, 64 ) (int64, error) { 65 if len(nextPageToken) == 0 { 66 partition, err := GetPartitionForQueueV2(queueType, queueName, queue) 67 if err != nil { 68 return 0, err 69 } 70 return partition.MinMessageId, nil 71 } 72 var token persistencespb.ReadQueueMessagesNextPageToken 73 74 // Skip the first byte. See the comment on pageTokenPrefixByte for more details. 75 err := token.Unmarshal(nextPageToken[1:]) 76 if err != nil { 77 return 0, fmt.Errorf( 78 "%w: %q: %v", 79 ErrInvalidReadQueueMessagesNextPageToken, 80 nextPageToken, 81 err, 82 ) 83 } 84 return token.LastReadMessageId + 1, nil 85 } 86 87 func GetNextPageTokenForListQueues(queueNumber int64) []byte { 88 token := &persistencespb.ListQueuesNextPageToken{ 89 LastReadQueueNumber: queueNumber, 90 } 91 // This can never fail if you inspect the implementation. 92 b, _ := token.Marshal() 93 94 // See the comment above pageTokenPrefixByte for why we want to do this. 95 return append([]byte{pageTokenPrefixByte}, b...) 96 } 97 98 func GetOffsetForListQueues( 99 nextPageToken []byte, 100 ) (int64, error) { 101 if len(nextPageToken) == 0 { 102 return 0, nil 103 } 104 var token persistencespb.ListQueuesNextPageToken 105 106 // Skip the first byte. See the comment on pageTokenPrefixByte for more details. 107 err := token.Unmarshal(nextPageToken[1:]) 108 if err != nil { 109 return 0, fmt.Errorf( 110 "%w: %q: %v", 111 ErrInvalidListQueuesNextPageToken, 112 nextPageToken, 113 err, 114 ) 115 } 116 return token.LastReadQueueNumber, nil 117 } 118 119 func GetPartitionForQueueV2( 120 queueType QueueV2Type, 121 queueName string, 122 queue *persistencespb.Queue, 123 ) (*persistencespb.QueuePartition, error) { 124 // Currently, we only have one partition for each queue. However, that might change in the future. If a queue is 125 // created with more than 1 partition by a server on a future release, and then that server is downgraded, we 126 // will need to handle this case. Since all DLQ tasks are retried infinitely, we just return an error. 127 numPartitions := len(queue.Partitions) 128 if numPartitions != 1 { 129 return nil, serviceerror.NewInternal( 130 fmt.Sprintf( 131 "queue without single partition detected. queue with type %v and queueName %v has %d partitions, "+ 132 "but this implementation only supports queues with 1 partition. Did you downgrade your Temporal server?", 133 queueType, 134 queueName, 135 numPartitions, 136 ), 137 ) 138 } 139 partition := queue.Partitions[0] 140 return partition, nil 141 } 142 143 type DeleteRequest struct { 144 // LastIDToDeleteInclusive represents the maximum message ID that the user wants to delete, inclusive. 145 LastIDToDeleteInclusive int64 146 // ExistingMessageRange represents an inclusive range of the minimum message ID and the maximum message ID in the queue. 147 ExistingMessageRange InclusiveMessageRange 148 } 149 150 type InclusiveMessageRange struct { 151 MinMessageID int64 152 MaxMessageID int64 153 } 154 155 type DeleteRange struct { 156 InclusiveMessageRange 157 NewMinMessageID int64 158 MessagesToDelete int64 159 } 160 161 // GetDeleteRange returns the range of messages to delete, and a boolean indicating whether there is any update to be 162 // made: meaning either we should delete messages, update the min message ID, or both. 163 func GetDeleteRange(request DeleteRequest) (DeleteRange, bool) { 164 if request.LastIDToDeleteInclusive < request.ExistingMessageRange.MinMessageID { 165 // Nothing to delete 166 return DeleteRange{}, false 167 } 168 return DeleteRange{ 169 InclusiveMessageRange: InclusiveMessageRange{ 170 MinMessageID: request.ExistingMessageRange.MinMessageID, 171 // Never actually delete the last message 172 MaxMessageID: min(request.LastIDToDeleteInclusive, request.ExistingMessageRange.MaxMessageID-1), 173 }, 174 NewMinMessageID: min(request.LastIDToDeleteInclusive, request.ExistingMessageRange.MaxMessageID) + 1, 175 MessagesToDelete: min(request.LastIDToDeleteInclusive, request.ExistingMessageRange.MaxMessageID) - request.ExistingMessageRange.MinMessageID + 1, 176 }, true 177 }