aboutsummaryrefslogtreecommitdiffstats
path: root/models/db/context.go
diff options
context:
space:
mode:
authorJason Song <i@wolfogre.com>2023-01-10 01:19:19 +0800
committerGitHub <noreply@github.com>2023-01-09 12:19:19 -0500
commita35714372d9e6be2cf92ce27ef8b05b37f8cb283 (patch)
treeda86138c14e428ec238d20ff2c76b7402657c3f6 /models/db/context.go
parent99a675f4a1fc32339e9b93ea33207322c3e8bef1 (diff)
downloadgitea-a35714372d9e6be2cf92ce27ef8b05b37f8cb283.tar.gz
gitea-a35714372d9e6be2cf92ce27ef8b05b37f8cb283.zip
Fix halfCommitter and WithTx (#22366)
Related to #22362. I overlooked that there's always `committer.Close()`, like: ```go ctx, committer, err := db.TxContext(db.DefaultContext) if err != nil { return nil } defer committer.Close() // ... if err != nil { return nil } // ... return committer.Commit() ``` So the `Close` of `halfCommitter` should ignore `commit and close`, it's not a rollback. See: [Why `halfCommitter` and `WithTx` should rollback IMMEDIATELY or commit LATER](https://github.com/go-gitea/gitea/pull/22366#issuecomment-1374778612). Co-authored-by: techknowlogick <techknowlogick@gitea.io>
Diffstat (limited to 'models/db/context.go')
-rw-r--r--models/db/context.go27
1 files changed, 22 insertions, 5 deletions
diff --git a/models/db/context.go b/models/db/context.go
index 455f3d1c5d..911dbd1c6f 100644
--- a/models/db/context.go
+++ b/models/db/context.go
@@ -98,19 +98,31 @@ type Committer interface {
// halfCommitter is a wrapper of Committer.
// It can be closed early, but can't be committed early, it is useful for reusing a transaction.
type halfCommitter struct {
- Committer
+ committer Committer
+ committed bool
}
-func (*halfCommitter) Commit() error {
- // do nothing
+func (c *halfCommitter) Commit() error {
+ c.committed = true
+ // should do nothing, and the parent committer will commit later
return nil
}
+func (c *halfCommitter) Close() error {
+ if c.committed {
+ // it's "commit and close", should do nothing, and the parent committer will commit later
+ return nil
+ }
+
+ // it's "rollback and close", let the parent committer rollback right now
+ return c.committer.Close()
+}
+
// TxContext represents a transaction Context,
// it will reuse the existing transaction in the parent context or create a new one.
func TxContext(parentCtx context.Context) (*Context, Committer, error) {
if sess, ok := inTransaction(parentCtx); ok {
- return newContext(parentCtx, sess, true), &halfCommitter{Committer: sess}, nil
+ return newContext(parentCtx, sess, true), &halfCommitter{committer: sess}, nil
}
sess := x.NewSession()
@@ -126,7 +138,12 @@ func TxContext(parentCtx context.Context) (*Context, Committer, error) {
// this function will reuse it otherwise will create a new one and close it when finished.
func WithTx(parentCtx context.Context, f func(ctx context.Context) error) error {
if sess, ok := inTransaction(parentCtx); ok {
- return f(newContext(parentCtx, sess, true))
+ err := f(newContext(parentCtx, sess, true))
+ if err != nil {
+ // rollback immediately, in case the caller ignores returned error and tries to commit the transaction.
+ _ = sess.Close()
+ }
+ return err
}
return txWithNoCheck(parentCtx, f)
}