cached.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	"github.com/MichaelMure/git-bug/util/lamport"
 10)
 11
 12var _ entity.Interface[entity.Snapshot, dag.Operation] = &CachedEntityBase[entity.Snapshot, dag.Operation]{}
 13var _ CacheEntity = &CachedEntityBase[entity.Snapshot, dag.Operation]{}
 14
 15// CachedEntityBase provide the base function of an entity managed by the cache.
 16type CachedEntityBase[SnapT entity.Snapshot, OpT dag.Operation] struct {
 17	repo            repository.ClockedRepo
 18	entityUpdated   func(id entity.Id) error
 19	getUserIdentity getUserIdentityFunc
 20
 21	mu     sync.RWMutex
 22	entity entity.WithCommit[SnapT, OpT]
 23}
 24
 25func (e *CachedEntityBase[SnapT, OpT]) Id() entity.Id {
 26	return e.entity.Id()
 27}
 28
 29func (e *CachedEntityBase[SnapT, OpT]) Compile() SnapT {
 30	e.mu.RLock()
 31	defer e.mu.RUnlock()
 32	return e.entity.Compile()
 33}
 34
 35func (e *CachedEntityBase[SnapT, OpT]) notifyUpdated() error {
 36	return e.entityUpdated(e.entity.Id())
 37}
 38
 39// ResolveOperationWithMetadata will find an operation that has the matching metadata
 40func (e *CachedEntityBase[SnapT, OpT]) ResolveOperationWithMetadata(key string, value string) (entity.Id, error) {
 41	e.mu.RLock()
 42	defer e.mu.RUnlock()
 43	// preallocate but empty
 44	matching := make([]entity.Id, 0, 5)
 45
 46	for _, op := range e.entity.Operations() {
 47		opValue, ok := op.GetMetadata(key)
 48		if ok && value == opValue {
 49			matching = append(matching, op.Id())
 50		}
 51	}
 52
 53	if len(matching) == 0 {
 54		return "", ErrNoMatchingOp
 55	}
 56
 57	if len(matching) > 1 {
 58		return "", entity.NewErrMultipleMatch("operation", matching)
 59	}
 60
 61	return matching[0], nil
 62}
 63
 64func (e *CachedEntityBase[SnapT, OpT]) Validate() error {
 65	e.mu.RLock()
 66	defer e.mu.RUnlock()
 67	return e.entity.Validate()
 68}
 69
 70func (e *CachedEntityBase[SnapT, OpT]) Append(op OpT) {
 71	e.mu.Lock()
 72	defer e.mu.Unlock()
 73	e.entity.Append(op)
 74}
 75
 76func (e *CachedEntityBase[SnapT, OpT]) Operations() []OpT {
 77	e.mu.RLock()
 78	defer e.mu.RUnlock()
 79	return e.entity.Operations()
 80}
 81
 82func (e *CachedEntityBase[SnapT, OpT]) Commit() error {
 83	e.mu.Lock()
 84	err := e.entity.Commit(e.repo)
 85	if err != nil {
 86		e.mu.Unlock()
 87		return err
 88	}
 89	e.mu.Unlock()
 90	return e.notifyUpdated()
 91}
 92
 93func (e *CachedEntityBase[SnapT, OpT]) CommitAsNeeded() error {
 94	e.mu.Lock()
 95	err := e.entity.CommitAsNeeded(e.repo)
 96	if err != nil {
 97		e.mu.Unlock()
 98		return err
 99	}
100	e.mu.Unlock()
101	return e.notifyUpdated()
102}
103
104func (e *CachedEntityBase[SnapT, OpT]) NeedCommit() bool {
105	e.mu.RLock()
106	defer e.mu.RUnlock()
107	return e.entity.NeedCommit()
108}
109
110func (e *CachedEntityBase[SnapT, OpT]) Lock() {
111	e.mu.Lock()
112}
113
114func (e *CachedEntityBase[SnapT, OpT]) CreateLamportTime() lamport.Time {
115	return e.entity.CreateLamportTime()
116}
117
118func (e *CachedEntityBase[SnapT, OpT]) EditLamportTime() lamport.Time {
119	return e.entity.EditLamportTime()
120}
121
122func (e *CachedEntityBase[SnapT, OpT]) FirstOp() OpT {
123	return e.entity.FirstOp()
124}