2020-12-17 17:00:47 +03:00
// Copyright 2020 The Gitea Authors. All rights reserved.
2022-11-27 21:20:29 +03:00
// SPDX-License-Identifier: MIT
2020-12-17 17:00:47 +03:00
package git
import (
2023-09-30 01:45:31 +03:00
"crypto/sha256"
2020-12-17 17:00:47 +03:00
"fmt"
2021-06-25 19:54:08 +03:00
"code.gitea.io/gitea/modules/log"
2022-07-25 18:39:42 +03:00
"code.gitea.io/gitea/modules/setting"
2020-12-17 17:00:47 +03:00
)
// Cache represents a caching interface
type Cache interface {
// Put puts value into cache with key and expire time.
2023-07-04 21:36:08 +03:00
Put ( key string , val any , timeout int64 ) error
2020-12-17 17:00:47 +03:00
// Get gets cached value by given key.
2023-07-04 21:36:08 +03:00
Get ( key string ) any
2020-12-17 17:00:47 +03:00
}
2022-07-25 18:39:42 +03:00
func getCacheKey ( repoPath , commitID , entryPath string ) string {
hashBytes := sha256 . Sum256 ( [ ] byte ( fmt . Sprintf ( "%s:%s:%s" , repoPath , commitID , entryPath ) ) )
2020-12-17 17:00:47 +03:00
return fmt . Sprintf ( "last_commit:%x" , hashBytes )
}
2022-07-25 18:39:42 +03:00
// LastCommitCache represents a cache to store last commit
type LastCommitCache struct {
repoPath string
ttl func ( ) int64
repo * Repository
commitCache map [ string ] * Commit
cache Cache
}
// NewLastCommitCache creates a new last commit cache for repo
func NewLastCommitCache ( count int64 , repoPath string , gitRepo * Repository , cache Cache ) * LastCommitCache {
if cache == nil {
return nil
}
2023-12-19 12:29:05 +03:00
if count < setting . CacheService . LastCommit . CommitsCount {
2022-07-25 18:39:42 +03:00
return nil
}
return & LastCommitCache {
repoPath : repoPath ,
repo : gitRepo ,
ttl : setting . LastCommitCacheTTLSeconds ,
cache : cache ,
}
}
2020-12-17 17:00:47 +03:00
// Put put the last commit id with commit and entry path
func ( c * LastCommitCache ) Put ( ref , entryPath , commitID string ) error {
2021-10-08 16:08:22 +03:00
if c == nil || c . cache == nil {
return nil
}
2021-06-25 19:54:08 +03:00
log . Debug ( "LastCommitCache save: [%s:%s:%s]" , ref , entryPath , commitID )
2022-07-25 18:39:42 +03:00
return c . cache . Put ( getCacheKey ( c . repoPath , ref , entryPath ) , commitID , c . ttl ( ) )
}
// Get gets the last commit information by commit id and entry path
func ( c * LastCommitCache ) Get ( ref , entryPath string ) ( * Commit , error ) {
if c == nil || c . cache == nil {
return nil , nil
}
commitID , ok := c . cache . Get ( getCacheKey ( c . repoPath , ref , entryPath ) ) . ( string )
if ! ok || commitID == "" {
return nil , nil
}
log . Debug ( "LastCommitCache hit level 1: [%s:%s:%s]" , ref , entryPath , commitID )
if c . commitCache != nil {
if commit , ok := c . commitCache [ commitID ] ; ok {
log . Debug ( "LastCommitCache hit level 2: [%s:%s:%s]" , ref , entryPath , commitID )
return commit , nil
}
}
commit , err := c . repo . GetCommit ( commitID )
if err != nil {
return nil , err
}
if c . commitCache == nil {
c . commitCache = make ( map [ string ] * Commit )
}
c . commitCache [ commitID ] = commit
return commit , nil
}
// GetCommitByPath gets the last commit for the entry in the provided commit
func ( c * LastCommitCache ) GetCommitByPath ( commitID , entryPath string ) ( * Commit , error ) {
2023-12-19 10:20:47 +03:00
sha , err := NewIDFromString ( commitID )
2022-07-25 18:39:42 +03:00
if err != nil {
return nil , err
}
2023-12-14 00:02:00 +03:00
lastCommit , err := c . Get ( sha . String ( ) , entryPath )
2022-07-25 18:39:42 +03:00
if err != nil || lastCommit != nil {
return lastCommit , err
}
2023-12-14 00:02:00 +03:00
lastCommit , err = c . repo . getCommitByPathWithID ( sha , entryPath )
2022-07-25 18:39:42 +03:00
if err != nil {
return nil , err
}
if err := c . Put ( commitID , entryPath , lastCommit . ID . String ( ) ) ; err != nil {
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 )
}
return lastCommit , nil
2020-12-17 17:00:47 +03:00
}