Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWill Chandler <wchandler@gitlab.com>2023-05-23 19:04:20 +0300
committerWill Chandler <wchandler@gitlab.com>2023-05-23 19:04:20 +0300
commit42b707da5e621f5e43d910f7eecf7887acde8b86 (patch)
tree3c54c91102f1efc5eb1fb21f534c37552e2302c4
parentc5238107b9d331c75918d6752c51d895e803a083 (diff)
parente65535f8b5b157a6c04f5fa6c302400f3f20dd8c (diff)
Merge branch 'smh-forced-reference-updates' into 'master'
Allow forcing reference updates in TransactionManager Closes #5141 See merge request https://gitlab.com/gitlab-org/gitaly/-/merge_requests/5800 Merged-by: Will Chandler <wchandler@gitlab.com> Approved-by: Toon Claes <toon@gitlab.com> Approved-by: Will Chandler <wchandler@gitlab.com> Co-authored-by: Sami Hiltunen <shiltunen@gitlab.com>
-rw-r--r--internal/gitaly/transaction_manager.go45
-rw-r--r--internal/gitaly/transaction_manager_test.go87
2 files changed, 111 insertions, 21 deletions
diff --git a/internal/gitaly/transaction_manager.go b/internal/gitaly/transaction_manager.go
index 4fecda296..4e2060dcf 100644
--- a/internal/gitaly/transaction_manager.go
+++ b/internal/gitaly/transaction_manager.go
@@ -93,6 +93,9 @@ func (index LogIndex) String() string {
// ReferenceUpdate describes the state of a reference's old and new tip in an update.
type ReferenceUpdate struct {
+ // Force indicates this is a forced reference update. If set, the reference is pointed
+ // to the new value regardless of the old value.
+ Force bool
// OldOID is the old OID the reference is expected to point to prior to updating it.
// If the reference does not point to the old value, the reference verification fails.
OldOID git.ObjectID
@@ -1027,7 +1030,7 @@ func packFilePathForLogIndex(repoPath string, index LogIndex) string {
// It returns the write-ahead log entry for the transaction if it was successfully verified.
func (mgr *TransactionManager) verifyReferences(ctx context.Context, transaction *Transaction) ([]*gitalypb.LogEntry_ReferenceUpdate, error) {
var referenceUpdates []*gitalypb.LogEntry_ReferenceUpdate
- for referenceName, tips := range transaction.referenceUpdates {
+ for referenceName, update := range transaction.referenceUpdates {
// 'git update-ref' doesn't ensure the loose references end up in the
// refs directory so we enforce that here.
if !strings.HasPrefix(referenceName.String(), "refs/") {
@@ -1043,33 +1046,35 @@ func (mgr *TransactionManager) verifyReferences(ctx context.Context, transaction
}
}
- actualOldTip, err := transaction.stagingRepository.ResolveRevision(ctx, referenceName.Revision())
- if errors.Is(err, git.ErrReferenceNotFound) {
- objectHash, err := transaction.stagingRepository.ObjectHash(ctx)
- if err != nil {
- return nil, fmt.Errorf("object hash: %w", err)
- }
-
- actualOldTip = objectHash.ZeroOID
- } else if err != nil {
- return nil, fmt.Errorf("resolve revision: %w", err)
- }
+ if !update.Force {
+ actualOldTip, err := transaction.stagingRepository.ResolveRevision(ctx, referenceName.Revision())
+ if errors.Is(err, git.ErrReferenceNotFound) {
+ objectHash, err := transaction.stagingRepository.ObjectHash(ctx)
+ if err != nil {
+ return nil, fmt.Errorf("object hash: %w", err)
+ }
- if tips.OldOID != actualOldTip {
- if transaction.skipVerificationFailures {
- continue
+ actualOldTip = objectHash.ZeroOID
+ } else if err != nil {
+ return nil, fmt.Errorf("resolve revision: %w", err)
}
- return nil, ReferenceVerificationError{
- ReferenceName: referenceName,
- ExpectedOID: tips.OldOID,
- ActualOID: actualOldTip,
+ if update.OldOID != actualOldTip {
+ if transaction.skipVerificationFailures {
+ continue
+ }
+
+ return nil, ReferenceVerificationError{
+ ReferenceName: referenceName,
+ ExpectedOID: update.OldOID,
+ ActualOID: actualOldTip,
+ }
}
}
referenceUpdates = append(referenceUpdates, &gitalypb.LogEntry_ReferenceUpdate{
ReferenceName: []byte(referenceName),
- NewOid: []byte(tips.NewOID),
+ NewOid: []byte(update.NewOID),
})
}
diff --git a/internal/gitaly/transaction_manager_test.go b/internal/gitaly/transaction_manager_test.go
index b8fb7c073..92eb248d3 100644
--- a/internal/gitaly/transaction_manager_test.go
+++ b/internal/gitaly/transaction_manager_test.go
@@ -2629,6 +2629,91 @@ func TestTransactionManager(t *testing.T) {
RepositoryDoesntExist: true,
},
},
+ {
+ desc: "forced reference creation succeeds",
+ steps: steps{
+ StartManager{},
+ Begin{},
+ Commit{
+ ReferenceUpdates: ReferenceUpdates{
+ "refs/heads/main": {Force: true, NewOID: setup.Commits.First.OID},
+ },
+ },
+ },
+ expectedState: StateAssertion{
+ DefaultBranch: "refs/heads/main",
+ References: []git.Reference{{Name: "refs/heads/main", Target: setup.Commits.First.OID.String()}},
+ Database: DatabaseState{
+ string(keyAppliedLogIndex(relativePath)): LogIndex(1).toProto(),
+ },
+ },
+ },
+ {
+ desc: "forced reference update succeeds",
+ steps: steps{
+ StartManager{},
+ Begin{
+ TransactionID: 1,
+ },
+ Commit{
+ TransactionID: 1,
+ ReferenceUpdates: ReferenceUpdates{
+ "refs/heads/main": {OldOID: setup.ObjectHash.ZeroOID, NewOID: setup.Commits.First.OID},
+ },
+ },
+ Begin{
+ TransactionID: 2,
+ ExpectedSnapshot: Snapshot{
+ ReadIndex: 1,
+ },
+ },
+ Commit{
+ TransactionID: 2,
+ ReferenceUpdates: ReferenceUpdates{
+ "refs/heads/main": {Force: true, NewOID: setup.Commits.Second.OID},
+ },
+ },
+ },
+ expectedState: StateAssertion{
+ DefaultBranch: "refs/heads/main",
+ References: []git.Reference{{Name: "refs/heads/main", Target: setup.Commits.Second.OID.String()}},
+ Database: DatabaseState{
+ string(keyAppliedLogIndex(relativePath)): LogIndex(2).toProto(),
+ },
+ },
+ },
+ {
+ desc: "forced reference deletion succeeds",
+ steps: steps{
+ StartManager{},
+ Begin{
+ TransactionID: 1,
+ },
+ Commit{
+ TransactionID: 1,
+ ReferenceUpdates: ReferenceUpdates{
+ "refs/heads/main": {OldOID: setup.ObjectHash.ZeroOID, NewOID: setup.Commits.First.OID},
+ },
+ },
+ Begin{
+ TransactionID: 2,
+ ExpectedSnapshot: Snapshot{
+ ReadIndex: 1,
+ },
+ },
+ Commit{
+ TransactionID: 2,
+ ReferenceUpdates: ReferenceUpdates{
+ "refs/heads/main": {Force: true, NewOID: setup.ObjectHash.ZeroOID},
+ },
+ },
+ },
+ expectedState: StateAssertion{
+ Database: DatabaseState{
+ string(keyAppliedLogIndex(relativePath)): LogIndex(2).toProto(),
+ },
+ },
+ },
}
type invalidReferenceTestCase struct {
@@ -2657,7 +2742,7 @@ func TestTransactionManager(t *testing.T) {
Begin{},
Commit{
ReferenceUpdates: ReferenceUpdates{
- tc.referenceName: {OldOID: setup.ObjectHash.ZeroOID, NewOID: setup.Commits.First.OID},
+ tc.referenceName: {Force: true, NewOID: setup.Commits.First.OID},
},
ExpectedError: err,
},