loading up the forgejo repo on tangled to test page performance
at forgejo 4.1 kB view raw
1// Copyright 2020 The Gitea Authors. All rights reserved. 2// SPDX-License-Identifier: MIT 3 4package git 5 6import ( 7 "context" 8 "crypto/sha256" 9 "fmt" 10 11 "forgejo.org/modules/log" 12 "forgejo.org/modules/setting" 13) 14 15// Cache represents a caching interface 16type Cache interface { 17 // Put puts value into cache with key and expire time. 18 Put(key string, val any, timeout int64) error 19 // Get gets cached value by given key. 20 Get(key string) any 21} 22 23func getCacheKey(repoPath, commitID, entryPath string) string { 24 hashBytes := sha256.Sum256([]byte(fmt.Sprintf("%s:%s:%s", repoPath, commitID, entryPath))) 25 return fmt.Sprintf("last_commit:%x", hashBytes) 26} 27 28// LastCommitCache represents a cache to store last commit 29type LastCommitCache struct { 30 repoPath string 31 ttl func() int64 32 repo *Repository 33 commitCache map[string]*Commit 34 cache Cache 35} 36 37// NewLastCommitCache creates a new last commit cache for repo 38func NewLastCommitCache(count int64, repoPath string, gitRepo *Repository, cache Cache) *LastCommitCache { 39 if cache == nil { 40 return nil 41 } 42 if count < setting.CacheService.LastCommit.CommitsCount { 43 return nil 44 } 45 46 return &LastCommitCache{ 47 repoPath: repoPath, 48 repo: gitRepo, 49 ttl: setting.LastCommitCacheTTLSeconds, 50 cache: cache, 51 } 52} 53 54// Put put the last commit id with commit and entry path 55func (c *LastCommitCache) Put(ref, entryPath, commitID string) error { 56 if c == nil || c.cache == nil { 57 return nil 58 } 59 log.Debug("LastCommitCache save: [%s:%s:%s]", ref, entryPath, commitID) 60 return c.cache.Put(getCacheKey(c.repoPath, ref, entryPath), commitID, c.ttl()) 61} 62 63// Get gets the last commit information by commit id and entry path 64func (c *LastCommitCache) Get(ref, entryPath string) (*Commit, error) { 65 if c == nil || c.cache == nil { 66 return nil, nil 67 } 68 69 commitID, ok := c.cache.Get(getCacheKey(c.repoPath, ref, entryPath)).(string) 70 if !ok || commitID == "" { 71 return nil, nil 72 } 73 74 log.Debug("LastCommitCache hit level 1: [%s:%s:%s]", ref, entryPath, commitID) 75 if c.commitCache != nil { 76 if commit, ok := c.commitCache[commitID]; ok { 77 log.Debug("LastCommitCache hit level 2: [%s:%s:%s]", ref, entryPath, commitID) 78 return commit, nil 79 } 80 } 81 82 commit, err := c.repo.GetCommit(commitID) 83 if err != nil { 84 return nil, err 85 } 86 if c.commitCache == nil { 87 c.commitCache = make(map[string]*Commit) 88 } 89 c.commitCache[commitID] = commit 90 return commit, nil 91} 92 93// GetCommitByPath gets the last commit for the entry in the provided commit 94func (c *LastCommitCache) GetCommitByPath(commitID, entryPath string) (*Commit, error) { 95 sha, err := NewIDFromString(commitID) 96 if err != nil { 97 return nil, err 98 } 99 100 lastCommit, err := c.Get(sha.String(), entryPath) 101 if err != nil || lastCommit != nil { 102 return lastCommit, err 103 } 104 105 lastCommit, err = c.repo.getCommitByPathWithID(sha, entryPath) 106 if err != nil { 107 return nil, err 108 } 109 110 if err := c.Put(commitID, entryPath, lastCommit.ID.String()); err != nil { 111 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) 112 } 113 114 return lastCommit, nil 115} 116 117// CacheCommit will cache the commit from the gitRepository 118func (c *Commit) CacheCommit(ctx context.Context) error { 119 if c.repo.LastCommitCache == nil { 120 return nil 121 } 122 return c.recursiveCache(ctx, &c.Tree, "", 1) 123} 124 125func (c *Commit) recursiveCache(ctx context.Context, tree *Tree, treePath string, level int) error { 126 if level == 0 { 127 return nil 128 } 129 130 entries, err := tree.ListEntries() 131 if err != nil { 132 return err 133 } 134 135 entryPaths := make([]string, len(entries)) 136 for i, entry := range entries { 137 entryPaths[i] = entry.Name() 138 } 139 140 _, err = WalkGitLog(ctx, c.repo, c, treePath, entryPaths...) 141 if err != nil { 142 return err 143 } 144 145 for _, treeEntry := range entries { 146 // entryMap won't contain "" therefore skip this. 147 if treeEntry.IsDir() { 148 subTree, err := tree.SubTree(treeEntry.Name()) 149 if err != nil { 150 return err 151 } 152 if err := c.recursiveCache(ctx, subTree, treeEntry.Name(), level-1); err != nil { 153 return err 154 } 155 } 156 } 157 158 return nil 159}