diff options
author | Ben Johnson <benbjohnson@yahoo.com> | 2015-03-22 15:26:13 -0600 |
---|---|---|
committer | Ben Johnson <benbjohnson@yahoo.com> | 2015-03-22 15:26:13 -0600 |
commit | a9651995e1950f66cdccfc390c8ba966c14465ec (patch) | |
tree | f242ce927a4decf473a64ba749227a3cfc3157c3 | |
parent | Merge pull request #285 from tv42/batch (diff) | |
parent | Implement io.WriterTo interface on Tx. (diff) | |
download | dedo-a9651995e1950f66cdccfc390c8ba966c14465ec.tar.gz dedo-a9651995e1950f66cdccfc390c8ba966c14465ec.tar.xz |
Merge pull request #330 from benbjohnson/tx-writer-to
Implement io.WriterTo interface on Tx.
-rw-r--r-- | README.md | 5 | ||||
-rw-r--r-- | tx.go | 27 |
2 files changed, 19 insertions, 13 deletions
@@ -370,7 +370,7 @@ func (*Bucket) DeleteBucket(key []byte) error ### Database backups -Bolt is a single file so it's easy to backup. You can use the `Tx.Copy()` +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 @@ -385,7 +385,8 @@ func BackupHandleFunc(w http.ResponseWriter, req *http.Request) { w.Header().Set("Content-Type", "application/octet-stream") w.Header().Set("Content-Disposition", `attachment; filename="my.db"`) w.Header().Set("Content-Length", strconv.Itoa(int(tx.Size()))) - return tx.Copy(w) + _, err := tx.WriteTo(w) + return err }) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) @@ -252,37 +252,42 @@ func (tx *Tx) close() { } // Copy writes the entire database to a writer. -// A reader transaction is maintained during the copy so it is safe to continue -// using the database while a copy is in progress. -// Copy will write exactly tx.Size() bytes into the writer. +// This function exists for backwards compatibility. Use WriteTo() in func (tx *Tx) Copy(w io.Writer) error { - var f *os.File - var err error + _, err := tx.WriteTo(w) + return err +} +// 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 err + return 0, err } } // Copy the meta pages. tx.db.metalock.Lock() - _, err = io.CopyN(w, f, int64(tx.db.pageSize*2)) + n, err = io.CopyN(w, f, int64(tx.db.pageSize*2)) tx.db.metalock.Unlock() if err != nil { _ = f.Close() - return fmt.Errorf("meta copy: %s", err) + return n, fmt.Errorf("meta copy: %s", err) } // Copy data pages. - if _, err := io.CopyN(w, f, tx.Size()-int64(tx.db.pageSize*2)); err != nil { + wn, err := io.CopyN(w, f, tx.Size()-int64(tx.db.pageSize*2)) + n += wn + if err != nil { _ = f.Close() - return err + return n, err } - return f.Close() + return n, f.Close() } // CopyFile copies the entire database to file at the given path. |