mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 00:02:59 -04:00 
			
		
		
		
	Noticed a SQL in gitea.com has a bigger load. It seems both `is_pull` and `pin_order` are not indexed columns in the database. ```SQL SELECT `id`, `repo_id`, `index`, `poster_id`, `original_author`, `original_author_id`, `name`, `content`, `content_version`, `milestone_id`, `priority`, `is_closed`, `is_pull`, `num_comments`, `ref`, `pin_order`, `deadline_unix`, `created_unix`, `updated_unix`, `closed_unix`, `is_locked`, `time_estimate` FROM `issue` WHERE (repo_id =?) AND (is_pull = 0) AND (pin_order > 0) ORDER BY pin_order ``` I came across a comment https://github.com/go-gitea/gitea/pull/24406#issuecomment-1527747296 from @delvh , which presents a more reasonable approach. Based on this, this PR will migrate all issue and pull request pin data from the `issue` table to the `issue_pin` table. This change benefits larger Gitea instances by improving scalability and performance. --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
		
			
				
	
	
		
			117 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			117 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2023 The Gitea Authors. All rights reserved.
 | |
| // SPDX-License-Identifier: MIT
 | |
| 
 | |
| package repo
 | |
| 
 | |
| import (
 | |
| 	"net/http"
 | |
| 
 | |
| 	"code.gitea.io/gitea/models/db"
 | |
| 	issues_model "code.gitea.io/gitea/models/issues"
 | |
| 	"code.gitea.io/gitea/modules/json"
 | |
| 	"code.gitea.io/gitea/modules/log"
 | |
| 	"code.gitea.io/gitea/services/context"
 | |
| )
 | |
| 
 | |
| // IssuePinOrUnpin pin or unpin a Issue
 | |
| func IssuePinOrUnpin(ctx *context.Context) {
 | |
| 	issue := GetActionIssue(ctx)
 | |
| 	if ctx.Written() {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// If we don't do this, it will crash when trying to add the pin event to the comment history
 | |
| 	err := issue.LoadRepo(ctx)
 | |
| 	if err != nil {
 | |
| 		ctx.ServerError("LoadRepo", err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// PinOrUnpin pins or unpins a Issue
 | |
| 	_, err = issues_model.GetIssuePin(ctx, issue)
 | |
| 	if err != nil && !db.IsErrNotExist(err) {
 | |
| 		ctx.ServerError("GetIssuePin", err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	if db.IsErrNotExist(err) {
 | |
| 		err = issues_model.PinIssue(ctx, issue, ctx.Doer)
 | |
| 	} else {
 | |
| 		err = issues_model.UnpinIssue(ctx, issue, ctx.Doer)
 | |
| 	}
 | |
| 
 | |
| 	if err != nil {
 | |
| 		if issues_model.IsErrIssueMaxPinReached(err) {
 | |
| 			ctx.JSONError(ctx.Tr("repo.issues.max_pinned"))
 | |
| 		} else {
 | |
| 			ctx.ServerError("Pin/Unpin failed", err)
 | |
| 		}
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	ctx.JSONRedirect(issue.Link())
 | |
| }
 | |
| 
 | |
| // IssueUnpin unpins a Issue
 | |
| func IssueUnpin(ctx *context.Context) {
 | |
| 	issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index"))
 | |
| 	if err != nil {
 | |
| 		ctx.ServerError("GetIssueByIndex", err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// If we don't do this, it will crash when trying to add the pin event to the comment history
 | |
| 	err = issue.LoadRepo(ctx)
 | |
| 	if err != nil {
 | |
| 		ctx.ServerError("LoadRepo", err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	err = issues_model.UnpinIssue(ctx, issue, ctx.Doer)
 | |
| 	if err != nil {
 | |
| 		ctx.ServerError("UnpinIssue", err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	ctx.Status(http.StatusNoContent)
 | |
| }
 | |
| 
 | |
| // IssuePinMove moves a pinned Issue
 | |
| func IssuePinMove(ctx *context.Context) {
 | |
| 	if ctx.Doer == nil {
 | |
| 		ctx.JSON(http.StatusForbidden, "Only signed in users are allowed to perform this action.")
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	type movePinIssueForm struct {
 | |
| 		ID       int64 `json:"id"`
 | |
| 		Position int   `json:"position"`
 | |
| 	}
 | |
| 
 | |
| 	form := &movePinIssueForm{}
 | |
| 	if err := json.NewDecoder(ctx.Req.Body).Decode(&form); err != nil {
 | |
| 		ctx.ServerError("Decode", err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	issue, err := issues_model.GetIssueByID(ctx, form.ID)
 | |
| 	if err != nil {
 | |
| 		ctx.ServerError("GetIssueByID", err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	if issue.RepoID != ctx.Repo.Repository.ID {
 | |
| 		ctx.Status(http.StatusNotFound)
 | |
| 		log.Error("Issue does not belong to this repository")
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	err = issues_model.MovePin(ctx, issue, form.Position)
 | |
| 	if err != nil {
 | |
| 		ctx.ServerError("MovePin", err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	ctx.Status(http.StatusNoContent)
 | |
| }
 |