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
104
105
106
107
108
109
110
111
|
package cache
import (
"sync"
"github.com/MichaelMure/git-bug/entity"
"github.com/MichaelMure/git-bug/entity/dag"
"github.com/MichaelMure/git-bug/repository"
"github.com/MichaelMure/git-bug/util/lamport"
)
var _ CacheEntity = &CachedEntityBase[dag.Snapshot, dag.Operation]{}
// CachedEntityBase provide the base function of an entity managed by the cache.
type CachedEntityBase[SnapT dag.Snapshot, OpT dag.Operation] struct {
repo repository.ClockedRepo
entityUpdated func(id entity.Id) error
getUserIdentity getUserIdentityFunc
mu sync.RWMutex
entity dag.Interface[SnapT, OpT]
}
func (e *CachedEntityBase[SnapT, OpT]) Id() entity.Id {
return e.entity.Id()
}
func (e *CachedEntityBase[SnapT, OpT]) Snapshot() SnapT {
e.mu.RLock()
defer e.mu.RUnlock()
return e.entity.Compile()
}
func (e *CachedEntityBase[SnapT, OpT]) notifyUpdated() error {
return e.entityUpdated(e.entity.Id())
}
// ResolveOperationWithMetadata will find an operation that has the matching metadata
func (e *CachedEntityBase[SnapT, OpT]) ResolveOperationWithMetadata(key string, value string) (entity.Id, error) {
e.mu.RLock()
defer e.mu.RUnlock()
// preallocate but empty
matching := make([]entity.Id, 0, 5)
for _, op := range e.entity.Operations() {
opValue, ok := op.GetMetadata(key)
if ok && value == opValue {
matching = append(matching, op.Id())
}
}
if len(matching) == 0 {
return "", ErrNoMatchingOp
}
if len(matching) > 1 {
return "", entity.NewErrMultipleMatch("operation", matching)
}
return matching[0], nil
}
func (e *CachedEntityBase[SnapT, OpT]) Validate() error {
e.mu.RLock()
defer e.mu.RUnlock()
return e.entity.Validate()
}
func (e *CachedEntityBase[SnapT, OpT]) Commit() error {
e.mu.Lock()
err := e.entity.Commit(e.repo)
if err != nil {
e.mu.Unlock()
return err
}
e.mu.Unlock()
return e.notifyUpdated()
}
func (e *CachedEntityBase[SnapT, OpT]) CommitAsNeeded() error {
e.mu.Lock()
err := e.entity.CommitAsNeeded(e.repo)
if err != nil {
e.mu.Unlock()
return err
}
e.mu.Unlock()
return e.notifyUpdated()
}
func (e *CachedEntityBase[SnapT, OpT]) NeedCommit() bool {
e.mu.RLock()
defer e.mu.RUnlock()
return e.entity.NeedCommit()
}
func (e *CachedEntityBase[SnapT, OpT]) Lock() {
e.mu.Lock()
}
func (e *CachedEntityBase[SnapT, OpT]) CreateLamportTime() lamport.Time {
return e.entity.CreateLamportTime()
}
func (e *CachedEntityBase[SnapT, OpT]) EditLamportTime() lamport.Time {
return e.entity.EditLamportTime()
}
func (e *CachedEntityBase[SnapT, OpT]) FirstOp() OpT {
return e.entity.FirstOp()
}
|