diff options
author | Michael Muré <batolettre@gmail.com> | 2019-02-18 14:11:37 +0100 |
---|---|---|
committer | Michael Muré <batolettre@gmail.com> | 2019-03-01 22:40:26 +0100 |
commit | 947ea63522610bd16c32cf70812c129eda9bbb02 (patch) | |
tree | 76542e4a5ab488dc45477d33c3f4e94b0eb36975 | |
parent | 976af3a4e8382d03e9f2ccb57e2ed3b783294138 (diff) | |
download | git-bug-947ea63522610bd16c32cf70812c129eda9bbb02.tar.gz |
identity: wip caching
-rw-r--r-- | cache/bug_cache.go | 12 | ||||
-rw-r--r-- | cache/bug_excerpt.go | 20 | ||||
-rw-r--r-- | cache/identity_cache.go | 6 | ||||
-rw-r--r-- | cache/identity_excerpt.go | 48 | ||||
-rw-r--r-- | cache/repo_cache.go | 88 |
5 files changed, 133 insertions, 41 deletions
diff --git a/cache/bug_cache.go b/cache/bug_cache.go index ce46837a..53a96275 100644 --- a/cache/bug_cache.go +++ b/cache/bug_cache.go @@ -228,9 +228,17 @@ func (c *BugCache) EditCommentRaw(author *IdentityCache, unixTime int64, target } func (c *BugCache) Commit() error { - return c.bug.Commit(c.repoCache.repo) + err := c.bug.Commit(c.repoCache.repo) + if err != nil { + return err + } + return c.notifyUpdated() } func (c *BugCache) CommitAsNeeded() error { - return c.bug.CommitAsNeeded(c.repoCache.repo) + err := c.bug.CommitAsNeeded(c.repoCache.repo) + if err != nil { + return err + } + return c.notifyUpdated() } diff --git a/cache/bug_excerpt.go b/cache/bug_excerpt.go index daf89c4f..d3645322 100644 --- a/cache/bug_excerpt.go +++ b/cache/bug_excerpt.go @@ -17,18 +17,13 @@ type BugExcerpt struct { CreateUnixTime int64 EditUnixTime int64 - Status bug.Status - Author AuthorExcerpt - Labels []bug.Label + Status bug.Status + AuthorId string + Labels []bug.Label CreateMetadata map[string]string } -type AuthorExcerpt struct { - Name string - Login string -} - func NewBugExcerpt(b bug.Interface, snap *bug.Snapshot) *BugExcerpt { return &BugExcerpt{ Id: b.Id(), @@ -37,12 +32,9 @@ func NewBugExcerpt(b bug.Interface, snap *bug.Snapshot) *BugExcerpt { CreateUnixTime: b.FirstOp().GetUnixTime(), EditUnixTime: snap.LastEditUnix(), Status: snap.Status, - Author: AuthorExcerpt{ - Login: snap.Author.Login(), - Name: snap.Author.Name(), - }, - Labels: snap.Labels, - CreateMetadata: b.FirstOp().AllMetadata(), + AuthorId: snap.Author.Id(), + Labels: snap.Labels, + CreateMetadata: b.FirstOp().AllMetadata(), } } diff --git a/cache/identity_cache.go b/cache/identity_cache.go index 93b2dc4b..c49e9519 100644 --- a/cache/identity_cache.go +++ b/cache/identity_cache.go @@ -4,7 +4,7 @@ import ( "github.com/MichaelMure/git-bug/identity" ) -// IdentityCache is a wrapper around an Identity. It provide multiple functions: +// IdentityCache is a wrapper around an Identity for caching. type IdentityCache struct { *identity.Identity repoCache *RepoCache @@ -17,6 +17,10 @@ func NewIdentityCache(repoCache *RepoCache, id *identity.Identity) *IdentityCach } } +func (i *IdentityCache) notifyUpdated() error { + return i.repoCache.identityUpdated(i.Identity.Id()) +} + func (i *IdentityCache) Commit() error { return i.Identity.Commit(i.repoCache.repo) } diff --git a/cache/identity_excerpt.go b/cache/identity_excerpt.go new file mode 100644 index 00000000..7bc660b6 --- /dev/null +++ b/cache/identity_excerpt.go @@ -0,0 +1,48 @@ +package cache + +import ( + "encoding/gob" + + "github.com/MichaelMure/git-bug/identity" +) + +// IdentityExcerpt hold a subset of the identity values to be able to sort and +// filter identities efficiently without having to read and compile each raw +// identity. +type IdentityExcerpt struct { + Id string + + Name string + Login string +} + +func NewIdentityExcerpt(i *identity.Identity) *IdentityExcerpt { + return &IdentityExcerpt{ + Id: i.Id(), + Name: i.Name(), + Login: i.Login(), + } +} + +// Package initialisation used to register the type for (de)serialization +func init() { + gob.Register(IdentityExcerpt{}) +} + +/* + * Sorting + */ + +type IdentityById []*IdentityExcerpt + +func (b IdentityById) Len() int { + return len(b) +} + +func (b IdentityById) Less(i, j int) bool { + return b[i].Id < b[j].Id +} + +func (b IdentityById) Swap(i, j int) { + b[i], b[j] = b[j], b[i] +} diff --git a/cache/repo_cache.go b/cache/repo_cache.go index f64a1b76..cec6f8b5 100644 --- a/cache/repo_cache.go +++ b/cache/repo_cache.go @@ -20,8 +20,12 @@ import ( "github.com/MichaelMure/git-bug/util/process" ) -const cacheFile = "cache" -const formatVersion = 1 +const bugCacheFile = "bug-cache" +const identityCacheFile = "identity-cache" + +// 1: original format +// 2: added cache for identities with a reference in the bug cache +const formatVersion = 2 // RepoCache is a cache for a Repository. This cache has multiple functions: // @@ -40,12 +44,17 @@ const formatVersion = 1 type RepoCache struct { // the underlying repo repo repository.ClockedRepo + // excerpt of bugs data for all bugs - excerpts map[string]*BugExcerpt + bugExcerpts map[string]*BugExcerpt // bug loaded in memory bugs map[string]*BugCache + + // excerpt of identities data for all identities + identitiesExcerpts map[string]*IdentityExcerpt // identities loaded in memory identities map[string]*IdentityCache + // the user identity's id, if known userIdentityId string } @@ -145,14 +154,27 @@ func (c *RepoCache) bugUpdated(id string) error { panic("missing bug in the cache") } - c.excerpts[id] = NewBugExcerpt(b.bug, b.Snapshot()) + c.bugExcerpts[id] = NewBugExcerpt(b.bug, b.Snapshot()) + + return c.write() +} + +// identityUpdated is a callback to trigger when the excerpt of an identity +// changed, that is each time an identity is updated +func (c *RepoCache) identityUpdated(id string) error { + i, ok := c.identities[id] + if !ok { + panic("missing identity in the cache") + } + + c.identitiesExcerpts[id] = NewIdentityExcerpt(i.Identity) return c.write() } // load will try to read from the disk the bug cache file func (c *RepoCache) load() error { - f, err := os.Open(cacheFilePath(c.repo)) + f, err := os.Open(bugCacheFilePath(c.repo)) if err != nil { return err } @@ -173,7 +195,7 @@ func (c *RepoCache) load() error { return fmt.Errorf("unknown cache format version %v", aux.Version) } - c.excerpts = aux.Excerpts + c.bugExcerpts = aux.Excerpts return nil } @@ -186,7 +208,7 @@ func (c *RepoCache) write() error { Excerpts map[string]*BugExcerpt }{ Version: formatVersion, - Excerpts: c.excerpts, + Excerpts: c.bugExcerpts, } encoder := gob.NewEncoder(&data) @@ -196,7 +218,7 @@ func (c *RepoCache) write() error { return err } - f, err := os.Create(cacheFilePath(c.repo)) + f, err := os.Create(bugCacheFilePath(c.repo)) if err != nil { return err } @@ -209,14 +231,18 @@ func (c *RepoCache) write() error { return f.Close() } -func cacheFilePath(repo repository.Repo) string { - return path.Join(repo.GetPath(), ".git", "git-bug", cacheFile) +func bugCacheFilePath(repo repository.Repo) string { + return path.Join(repo.GetPath(), ".git", "git-bug", bugCacheFile) +} + +func identityCacheFilePath(repo repository.Repo) string { + return path.Join(repo.GetPath(), ".git", "git-bug", bugCacheFile) } func (c *RepoCache) buildCache() error { _, _ = fmt.Fprintf(os.Stderr, "Building bug cache... ") - c.excerpts = make(map[string]*BugExcerpt) + c.bugExcerpts = make(map[string]*BugExcerpt) allBugs := bug.ReadAllLocalBugs(c.repo) @@ -226,7 +252,7 @@ func (c *RepoCache) buildCache() error { } snap := b.Bug.Compile() - c.excerpts[b.Bug.Id()] = NewBugExcerpt(b.Bug, &snap) + c.bugExcerpts[b.Bug.Id()] = NewBugExcerpt(b.Bug, &snap) } _, _ = fmt.Fprintln(os.Stderr, "Done.") @@ -257,7 +283,7 @@ func (c *RepoCache) ResolveBugPrefix(prefix string) (*BugCache, error) { // preallocate but empty matching := make([]string, 0, 5) - for id := range c.excerpts { + for id := range c.bugExcerpts { if strings.HasPrefix(id, prefix) { matching = append(matching, id) } @@ -281,7 +307,7 @@ func (c *RepoCache) ResolveBugCreateMetadata(key string, value string) (*BugCach // preallocate but empty matching := make([]string, 0, 5) - for id, excerpt := range c.excerpts { + for id, excerpt := range c.bugExcerpts { if excerpt.CreateMetadata[key] == value { matching = append(matching, id) } @@ -306,7 +332,7 @@ func (c *RepoCache) QueryBugs(query *Query) []string { var filtered []*BugExcerpt - for _, excerpt := range c.excerpts { + for _, excerpt := range c.bugExcerpts { if query.Match(excerpt) { filtered = append(filtered, excerpt) } @@ -342,10 +368,10 @@ func (c *RepoCache) QueryBugs(query *Query) []string { // AllBugsIds return all known bug ids func (c *RepoCache) AllBugsIds() []string { - result := make([]string, len(c.excerpts)) + result := make([]string, len(c.bugExcerpts)) i := 0 - for _, excerpt := range c.excerpts { + for _, excerpt := range c.bugExcerpts { result[i] = excerpt.Id i++ } @@ -353,11 +379,6 @@ func (c *RepoCache) AllBugsIds() []string { return result } -// ClearAllBugs clear all bugs kept in memory -func (c *RepoCache) ClearAllBugs() { - c.bugs = make(map[string]*BugCache) -} - // ValidLabels list valid labels // // Note: in the future, a proper label policy could be implemented where valid @@ -366,7 +387,7 @@ func (c *RepoCache) ClearAllBugs() { func (c *RepoCache) ValidLabels() []bug.Label { set := map[bug.Label]interface{}{} - for _, excerpt := range c.excerpts { + for _, excerpt := range c.bugExcerpts { for _, l := range excerpt.Labels { set[l] = nil } @@ -467,7 +488,7 @@ func (c *RepoCache) MergeAll(remote string) <-chan bug.MergeResult { case bug.MergeStatusNew, bug.MergeStatusUpdated: b := result.Bug snap := b.Compile() - c.excerpts[id] = NewBugExcerpt(b, &snap) + c.bugExcerpts[id] = NewBugExcerpt(b, &snap) } } @@ -615,6 +636,19 @@ func (c *RepoCache) ResolveIdentityImmutableMetadata(key string, value string) ( return c.ResolveIdentity(matching[0]) } +// AllIdentityIds return all known identity ids +func (c *RepoCache) AllIdentityIds() []string { + result := make([]string, len(c.identitiesExcerpts)) + + i := 0 + for _, excerpt := range c.identitiesExcerpts { + result[i] = excerpt.Id + i++ + } + + return result +} + func (c *RepoCache) SetUserIdentity(i *IdentityCache) error { err := identity.SetUserIdentity(c.repo, i.Identity) if err != nil { @@ -677,5 +711,11 @@ func (c *RepoCache) NewIdentityRaw(name string, email string, login string, avat cached := NewIdentityCache(c, i) c.identities[i.Id()] = cached + // force the write of the excerpt + err = c.identityUpdated(i.Id()) + if err != nil { + return nil, err + } + return cached, nil } |