mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 07:21:36 +01:00 
			
		
		
		
	Add commit count caching (#2774)
* Add commit count caching * Small refactoring * Add different key prefix for refs and commits * Add configuratuion option to allow to change caching time or disable it
This commit is contained in:
		
							parent
							
								
									3ab580c8d6
								
							
						
					
					
						commit
						eca05b09aa
					
				
							
								
								
									
										3
									
								
								conf/app.ini
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								conf/app.ini
									
									
									
									
										vendored
									
									
								
							| @ -339,6 +339,9 @@ INTERVAL = 60 | ||||
| ; redis: network=tcp,addr=:6379,password=macaron,db=0,pool_size=100,idle_timeout=180 | ||||
| ; memcache: `127.0.0.1:11211` | ||||
| HOST = | ||||
| ; Time to keep items in cache if not used, default is 16 hours. | ||||
| ; Setting it to 0 disables caching | ||||
| ITEM_TTL = 16h | ||||
| 
 | ||||
| [session] | ||||
| ; Either "memory", "file", or "redis", default is "memory" | ||||
|  | ||||
| @ -258,6 +258,17 @@ func (repo *Repository) APIFormat(mode AccessMode) *api.Repository { | ||||
| 	return repo.innerAPIFormat(mode, false) | ||||
| } | ||||
| 
 | ||||
| // GetCommitsCountCacheKey returns cache key used for commits count caching. | ||||
| func (repo *Repository) GetCommitsCountCacheKey(contextName string, isRef bool) string { | ||||
| 	var prefix string | ||||
| 	if isRef { | ||||
| 		prefix = "ref" | ||||
| 	} else { | ||||
| 		prefix = "commit" | ||||
| 	} | ||||
| 	return fmt.Sprintf("commits-count-%d-%s-%s", repo.ID, prefix, contextName) | ||||
| } | ||||
| 
 | ||||
| func (repo *Repository) innerAPIFormat(mode AccessMode, isParent bool) *api.Repository { | ||||
| 	var parent *api.Repository | ||||
| 
 | ||||
|  | ||||
| @ -11,7 +11,7 @@ import ( | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"code.gitea.io/git" | ||||
| 
 | ||||
| 	"code.gitea.io/gitea/modules/cache" | ||||
| 	"code.gitea.io/gitea/modules/log" | ||||
| ) | ||||
| 
 | ||||
| @ -205,19 +205,26 @@ func pushUpdate(opts PushUpdateOptions) (repo *Repository, err error) { | ||||
| 	var commits = &PushCommits{} | ||||
| 	if strings.HasPrefix(opts.RefFullName, git.TagPrefix) { | ||||
| 		// If is tag reference | ||||
| 		tagName := opts.RefFullName[len(git.TagPrefix):] | ||||
| 		if isDelRef { | ||||
| 			err = pushUpdateDeleteTag(repo, gitRepo, opts.RefFullName[len(git.TagPrefix):]) | ||||
| 			err = pushUpdateDeleteTag(repo, gitRepo, tagName) | ||||
| 			if err != nil { | ||||
| 				return nil, fmt.Errorf("pushUpdateDeleteTag: %v", err) | ||||
| 			} | ||||
| 		} else { | ||||
| 			err = pushUpdateAddTag(repo, gitRepo, opts.RefFullName[len(git.TagPrefix):]) | ||||
| 			// Clear cache for tag commit count | ||||
| 			cache.Remove(repo.GetCommitsCountCacheKey(tagName, true)) | ||||
| 			err = pushUpdateAddTag(repo, gitRepo, tagName) | ||||
| 			if err != nil { | ||||
| 				return nil, fmt.Errorf("pushUpdateAddTag: %v", err) | ||||
| 			} | ||||
| 		} | ||||
| 	} else if !isDelRef { | ||||
| 		// If is branch reference | ||||
| 
 | ||||
| 		// Clear cache for branch commit count | ||||
| 		cache.Remove(repo.GetCommitsCountCacheKey(opts.RefFullName[len(git.BranchPrefix):], true)) | ||||
| 
 | ||||
| 		newCommit, err := gitRepo.GetCommit(opts.NewCommitID) | ||||
| 		if err != nil { | ||||
| 			return nil, fmt.Errorf("gitRepo.GetCommit: %v", err) | ||||
|  | ||||
							
								
								
									
										72
									
								
								modules/cache/cache.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								modules/cache/cache.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,72 @@ | ||||
| // Copyright 2017 The Gitea Authors. All rights reserved. | ||||
| // Use of this source code is governed by a MIT-style | ||||
| // license that can be found in the LICENSE file. | ||||
| 
 | ||||
| package cache | ||||
| 
 | ||||
| import ( | ||||
| 	"code.gitea.io/gitea/modules/setting" | ||||
| 
 | ||||
| 	mc "github.com/go-macaron/cache" | ||||
| ) | ||||
| 
 | ||||
| var conn mc.Cache | ||||
| 
 | ||||
| // NewContext start cache service | ||||
| func NewContext() error { | ||||
| 	if setting.CacheService == nil || conn != nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	var err error | ||||
| 	conn, err = mc.NewCacher(setting.CacheService.Adapter, mc.Options{ | ||||
| 		Adapter:       setting.CacheService.Adapter, | ||||
| 		AdapterConfig: setting.CacheService.Conn, | ||||
| 		Interval:      setting.CacheService.Interval, | ||||
| 	}) | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| // GetInt returns key value from cache with callback when no key exists in cache | ||||
| func GetInt(key string, getFunc func() (int, error)) (int, error) { | ||||
| 	if conn == nil || setting.CacheService.TTL == 0 { | ||||
| 		return getFunc() | ||||
| 	} | ||||
| 	if !conn.IsExist(key) { | ||||
| 		var ( | ||||
| 			value int | ||||
| 			err   error | ||||
| 		) | ||||
| 		if value, err = getFunc(); err != nil { | ||||
| 			return value, err | ||||
| 		} | ||||
| 		conn.Put(key, value, int64(setting.CacheService.TTL.Seconds())) | ||||
| 	} | ||||
| 	return conn.Get(key).(int), nil | ||||
| } | ||||
| 
 | ||||
| // GetInt64 returns key value from cache with callback when no key exists in cache | ||||
| func GetInt64(key string, getFunc func() (int64, error)) (int64, error) { | ||||
| 	if conn == nil || setting.CacheService.TTL == 0 { | ||||
| 		return getFunc() | ||||
| 	} | ||||
| 	if !conn.IsExist(key) { | ||||
| 		var ( | ||||
| 			value int64 | ||||
| 			err   error | ||||
| 		) | ||||
| 		if value, err = getFunc(); err != nil { | ||||
| 			return value, err | ||||
| 		} | ||||
| 		conn.Put(key, value, int64(setting.CacheService.TTL.Seconds())) | ||||
| 	} | ||||
| 	return conn.Get(key).(int64), nil | ||||
| } | ||||
| 
 | ||||
| // Remove key from cache | ||||
| func Remove(key string) { | ||||
| 	if conn == nil { | ||||
| 		return | ||||
| 	} | ||||
| 	conn.Delete(key) | ||||
| } | ||||
| @ -13,7 +13,9 @@ import ( | ||||
| 
 | ||||
| 	"code.gitea.io/git" | ||||
| 	"code.gitea.io/gitea/models" | ||||
| 	"code.gitea.io/gitea/modules/cache" | ||||
| 	"code.gitea.io/gitea/modules/setting" | ||||
| 
 | ||||
| 	"github.com/Unknwon/com" | ||||
| 	"gopkg.in/editorconfig/editorconfig-core-go.v1" | ||||
| 	"gopkg.in/macaron.v1" | ||||
| @ -100,6 +102,21 @@ func (r *Repository) CanUseTimetracker(issue *models.Issue, user *models.User) b | ||||
| 		r.IsWriter() || issue.IsPoster(user.ID) || issue.AssigneeID == user.ID) | ||||
| } | ||||
| 
 | ||||
| // GetCommitsCount returns cached commit count for current view | ||||
| func (r *Repository) GetCommitsCount() (int64, error) { | ||||
| 	var contextName string | ||||
| 	if r.IsViewBranch { | ||||
| 		contextName = r.BranchName | ||||
| 	} else if r.IsViewTag { | ||||
| 		contextName = r.TagName | ||||
| 	} else { | ||||
| 		contextName = r.CommitID | ||||
| 	} | ||||
| 	return cache.GetInt64(r.Repository.GetCommitsCountCacheKey(contextName, r.IsViewBranch || r.IsViewTag), func() (int64, error) { | ||||
| 		return r.Commit.CommitsCount() | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| // GetEditorconfig returns the .editorconfig definition if found in the | ||||
| // HEAD of the default repo branch. | ||||
| func (r *Repository) GetEditorconfig() (*editorconfig.Editorconfig, error) { | ||||
| @ -535,9 +552,9 @@ func RepoRef() macaron.Handler { | ||||
| 		ctx.Data["IsViewCommit"] = ctx.Repo.IsViewCommit | ||||
| 		ctx.Data["CanCreateBranch"] = ctx.Repo.CanCreateBranch() | ||||
| 
 | ||||
| 		ctx.Repo.CommitsCount, err = ctx.Repo.Commit.CommitsCount() | ||||
| 		ctx.Repo.CommitsCount, err = ctx.Repo.GetCommitsCount() | ||||
| 		if err != nil { | ||||
| 			ctx.Handle(500, "CommitsCount", err) | ||||
| 			ctx.Handle(500, "GetCommitsCount", err) | ||||
| 			return | ||||
| 		} | ||||
| 		ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount | ||||
|  | ||||
| @ -325,11 +325,6 @@ var ( | ||||
| 	// Time settings | ||||
| 	TimeFormat string | ||||
| 
 | ||||
| 	// Cache settings | ||||
| 	CacheAdapter  string | ||||
| 	CacheInterval int | ||||
| 	CacheConn     string | ||||
| 
 | ||||
| 	// Session settings | ||||
| 	SessionConfig  session.Options | ||||
| 	CSRFCookieName = "_csrf" | ||||
| @ -1295,16 +1290,33 @@ func NewXORMLogService(disableConsole bool) { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Cache represents cache settings | ||||
| type Cache struct { | ||||
| 	Adapter  string | ||||
| 	Interval int | ||||
| 	Conn     string | ||||
| 	TTL      time.Duration | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| 	// CacheService the global cache | ||||
| 	CacheService *Cache | ||||
| ) | ||||
| 
 | ||||
| func newCacheService() { | ||||
| 	CacheAdapter = Cfg.Section("cache").Key("ADAPTER").In("memory", []string{"memory", "redis", "memcache"}) | ||||
| 	switch CacheAdapter { | ||||
| 	case "memory": | ||||
| 		CacheInterval = Cfg.Section("cache").Key("INTERVAL").MustInt(60) | ||||
| 	case "redis", "memcache": | ||||
| 		CacheConn = strings.Trim(Cfg.Section("cache").Key("HOST").String(), "\" ") | ||||
| 	default: | ||||
| 		log.Fatal(4, "Unknown cache adapter: %s", CacheAdapter) | ||||
| 	sec := Cfg.Section("cache") | ||||
| 	CacheService = &Cache{ | ||||
| 		Adapter: sec.Key("ADAPTER").In("memory", []string{"memory", "redis", "memcache"}), | ||||
| 	} | ||||
| 	switch CacheService.Adapter { | ||||
| 	case "memory": | ||||
| 		CacheService.Interval = sec.Key("INTERVAL").MustInt(60) | ||||
| 	case "redis", "memcache": | ||||
| 		CacheService.Conn = strings.Trim(sec.Key("HOST").String(), "\" ") | ||||
| 	default: | ||||
| 		log.Fatal(4, "Unknown cache adapter: %s", CacheService.Adapter) | ||||
| 	} | ||||
| 	CacheService.TTL = sec.Key("ITEM_TTL").MustDuration(16 * time.Hour) | ||||
| 
 | ||||
| 	log.Info("Cache Service Enabled") | ||||
| } | ||||
|  | ||||
| @ -224,9 +224,9 @@ func Config(ctx *context.Context) { | ||||
| 		ctx.Data["Mailer"] = setting.MailService | ||||
| 	} | ||||
| 
 | ||||
| 	ctx.Data["CacheAdapter"] = setting.CacheAdapter | ||||
| 	ctx.Data["CacheInterval"] = setting.CacheInterval | ||||
| 	ctx.Data["CacheConn"] = setting.CacheConn | ||||
| 	ctx.Data["CacheAdapter"] = setting.CacheService.Adapter | ||||
| 	ctx.Data["CacheInterval"] = setting.CacheService.Interval | ||||
| 	ctx.Data["CacheConn"] = setting.CacheService.Conn | ||||
| 
 | ||||
| 	ctx.Data["SessionConfig"] = setting.SessionConfig | ||||
| 
 | ||||
|  | ||||
| @ -11,6 +11,7 @@ import ( | ||||
| 	"code.gitea.io/git" | ||||
| 	"code.gitea.io/gitea/models" | ||||
| 	"code.gitea.io/gitea/models/migrations" | ||||
| 	"code.gitea.io/gitea/modules/cache" | ||||
| 	"code.gitea.io/gitea/modules/cron" | ||||
| 	"code.gitea.io/gitea/modules/highlight" | ||||
| 	"code.gitea.io/gitea/modules/log" | ||||
| @ -18,6 +19,7 @@ import ( | ||||
| 	"code.gitea.io/gitea/modules/markup" | ||||
| 	"code.gitea.io/gitea/modules/setting" | ||||
| 	"code.gitea.io/gitea/modules/ssh" | ||||
| 
 | ||||
| 	macaron "gopkg.in/macaron.v1" | ||||
| ) | ||||
| 
 | ||||
| @ -37,6 +39,7 @@ func checkRunMode() { | ||||
| func NewServices() { | ||||
| 	setting.NewServices() | ||||
| 	mailer.NewContext() | ||||
| 	cache.NewContext() | ||||
| } | ||||
| 
 | ||||
| // GlobalInit is for global configuration reload-able. | ||||
|  | ||||
| @ -55,7 +55,7 @@ func Commits(ctx *context.Context) { | ||||
| 	} | ||||
| 	ctx.Data["PageIsViewCode"] = true | ||||
| 
 | ||||
| 	commitsCount, err := ctx.Repo.Commit.CommitsCount() | ||||
| 	commitsCount, err := ctx.Repo.GetCommitsCount() | ||||
| 	if err != nil { | ||||
| 		ctx.Handle(500, "GetCommitsCount", err) | ||||
| 		return | ||||
| @ -91,7 +91,7 @@ func Graph(ctx *context.Context) { | ||||
| 	ctx.Data["PageIsCommits"] = true | ||||
| 	ctx.Data["PageIsViewCode"] = true | ||||
| 
 | ||||
| 	commitsCount, err := ctx.Repo.Commit.CommitsCount() | ||||
| 	commitsCount, err := ctx.Repo.GetCommitsCount() | ||||
| 	if err != nil { | ||||
| 		ctx.Handle(500, "GetCommitsCount", err) | ||||
| 		return | ||||
|  | ||||
| @ -99,9 +99,9 @@ func NewMacaron() *macaron.Macaron { | ||||
| 		Redirect:    true, | ||||
| 	})) | ||||
| 	m.Use(cache.Cacher(cache.Options{ | ||||
| 		Adapter:       setting.CacheAdapter, | ||||
| 		AdapterConfig: setting.CacheConn, | ||||
| 		Interval:      setting.CacheInterval, | ||||
| 		Adapter:       setting.CacheService.Adapter, | ||||
| 		AdapterConfig: setting.CacheService.Conn, | ||||
| 		Interval:      setting.CacheService.Interval, | ||||
| 	})) | ||||
| 	m.Use(captcha.Captchaer(captcha.Options{ | ||||
| 		SubURL: setting.AppSubURL, | ||||
| @ -576,9 +576,9 @@ func RegisterRoutes(m *macaron.Macaron) { | ||||
| 				ctx.Handle(500, "GetBranchCommit", err) | ||||
| 				return | ||||
| 			} | ||||
| 			ctx.Repo.CommitsCount, err = ctx.Repo.Commit.CommitsCount() | ||||
| 			ctx.Repo.CommitsCount, err = ctx.Repo.GetCommitsCount() | ||||
| 			if err != nil { | ||||
| 				ctx.Handle(500, "CommitsCount", err) | ||||
| 				ctx.Handle(500, "GetCommitsCount", err) | ||||
| 				return | ||||
| 			} | ||||
| 			ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user