Do not attempt manual transaction rollback in Tx.Copy

The typical use these days is with a managed transaction, via db.View.

The first case (error when re-opening database file) is not tested;
it is harder to instrument, and I have other plans for it.
master
Tommi Virtanen 2014-05-28 10:14:00 -07:00
parent b9b1bb5b29
commit 394862d541
2 changed files with 51 additions and 3 deletions

3
tx.go
View File

@ -242,7 +242,6 @@ func (tx *Tx) Copy(w io.Writer) error {
// Open reader on the database.
f, err := os.OpenFile(tx.db.path, os.O_RDONLY|odirect, 0)
if err != nil {
_ = tx.Rollback()
return err
}
@ -251,14 +250,12 @@ func (tx *Tx) Copy(w io.Writer) error {
_, err = io.CopyN(w, f, int64(tx.db.pageSize*2))
tx.db.metalock.Unlock()
if err != nil {
_ = tx.Rollback()
_ = f.Close()
return fmt.Errorf("meta copy: %s", err)
}
// Copy data pages.
if _, err := io.CopyN(w, f, tx.Size()-int64(tx.db.pageSize*2)); err != nil {
_ = tx.Rollback()
_ = f.Close()
return err
}

View File

@ -338,6 +338,57 @@ func TestTx_CopyFile(t *testing.T) {
})
}
type failWriterError struct{}
func (failWriterError) Error() string {
return "error injected for tests"
}
type failWriter struct {
// fail after this many bytes
After int
}
func (f *failWriter) Write(p []byte) (n int, err error) {
n = len(p)
if n > f.After {
n = f.After
err = failWriterError{}
}
f.After -= n
return n, err
}
// Ensure that Copy handles write errors right.
func TestTx_CopyFile_Error_Meta(t *testing.T) {
withOpenDB(func(db *DB, path string) {
db.Update(func(tx *Tx) error {
tx.CreateBucket([]byte("widgets"))
tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar"))
tx.Bucket([]byte("widgets")).Put([]byte("baz"), []byte("bat"))
return nil
})
err := db.View(func(tx *Tx) error { return tx.Copy(&failWriter{}) })
assert.EqualError(t, err, "meta copy: error injected for tests")
})
}
// Ensure that Copy handles write errors right.
func TestTx_CopyFile_Error_Normal(t *testing.T) {
withOpenDB(func(db *DB, path string) {
db.Update(func(tx *Tx) error {
tx.CreateBucket([]byte("widgets"))
tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar"))
tx.Bucket([]byte("widgets")).Put([]byte("baz"), []byte("bat"))
return nil
})
err := db.View(func(tx *Tx) error { return tx.Copy(&failWriter{3 * db.pageSize}) })
assert.EqualError(t, err, "error injected for tests")
})
}
func ExampleTx_Rollback() {
// Open the database.
db, _ := Open(tempfile(), 0666)