1
0
Fork 0
mirror of https://codeberg.org/forgejo/forgejo.git synced 2024-12-22 12:54:53 -05:00

Ensure that sessions are passed into queries that could use the database to prevent deadlocks (#5718)

* Fixed deadlock in CreateComment

* Fix possible deadlock in UpdateIssueDeadline from createDeadlineComment

* Ensure that calls to IsTimeTracker enabled are called within session

Signed-off-by: Andrew Thornton <art27@cantab.net>

* Ensure that calls to reactionList are also called within session

Signed-off-by: Andrew Thornton <art27@cantab.net>

* Ensure all calls in NewPullRequest with the session are called within the session

Signed-off-by: Andrew Thornton <art27@cantab.net>

* Deal with potential deadlocks in repo

Signed-off-by: Andrew Thornton <art27@cantab.net>

* Ensure that isStaring is checked within our transaction

Signed-off-by: Andrew Thornton <art27@cantab.net>

* Fix mistake in isOrganizationMember

Sorry.
This commit is contained in:
zeripath 2019-01-14 02:29:58 +00:00 committed by techknowlogick
parent 656456441c
commit 6868378673
6 changed files with 42 additions and 22 deletions

View file

@ -103,7 +103,11 @@ func (issue *Issue) loadRepo(e Engine) (err error) {
// IsTimetrackerEnabled returns true if the repo enables timetracking // IsTimetrackerEnabled returns true if the repo enables timetracking
func (issue *Issue) IsTimetrackerEnabled() bool { func (issue *Issue) IsTimetrackerEnabled() bool {
if err := issue.loadRepo(x); err != nil { return issue.isTimetrackerEnabled(x)
}
func (issue *Issue) isTimetrackerEnabled(e Engine) bool {
if err := issue.loadRepo(e); err != nil {
log.Error(4, fmt.Sprintf("loadRepo: %v", err)) log.Error(4, fmt.Sprintf("loadRepo: %v", err))
return false return false
} }
@ -196,7 +200,7 @@ func (issue *Issue) loadReactions(e Engine) (err error) {
return err return err
} }
// Load reaction user data // Load reaction user data
if _, err := ReactionList(reactions).LoadUsers(); err != nil { if _, err := ReactionList(reactions).loadUsers(e); err != nil {
return err return err
} }
@ -255,7 +259,7 @@ func (issue *Issue) loadAttributes(e Engine) (err error) {
if err = issue.loadComments(e); err != nil { if err = issue.loadComments(e); err != nil {
return err return err
} }
if issue.IsTimetrackerEnabled() { if issue.isTimetrackerEnabled(e) {
if err = issue.loadTotalTimes(e); err != nil { if err = issue.loadTotalTimes(e); err != nil {
return err return err
} }

View file

@ -559,7 +559,7 @@ func sendCreateCommentAction(e *xorm.Session, opts *CreateCommentOptions, commen
case CommentTypeCode: case CommentTypeCode:
if comment.ReviewID != 0 { if comment.ReviewID != 0 {
if comment.Review == nil { if comment.Review == nil {
if err := comment.LoadReview(); err != nil { if err := comment.loadReview(e); err != nil {
return err return err
} }
} }
@ -709,7 +709,7 @@ func createDeadlineComment(e *xorm.Session, doer *User, issue *Issue, newDeadlin
content = newDeadlineUnix.Format("2006-01-02") + "|" + issue.DeadlineUnix.Format("2006-01-02") content = newDeadlineUnix.Format("2006-01-02") + "|" + issue.DeadlineUnix.Format("2006-01-02")
} }
if err := issue.LoadRepo(); err != nil { if err := issue.loadRepo(e); err != nil {
return nil, err return nil, err
} }

View file

@ -314,7 +314,11 @@ func IsOrganizationOwner(orgID, uid int64) (bool, error) {
// IsOrganizationMember returns true if given user is member of organization. // IsOrganizationMember returns true if given user is member of organization.
func IsOrganizationMember(orgID, uid int64) (bool, error) { func IsOrganizationMember(orgID, uid int64) (bool, error) {
return x. return isOrganizationMember(x, orgID, uid)
}
func isOrganizationMember(e Engine, orgID, uid int64) (bool, error) {
return e.
Where("uid=?", uid). Where("uid=?", uid).
And("org_id=?", orgID). And("org_id=?", orgID).
Table("org_user"). Table("org_user").

View file

@ -721,15 +721,15 @@ var patchConflicts = []string{
} }
// testPatch checks if patch can be merged to base repository without conflict. // testPatch checks if patch can be merged to base repository without conflict.
func (pr *PullRequest) testPatch() (err error) { func (pr *PullRequest) testPatch(e Engine) (err error) {
if pr.BaseRepo == nil { if pr.BaseRepo == nil {
pr.BaseRepo, err = GetRepositoryByID(pr.BaseRepoID) pr.BaseRepo, err = getRepositoryByID(e, pr.BaseRepoID)
if err != nil { if err != nil {
return fmt.Errorf("GetRepositoryByID: %v", err) return fmt.Errorf("GetRepositoryByID: %v", err)
} }
} }
patchPath, err := pr.BaseRepo.PatchPath(pr.Index) patchPath, err := pr.BaseRepo.patchPath(e, pr.Index)
if err != nil { if err != nil {
return fmt.Errorf("BaseRepo.PatchPath: %v", err) return fmt.Errorf("BaseRepo.PatchPath: %v", err)
} }
@ -758,7 +758,7 @@ func (pr *PullRequest) testPatch() (err error) {
return fmt.Errorf("git read-tree --index-output=%s %s: %v - %s", indexTmpPath, pr.BaseBranch, err, stderr) return fmt.Errorf("git read-tree --index-output=%s %s: %v - %s", indexTmpPath, pr.BaseBranch, err, stderr)
} }
prUnit, err := pr.BaseRepo.GetUnit(UnitTypePullRequests) prUnit, err := pr.BaseRepo.getUnit(e, UnitTypePullRequests)
if err != nil { if err != nil {
return err return err
} }
@ -811,12 +811,12 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str
} }
pr.Index = pull.Index pr.Index = pull.Index
if err = repo.SavePatch(pr.Index, patch); err != nil { if err = repo.savePatch(sess, pr.Index, patch); err != nil {
return fmt.Errorf("SavePatch: %v", err) return fmt.Errorf("SavePatch: %v", err)
} }
pr.BaseRepo = repo pr.BaseRepo = repo
if err = pr.testPatch(); err != nil { if err = pr.testPatch(sess); err != nil {
return fmt.Errorf("testPatch: %v", err) return fmt.Errorf("testPatch: %v", err)
} }
// No conflict appears after test means mergeable. // No conflict appears after test means mergeable.
@ -1363,7 +1363,7 @@ func TestPullRequests() {
if pr.manuallyMerged() { if pr.manuallyMerged() {
continue continue
} }
if err := pr.testPatch(); err != nil { if err := pr.testPatch(x); err != nil {
log.Error(3, "testPatch: %v", err) log.Error(3, "testPatch: %v", err)
continue continue
} }
@ -1387,7 +1387,7 @@ func TestPullRequests() {
continue continue
} else if pr.manuallyMerged() { } else if pr.manuallyMerged() {
continue continue
} else if err = pr.testPatch(); err != nil { } else if err = pr.testPatch(x); err != nil {
log.Error(4, "testPatch[%d]: %v", pr.ID, err) log.Error(4, "testPatch[%d]: %v", pr.ID, err)
continue continue
} }

View file

@ -776,7 +776,11 @@ func (repo *Repository) UpdateLocalCopyBranch(branch string) error {
// PatchPath returns corresponding patch file path of repository by given issue ID. // PatchPath returns corresponding patch file path of repository by given issue ID.
func (repo *Repository) PatchPath(index int64) (string, error) { func (repo *Repository) PatchPath(index int64) (string, error) {
if err := repo.GetOwner(); err != nil { return repo.patchPath(x, index)
}
func (repo *Repository) patchPath(e Engine, index int64) (string, error) {
if err := repo.getOwner(e); err != nil {
return "", err return "", err
} }
@ -785,7 +789,11 @@ func (repo *Repository) PatchPath(index int64) (string, error) {
// SavePatch saves patch data to corresponding location by given issue ID. // SavePatch saves patch data to corresponding location by given issue ID.
func (repo *Repository) SavePatch(index int64, patch []byte) error { func (repo *Repository) SavePatch(index int64, patch []byte) error {
patchPath, err := repo.PatchPath(index) return repo.savePatch(x, index, patch)
}
func (repo *Repository) savePatch(e Engine, index int64, patch []byte) error {
patchPath, err := repo.patchPath(e, index)
if err != nil { if err != nil {
return fmt.Errorf("PatchPath: %v", err) return fmt.Errorf("PatchPath: %v", err)
} }
@ -1479,7 +1487,7 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) error
collaboration := &Collaboration{RepoID: repo.ID} collaboration := &Collaboration{RepoID: repo.ID}
for _, c := range collaborators { for _, c := range collaborators {
if c.ID != newOwner.ID { if c.ID != newOwner.ID {
isMember, err := newOwner.IsOrgMember(c.ID) isMember, err := isOrganizationMember(sess, newOwner.ID, c.ID)
if err != nil { if err != nil {
return fmt.Errorf("IsOrgMember: %v", err) return fmt.Errorf("IsOrgMember: %v", err)
} else if !isMember { } else if !isMember {
@ -1536,12 +1544,12 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) error
if err = os.Rename(RepoPath(owner.Name, repo.Name), RepoPath(newOwner.Name, repo.Name)); err != nil { if err = os.Rename(RepoPath(owner.Name, repo.Name), RepoPath(newOwner.Name, repo.Name)); err != nil {
return fmt.Errorf("rename repository directory: %v", err) return fmt.Errorf("rename repository directory: %v", err)
} }
RemoveAllWithNotice("Delete repository local copy", repo.LocalCopyPath()) removeAllWithNotice(sess, "Delete repository local copy", repo.LocalCopyPath())
// Rename remote wiki repository to new path and delete local copy. // Rename remote wiki repository to new path and delete local copy.
wikiPath := WikiPath(owner.Name, repo.Name) wikiPath := WikiPath(owner.Name, repo.Name)
if com.IsExist(wikiPath) { if com.IsExist(wikiPath) {
RemoveAllWithNotice("Delete repository wiki local copy", repo.LocalWikiPath()) removeAllWithNotice(sess, "Delete repository wiki local copy", repo.LocalWikiPath())
if err = os.Rename(wikiPath, WikiPath(newOwner.Name, repo.Name)); err != nil { if err = os.Rename(wikiPath, WikiPath(newOwner.Name, repo.Name)); err != nil {
return fmt.Errorf("rename repository wiki: %v", err) return fmt.Errorf("rename repository wiki: %v", err)
} }

View file

@ -21,7 +21,7 @@ func StarRepo(userID, repoID int64, star bool) error {
} }
if star { if star {
if IsStaring(userID, repoID) { if isStaring(sess, userID, repoID) {
return nil return nil
} }
@ -35,7 +35,7 @@ func StarRepo(userID, repoID int64, star bool) error {
return err return err
} }
} else { } else {
if !IsStaring(userID, repoID) { if !isStaring(sess, userID, repoID) {
return nil return nil
} }
@ -55,7 +55,11 @@ func StarRepo(userID, repoID int64, star bool) error {
// IsStaring checks if user has starred given repository. // IsStaring checks if user has starred given repository.
func IsStaring(userID, repoID int64) bool { func IsStaring(userID, repoID int64) bool {
has, _ := x.Get(&Star{0, userID, repoID}) return isStaring(x, userID, repoID)
}
func isStaring(e Engine, userID, repoID int64) bool {
has, _ := e.Get(&Star{0, userID, repoID})
return has return has
} }