2022-11-19 13:33:12 +03:00
|
|
|
package cache
|
|
|
|
|
|
|
|
import (
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
"github.com/MichaelMure/git-bug/entity"
|
|
|
|
"github.com/MichaelMure/git-bug/entity/dag"
|
|
|
|
"github.com/MichaelMure/git-bug/repository"
|
2022-12-21 23:54:36 +03:00
|
|
|
"github.com/MichaelMure/git-bug/util/lamport"
|
2022-11-19 13:33:12 +03:00
|
|
|
)
|
|
|
|
|
2022-12-23 01:19:31 +03:00
|
|
|
var _ CacheEntity = &CachedEntityBase[dag.Snapshot, dag.Operation]{}
|
|
|
|
|
2022-12-22 02:48:00 +03:00
|
|
|
// CachedEntityBase provide the base function of an entity managed by the cache.
|
2022-11-19 13:33:12 +03:00
|
|
|
type CachedEntityBase[SnapT dag.Snapshot, OpT dag.Operation] struct {
|
|
|
|
repo repository.ClockedRepo
|
2022-12-19 20:09:59 +03:00
|
|
|
entityUpdated func(id entity.Id) error
|
|
|
|
getUserIdentity getUserIdentityFunc
|
2022-11-19 13:33:12 +03:00
|
|
|
|
|
|
|
mu sync.RWMutex
|
|
|
|
entity dag.Interface[SnapT, OpT]
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *CachedEntityBase[SnapT, OpT]) Id() entity.Id {
|
|
|
|
return e.entity.Id()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *CachedEntityBase[SnapT, OpT]) Snapshot() SnapT {
|
|
|
|
e.mu.RLock()
|
|
|
|
defer e.mu.RUnlock()
|
|
|
|
return e.entity.Compile()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *CachedEntityBase[SnapT, OpT]) notifyUpdated() error {
|
|
|
|
return e.entityUpdated(e.entity.Id())
|
|
|
|
}
|
|
|
|
|
|
|
|
// ResolveOperationWithMetadata will find an operation that has the matching metadata
|
|
|
|
func (e *CachedEntityBase[SnapT, OpT]) ResolveOperationWithMetadata(key string, value string) (entity.Id, error) {
|
|
|
|
e.mu.RLock()
|
|
|
|
defer e.mu.RUnlock()
|
|
|
|
// preallocate but empty
|
|
|
|
matching := make([]entity.Id, 0, 5)
|
|
|
|
|
|
|
|
for _, op := range e.entity.Operations() {
|
|
|
|
opValue, ok := op.GetMetadata(key)
|
|
|
|
if ok && value == opValue {
|
|
|
|
matching = append(matching, op.Id())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(matching) == 0 {
|
|
|
|
return "", ErrNoMatchingOp
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(matching) > 1 {
|
2022-12-21 23:54:36 +03:00
|
|
|
return "", entity.NewErrMultipleMatch("operation", matching)
|
2022-11-19 13:33:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return matching[0], nil
|
|
|
|
}
|
|
|
|
|
2022-11-29 15:01:53 +03:00
|
|
|
func (e *CachedEntityBase[SnapT, OpT]) Validate() error {
|
|
|
|
e.mu.RLock()
|
|
|
|
defer e.mu.RUnlock()
|
|
|
|
return e.entity.Validate()
|
|
|
|
}
|
|
|
|
|
2022-11-19 13:33:12 +03:00
|
|
|
func (e *CachedEntityBase[SnapT, OpT]) Commit() error {
|
|
|
|
e.mu.Lock()
|
|
|
|
err := e.entity.Commit(e.repo)
|
|
|
|
if err != nil {
|
|
|
|
e.mu.Unlock()
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
e.mu.Unlock()
|
|
|
|
return e.notifyUpdated()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *CachedEntityBase[SnapT, OpT]) CommitAsNeeded() error {
|
|
|
|
e.mu.Lock()
|
|
|
|
err := e.entity.CommitAsNeeded(e.repo)
|
|
|
|
if err != nil {
|
|
|
|
e.mu.Unlock()
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
e.mu.Unlock()
|
|
|
|
return e.notifyUpdated()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *CachedEntityBase[SnapT, OpT]) NeedCommit() bool {
|
|
|
|
e.mu.RLock()
|
|
|
|
defer e.mu.RUnlock()
|
|
|
|
return e.entity.NeedCommit()
|
|
|
|
}
|
2022-12-21 23:54:36 +03:00
|
|
|
|
2022-12-23 01:19:31 +03:00
|
|
|
func (e *CachedEntityBase[SnapT, OpT]) Lock() {
|
|
|
|
e.mu.Lock()
|
|
|
|
}
|
|
|
|
|
2022-12-21 23:54:36 +03:00
|
|
|
func (e *CachedEntityBase[SnapT, OpT]) CreateLamportTime() lamport.Time {
|
|
|
|
return e.entity.CreateLamportTime()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *CachedEntityBase[SnapT, OpT]) EditLamportTime() lamport.Time {
|
|
|
|
return e.entity.EditLamportTime()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *CachedEntityBase[SnapT, OpT]) FirstOp() OpT {
|
|
|
|
return e.entity.FirstOp()
|
|
|
|
}
|