aboutsummaryrefslogtreecommitdiffstats
path: root/cache
diff options
context:
space:
mode:
authorMichael Muré <batolettre@gmail.com>2023-01-10 21:36:03 +0100
committerMichael Muré <batolettre@gmail.com>2023-01-11 14:31:22 +0100
commit7df34aa7a40be0d7b759ea3ef42cedf9f25f32b2 (patch)
treea3d1cc77f56814d4ec8838f18cb6768035c1b290 /cache
parent9c50a359704f4edd2f33df6d256e032feae3a576 (diff)
downloadgit-bug-7df34aa7a40be0d7b759ea3ef42cedf9f25f32b2.tar.gz
commands: add a nice terminal progress bar when building the cache
One issue remaining is that writing the cache takes significant time, but I don't know how to reflect that nicely to the user.
Diffstat (limited to 'cache')
-rw-r--r--cache/repo_cache.go27
-rw-r--r--cache/subcache.go113
2 files changed, 91 insertions, 49 deletions
diff --git a/cache/repo_cache.go b/cache/repo_cache.go
index 99e9abbd..9c7e945a 100644
--- a/cache/repo_cache.go
+++ b/cache/repo_cache.go
@@ -30,7 +30,7 @@ var _ repository.RepoKeyring = &RepoCache{}
type cacheMgmt interface {
Typename() string
Load() error
- Build() error
+ Build() <-chan BuildEvent
SetCacheSize(size int)
MergeAll(remote string) <-chan entity.MergeResult
GetNamespace() string
@@ -212,6 +212,7 @@ const (
BuildEventCacheIsBuilt
BuildEventRemoveLock
BuildEventStarted
+ BuildEventProgress
BuildEventFinished
)
@@ -223,6 +224,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 +238,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/subcache.go b/cache/subcache.go
index 7b599b10..29155e82 100644
--- a/cache/subcache.go
+++ b/cache/subcache.go
@@ -185,51 +185,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)
+
+ allEntities := sc.actions.ReadAllWithResolver(sc.repo, sc.resolvers())
- indexer, indexEnd := index.IndexBatch()
+ index, err := sc.repo.GetIndex(sc.namespace)
+ if err != nil {
+ out <- BuildEvent{
+ Typename: sc.typename,
+ Err: err,
+ }
+ return
+ }
- for e := range allEntities {
- if e.Err != nil {
- return e.Err
+ // 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
+ }
+
+ 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,
+ }
+ }
- indexData := sc.makeIndexData(cached)
- if err := indexer(e.Entity.Id().String(), indexData); err != nil {
- return err
+ err = indexEnd()
+ if err != nil {
+ out <- BuildEvent{
+ Typename: sc.typename,
+ Err: err,
+ }
+ return
}
- }
- err = indexEnd()
- if err != nil {
- return err
- }
+ err = sc.write()
+ if err != nil {
+ out <- BuildEvent{
+ Typename: sc.typename,
+ Err: err,
+ }
+ return
+ }
- err = sc.write()
- if err != nil {
- return err
- }
+ out <- BuildEvent{
+ Typename: sc.typename,
+ Event: BuildEventFinished,
+ }
+ }()
- return nil
+ return out
}
func (sc *SubCache[EntityT, ExcerptT, CacheT]) SetCacheSize(size int) {