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