go.temporal.io/server@v1.23.0/common/persistence/versionhistory/version_histories.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 "go.temporal.io/api/serviceerror" 29 30 historyspb "go.temporal.io/server/api/history/v1" 31 ) 32 33 // NewVersionHistories create a new instance of VersionHistories. 34 func NewVersionHistories(versionHistory *historyspb.VersionHistory) *historyspb.VersionHistories { 35 if versionHistory == nil { 36 panic("version history cannot be null") 37 } 38 39 return &historyspb.VersionHistories{ 40 CurrentVersionHistoryIndex: 0, 41 Histories: []*historyspb.VersionHistory{versionHistory}, 42 } 43 } 44 45 // Copy VersionHistories. 46 func CopyVersionHistories(h *historyspb.VersionHistories) *historyspb.VersionHistories { 47 var histories []*historyspb.VersionHistory 48 for _, history := range h.Histories { 49 histories = append(histories, CopyVersionHistory(history)) 50 } 51 52 return &historyspb.VersionHistories{ 53 CurrentVersionHistoryIndex: h.CurrentVersionHistoryIndex, 54 Histories: histories, 55 } 56 } 57 58 // GetVersionHistory gets the VersionHistory according to index provided. 59 func GetVersionHistory(h *historyspb.VersionHistories, index int32) (*historyspb.VersionHistory, error) { 60 if index < 0 || index >= int32(len(h.Histories)) { 61 return nil, serviceerror.NewInternal("version histories index is out of range.") 62 } 63 64 return h.Histories[index], nil 65 } 66 67 // AddVersionHistory adds a VersionHistory and return the whether current branch is changed. 68 func AddVersionHistory(h *historyspb.VersionHistories, v *historyspb.VersionHistory) (bool, int32, error) { 69 if v == nil { 70 return false, 0, serviceerror.NewInternal("version histories is null.") 71 } 72 73 // assuming existing version histories inside are valid 74 incomingFirstItem, err := GetFirstVersionHistoryItem(v) 75 if err != nil { 76 return false, 0, err 77 } 78 79 currentVersionHistory, err := GetVersionHistory(h, h.CurrentVersionHistoryIndex) 80 if err != nil { 81 return false, 0, err 82 } 83 currentFirstItem, err := GetFirstVersionHistoryItem(currentVersionHistory) 84 if err != nil { 85 return false, 0, err 86 } 87 88 if incomingFirstItem.Version != currentFirstItem.Version { 89 return false, 0, serviceerror.NewInternal("version history first item does not match.") 90 } 91 92 // TODO maybe we need more strict validation 93 94 newVersionHistory := CopyVersionHistory(v) 95 h.Histories = append(h.Histories, newVersionHistory) 96 newVersionHistoryIndex := int32(len(h.Histories)) - 1 97 98 // check if need to switch current branch 99 newLastItem, err := GetLastVersionHistoryItem(newVersionHistory) 100 if err != nil { 101 return false, 0, err 102 } 103 currentLastItem, err := GetLastVersionHistoryItem(currentVersionHistory) 104 if err != nil { 105 return false, 0, err 106 } 107 108 currentBranchChanged := false 109 if newLastItem.Version > currentLastItem.Version { 110 currentBranchChanged = true 111 h.CurrentVersionHistoryIndex = newVersionHistoryIndex 112 } 113 return currentBranchChanged, newVersionHistoryIndex, nil 114 } 115 116 // FindLCAVersionHistoryItemAndIndex finds the lowest common ancestor VersionHistory index and corresponding item. 117 func FindLCAVersionHistoryItemAndIndex(h *historyspb.VersionHistories, incomingHistory *historyspb.VersionHistory) (*historyspb.VersionHistoryItem, int32, error) { 118 var versionHistoryIndex int32 119 var versionHistoryLength int32 120 var versionHistoryItem *historyspb.VersionHistoryItem 121 122 for index, localHistory := range h.Histories { 123 item, err := FindLCAVersionHistoryItem(localHistory, incomingHistory) 124 if err != nil { 125 return nil, 0, err 126 } 127 128 // if not set 129 if versionHistoryItem == nil || 130 // if seeing LCA item with higher event ID 131 item.GetEventId() > versionHistoryItem.GetEventId() || 132 // if seeing LCA item with equal event ID but shorter history 133 (item.GetEventId() == versionHistoryItem.GetEventId() && int32(len(localHistory.Items)) < versionHistoryLength) { 134 135 versionHistoryIndex = int32(index) 136 versionHistoryLength = int32(len(localHistory.Items)) 137 versionHistoryItem = item 138 } 139 } 140 return CopyVersionHistoryItem(versionHistoryItem), versionHistoryIndex, nil 141 } 142 143 // FindFirstVersionHistoryIndexByVersionHistoryItem find the first VersionHistory index which contains the given version history item. 144 func FindFirstVersionHistoryIndexByVersionHistoryItem(h *historyspb.VersionHistories, item *historyspb.VersionHistoryItem) (int32, error) { 145 for versionHistoryIndex, history := range h.Histories { 146 if ContainsVersionHistoryItem(history, item) { 147 return int32(versionHistoryIndex), nil 148 } 149 } 150 return 0, serviceerror.NewInternal("version histories does not contains given item.") 151 } 152 153 // IsVersionHistoriesRebuilt returns true if the current branch index's last write version is not the largest among all branches' last write version. 154 func IsVersionHistoriesRebuilt(h *historyspb.VersionHistories) (bool, error) { 155 currentVersionHistory, err := GetCurrentVersionHistory(h) 156 if err != nil { 157 return false, err 158 } 159 160 currentLastItem, err := GetLastVersionHistoryItem(currentVersionHistory) 161 if err != nil { 162 return false, err 163 } 164 165 for _, versionHistory := range h.Histories { 166 lastItem, err := GetLastVersionHistoryItem(versionHistory) 167 if err != nil { 168 return false, err 169 } 170 if lastItem.GetVersion() > currentLastItem.GetVersion() { 171 return true, nil 172 } 173 } 174 175 return false, nil 176 } 177 178 // SetCurrentVersionHistoryIndex set the current VersionHistory index. 179 func SetCurrentVersionHistoryIndex(h *historyspb.VersionHistories, currentVersionHistoryIndex int32) error { 180 if currentVersionHistoryIndex < 0 || currentVersionHistoryIndex >= int32(len(h.Histories)) { 181 return serviceerror.NewInternal("invalid current version history index.") 182 } 183 184 h.CurrentVersionHistoryIndex = currentVersionHistoryIndex 185 return nil 186 } 187 188 // GetCurrentVersionHistory gets the current VersionHistory. 189 func GetCurrentVersionHistory(h *historyspb.VersionHistories) (*historyspb.VersionHistory, error) { 190 return GetVersionHistory(h, h.GetCurrentVersionHistoryIndex()) 191 }