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
|
|
|
)
|
|
|
|
|
|
|
|
// type withSnapshot[SnapT dag.Snapshot, OpT dag.OperationWithApply[SnapT]] struct {
|
|
|
|
// dag.Interface[SnapT, OpT]
|
|
|
|
// snap dag.Snapshot
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// func (ws *withSnapshot[SnapT, OpT]) Compile() dag.Snapshot {
|
|
|
|
// if ws.snap == nil {
|
|
|
|
// snap := ws.Interface.Compile()
|
|
|
|
// ws.snap = snap
|
|
|
|
// }
|
|
|
|
// return ws.snap
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// // Append intercept Bug.Append() to update the snapshot efficiently
|
|
|
|
// func (ws *withSnapshot[SnapT, OpT]) Append(op OpT) {
|
|
|
|
// ws.Interface.Append(op)
|
|
|
|
//
|
|
|
|
// if ws.snap == nil {
|
|
|
|
// return
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// op.Apply(ws.snap)
|
|
|
|
// ws.snap. = append(ws.snap.Operations, op)
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// // Commit intercept Bug.Commit() to update the snapshot efficiently
|
|
|
|
// func (ws *withSnapshot[SnapT, OpT]) Commit(repo repository.ClockedRepo) error {
|
|
|
|
// err := ws.Interface.Commit(repo)
|
|
|
|
//
|
|
|
|
// if err != nil {
|
|
|
|
// ws.snap = nil
|
|
|
|
// return err
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// // Commit() shouldn't change anything of the bug state apart from the
|
|
|
|
// // initial ID set
|
|
|
|
//
|
|
|
|
// if ws.snap == nil {
|
|
|
|
// return nil
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// ws.snap.id = ws.Interface.Id()
|
|
|
|
// return nil
|
|
|
|
// }
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
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()
|
|
|
|
}
|