Monorepo for Tangled tangled.org

knotserver/git: cache just the commit hash and time

This should help alleviate the memory leakyness that was exhibited when
we stored the entire object.Commit in memory.

anirudh.fi 31c88431 f164a6f6

verified
Changed files
+40 -17
appview
pages
templates
knotserver
git
types
+2 -2
appview/pages/templates/repo/index.html
··· 79 79 </a> 80 80 81 81 <time class="text-xs text-gray-500" 82 - >{{ timeFmt .LastCommit.Author.When }}</time 82 + >{{ timeFmt .LastCommit.When }}</time 83 83 > 84 84 </div> 85 85 </div> ··· 104 104 </a> 105 105 106 106 <time class="text-xs text-gray-500" 107 - >{{ timeFmt .LastCommit.Author.When }}</time 107 + >{{ timeFmt .LastCommit.When }}</time 108 108 > 109 109 </div> 110 110 </div>
+2 -2
appview/pages/templates/repo/tree.html
··· 44 44 <i class="w-3 h-3 fill-current" data-lucide="folder"></i>{{ .Name }} 45 45 </div> 46 46 </a> 47 - <time class="text-xs text-gray-500">{{ timeFmt .LastCommit.Author.When }}</time> 47 + <time class="text-xs text-gray-500">{{ timeFmt .LastCommit.When }}</time> 48 48 </div> 49 49 </div> 50 50 {{ end }} ··· 59 59 <i class="w-3 h-3" data-lucide="file"></i>{{ .Name }} 60 60 </div> 61 61 </a> 62 - <time class="text-xs text-gray-500">{{ timeFmt .LastCommit.Author.When }}</time> 62 + <time class="text-xs text-gray-500">{{ timeFmt .LastCommit.When }}</time> 63 63 </div> 64 64 </div> 65 65 {{ end }}
+26 -11
knotserver/git/git.go
··· 9 9 "os/exec" 10 10 "path" 11 11 "sort" 12 + "strconv" 12 13 "strings" 13 14 "sync" 14 15 "time" ··· 17 18 "github.com/go-git/go-git/v5" 18 19 "github.com/go-git/go-git/v5/plumbing" 19 20 "github.com/go-git/go-git/v5/plumbing/object" 21 + "github.com/sotangled/tangled/types" 20 22 ) 21 23 22 24 var ( ··· 297 299 return nil 298 300 } 299 301 300 - func (g *GitRepo) LastCommitForPath(path string) (*object.Commit, error) { 302 + func (g *GitRepo) LastCommitForPath(path string) (*types.LastCommitInfo, error) { 301 303 cacheKey := fmt.Sprintf("%s:%s", g.h.String(), path) 302 304 cacheMu.RLock() 303 - if commit, found := commitCache.Get(cacheKey); found { 305 + if commitInfo, found := commitCache.Get(cacheKey); found { 304 306 cacheMu.RUnlock() 305 - return commit.(*object.Commit), nil 307 + return commitInfo.(*types.LastCommitInfo), nil 306 308 } 307 309 cacheMu.RUnlock() 308 310 309 - cmd := exec.Command("git", "-C", g.path, "log", "-1", "--format=%H", "--", path) 311 + cmd := exec.Command("git", "-C", g.path, "log", "-1", "--format=%H %ct", "--", path) 310 312 311 313 var out bytes.Buffer 312 314 cmd.Stdout = &out ··· 316 318 return nil, fmt.Errorf("failed to get commit hash: %w", err) 317 319 } 318 320 319 - commitHash := strings.TrimSpace(out.String()) 320 - if commitHash == "" { 321 + output := strings.TrimSpace(out.String()) 322 + if output == "" { 321 323 return nil, fmt.Errorf("no commits found for path: %s", path) 322 324 } 323 325 326 + parts := strings.SplitN(output, " ", 2) 327 + if len(parts) < 2 { 328 + return nil, fmt.Errorf("unexpected commit log format") 329 + } 330 + 331 + commitHash := parts[0] 332 + commitTimeUnix, err := strconv.ParseInt(parts[1], 10, 64) 333 + if err != nil { 334 + return nil, fmt.Errorf("parsing commit time: %w", err) 335 + } 336 + commitTime := time.Unix(commitTimeUnix, 0) 337 + 324 338 hash := plumbing.NewHash(commitHash) 325 339 326 - commit, err := g.r.CommitObject(hash) 327 - if err != nil { 328 - return nil, err 340 + commitInfo := &types.LastCommitInfo{ 341 + Hash: hash, 342 + Message: "", 343 + When: commitTime, 329 344 } 330 345 331 346 cacheMu.Lock() 332 - commitCache.Set(cacheKey, commit, 1) 347 + commitCache.Set(cacheKey, commitInfo, 1) 333 348 cacheMu.Unlock() 334 349 335 - return commit, nil 350 + return commitInfo, nil 336 351 } 337 352 338 353 func newInfoWrapper(
+10 -2
types/tree.go
··· 1 1 package types 2 2 3 3 import ( 4 - "github.com/go-git/go-git/v5/plumbing/object" 4 + "time" 5 + 6 + "github.com/go-git/go-git/v5/plumbing" 5 7 ) 6 8 7 9 // A nicer git tree representation. ··· 12 14 IsFile bool `json:"is_file"` 13 15 IsSubtree bool `json:"is_subtree"` 14 16 15 - LastCommit *object.Commit `json:"last_commit,omitempty"` 17 + LastCommit *LastCommitInfo `json:"last_commit,omitempty"` 18 + } 19 + 20 + type LastCommitInfo struct { 21 + Hash plumbing.Hash 22 + Message string 23 + When time.Time 16 24 }