cached.go

  1package cache
  2
  3import (
  4	"sync"
  5
  6	"github.com/git-bug/git-bug/entity"
  7	"github.com/git-bug/git-bug/entity/dag"
  8	"github.com/git-bug/git-bug/repository"
  9	"github.com/git-bug/git-bug/util/lamport"
 10)
 11
 12var _ dag.ReadOnly[dag.Snapshot, dag.Operation] = &CachedEntityBase[dag.Snapshot, dag.Operation]{}
 13var _ CacheEntity = &CachedEntityBase[dag.Snapshot, dag.Operation]{}
 14
 15// CachedEntityBase provide the base function of an entity managed by the cache.
 16type CachedEntityBase[SnapT dag.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 dag.ReadWrite[SnapT, OpT]
 23}
 24
 25func (e *CachedEntityBase[SnapT, OpT]) Id() entity.Id {
 26	return e.entity.Id()
 27}
 28
 29func (e *CachedEntityBase[SnapT, OpT]) Snapshot() SnapT {
 30	e.mu.RLock()
 31	defer e.mu.RUnlock()
 32	return e.entity.Snapshot()
 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]) Commit() error {
 71	e.mu.Lock()
 72	err := e.entity.Commit(e.repo)
 73	if err != nil {
 74		e.mu.Unlock()
 75		return err
 76	}
 77	e.mu.Unlock()
 78	return e.notifyUpdated()
 79}
 80
 81func (e *CachedEntityBase[SnapT, OpT]) CommitAsNeeded() error {
 82	e.mu.Lock()
 83	err := e.entity.CommitAsNeeded(e.repo)
 84	if err != nil {
 85		e.mu.Unlock()
 86		return err
 87	}
 88	e.mu.Unlock()
 89	return e.notifyUpdated()
 90}
 91
 92func (e *CachedEntityBase[SnapT, OpT]) NeedCommit() bool {
 93	e.mu.RLock()
 94	defer e.mu.RUnlock()
 95	return e.entity.NeedCommit()
 96}
 97
 98func (e *CachedEntityBase[SnapT, OpT]) Lock() {
 99	e.mu.Lock()
100}
101
102func (e *CachedEntityBase[SnapT, OpT]) CreateLamportTime() lamport.Time {
103	return e.entity.CreateLamportTime()
104}
105
106func (e *CachedEntityBase[SnapT, OpT]) EditLamportTime() lamport.Time {
107	return e.entity.EditLamportTime()
108}
109
110func (e *CachedEntityBase[SnapT, OpT]) FirstOp() OpT {
111	return e.entity.FirstOp()
112}
113
114func (e *CachedEntityBase[SnapT, OpT]) LastOp() OpT {
115	return e.entity.LastOp()
116}