with_snapshot.go

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