with_snapshot.go

 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}