diff options
Diffstat (limited to 'cache')
-rw-r--r-- | cache/bug_subcache.go | 1 | ||||
-rw-r--r-- | cache/identity_subcache.go | 3 | ||||
-rw-r--r-- | cache/repo_cache.go | 28 | ||||
-rw-r--r-- | cache/repo_cache_common.go | 26 | ||||
-rw-r--r-- | cache/repo_cache_test.go | 33 | ||||
-rw-r--r-- | cache/subcache.go | 156 |
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() } |