leveldb: don't discard transaction if cannot commit, returns error instead
diff --git a/leveldb/db_transaction.go b/leveldb/db_transaction.go
index 5deb57e..ec55dfe 100644
--- a/leveldb/db_transaction.go
+++ b/leveldb/db_transaction.go
@@ -179,7 +179,8 @@
<-tr.db.writeLockC
}
-// Commit commits the transaction.
+// Commit commits the transaction. If error is not nil, then the transaction is
+// not committed, it can then either be retried or discarded.
//
// Other methods should not be called after transaction has been committed.
func (tr *Transaction) Commit() error {
@@ -192,24 +193,27 @@
if tr.closed {
return errTransactionDone
}
- defer tr.setDone()
if err := tr.flush(); err != nil {
- tr.discard()
+ // Return error, lets user decide either to retry or discard
+ // transaction.
return err
}
if len(tr.tables) != 0 {
// Committing transaction.
tr.rec.setSeqNum(tr.seq)
tr.db.compCommitLk.Lock()
+ tr.stats.startTimer()
+ var cerr error
for retry := 0; retry < 3; retry++ {
- if err := tr.db.s.commit(&tr.rec); err != nil {
- tr.db.logf("transaction@commit error R·%d %q", retry, err)
+ cerr = tr.db.s.commit(&tr.rec)
+ if cerr != nil {
+ tr.db.logf("transaction@commit error R·%d %q", retry, cerr)
select {
case <-time.After(time.Second):
- case _, _ = <-tr.db.closeC:
+ case <-tr.db.closeC:
tr.db.logf("transaction@commit exiting")
tr.db.compCommitLk.Unlock()
- return err
+ return cerr
}
} else {
// Success. Set db.seq.
@@ -217,15 +221,26 @@
break
}
}
+ tr.stats.stopTimer()
+ if cerr != nil {
+ // Return error, lets user decide either to retry or discard
+ // transaction.
+ return cerr
+ }
+
+ // Update compaction stats. This is safe as long as we hold compCommitLk.
+ tr.db.compStats.addStat(0, &tr.stats)
+
// Trigger table auto-compaction.
tr.db.compTrigger(tr.db.tcompCmdC)
tr.db.compCommitLk.Unlock()
// Additionally, wait compaction when certain threshold reached.
- if err := tr.db.waitCompaction(); err != nil {
- return err
- }
+ // Ignore error, returns error only if transaction can't be committed.
+ tr.db.waitCompaction()
}
+ // Only mark as done if transaction committed successfully.
+ tr.setDone()
return nil
}