File: cache.go

package info (click to toggle)
git-lfs 3.6.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 4,808 kB
  • sloc: sh: 21,256; makefile: 507; ruby: 417
file content (103 lines) | stat: -rw-r--r-- 2,268 bytes parent folder | download | duplicates (2)
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package locking

import (
	"strings"

	"github.com/git-lfs/git-lfs/v3/tools/kv"
)

const (
	// We want to use a single cache file for integrity, but to make it easy to
	// list all locks, prefix the id->path map in a way we can identify (something
	// that won't be in a path)
	idKeyPrefix string = "*id*://"
)

type LockCache struct {
	kv *kv.Store
}

func NewLockCache(filepath string) (*LockCache, error) {
	kv, err := kv.NewStore(filepath)
	if err != nil {
		return nil, err
	}
	return &LockCache{kv}, nil
}

// Cache a successful lock for faster local lookup later
func (c *LockCache) Add(l Lock) error {
	// Store reference in both directions
	// Path -> Lock
	c.kv.Set(l.Path, &l)
	// EncodedId -> Lock (encoded so we can easily identify)
	c.kv.Set(c.encodeIdKey(l.Id), &l)
	return nil
}

// Remove a cached lock by path because it's been relinquished
func (c *LockCache) RemoveByPath(filePath string) error {
	ilock := c.kv.Get(filePath)
	if lock, ok := ilock.(*Lock); ok && lock != nil {
		c.kv.Remove(lock.Path)
		// Id as key is encoded
		c.kv.Remove(c.encodeIdKey(lock.Id))
	}
	return nil
}

// Remove a cached lock by id because it's been relinquished
func (c *LockCache) RemoveById(id string) error {
	// Id as key is encoded
	idkey := c.encodeIdKey(id)
	ilock := c.kv.Get(idkey)
	if lock, ok := ilock.(*Lock); ok && lock != nil {
		c.kv.Remove(idkey)
		c.kv.Remove(lock.Path)
	}
	return nil
}

// Get the list of cached locked files
func (c *LockCache) Locks() []Lock {
	var locks []Lock
	c.kv.Visit(func(key string, val interface{}) bool {
		// Only report file->id entries not reverse
		if !c.isIdKey(key) {
			lock := val.(*Lock)
			locks = append(locks, *lock)
		}
		return true // continue
	})
	return locks
}

// Clear the cache
func (c *LockCache) Clear() {
	c.kv.RemoveAll()
}

// Save the cache
func (c *LockCache) Save() error {
	return c.kv.Save()
}

func (c *LockCache) encodeIdKey(id string) string {
	// Safety against accidents
	if !c.isIdKey(id) {
		return idKeyPrefix + id
	}
	return id
}

func (c *LockCache) decodeIdKey(key string) string {
	// Safety against accidents
	if c.isIdKey(key) {
		return key[len(idKeyPrefix):]
	}
	return key
}

func (c *LockCache) isIdKey(key string) bool {
	return strings.HasPrefix(key, idKeyPrefix)
}