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  }