code.gitea.io/gitea@v1.22.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/cache"
    11  	"code.gitea.io/gitea/modules/log"
    12  	"code.gitea.io/gitea/modules/setting"
    13  )
    14  
    15  func getCacheKey(repoPath, commitID, entryPath string) string {
    16  	hashBytes := sha256.Sum256([]byte(fmt.Sprintf("%s:%s:%s", repoPath, commitID, entryPath)))
    17  	return fmt.Sprintf("last_commit:%x", hashBytes)
    18  }
    19  
    20  // LastCommitCache represents a cache to store last commit
    21  type LastCommitCache struct {
    22  	repoPath    string
    23  	ttl         func() int64
    24  	repo        *Repository
    25  	commitCache map[string]*Commit
    26  	cache       cache.StringCache
    27  }
    28  
    29  // NewLastCommitCache creates a new last commit cache for repo
    30  func NewLastCommitCache(count int64, repoPath string, gitRepo *Repository, cache cache.StringCache) *LastCommitCache {
    31  	if cache == nil {
    32  		return nil
    33  	}
    34  	if count < setting.CacheService.LastCommit.CommitsCount {
    35  		return nil
    36  	}
    37  
    38  	return &LastCommitCache{
    39  		repoPath: repoPath,
    40  		repo:     gitRepo,
    41  		ttl:      setting.LastCommitCacheTTLSeconds,
    42  		cache:    cache,
    43  	}
    44  }
    45  
    46  // Put put the last commit id with commit and entry path
    47  func (c *LastCommitCache) Put(ref, entryPath, commitID string) error {
    48  	if c == nil || c.cache == nil {
    49  		return nil
    50  	}
    51  	log.Debug("LastCommitCache save: [%s:%s:%s]", ref, entryPath, commitID)
    52  	return c.cache.Put(getCacheKey(c.repoPath, ref, entryPath), commitID, c.ttl())
    53  }
    54  
    55  // Get gets the last commit information by commit id and entry path
    56  func (c *LastCommitCache) Get(ref, entryPath string) (*Commit, error) {
    57  	if c == nil || c.cache == nil {
    58  		return nil, nil
    59  	}
    60  
    61  	commitID, ok := c.cache.Get(getCacheKey(c.repoPath, ref, entryPath))
    62  	if !ok || commitID == "" {
    63  		return nil, nil
    64  	}
    65  
    66  	log.Debug("LastCommitCache hit level 1: [%s:%s:%s]", ref, entryPath, commitID)
    67  	if c.commitCache != nil {
    68  		if commit, ok := c.commitCache[commitID]; ok {
    69  			log.Debug("LastCommitCache hit level 2: [%s:%s:%s]", ref, entryPath, commitID)
    70  			return commit, nil
    71  		}
    72  	}
    73  
    74  	commit, err := c.repo.GetCommit(commitID)
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  	if c.commitCache == nil {
    79  		c.commitCache = make(map[string]*Commit)
    80  	}
    81  	c.commitCache[commitID] = commit
    82  	return commit, nil
    83  }
    84  
    85  // GetCommitByPath gets the last commit for the entry in the provided commit
    86  func (c *LastCommitCache) GetCommitByPath(commitID, entryPath string) (*Commit, error) {
    87  	sha, err := NewIDFromString(commitID)
    88  	if err != nil {
    89  		return nil, err
    90  	}
    91  
    92  	lastCommit, err := c.Get(sha.String(), entryPath)
    93  	if err != nil || lastCommit != nil {
    94  		return lastCommit, err
    95  	}
    96  
    97  	lastCommit, err = c.repo.getCommitByPathWithID(sha, entryPath)
    98  	if err != nil {
    99  		return nil, err
   100  	}
   101  
   102  	if err := c.Put(commitID, entryPath, lastCommit.ID.String()); err != nil {
   103  		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)
   104  	}
   105  
   106  	return lastCommit, nil
   107  }