aboutsummaryrefslogtreecommitdiffstats
path: root/cache
diff options
context:
space:
mode:
Diffstat (limited to 'cache')
-rw-r--r--cache/bug_subcache.go1
-rw-r--r--cache/identity_subcache.go3
-rw-r--r--cache/repo_cache.go28
-rw-r--r--cache/repo_cache_common.go26
-rw-r--r--cache/repo_cache_test.go33
-rw-r--r--cache/subcache.go156
6 files changed, 195 insertions, 52 deletions
diff --git a/cache/bug_subcache.go b/cache/bug_subcache.go
index 920fe1dc..21c9a6d2 100644
--- a/cache/bug_subcache.go
+++ b/cache/bug_subcache.go
@@ -38,6 +38,7 @@ func NewRepoCacheBug(repo repository.ClockedRepo,
ReadWithResolver: bug.ReadWithResolver,
ReadAllWithResolver: bug.ReadAllWithResolver,
Remove: bug.Remove,
+ RemoveAll: bug.RemoveAll,
MergeAll: bug.MergeAll,
}
diff --git a/cache/identity_subcache.go b/cache/identity_subcache.go
index f862ca8b..05a91358 100644
--- a/cache/identity_subcache.go
+++ b/cache/identity_subcache.go
@@ -39,7 +39,8 @@ func NewRepoCacheIdentity(repo repository.ClockedRepo,
ReadAllWithResolver: func(repo repository.ClockedRepo, resolvers entity.Resolvers) <-chan entity.StreamedEntity[*identity.Identity] {
return identity.ReadAllLocal(repo)
},
- Remove: identity.RemoveIdentity,
+ Remove: identity.Remove,
+ RemoveAll: identity.RemoveAll,
MergeAll: func(repo repository.ClockedRepo, resolvers entity.Resolvers, remote string, mergeAuthor identity.Interface) <-chan entity.MergeResult {
return identity.MergeAll(repo, remote)
},
diff --git a/cache/repo_cache.go b/cache/repo_cache.go
index 99e9abbd..9e45d1f1 100644
--- a/cache/repo_cache.go
+++ b/cache/repo_cache.go
@@ -30,8 +30,9 @@ var _ repository.RepoKeyring = &RepoCache{}
type cacheMgmt interface {
Typename() string
Load() error
- Build() error
+ Build() <-chan BuildEvent
SetCacheSize(size int)
+ RemoveAll() error
MergeAll(remote string) <-chan entity.MergeResult
GetNamespace() string
Close() error
@@ -212,6 +213,7 @@ const (
BuildEventCacheIsBuilt
BuildEventRemoveLock
BuildEventStarted
+ BuildEventProgress
BuildEventFinished
)
@@ -223,6 +225,10 @@ type BuildEvent struct {
Typename string
// Event is the type of the event.
Event BuildEventType
+ // Total is the total number of element being built. Set if Event is BuildEventStarted.
+ Total int64
+ // Progress is the current count of processed element. Set if Event is BuildEventProgress.
+ Progress int64
}
func (c *RepoCache) buildCache(events chan BuildEvent) {
@@ -233,23 +239,13 @@ func (c *RepoCache) buildCache(events chan BuildEvent) {
wg.Add(1)
go func(subcache cacheMgmt) {
defer wg.Done()
- events <- BuildEvent{
- Typename: subcache.Typename(),
- Event: BuildEventStarted,
- }
- err := subcache.Build()
- if err != nil {
- events <- BuildEvent{
- Typename: subcache.Typename(),
- Err: err,
+ buildEvents := subcache.Build()
+ for buildEvent := range buildEvents {
+ events <- buildEvent
+ if buildEvent.Err != nil {
+ return
}
- return
- }
-
- events <- BuildEvent{
- Typename: subcache.Typename(),
- Event: BuildEventFinished,
}
}(subcache)
}
diff --git a/cache/repo_cache_common.go b/cache/repo_cache_common.go
index f768b8e2..759536bd 100644
--- a/cache/repo_cache_common.go
+++ b/cache/repo_cache_common.go
@@ -3,12 +3,12 @@ package cache
import (
"sync"
- "github.com/go-git/go-billy/v5"
"github.com/pkg/errors"
"github.com/MichaelMure/git-bug/entities/identity"
"github.com/MichaelMure/git-bug/entity"
"github.com/MichaelMure/git-bug/repository"
+ "github.com/MichaelMure/git-bug/util/multierr"
)
func (c *RepoCache) Name() string {
@@ -56,7 +56,7 @@ func (c *RepoCache) GetRemotes() (map[string]string, error) {
}
// LocalStorage return a billy.Filesystem giving access to $RepoPath/.git/git-bug
-func (c *RepoCache) LocalStorage() billy.Filesystem {
+func (c *RepoCache) LocalStorage() repository.LocalStorage {
return c.repo.LocalStorage()
}
@@ -82,6 +82,15 @@ func (c *RepoCache) Fetch(remote string) (string, error) {
return c.repo.FetchRefs(remote, prefixes...)
}
+// RemoveAll deletes all entities from the cache and the disk.
+func (c *RepoCache) RemoveAll() error {
+ var errWait multierr.ErrWaitGroup
+ for _, mgmt := range c.subcaches {
+ errWait.Go(mgmt.RemoveAll)
+ }
+ return errWait.Wait()
+}
+
// MergeAll will merge all the available remote bug and identities
func (c *RepoCache) MergeAll(remote string) <-chan entity.MergeResult {
out := make(chan entity.MergeResult)
@@ -163,6 +172,19 @@ func (c *RepoCache) SetUserIdentity(i *IdentityCache) error {
return nil
}
+func (c *RepoCache) ClearUserIdentity() error {
+ c.muUserIdentity.Lock()
+ defer c.muUserIdentity.Unlock()
+
+ err := identity.ClearUserIdentity(c.repo)
+ if err != nil {
+ return err
+ }
+
+ c.userIdentityId = ""
+ return nil
+}
+
func (c *RepoCache) GetUserIdentity() (*IdentityCache, error) {
c.muUserIdentity.RLock()
if c.userIdentityId != "" {
diff --git a/cache/repo_cache_test.go b/cache/repo_cache_test.go
index 07a3fee8..3c11220d 100644
--- a/cache/repo_cache_test.go
+++ b/cache/repo_cache_test.go
@@ -135,6 +135,39 @@ func TestCache(t *testing.T) {
_, err = cache.Bugs().ResolvePrefix(bug1.Id().String()[:10])
require.NoError(t, err)
+ require.Len(t, cache.bugs.cached, 1)
+ require.Len(t, cache.bugs.excerpts, 2)
+ require.Len(t, cache.identities.cached, 1)
+ require.Len(t, cache.identities.excerpts, 2)
+ require.Equal(t, uint64(2), indexCount(t, identity.Namespace))
+ require.Equal(t, uint64(2), indexCount(t, bug.Namespace))
+
+ // Remove + RemoveAll
+ err = cache.Identities().Remove(iden1.Id().String()[:10])
+ require.NoError(t, err)
+ err = cache.Bugs().Remove(bug1.Id().String()[:10])
+ require.NoError(t, err)
+ require.Len(t, cache.bugs.cached, 0)
+ require.Len(t, cache.bugs.excerpts, 1)
+ require.Len(t, cache.identities.cached, 0)
+ require.Len(t, cache.identities.excerpts, 1)
+ require.Equal(t, uint64(1), indexCount(t, identity.Namespace))
+ require.Equal(t, uint64(1), indexCount(t, bug.Namespace))
+
+ _, err = cache.Identities().New("René Descartes", "rene@descartes.fr")
+ require.NoError(t, err)
+ _, _, err = cache.Bugs().NewRaw(iden2, time.Now().Unix(), "title", "message", nil, nil)
+ require.NoError(t, err)
+
+ err = cache.RemoveAll()
+ require.NoError(t, err)
+ require.Len(t, cache.bugs.cached, 0)
+ require.Len(t, cache.bugs.excerpts, 0)
+ require.Len(t, cache.identities.cached, 0)
+ require.Len(t, cache.identities.excerpts, 0)
+ require.Equal(t, uint64(0), indexCount(t, identity.Namespace))
+ require.Equal(t, uint64(0), indexCount(t, bug.Namespace))
+
// Close
require.NoError(t, cache.Close())
require.Empty(t, cache.bugs.cached)
diff --git a/cache/subcache.go b/cache/subcache.go
index 7b599b10..09e53c23 100644
--- a/cache/subcache.go
+++ b/cache/subcache.go
@@ -34,6 +34,7 @@ type Actions[EntityT entity.Interface] struct {
ReadWithResolver func(repo repository.ClockedRepo, resolvers entity.Resolvers, id entity.Id) (EntityT, error)
ReadAllWithResolver func(repo repository.ClockedRepo, resolvers entity.Resolvers) <-chan entity.StreamedEntity[EntityT]
Remove func(repo repository.ClockedRepo, id entity.Id) error
+ RemoveAll func(repo repository.ClockedRepo) error
MergeAll func(repo repository.ClockedRepo, resolvers entity.Resolvers, remote string, mergeAuthor identity.Interface) <-chan entity.MergeResult
}
@@ -185,51 +186,98 @@ func (sc *SubCache[EntityT, ExcerptT, CacheT]) write() error {
return f.Close()
}
-func (sc *SubCache[EntityT, ExcerptT, CacheT]) Build() error {
- sc.excerpts = make(map[entity.Id]ExcerptT)
+func (sc *SubCache[EntityT, ExcerptT, CacheT]) Build() <-chan BuildEvent {
+ out := make(chan BuildEvent)
- allEntities := sc.actions.ReadAllWithResolver(sc.repo, sc.resolvers())
+ go func() {
+ defer close(out)
- index, err := sc.repo.GetIndex(sc.namespace)
- if err != nil {
- return err
- }
+ out <- BuildEvent{
+ Typename: sc.typename,
+ Event: BuildEventStarted,
+ }
- // wipe the index just to be sure
- err = index.Clear()
- if err != nil {
- return err
- }
+ sc.excerpts = make(map[entity.Id]ExcerptT)
- indexer, indexEnd := index.IndexBatch()
+ allEntities := sc.actions.ReadAllWithResolver(sc.repo, sc.resolvers())
- for e := range allEntities {
- if e.Err != nil {
- return e.Err
+ index, err := sc.repo.GetIndex(sc.namespace)
+ if err != nil {
+ out <- BuildEvent{
+ Typename: sc.typename,
+ Err: err,
+ }
+ return
+ }
+
+ // wipe the index just to be sure
+ err = index.Clear()
+ if err != nil {
+ out <- BuildEvent{
+ Typename: sc.typename,
+ Err: err,
+ }
+ return
}
- cached := sc.makeCached(e.Entity, sc.entityUpdated)
- sc.excerpts[e.Entity.Id()] = sc.makeExcerpt(cached)
- // might as well keep them in memory
- sc.cached[e.Entity.Id()] = cached
+ indexer, indexEnd := index.IndexBatch()
+
+ for e := range allEntities {
+ if e.Err != nil {
+ out <- BuildEvent{
+ Typename: sc.typename,
+ Err: e.Err,
+ }
+ return
+ }
- indexData := sc.makeIndexData(cached)
- if err := indexer(e.Entity.Id().String(), indexData); err != nil {
- return err
+ cached := sc.makeCached(e.Entity, sc.entityUpdated)
+ sc.excerpts[e.Entity.Id()] = sc.makeExcerpt(cached)
+ // might as well keep them in memory
+ sc.cached[e.Entity.Id()] = cached
+
+ indexData := sc.makeIndexData(cached)
+ if err := indexer(e.Entity.Id().String(), indexData); err != nil {
+ out <- BuildEvent{
+ Typename: sc.typename,
+ Err: err,
+ }
+ return
+ }
+
+ out <- BuildEvent{
+ Typename: sc.typename,
+ Event: BuildEventProgress,
+ Progress: e.CurrentEntity,
+ Total: e.TotalEntities,
+ }
}
- }
- err = indexEnd()
- if err != nil {
- return err
- }
+ err = indexEnd()
+ if err != nil {
+ out <- BuildEvent{
+ Typename: sc.typename,
+ Err: err,
+ }
+ return
+ }
- err = sc.write()
- if err != nil {
- return err
- }
+ err = sc.write()
+ if err != nil {
+ out <- BuildEvent{
+ Typename: sc.typename,
+ Err: err,
+ }
+ return
+ }
- return nil
+ out <- BuildEvent{
+ Typename: sc.typename,
+ Event: BuildEventFinished,
+ }
+ }()
+
+ return out
}
func (sc *SubCache[EntityT, ExcerptT, CacheT]) SetCacheSize(size int) {
@@ -399,7 +447,49 @@ func (sc *SubCache[EntityT, ExcerptT, CacheT]) Remove(prefix string) error {
delete(sc.excerpts, e.Id())
sc.lru.Remove(e.Id())
+ index, err := sc.repo.GetIndex(sc.namespace)
+ if err != nil {
+ sc.mu.Unlock()
+ return err
+ }
+
+ err = index.Remove(e.Id().String())
+ sc.mu.Unlock()
+ if err != nil {
+ return err
+ }
+
+ return sc.write()
+}
+
+func (sc *SubCache[EntityT, ExcerptT, CacheT]) RemoveAll() error {
+ sc.mu.Lock()
+
+ err := sc.actions.RemoveAll(sc.repo)
+ if err != nil {
+ sc.mu.Unlock()
+ return err
+ }
+
+ for id, _ := range sc.cached {
+ delete(sc.cached, id)
+ sc.lru.Remove(id)
+ }
+ for id, _ := range sc.excerpts {
+ delete(sc.excerpts, id)
+ }
+
+ index, err := sc.repo.GetIndex(sc.namespace)
+ if err != nil {
+ sc.mu.Unlock()
+ return err
+ }
+
+ err = index.Clear()
sc.mu.Unlock()
+ if err != nil {
+ return err
+ }
return sc.write()
}