aboutsummaryrefslogtreecommitdiff
path: root/refstore/files/transaction_lock.go
blob: e10c1a689071b8eca409b73c5aa361c9dc3407b0 (about) (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package files

import (
	"errors"
	"fmt"
	"os"
	"path"
	"strings"
	"time"
)

func (tx *Transaction) createLock(name refPath) error {
	root := tx.store.rootFor(name.root)
	dir := path.Dir(name.path)

	if dir != "." {
		err := root.MkdirAll(dir, 0o755)
		if err != nil {
			return err
		}
	}

	file, err := root.OpenFile(name.path+".lock", os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0o644)
	if err != nil {
		return err
	}

	return file.Close()
}

func (tx *Transaction) createPackedLock() error {
	const (
		initialBackoffMs     = 1
		backoffMaxMultiplier = 1000
	)

	timeout := tx.store.packedRefsTimeout
	deadline := time.Now().Add(timeout)
	multiplier := 1
	n := 1

	for {
		file, err := tx.store.commonRoot.OpenFile("packed-refs.lock", os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0o644)
		if err == nil {
			return file.Close()
		}

		if !errors.Is(err, os.ErrExist) {
			return err
		}

		if timeout == 0 || (timeout > 0 && time.Now().After(deadline)) {
			return err
		}

		backoffMs := multiplier * initialBackoffMs
		waitMs := (750 + tx.store.lockRand.Intn(500)) * backoffMs / 1000
		time.Sleep(time.Duration(waitMs) * time.Millisecond)

		multiplier += 2*n + 1
		if multiplier > backoffMaxMultiplier {
			multiplier = backoffMaxMultiplier
		} else {
			n++
		}
	}
}

func (tx *Transaction) targetKey(name refPath) string {
	return fmt.Sprintf("%d:%s", name.root, name.path)
}

func refPathFromKey(key string) refPath {
	rootValue, pathValue, ok := strings.Cut(key, ":")
	if !ok || rootValue == "" {
		return refPath{root: rootCommon, path: key}
	}

	if rootValue == "0" {
		return refPath{root: rootGit, path: pathValue}
	}

	return refPath{root: rootCommon, path: pathValue}
}