Skip to content
This repository has been archived by the owner on Mar 9, 2019. It is now read-only.

Commit

Permalink
Merge branch 'xiang90-tx_write'
Browse files Browse the repository at this point in the history
  • Loading branch information
benbjohnson committed Nov 6, 2015
2 parents 47d80ed + 6b1bbf0 commit 81db894
Show file tree
Hide file tree
Showing 6 changed files with 18 additions and 19 deletions.
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -426,8 +426,11 @@ func (*Bucket) DeleteBucket(key []byte) error
Bolt is a single file so it's easy to backup. You can use the `Tx.WriteTo()`
function to write a consistent view of the database to a writer. If you call
this from a read-only transaction, it will perform a hot backup and not block
your other database reads and writes. It will also use `O_DIRECT` when available
to prevent page cache trashing.
your other database reads and writes.

By default, it will use a regular file handle which will utilize the operating
system's page cache. See the [`Tx`](https://godoc.org/github.com/boltdb/bolt#Tx)
documentation for information about optimizing for larger-than-RAM datasets.

One common use case is to backup over HTTP so you can use tools like `cURL` to
do database backups:
Expand Down
2 changes: 0 additions & 2 deletions bolt_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import (
"syscall"
)

var odirect = syscall.O_DIRECT

// fdatasync flushes written data to a file descriptor.
func fdatasync(db *DB) error {
return syscall.Fdatasync(int(db.file.Fd()))
Expand Down
2 changes: 0 additions & 2 deletions bolt_openbsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ const (
msInvalidate // invalidate cached data
)

var odirect int

func msync(db *DB) error {
_, _, errno := syscall.Syscall(syscall.SYS_MSYNC, uintptr(unsafe.Pointer(db.data)), uintptr(db.datasz), msInvalidate)
if errno != 0 {
Expand Down
2 changes: 0 additions & 2 deletions bolt_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@ func unlockFileEx(h syscall.Handle, reserved, locklow, lockhigh uint32, ol *sysc
return nil
}

var odirect int

// fdatasync flushes written data to a file descriptor.
func fdatasync(db *DB) error {
return db.file.Sync()
Expand Down
2 changes: 0 additions & 2 deletions boltsync_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

package bolt

var odirect int

// fdatasync flushes written data to a file descriptor.
func fdatasync(db *DB) error {
return db.file.Sync()
Expand Down
22 changes: 13 additions & 9 deletions tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ type Tx struct {
pages map[pgid]*page
stats TxStats
commitHandlers []func()

// WriteFlag specifies the flag for write-related methods like WriteTo().
// Tx opens the database file with the specified flag to copy the data.
//
// By default, the flag is unset, which works well for mostly in-memory
// workloads. For databases that are much larger than available RAM,
// set the flag to syscall.O_DIRECT to avoid trashing the page cache.
WriteFlag int
}

// init initializes the transaction.
Expand Down Expand Up @@ -272,29 +280,25 @@ func (tx *Tx) Copy(w io.Writer) error {
// WriteTo writes the entire database to a writer.
// If err == nil then exactly tx.Size() bytes will be written into the writer.
func (tx *Tx) WriteTo(w io.Writer) (n int64, err error) {
// Attempt to open reader directly.
var f *os.File
if f, err = os.OpenFile(tx.db.path, os.O_RDONLY|odirect, 0); err != nil {
// Fallback to a regular open if that doesn't work.
if f, err = os.OpenFile(tx.db.path, os.O_RDONLY, 0); err != nil {
return 0, err
}
// Attempt to open reader with WriteFlag
f, err := os.OpenFile(tx.db.path, os.O_RDONLY|tx.WriteFlag, 0)
if err != nil {
return 0, err
}
defer f.Close()

// Copy the meta pages.
tx.db.metalock.Lock()
n, err = io.CopyN(w, f, int64(tx.db.pageSize*2))
tx.db.metalock.Unlock()
if err != nil {
_ = f.Close()
return n, fmt.Errorf("meta copy: %s", err)
}

// Copy data pages.
wn, err := io.CopyN(w, f, tx.Size()-int64(tx.db.pageSize*2))
n += wn
if err != nil {
_ = f.Close()
return n, err
}

Expand Down

0 comments on commit 81db894

Please sign in to comment.