mirror of https://github.com/hak5/bolt.git
use tx.meta during Tx.WriteTo()
This commit changes `Tx.WriteTo()` to use the transaction's in-memory meta page instead of copying from the disk. This is needed because the transaction uses the size from its meta page but writes the current meta page on disk which may have allocated additional pages since the transaction started. Fixes #513master
parent
b514920f8f
commit
522043366c
32
tx.go
32
tx.go
|
@ -297,12 +297,34 @@ func (tx *Tx) WriteTo(w io.Writer) (n int64, err error) {
|
||||||
}
|
}
|
||||||
defer func() { _ = f.Close() }()
|
defer func() { _ = f.Close() }()
|
||||||
|
|
||||||
// Copy the meta pages.
|
// Generate a meta page. We use the same page data for both meta pages.
|
||||||
tx.db.metalock.Lock()
|
buf := make([]byte, tx.db.pageSize)
|
||||||
n, err = io.CopyN(w, f, int64(tx.db.pageSize*2))
|
page := (*page)(unsafe.Pointer(&buf[0]))
|
||||||
tx.db.metalock.Unlock()
|
page.flags = metaPageFlag
|
||||||
|
*page.meta() = *tx.meta
|
||||||
|
|
||||||
|
// Write meta 0.
|
||||||
|
page.id = 0
|
||||||
|
page.meta().checksum = page.meta().sum64()
|
||||||
|
nn, err := w.Write(buf)
|
||||||
|
n += int64(nn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return n, fmt.Errorf("meta copy: %s", err)
|
return n, fmt.Errorf("meta 0 copy: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write meta 1 with a lower transaction id.
|
||||||
|
page.id = 1
|
||||||
|
page.meta().txid -= 1
|
||||||
|
page.meta().checksum = page.meta().sum64()
|
||||||
|
nn, err = w.Write(buf)
|
||||||
|
n += int64(nn)
|
||||||
|
if err != nil {
|
||||||
|
return n, fmt.Errorf("meta 1 copy: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move past the meta pages in the file.
|
||||||
|
if _, err := f.Seek(int64(tx.db.pageSize*2), os.SEEK_SET); err != nil {
|
||||||
|
return n, fmt.Errorf("seek: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy data pages.
|
// Copy data pages.
|
||||||
|
|
|
@ -570,7 +570,7 @@ func TestTx_CopyFile_Error_Meta(t *testing.T) {
|
||||||
|
|
||||||
if err := db.View(func(tx *bolt.Tx) error {
|
if err := db.View(func(tx *bolt.Tx) error {
|
||||||
return tx.Copy(&failWriter{})
|
return tx.Copy(&failWriter{})
|
||||||
}); err == nil || err.Error() != "meta copy: error injected for tests" {
|
}); err == nil || err.Error() != "meta 0 copy: error injected for tests" {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue