loading up the forgejo repo on tangled to test page performance
at forgejo 4.6 kB view raw
1// Copyright 2017 The Gitea Authors. All rights reserved. 2// SPDX-License-Identifier: MIT 3 4package git 5 6import ( 7 "context" 8 "fmt" 9 "io" 10 "path" 11 "sort" 12 13 "forgejo.org/modules/log" 14) 15 16// CommitInfo describes the first commit with the provided entry 17type CommitInfo struct { 18 Entry *TreeEntry 19 Commit *Commit 20 SubModuleFile *SubModuleFile 21} 22 23// GetCommitsInfo gets information of all commits that are corresponding to these entries 24func (tes Entries) GetCommitsInfo(ctx context.Context, commit *Commit, treePath string) ([]CommitInfo, *Commit, error) { 25 entryPaths := make([]string, len(tes)+1) 26 // Get the commit for the treePath itself 27 entryPaths[0] = "" 28 for i, entry := range tes { 29 entryPaths[i+1] = entry.Name() 30 } 31 32 var err error 33 34 var revs map[string]*Commit 35 if commit.repo.LastCommitCache != nil { 36 var unHitPaths []string 37 revs, unHitPaths, err = getLastCommitForPathsByCache(commit.ID.String(), treePath, entryPaths, commit.repo.LastCommitCache) 38 if err != nil { 39 return nil, nil, err 40 } 41 if len(unHitPaths) > 0 { 42 sort.Strings(unHitPaths) 43 commits, err := GetLastCommitForPaths(ctx, commit, treePath, unHitPaths) 44 if err != nil { 45 return nil, nil, err 46 } 47 48 for pth, found := range commits { 49 revs[pth] = found 50 } 51 } 52 } else { 53 sort.Strings(entryPaths) 54 revs, err = GetLastCommitForPaths(ctx, commit, treePath, entryPaths) 55 } 56 if err != nil { 57 return nil, nil, err 58 } 59 60 commitsInfo := make([]CommitInfo, len(tes)) 61 for i, entry := range tes { 62 commitsInfo[i] = CommitInfo{ 63 Entry: entry, 64 } 65 66 // Check if we have found a commit for this entry in time 67 if entryCommit, ok := revs[entry.Name()]; ok { 68 commitsInfo[i].Commit = entryCommit 69 } else { 70 log.Debug("missing commit for %s", entry.Name()) 71 } 72 73 // If the entry if a submodule add a submodule file for this 74 if entry.IsSubModule() { 75 var fullPath string 76 if len(treePath) > 0 { 77 fullPath = treePath + "/" + entry.Name() 78 } else { 79 fullPath = entry.Name() 80 } 81 subModuleURL, err := commit.GetSubModule(fullPath) 82 if err != nil { 83 return nil, nil, err 84 } 85 subModuleFile := NewSubModuleFile(commitsInfo[i].Commit, subModuleURL, entry.ID.String()) 86 commitsInfo[i].SubModuleFile = subModuleFile 87 } 88 } 89 90 // Retrieve the commit for the treePath itself (see above). We basically 91 // get it for free during the tree traversal and it's used for listing 92 // pages to display information about newest commit for a given path. 93 var treeCommit *Commit 94 var ok bool 95 if treePath == "" { 96 treeCommit = commit 97 } else if treeCommit, ok = revs[""]; ok { 98 treeCommit.repo = commit.repo 99 } 100 return commitsInfo, treeCommit, nil 101} 102 103func getLastCommitForPathsByCache(commitID, treePath string, paths []string, cache *LastCommitCache) (map[string]*Commit, []string, error) { 104 var unHitEntryPaths []string 105 results := make(map[string]*Commit) 106 for _, p := range paths { 107 lastCommit, err := cache.Get(commitID, path.Join(treePath, p)) 108 if err != nil { 109 return nil, nil, err 110 } 111 if lastCommit != nil { 112 results[p] = lastCommit 113 continue 114 } 115 116 unHitEntryPaths = append(unHitEntryPaths, p) 117 } 118 119 return results, unHitEntryPaths, nil 120} 121 122// GetLastCommitForPaths returns last commit information 123func GetLastCommitForPaths(ctx context.Context, commit *Commit, treePath string, paths []string) (map[string]*Commit, error) { 124 // We read backwards from the commit to obtain all of the commits 125 revs, err := WalkGitLog(ctx, commit.repo, commit, treePath, paths...) 126 if err != nil { 127 return nil, err 128 } 129 130 batchStdinWriter, batchReader, cancel, err := commit.repo.CatFileBatch(ctx) 131 if err != nil { 132 return nil, err 133 } 134 defer cancel() 135 136 commitsMap := map[string]*Commit{} 137 commitsMap[commit.ID.String()] = commit 138 139 commitCommits := map[string]*Commit{} 140 for path, commitID := range revs { 141 c, ok := commitsMap[commitID] 142 if ok { 143 commitCommits[path] = c 144 continue 145 } 146 147 if len(commitID) == 0 { 148 continue 149 } 150 151 _, err := batchStdinWriter.Write([]byte(commitID + "\n")) 152 if err != nil { 153 return nil, err 154 } 155 _, typ, size, err := ReadBatchLine(batchReader) 156 if err != nil { 157 return nil, err 158 } 159 if typ != "commit" { 160 if err := DiscardFull(batchReader, size+1); err != nil { 161 return nil, err 162 } 163 return nil, fmt.Errorf("unexpected type: %s for commit id: %s", typ, commitID) 164 } 165 c, err = CommitFromReader(commit.repo, MustIDFromString(commitID), io.LimitReader(batchReader, size)) 166 if err != nil { 167 return nil, err 168 } 169 if _, err := batchReader.Discard(1); err != nil { 170 return nil, err 171 } 172 commitCommits[path] = c 173 } 174 175 return commitCommits, nil 176}