code.gitea.io/gitea@v1.19.3/modules/git/last_commit_cache.go (about) 1 // Copyright 2020 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package git 5 6 import ( 7 "crypto/sha256" 8 "fmt" 9 10 "code.gitea.io/gitea/modules/log" 11 "code.gitea.io/gitea/modules/setting" 12 ) 13 14 // Cache represents a caching interface 15 type Cache interface { 16 // Put puts value into cache with key and expire time. 17 Put(key string, val interface{}, timeout int64) error 18 // Get gets cached value by given key. 19 Get(key string) interface{} 20 } 21 22 func getCacheKey(repoPath, commitID, entryPath string) string { 23 hashBytes := sha256.Sum256([]byte(fmt.Sprintf("%s:%s:%s", repoPath, commitID, entryPath))) 24 return fmt.Sprintf("last_commit:%x", hashBytes) 25 } 26 27 // LastCommitCache represents a cache to store last commit 28 type LastCommitCache struct { 29 repoPath string 30 ttl func() int64 31 repo *Repository 32 commitCache map[string]*Commit 33 cache Cache 34 } 35 36 // NewLastCommitCache creates a new last commit cache for repo 37 func NewLastCommitCache(count int64, repoPath string, gitRepo *Repository, cache Cache) *LastCommitCache { 38 if cache == nil { 39 return nil 40 } 41 if !setting.CacheService.LastCommit.Enabled || count < setting.CacheService.LastCommit.CommitsCount { 42 return nil 43 } 44 45 return &LastCommitCache{ 46 repoPath: repoPath, 47 repo: gitRepo, 48 ttl: setting.LastCommitCacheTTLSeconds, 49 cache: cache, 50 } 51 } 52 53 // Put put the last commit id with commit and entry path 54 func (c *LastCommitCache) Put(ref, entryPath, commitID string) error { 55 if c == nil || c.cache == nil { 56 return nil 57 } 58 log.Debug("LastCommitCache save: [%s:%s:%s]", ref, entryPath, commitID) 59 return c.cache.Put(getCacheKey(c.repoPath, ref, entryPath), commitID, c.ttl()) 60 } 61 62 // Get gets the last commit information by commit id and entry path 63 func (c *LastCommitCache) Get(ref, entryPath string) (*Commit, error) { 64 if c == nil || c.cache == nil { 65 return nil, nil 66 } 67 68 commitID, ok := c.cache.Get(getCacheKey(c.repoPath, ref, entryPath)).(string) 69 if !ok || commitID == "" { 70 return nil, nil 71 } 72 73 log.Debug("LastCommitCache hit level 1: [%s:%s:%s]", ref, entryPath, commitID) 74 if c.commitCache != nil { 75 if commit, ok := c.commitCache[commitID]; ok { 76 log.Debug("LastCommitCache hit level 2: [%s:%s:%s]", ref, entryPath, commitID) 77 return commit, nil 78 } 79 } 80 81 commit, err := c.repo.GetCommit(commitID) 82 if err != nil { 83 return nil, err 84 } 85 if c.commitCache == nil { 86 c.commitCache = make(map[string]*Commit) 87 } 88 c.commitCache[commitID] = commit 89 return commit, nil 90 } 91 92 // GetCommitByPath gets the last commit for the entry in the provided commit 93 func (c *LastCommitCache) GetCommitByPath(commitID, entryPath string) (*Commit, error) { 94 sha1, err := NewIDFromString(commitID) 95 if err != nil { 96 return nil, err 97 } 98 99 lastCommit, err := c.Get(sha1.String(), entryPath) 100 if err != nil || lastCommit != nil { 101 return lastCommit, err 102 } 103 104 lastCommit, err = c.repo.getCommitByPathWithID(sha1, entryPath) 105 if err != nil { 106 return nil, err 107 } 108 109 if err := c.Put(commitID, entryPath, lastCommit.ID.String()); err != nil { 110 log.Error("Unable to cache %s as the last commit for %q in %s %s. Error %v", lastCommit.ID.String(), entryPath, commitID, c.repoPath, err) 111 } 112 113 return lastCommit, nil 114 }