ReadModifyUpdate is a helper function to run a db transaction that reads some object(s), modifies some of the data, and writes the modified object(s) back to the database. It is run in a transaction at RepeatableRead isolation so that if another database client also modifies the data we are writing
(db Store, f func(tx Store) error, )
| 30 | // transaction fails, but here we retry. The second attempt we read A=2, B=1, |
| 31 | // then write A=2, B=2 as desired, and this succeeds. |
| 32 | func ReadModifyUpdate(db Store, f func(tx Store) error, |
| 33 | ) error { |
| 34 | var err error |
| 35 | for retries := 0; retries < maxRetries; retries++ { |
| 36 | err = db.InTx(f, &TxOptions{ |
| 37 | Isolation: sql.LevelRepeatableRead, |
| 38 | }) |
| 39 | var pqe *pq.Error |
| 40 | if xerrors.As(err, &pqe) { |
| 41 | if pqe.Code == "40001" { |
| 42 | // serialization error, retry |
| 43 | continue |
| 44 | } |
| 45 | } |
| 46 | return err |
| 47 | } |
| 48 | return xerrors.Errorf("too many errors; last error: %w", err) |
| 49 | } |