go.temporal.io/server@v1.23.0/common/persistence/versionhistory/version_history.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 versionhistory 26 27 import ( 28 "fmt" 29 30 "go.temporal.io/api/serviceerror" 31 32 historyspb "go.temporal.io/server/api/history/v1" 33 "go.temporal.io/server/common" 34 ) 35 36 // NewVersionHistory create a new instance of VersionHistory. 37 func NewVersionHistory(branchToken []byte, items []*historyspb.VersionHistoryItem) *historyspb.VersionHistory { 38 return &historyspb.VersionHistory{ 39 BranchToken: branchToken, 40 Items: items, 41 } 42 } 43 44 // CopyVersionHistory copies VersionHistory. 45 func CopyVersionHistory(v *historyspb.VersionHistory) *historyspb.VersionHistory { 46 token := make([]byte, len(v.BranchToken)) 47 copy(token, v.BranchToken) 48 49 var items []*historyspb.VersionHistoryItem 50 for _, item := range v.Items { 51 items = append(items, CopyVersionHistoryItem(item)) 52 } 53 54 return NewVersionHistory(token, items) 55 } 56 57 // CopyVersionHistoryUntilLCAVersionHistoryItem returns copy of VersionHistory up until LCA item. 58 func CopyVersionHistoryUntilLCAVersionHistoryItem(v *historyspb.VersionHistory, lcaItem *historyspb.VersionHistoryItem) (*historyspb.VersionHistory, error) { 59 versionHistory := &historyspb.VersionHistory{} 60 notFoundErr := serviceerror.NewInternal("version history does not contains the LCA item.") 61 for _, item := range v.Items { 62 if item.Version < lcaItem.Version { 63 if err := AddOrUpdateVersionHistoryItem(versionHistory, item); err != nil { 64 return nil, err 65 } 66 } else if item.Version == lcaItem.Version { 67 if lcaItem.GetEventId() > item.GetEventId() { 68 return nil, notFoundErr 69 } 70 if err := AddOrUpdateVersionHistoryItem(versionHistory, lcaItem); err != nil { 71 return nil, err 72 } 73 return versionHistory, nil 74 } else { 75 return nil, notFoundErr 76 } 77 } 78 return nil, notFoundErr 79 } 80 81 // SetVersionHistoryBranchToken sets the branch token. 82 func SetVersionHistoryBranchToken(v *historyspb.VersionHistory, branchToken []byte) { 83 v.BranchToken = make([]byte, len(branchToken)) 84 copy(v.BranchToken, branchToken) 85 } 86 87 // AddOrUpdateVersionHistoryItem updates the VersionHistory with new VersionHistoryItem. 88 func AddOrUpdateVersionHistoryItem(v *historyspb.VersionHistory, item *historyspb.VersionHistoryItem) error { 89 if len(v.Items) == 0 { 90 v.Items = []*historyspb.VersionHistoryItem{CopyVersionHistoryItem(item)} 91 return nil 92 } 93 94 lastItem := v.Items[len(v.Items)-1] 95 if item.Version < lastItem.Version { 96 return serviceerror.NewInternal(fmt.Sprintf("cannot update version history with a lower version %v. Last version: %v", item.Version, lastItem.Version)) 97 } 98 99 if item.GetEventId() <= lastItem.GetEventId() { 100 return serviceerror.NewInternal(fmt.Sprintf("cannot add version history with a lower event id %v. Last event id: %v", item.GetEventId(), lastItem.GetEventId())) 101 } 102 103 if item.Version > lastItem.Version { 104 // Add a new history 105 v.Items = append(v.Items, CopyVersionHistoryItem(item)) 106 } else { 107 // item.Version == lastItem.Version && item.EventID > lastItem.EventID 108 // Update event ID 109 lastItem.EventId = item.GetEventId() 110 } 111 return nil 112 } 113 114 // ContainsVersionHistoryItem check whether VersionHistory has given VersionHistoryItem. 115 func ContainsVersionHistoryItem(v *historyspb.VersionHistory, item *historyspb.VersionHistoryItem) bool { 116 prevEventID := common.FirstEventID - 1 117 for _, currentItem := range v.Items { 118 if item.GetVersion() == currentItem.GetVersion() { 119 if prevEventID < item.GetEventId() && item.GetEventId() <= currentItem.GetEventId() { 120 return true 121 } 122 } else if item.GetVersion() < currentItem.GetVersion() { 123 return false 124 } 125 prevEventID = currentItem.GetEventId() 126 } 127 return false 128 } 129 130 // FindLCAVersionHistoryItem returns the lowest common ancestor VersionHistoryItem. 131 func FindLCAVersionHistoryItem(v *historyspb.VersionHistory, remote *historyspb.VersionHistory) (*historyspb.VersionHistoryItem, error) { 132 return FindLCAVersionHistoryItemFromItemSlice(v.Items, remote.Items) 133 } 134 135 func FindLCAVersionHistoryItemFromItemSlice(versionHistoryItemsA []*historyspb.VersionHistoryItem, versionHistoryItemsB []*historyspb.VersionHistoryItem) (*historyspb.VersionHistoryItem, error) { 136 aIndex := len(versionHistoryItemsA) - 1 137 bIndex := len(versionHistoryItemsB) - 1 138 139 for aIndex >= 0 && bIndex >= 0 { 140 aVersionItem := versionHistoryItemsA[aIndex] 141 bVersionItem := versionHistoryItemsB[bIndex] 142 143 if aVersionItem.Version == bVersionItem.Version { 144 if aVersionItem.GetEventId() > bVersionItem.GetEventId() { 145 return CopyVersionHistoryItem(bVersionItem), nil 146 } 147 return aVersionItem, nil 148 } else if aVersionItem.Version > bVersionItem.Version { 149 aIndex-- 150 } else { 151 // aVersionItem.Version < bVersionItem.Version 152 bIndex-- 153 } 154 } 155 156 return nil, serviceerror.NewInternal("version history is malformed. No joint point found.") 157 } 158 159 // IsVersionHistoryItemsInSameBranch checks if two version history items are in the same branch 160 func IsVersionHistoryItemsInSameBranch(versionHistoryItemsA []*historyspb.VersionHistoryItem, versionHistoryItemsB []*historyspb.VersionHistoryItem) bool { 161 lowestCommonAncestor, err := FindLCAVersionHistoryItemFromItemSlice(versionHistoryItemsA, versionHistoryItemsB) 162 if err != nil { 163 return false 164 } 165 166 aLastItem, err := getLastVersionHistoryItem(versionHistoryItemsA) 167 if err != nil { 168 return false 169 } 170 171 bLastItem, err := getLastVersionHistoryItem(versionHistoryItemsB) 172 if err != nil { 173 return false 174 } 175 176 return lowestCommonAncestor.Equal(aLastItem) || lowestCommonAncestor.Equal(bLastItem) 177 } 178 179 // IsLCAVersionHistoryItemAppendable checks if a LCA VersionHistoryItem is appendable. 180 func IsLCAVersionHistoryItemAppendable(v *historyspb.VersionHistory, lcaItem *historyspb.VersionHistoryItem) bool { 181 if len(v.Items) == 0 { 182 panic("version history not initialized") 183 } 184 if lcaItem == nil { 185 panic("lcaItem is nil") 186 } 187 188 return IsEqualVersionHistoryItem(v.Items[len(v.Items)-1], lcaItem) 189 } 190 191 // GetFirstVersionHistoryItem return the first VersionHistoryItem. 192 func GetFirstVersionHistoryItem(v *historyspb.VersionHistory) (*historyspb.VersionHistoryItem, error) { 193 if len(v.Items) == 0 { 194 return nil, serviceerror.NewInternal("version history is empty.") 195 } 196 return CopyVersionHistoryItem(v.Items[0]), nil 197 } 198 199 // GetLastVersionHistoryItem return the last VersionHistoryItem. 200 func GetLastVersionHistoryItem(v *historyspb.VersionHistory) (*historyspb.VersionHistoryItem, error) { 201 return getLastVersionHistoryItem(v.Items) 202 } 203 204 func getLastVersionHistoryItem(v []*historyspb.VersionHistoryItem) (*historyspb.VersionHistoryItem, error) { 205 if len(v) == 0 { 206 return nil, serviceerror.NewInternal("version history is empty.") 207 } 208 return CopyVersionHistoryItem(v[len(v)-1]), nil 209 } 210 211 // GetVersionHistoryEventVersion return the corresponding event version of an event ID. 212 func GetVersionHistoryEventVersion(v *historyspb.VersionHistory, eventID int64) (int64, error) { 213 lastItem, err := GetLastVersionHistoryItem(v) 214 if err != nil { 215 return 0, err 216 } 217 if eventID < common.FirstEventID || eventID > lastItem.GetEventId() { 218 return 0, serviceerror.NewInternal("input event ID is not in range.") 219 } 220 221 // items are sorted by eventID & version 222 // so the fist item with item event ID >= input event ID 223 // the item version is the result 224 for _, currentItem := range v.Items { 225 if eventID <= currentItem.GetEventId() { 226 return currentItem.GetVersion(), nil 227 } 228 } 229 return 0, serviceerror.NewInternal("input event ID is not in range.") 230 } 231 232 // IsEmptyVersionHistory indicate whether version history is empty 233 func IsEmptyVersionHistory(v *historyspb.VersionHistory) bool { 234 return len(v.Items) == 0 235 } 236 237 // CompareVersionHistory compares 2 version history items 238 func CompareVersionHistory(v1 *historyspb.VersionHistory, v2 *historyspb.VersionHistory) (int, error) { 239 lastItem1, err := GetLastVersionHistoryItem(v1) 240 if err != nil { 241 return 0, err 242 } 243 lastItem2, err := GetLastVersionHistoryItem(v2) 244 if err != nil { 245 return 0, err 246 } 247 return CompareVersionHistoryItem(lastItem1, lastItem2), nil 248 }