1package cache
2
3import (
4 "sync"
5
6 "github.com/git-bug/git-bug/entity/dag"
7 "github.com/git-bug/git-bug/repository"
8)
9
10var _ dag.Interface[dag.Snapshot, dag.OperationWithApply[dag.Snapshot]] = &withSnapshot[dag.Snapshot, dag.OperationWithApply[dag.Snapshot]]{}
11
12// withSnapshot encapsulate an entity and maintain a snapshot efficiently.
13type withSnapshot[SnapT dag.Snapshot, OpT dag.OperationWithApply[SnapT]] struct {
14 dag.Interface[SnapT, OpT]
15 mu sync.Mutex
16 snap *SnapT
17}
18
19func (ws *withSnapshot[SnapT, OpT]) Compile() SnapT {
20 ws.mu.Lock()
21 defer ws.mu.Unlock()
22 if ws.snap == nil {
23 snap := ws.Interface.Compile()
24 ws.snap = &snap
25 }
26 return *ws.snap
27}
28
29// Append intercept Bug.Append() to update the snapshot efficiently
30func (ws *withSnapshot[SnapT, OpT]) Append(op OpT) {
31 ws.mu.Lock()
32 defer ws.mu.Unlock()
33
34 ws.Interface.Append(op)
35
36 if ws.snap == nil {
37 return
38 }
39
40 op.Apply(*ws.snap)
41 (*ws.snap).AppendOperation(op)
42}
43
44// Commit intercept Bug.Commit() to update the snapshot efficiently
45func (ws *withSnapshot[SnapT, OpT]) Commit(repo repository.ClockedRepo) error {
46 ws.mu.Lock()
47 defer ws.mu.Unlock()
48
49 err := ws.Interface.Commit(repo)
50 if err != nil {
51 ws.snap = nil
52 return err
53 }
54
55 return nil
56}