Move repoWorkPool outside rename/transfer repository (#9086)

* Move repoWorkPool outside rename/transfer repository

* fix import

* Fix test
This commit is contained in:
Lunny Xiao 2019-12-06 12:00:50 +08:00 committed by GitHub
parent 9ff5b75559
commit 77730db257
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 40 additions and 54 deletions

View file

@ -609,8 +609,8 @@ func (pr *PullRequest) testPatch(e Engine) (err error) {
return nil return nil
} }
repoWorkingPool.CheckIn(com.ToStr(pr.BaseRepoID)) RepoWorkingPool.CheckIn(com.ToStr(pr.BaseRepoID))
defer repoWorkingPool.CheckOut(com.ToStr(pr.BaseRepoID)) defer RepoWorkingPool.CheckOut(com.ToStr(pr.BaseRepoID))
log.Trace("PullRequest[%d].testPatch (patchPath): %s", pr.ID, patchPath) log.Trace("PullRequest[%d].testPatch (patchPath): %s", pr.ID, patchPath)

View file

@ -43,7 +43,8 @@ import (
"xorm.io/builder" "xorm.io/builder"
) )
var repoWorkingPool = sync.NewExclusivePool() // RepoWorkingPool represents a working pool to order the parallel changes to the same repository
var RepoWorkingPool = sync.NewExclusivePool()
var ( var (
// ErrMirrorNotExist mirror does not exist error // ErrMirrorNotExist mirror does not exist error
@ -1655,7 +1656,7 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) error
return fmt.Errorf("sess.Begin: %v", err) return fmt.Errorf("sess.Begin: %v", err)
} }
owner := repo.Owner oldOwner := repo.Owner
// Note: we have to set value here to make sure recalculate accesses is based on // Note: we have to set value here to make sure recalculate accesses is based on
// new owner. // new owner.
@ -1691,8 +1692,8 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) error
} }
// Remove old team-repository relations. // Remove old team-repository relations.
if owner.IsOrganization() { if oldOwner.IsOrganization() {
if err = owner.removeOrgRepo(sess, repo.ID); err != nil { if err = oldOwner.removeOrgRepo(sess, repo.ID); err != nil {
return fmt.Errorf("removeOrgRepo: %v", err) return fmt.Errorf("removeOrgRepo: %v", err)
} }
} }
@ -1716,7 +1717,7 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) error
// Update repository count. // Update repository count.
if _, err = sess.Exec("UPDATE `user` SET num_repos=num_repos+1 WHERE id=?", newOwner.ID); err != nil { if _, err = sess.Exec("UPDATE `user` SET num_repos=num_repos+1 WHERE id=?", newOwner.ID); err != nil {
return fmt.Errorf("increase new owner repository count: %v", err) return fmt.Errorf("increase new owner repository count: %v", err)
} else if _, err = sess.Exec("UPDATE `user` SET num_repos=num_repos-1 WHERE id=?", owner.ID); err != nil { } else if _, err = sess.Exec("UPDATE `user` SET num_repos=num_repos-1 WHERE id=?", oldOwner.ID); err != nil {
return fmt.Errorf("decrease old owner repository count: %v", err) return fmt.Errorf("decrease old owner repository count: %v", err)
} }
@ -1725,8 +1726,8 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) error
} }
// Remove watch for organization. // Remove watch for organization.
if owner.IsOrganization() { if oldOwner.IsOrganization() {
if err = watchRepo(sess, owner.ID, repo.ID, false); err != nil { if err = watchRepo(sess, oldOwner.ID, repo.ID, false); err != nil {
return fmt.Errorf("watchRepo [false]: %v", err) return fmt.Errorf("watchRepo [false]: %v", err)
} }
} }
@ -1738,12 +1739,12 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) error
return fmt.Errorf("Failed to create dir %s: %v", dir, err) return fmt.Errorf("Failed to create dir %s: %v", dir, err)
} }
if err = os.Rename(RepoPath(owner.Name, repo.Name), RepoPath(newOwner.Name, repo.Name)); err != nil { if err = os.Rename(RepoPath(oldOwner.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)
} }
// 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(oldOwner.Name, repo.Name)
if com.IsExist(wikiPath) { if com.IsExist(wikiPath) {
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)
@ -1755,11 +1756,16 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) error
return fmt.Errorf("delete repo redirect: %v", err) return fmt.Errorf("delete repo redirect: %v", err)
} }
if err := NewRepoRedirect(DBContext{sess}, oldOwner.ID, repo.ID, repo.Name, repo.Name); err != nil {
return fmt.Errorf("NewRepoRedirect: %v", err)
}
return sess.Commit() return sess.Commit()
} }
// ChangeRepositoryName changes all corresponding setting from old repository name to new one. // ChangeRepositoryName changes all corresponding setting from old repository name to new one.
func ChangeRepositoryName(doer *User, repo *Repository, newRepoName string) (err error) { func ChangeRepositoryName(doer *User, repo *Repository, newRepoName string) (err error) {
oldRepoName := repo.Name
newRepoName = strings.ToLower(newRepoName) newRepoName = strings.ToLower(newRepoName)
if err = IsUsableRepoName(newRepoName); err != nil { if err = IsUsableRepoName(newRepoName); err != nil {
return err return err
@ -1776,12 +1782,6 @@ func ChangeRepositoryName(doer *User, repo *Repository, newRepoName string) (err
return ErrRepoAlreadyExist{repo.Owner.Name, newRepoName} return ErrRepoAlreadyExist{repo.Owner.Name, newRepoName}
} }
// Change repository directory name. We must lock the local copy of the
// repo so that we can atomically rename the repo path and updates the
// local copy's origin accordingly.
repoWorkingPool.CheckIn(com.ToStr(repo.ID))
defer repoWorkingPool.CheckOut(com.ToStr(repo.ID))
newRepoPath := RepoPath(repo.Owner.Name, newRepoName) newRepoPath := RepoPath(repo.Owner.Name, newRepoName)
if err = os.Rename(repo.RepoPath(), newRepoPath); err != nil { if err = os.Rename(repo.RepoPath(), newRepoPath); err != nil {
return fmt.Errorf("rename repository directory: %v", err) return fmt.Errorf("rename repository directory: %v", err)
@ -1805,6 +1805,10 @@ func ChangeRepositoryName(doer *User, repo *Repository, newRepoName string) (err
return fmt.Errorf("delete repo redirect: %v", err) return fmt.Errorf("delete repo redirect: %v", err)
} }
if err := NewRepoRedirect(DBContext{sess}, repo.Owner.ID, repo.ID, oldRepoName, newRepoName); err != nil {
return err
}
return sess.Commit() return sess.Commit()
} }

View file

@ -6,8 +6,6 @@ package models
import ( import (
"strings" "strings"
"code.gitea.io/gitea/modules/log"
) )
// RepoRedirect represents that a repo name should be redirected to another // RepoRedirect represents that a repo name should be redirected to another
@ -31,36 +29,22 @@ func LookupRepoRedirect(ownerID int64, repoName string) (int64, error) {
} }
// NewRepoRedirect create a new repo redirect // NewRepoRedirect create a new repo redirect
func NewRepoRedirect(ownerID, repoID int64, oldRepoName, newRepoName string) error { func NewRepoRedirect(ctx DBContext, ownerID, repoID int64, oldRepoName, newRepoName string) error {
oldRepoName = strings.ToLower(oldRepoName) oldRepoName = strings.ToLower(oldRepoName)
newRepoName = strings.ToLower(newRepoName) newRepoName = strings.ToLower(newRepoName)
sess := x.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil { if err := deleteRepoRedirect(ctx.e, ownerID, newRepoName); err != nil {
return err return err
} }
if err := deleteRepoRedirect(sess, ownerID, newRepoName); err != nil { if _, err := ctx.e.Insert(&RepoRedirect{
errRollback := sess.Rollback()
if errRollback != nil {
log.Error("NewRepoRedirect sess.Rollback: %v", errRollback)
}
return err
}
if _, err := sess.Insert(&RepoRedirect{
OwnerID: ownerID, OwnerID: ownerID,
LowerName: oldRepoName, LowerName: oldRepoName,
RedirectRepoID: repoID, RedirectRepoID: repoID,
}); err != nil { }); err != nil {
errRollback := sess.Rollback()
if errRollback != nil {
log.Error("NewRepoRedirect sess.Rollback: %v", errRollback)
}
return err return err
} }
return sess.Commit() return nil
} }
// deleteRepoRedirect delete any redirect from the specified repo name to // deleteRepoRedirect delete any redirect from the specified repo name to

View file

@ -26,7 +26,7 @@ func TestNewRepoRedirect(t *testing.T) {
assert.NoError(t, PrepareTestDatabase()) assert.NoError(t, PrepareTestDatabase())
repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
assert.NoError(t, NewRepoRedirect(repo.OwnerID, repo.ID, repo.Name, "newreponame")) assert.NoError(t, NewRepoRedirect(DefaultDBContext(), repo.OwnerID, repo.ID, repo.Name, "newreponame"))
AssertExistsAndLoadBean(t, &RepoRedirect{ AssertExistsAndLoadBean(t, &RepoRedirect{
OwnerID: repo.OwnerID, OwnerID: repo.OwnerID,
@ -45,7 +45,7 @@ func TestNewRepoRedirect2(t *testing.T) {
assert.NoError(t, PrepareTestDatabase()) assert.NoError(t, PrepareTestDatabase())
repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
assert.NoError(t, NewRepoRedirect(repo.OwnerID, repo.ID, repo.Name, "oldrepo1")) assert.NoError(t, NewRepoRedirect(DefaultDBContext(), repo.OwnerID, repo.ID, repo.Name, "oldrepo1"))
AssertExistsAndLoadBean(t, &RepoRedirect{ AssertExistsAndLoadBean(t, &RepoRedirect{
OwnerID: repo.OwnerID, OwnerID: repo.OwnerID,
@ -64,7 +64,7 @@ func TestNewRepoRedirect3(t *testing.T) {
assert.NoError(t, PrepareTestDatabase()) assert.NoError(t, PrepareTestDatabase())
repo := AssertExistsAndLoadBean(t, &Repository{ID: 2}).(*Repository) repo := AssertExistsAndLoadBean(t, &Repository{ID: 2}).(*Repository)
assert.NoError(t, NewRepoRedirect(repo.OwnerID, repo.ID, repo.Name, "newreponame")) assert.NoError(t, NewRepoRedirect(DefaultDBContext(), repo.OwnerID, repo.ID, repo.Name, "newreponame"))
AssertExistsAndLoadBean(t, &RepoRedirect{ AssertExistsAndLoadBean(t, &RepoRedirect{
OwnerID: repo.OwnerID, OwnerID: repo.OwnerID,

View file

@ -5,10 +5,10 @@
package repository package repository
import ( import (
"fmt"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/notification" "code.gitea.io/gitea/modules/notification"
"github.com/unknwon/com"
) )
// TransferOwnership transfers all corresponding setting from old user to new one. // TransferOwnership transfers all corresponding setting from old user to new one.
@ -19,13 +19,12 @@ func TransferOwnership(doer *models.User, newOwnerName string, repo *models.Repo
oldOwner := repo.Owner oldOwner := repo.Owner
models.RepoWorkingPool.CheckIn(com.ToStr(repo.ID))
if err := models.TransferOwnership(doer, newOwnerName, repo); err != nil { if err := models.TransferOwnership(doer, newOwnerName, repo); err != nil {
models.RepoWorkingPool.CheckOut(com.ToStr(repo.ID))
return err return err
} }
models.RepoWorkingPool.CheckOut(com.ToStr(repo.ID))
if err := models.NewRepoRedirect(oldOwner.ID, repo.ID, repo.Name, repo.Name); err != nil {
return fmt.Errorf("NewRepoRedirect: %v", err)
}
notification.NotifyTransferRepository(doer, repo, oldOwner.Name) notification.NotifyTransferRepository(doer, repo, oldOwner.Name)
@ -36,17 +35,16 @@ func TransferOwnership(doer *models.User, newOwnerName string, repo *models.Repo
func ChangeRepositoryName(doer *models.User, repo *models.Repository, newRepoName string) error { func ChangeRepositoryName(doer *models.User, repo *models.Repository, newRepoName string) error {
oldRepoName := repo.Name oldRepoName := repo.Name
// Change repository directory name. We must lock the local copy of the
// repo so that we can atomically rename the repo path and updates the
// local copy's origin accordingly.
models.RepoWorkingPool.CheckIn(com.ToStr(repo.ID))
if err := models.ChangeRepositoryName(doer, repo, newRepoName); err != nil { if err := models.ChangeRepositoryName(doer, repo, newRepoName); err != nil {
models.RepoWorkingPool.CheckOut(com.ToStr(repo.ID))
return err return err
} }
models.RepoWorkingPool.CheckOut(com.ToStr(repo.ID))
if err := repo.GetOwner(); err != nil {
return err
}
if err := models.NewRepoRedirect(repo.Owner.ID, repo.ID, oldRepoName, newRepoName); err != nil {
return err
}
notification.NotifyRenameRepository(doer, repo, oldRepoName) notification.NotifyRenameRepository(doer, repo, oldRepoName)