blob: ab5044ff206e2c2910b737fc3174e86be338e380 [file] [log] [blame]
package mem_gitstore
import (
"context"
"sort"
"sync"
"time"
"go.skia.org/infra/go/gitstore"
"go.skia.org/infra/go/skerr"
"go.skia.org/infra/go/vcsinfo"
)
// MemGitStore implements the gitstore.GitStore interface in memory.
type MemGitStore struct {
mtx sync.RWMutex
branches map[string]*gitstore.BranchPointer
commits map[string]*vcsinfo.LongCommit
}
// New returns an in-memory gitstore.GitStore implementation.
func New() *MemGitStore {
return &MemGitStore{
branches: map[string]*gitstore.BranchPointer{},
commits: map[string]*vcsinfo.LongCommit{},
}
}
// See documentation for gitstore.GitStore interface.
func (gs *MemGitStore) Put(ctx context.Context, commits []*vcsinfo.LongCommit) error {
gs.mtx.Lock()
defer gs.mtx.Unlock()
for _, c := range commits {
gs.commits[c.Hash] = c
}
return nil
}
// See documentation for gitstore.GitStore interface.
func (gs *MemGitStore) Get(ctx context.Context, hashes []string) ([]*vcsinfo.LongCommit, error) {
gs.mtx.RLock()
defer gs.mtx.RUnlock()
rv := make([]*vcsinfo.LongCommit, 0, len(hashes))
for _, hash := range hashes {
// Don't bother checking whether the commit exists; per the
// GitStore docs, Get may contain nil entries in the returned
// slice.
rv = append(rv, gs.commits[hash])
}
return rv, nil
}
// See documentation for gitstore.GitStore interface.
func (gs *MemGitStore) PutBranches(ctx context.Context, branches map[string]string) error {
gs.mtx.Lock()
defer gs.mtx.Unlock()
for name, hash := range branches {
if hash == gitstore.DELETE_BRANCH {
delete(gs.branches, name)
} else {
head, ok := gs.commits[hash]
if !ok {
return skerr.Fmt("Unknown commit %s for branch %s", hash, name)
}
gs.branches[name] = &gitstore.BranchPointer{
Head: hash,
Index: head.Index,
}
}
}
return nil
}
// See documentation for gitstore.GitStore interface.
func (gs *MemGitStore) GetBranches(ctx context.Context) (map[string]*gitstore.BranchPointer, error) {
gs.mtx.RLock()
defer gs.mtx.RUnlock()
rv := make(map[string]*gitstore.BranchPointer, len(gs.branches))
for name, ptr := range gs.branches {
rv[name] = &gitstore.BranchPointer{
Head: ptr.Head,
Index: ptr.Index,
}
}
return rv, nil
}
// getIndexCommits is a helper function for retrieving IndexCommits.
func (gs *MemGitStore) getIndexCommits(branch string, include func(*vcsinfo.LongCommit) bool) []*vcsinfo.IndexCommit {
gs.mtx.RLock()
defer gs.mtx.RUnlock()
ptr := gs.branches[branch]
rv := []*vcsinfo.IndexCommit{}
// TODO(borenet): This could be more efficient if we maintained a sorted
// slice of commits.
for _, c := range gs.commits {
if (branch == gitstore.ALL_BRANCHES || ptr != nil && c.Branches[branch] && c.Index <= ptr.Index) && include(c) {
rv = append(rv, c.IndexCommit())
}
}
sort.Sort(vcsinfo.IndexCommitSlice(rv))
return rv
}
// See documentation for gitstore.GitStore interface.
func (gs *MemGitStore) RangeN(ctx context.Context, startIndex, endIndex int, branch string) ([]*vcsinfo.IndexCommit, error) {
return gs.getIndexCommits(branch, func(c *vcsinfo.LongCommit) bool {
return c.Index >= startIndex && c.Index < endIndex
}), nil
}
// See documentation for gitstore.GitStore interface.
func (gs *MemGitStore) RangeByTime(ctx context.Context, start, end time.Time, branch string) ([]*vcsinfo.IndexCommit, error) {
return gs.getIndexCommits(branch, func(c *vcsinfo.LongCommit) bool {
return !c.Timestamp.Before(start) && c.Timestamp.Before(end)
}), nil
}
var _ gitstore.GitStore = &MemGitStore{}