diff options
author | Lunny Xiao <xiaolunwen@gmail.com> | 2023-06-05 18:33:47 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-06-05 10:33:47 +0000 |
commit | 315124b4693dd56d94d52cda3015611184a49a27 (patch) | |
tree | 273ea4fcb2c1bff7409834477d2a7287c7580ce1 /models | |
parent | 3d1fda737bc36e80a670f856fd85f6b884872b73 (diff) | |
download | gitea-315124b4693dd56d94d52cda3015611184a49a27.tar.gz gitea-315124b4693dd56d94d52cda3015611184a49a27.zip |
Fix parallelly generating index failure with Mysql (#24567)
Diffstat (limited to 'models')
-rw-r--r-- | models/db/index.go | 23 | ||||
-rw-r--r-- | models/git/commit_status.go | 34 |
2 files changed, 50 insertions, 7 deletions
diff --git a/models/db/index.go b/models/db/index.go index 7609d8fb6e..259ddd6ade 100644 --- a/models/db/index.go +++ b/models/db/index.go @@ -71,10 +71,31 @@ func postgresGetNextResourceIndex(ctx context.Context, tableName string, groupID return strconv.ParseInt(string(res[0]["max_index"]), 10, 64) } +func mysqlGetNextResourceIndex(ctx context.Context, tableName string, groupID int64) (int64, error) { + if _, err := GetEngine(ctx).Exec(fmt.Sprintf("INSERT INTO %s (group_id, max_index) "+ + "VALUES (?,1) ON DUPLICATE KEY UPDATE max_index = max_index+1", + tableName), groupID); err != nil { + return 0, err + } + + var idx int64 + _, err := GetEngine(ctx).SQL(fmt.Sprintf("SELECT max_index FROM %s WHERE group_id = ?", tableName), groupID).Get(&idx) + if err != nil { + return 0, err + } + if idx == 0 { + return 0, errors.New("cannot get the correct index") + } + return idx, nil +} + // GetNextResourceIndex generates a resource index, it must run in the same transaction where the resource is created func GetNextResourceIndex(ctx context.Context, tableName string, groupID int64) (int64, error) { - if setting.Database.Type.IsPostgreSQL() { + switch { + case setting.Database.Type.IsPostgreSQL(): return postgresGetNextResourceIndex(ctx, tableName, groupID) + case setting.Database.Type.IsMySQL(): + return mysqlGetNextResourceIndex(ctx, tableName, groupID) } e := GetEngine(ctx) diff --git a/models/git/commit_status.go b/models/git/commit_status.go index 6028e46649..a018bb0553 100644 --- a/models/git/commit_status.go +++ b/models/git/commit_status.go @@ -64,10 +64,32 @@ func postgresGetCommitStatusIndex(ctx context.Context, repoID int64, sha string) return strconv.ParseInt(string(res[0]["max_index"]), 10, 64) } +func mysqlGetCommitStatusIndex(ctx context.Context, repoID int64, sha string) (int64, error) { + if _, err := db.GetEngine(ctx).Exec("INSERT INTO `commit_status_index` (repo_id, sha, max_index) "+ + "VALUES (?,?,1) ON DUPLICATE KEY UPDATE max_index = max_index+1", + repoID, sha); err != nil { + return 0, err + } + + var idx int64 + _, err := db.GetEngine(ctx).SQL("SELECT max_index FROM `commit_status_index` WHERE repo_id = ? AND sha = ?", + repoID, sha).Get(&idx) + if err != nil { + return 0, err + } + if idx == 0 { + return 0, errors.New("cannot get the correct index") + } + return idx, nil +} + // GetNextCommitStatusIndex retried 3 times to generate a resource index func GetNextCommitStatusIndex(ctx context.Context, repoID int64, sha string) (int64, error) { - if setting.Database.Type.IsPostgreSQL() { + switch { + case setting.Database.Type.IsPostgreSQL(): return postgresGetCommitStatusIndex(ctx, repoID, sha) + case setting.Database.Type.IsMySQL(): + return mysqlGetCommitStatusIndex(ctx, repoID, sha) } e := db.GetEngine(ctx) @@ -75,7 +97,7 @@ func GetNextCommitStatusIndex(ctx context.Context, repoID int64, sha string) (in // try to update the max_index to next value, and acquire the write-lock for the record res, err := e.Exec("UPDATE `commit_status_index` SET max_index=max_index+1 WHERE repo_id=? AND sha=?", repoID, sha) if err != nil { - return 0, err + return 0, fmt.Errorf("update failed: %w", err) } affected, err := res.RowsAffected() if err != nil { @@ -86,18 +108,18 @@ func GetNextCommitStatusIndex(ctx context.Context, repoID int64, sha string) (in _, errIns := e.Exec("INSERT INTO `commit_status_index` (repo_id, sha, max_index) VALUES (?, ?, 0)", repoID, sha) res, err = e.Exec("UPDATE `commit_status_index` SET max_index=max_index+1 WHERE repo_id=? AND sha=?", repoID, sha) if err != nil { - return 0, err + return 0, fmt.Errorf("update2 failed: %w", err) } affected, err = res.RowsAffected() if err != nil { - return 0, err + return 0, fmt.Errorf("RowsAffected failed: %w", err) } // if the update still can not update any records, the record must not exist and there must be some errors (insert error) if affected == 0 { if errIns == nil { return 0, errors.New("impossible error when GetNextCommitStatusIndex, insert and update both succeeded but no record is updated") } - return 0, errIns + return 0, fmt.Errorf("insert failed: %w", errIns) } } @@ -105,7 +127,7 @@ func GetNextCommitStatusIndex(ctx context.Context, repoID int64, sha string) (in var newIdx int64 has, err := e.SQL("SELECT max_index FROM `commit_status_index` WHERE repo_id=? AND sha=?", repoID, sha).Get(&newIdx) if err != nil { - return 0, err + return 0, fmt.Errorf("select failed: %w", err) } if !has { return 0, errors.New("impossible error when GetNextCommitStatusIndex, upsert succeeded but no record can be selected") |