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.ReadWrite[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.ReadWrite[SnapT, OpT]
15 mu sync.Mutex
16 snap *SnapT
17}
18
19func newWithSnapshot[SnapT dag.Snapshot, OpT dag.OperationWithApply[SnapT]](readWrite dag.ReadWrite[SnapT, OpT]) *withSnapshot[SnapT, OpT] {
20 return &withSnapshot[SnapT, OpT]{ReadWrite: readWrite}
21}
22
23func (ws *withSnapshot[SnapT, OpT]) Snapshot() SnapT {
24 ws.mu.Lock()
25 defer ws.mu.Unlock()
26 if ws.snap == nil {
27 snap := ws.ReadWrite.Snapshot()
28 ws.snap = &snap
29 }
30 return *ws.snap
31}
32
33// Append intercept Bug.Append() to update the snapshot efficiently
34func (ws *withSnapshot[SnapT, OpT]) Append(op OpT) {
35 ws.mu.Lock()
36 defer ws.mu.Unlock()
37
38 ws.ReadWrite.Append(op)
39
40 if ws.snap == nil {
41 return
42 }
43
44 op.Apply(*ws.snap)
45 (*ws.snap).AppendOperation(op)
46}
47
48// Commit intercept Bug.Commit() to update the snapshot efficiently
49func (ws *withSnapshot[SnapT, OpT]) Commit(repo repository.ClockedRepo) error {
50 ws.mu.Lock()
51 defer ws.mu.Unlock()
52
53 err := ws.ReadWrite.Commit(repo)
54 if err != nil {
55 ws.snap = nil
56 return err
57 }
58
59 return nil
60}