mirror of https://github.com/hak5/bolt.git
Add Open() options, flock timeout.
This commit changes Open() to provide an additional Options argument. The options argument currently only has a Timeout which will cause the Open() to return ErrTimeout if a file lock cannot be obtained in time. Fixes #207.master
parent
0a59a75472
commit
00ee0da528
|
@ -2,8 +2,6 @@ package bolt
|
|||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var odirect int
|
||||
|
@ -12,42 +10,3 @@ var odirect int
|
|||
func fdatasync(f *os.File) error {
|
||||
return f.Sync()
|
||||
}
|
||||
|
||||
// flock acquires an advisory lock on a file descriptor.
|
||||
func flock(f *os.File) error {
|
||||
return syscall.Flock(int(f.Fd()), syscall.LOCK_EX)
|
||||
}
|
||||
|
||||
// funlock releases an advisory lock on a file descriptor.
|
||||
func funlock(f *os.File) error {
|
||||
return syscall.Flock(int(f.Fd()), syscall.LOCK_UN)
|
||||
}
|
||||
|
||||
// mmap memory maps a DB's data file.
|
||||
func mmap(db *DB, sz int) error {
|
||||
b, err := syscall.Mmap(int(db.file.Fd()), 0, sz, syscall.PROT_READ, syscall.MAP_SHARED)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Save the original byte slice and convert to a byte array pointer.
|
||||
db.dataref = b
|
||||
db.data = (*[maxMapSize]byte)(unsafe.Pointer(&b[0]))
|
||||
db.datasz = sz
|
||||
return nil
|
||||
}
|
||||
|
||||
// munmap unmaps a DB's data file from memory.
|
||||
func munmap(db *DB) error {
|
||||
// Ignore the unmap if we have no mapped data.
|
||||
if db.dataref == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unmap using the original byte slice.
|
||||
err := syscall.Munmap(db.dataref)
|
||||
db.dataref = nil
|
||||
db.data = nil
|
||||
db.datasz = 0
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package bolt
|
|||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var odirect = syscall.O_DIRECT
|
||||
|
@ -12,42 +11,3 @@ var odirect = syscall.O_DIRECT
|
|||
func fdatasync(f *os.File) error {
|
||||
return syscall.Fdatasync(int(f.Fd()))
|
||||
}
|
||||
|
||||
// flock acquires an advisory lock on a file descriptor.
|
||||
func flock(f *os.File) error {
|
||||
return syscall.Flock(int(f.Fd()), syscall.LOCK_EX)
|
||||
}
|
||||
|
||||
// funlock releases an advisory lock on a file descriptor.
|
||||
func funlock(f *os.File) error {
|
||||
return syscall.Flock(int(f.Fd()), syscall.LOCK_UN)
|
||||
}
|
||||
|
||||
// mmap memory maps a DB's data file.
|
||||
func mmap(db *DB, sz int) error {
|
||||
b, err := syscall.Mmap(int(db.file.Fd()), 0, sz, syscall.PROT_READ, syscall.MAP_SHARED)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Save the original byte slice and convert to a byte array pointer.
|
||||
db.dataref = b
|
||||
db.data = (*[maxMapSize]byte)(unsafe.Pointer(&b[0]))
|
||||
db.datasz = sz
|
||||
return nil
|
||||
}
|
||||
|
||||
// munmap unmaps a DB's data file from memory.
|
||||
func munmap(db *DB) error {
|
||||
// Ignore the unmap if we have no mapped data.
|
||||
if db.dataref == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unmap using the original byte slice.
|
||||
err := syscall.Munmap(db.dataref)
|
||||
db.dataref = nil
|
||||
db.data = nil
|
||||
db.datasz = 0
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
// +build linux darwin
|
||||
|
||||
package bolt
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// flock acquires an advisory lock on a file descriptor.
|
||||
func flock(f *os.File, timeout time.Duration) error {
|
||||
var t time.Time
|
||||
for {
|
||||
// If we're beyond our timeout then return an error.
|
||||
// This can only occur after we've attempted a flock once.
|
||||
if t.IsZero() {
|
||||
t = time.Now()
|
||||
} else if timeout > 0 && time.Since(t) > timeout {
|
||||
return ErrTimeout
|
||||
}
|
||||
|
||||
// Otherwise attempt to obtain an exclusive lock.
|
||||
err := syscall.Flock(int(f.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)
|
||||
if err == nil {
|
||||
return nil
|
||||
} else if err != syscall.EWOULDBLOCK {
|
||||
return err
|
||||
}
|
||||
|
||||
// Wait for a bit and try again.
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
// funlock releases an advisory lock on a file descriptor.
|
||||
func funlock(f *os.File) error {
|
||||
return syscall.Flock(int(f.Fd()), syscall.LOCK_UN)
|
||||
}
|
||||
|
||||
// mmap memory maps a DB's data file.
|
||||
func mmap(db *DB, sz int) error {
|
||||
b, err := syscall.Mmap(int(db.file.Fd()), 0, sz, syscall.PROT_READ, syscall.MAP_SHARED)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Save the original byte slice and convert to a byte array pointer.
|
||||
db.dataref = b
|
||||
db.data = (*[maxMapSize]byte)(unsafe.Pointer(&b[0]))
|
||||
db.datasz = sz
|
||||
return nil
|
||||
}
|
||||
|
||||
// munmap unmaps a DB's data file from memory.
|
||||
func munmap(db *DB) error {
|
||||
// Ignore the unmap if we have no mapped data.
|
||||
if db.dataref == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unmap using the original byte slice.
|
||||
err := syscall.Munmap(db.dataref)
|
||||
db.dataref = nil
|
||||
db.data = nil
|
||||
db.datasz = 0
|
||||
return err
|
||||
}
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
|
@ -15,7 +16,7 @@ func fdatasync(f *os.File) error {
|
|||
}
|
||||
|
||||
// flock acquires an advisory lock on a file descriptor.
|
||||
func flock(f *os.File) error {
|
||||
func flock(f *os.File, _ time.Duration) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -1021,7 +1021,7 @@ func TestBucket_Delete_Quick(t *testing.T) {
|
|||
|
||||
func ExampleBucket_Put() {
|
||||
// Open the database.
|
||||
db, _ := Open(tempfile(), 0666)
|
||||
db, _ := Open(tempfile(), 0666, nil)
|
||||
defer os.Remove(db.Path())
|
||||
defer db.Close()
|
||||
|
||||
|
@ -1048,7 +1048,7 @@ func ExampleBucket_Put() {
|
|||
|
||||
func ExampleBucket_Delete() {
|
||||
// Open the database.
|
||||
db, _ := Open(tempfile(), 0666)
|
||||
db, _ := Open(tempfile(), 0666, nil)
|
||||
defer os.Remove(db.Path())
|
||||
defer db.Close()
|
||||
|
||||
|
@ -1088,7 +1088,7 @@ func ExampleBucket_Delete() {
|
|||
|
||||
func ExampleBucket_ForEach() {
|
||||
// Open the database.
|
||||
db, _ := Open(tempfile(), 0666)
|
||||
db, _ := Open(tempfile(), 0666, nil)
|
||||
defer os.Remove(db.Path())
|
||||
defer db.Close()
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ func Bench(options *BenchOptions) {
|
|||
}
|
||||
|
||||
// Create database.
|
||||
db, err := bolt.Open(path, 0600)
|
||||
db, err := bolt.Open(path, 0600, nil)
|
||||
if err != nil {
|
||||
fatal(err)
|
||||
return
|
||||
|
|
|
@ -13,7 +13,7 @@ func Buckets(path string) {
|
|||
return
|
||||
}
|
||||
|
||||
db, err := bolt.Open(path, 0600)
|
||||
db, err := bolt.Open(path, 0600, nil)
|
||||
if err != nil {
|
||||
fatal(err)
|
||||
return
|
||||
|
|
|
@ -13,7 +13,7 @@ func Check(path string) {
|
|||
return
|
||||
}
|
||||
|
||||
db, err := bolt.Open(path, 0600)
|
||||
db, err := bolt.Open(path, 0600, nil)
|
||||
if err != nil {
|
||||
fatal(err)
|
||||
return
|
||||
|
|
|
@ -16,7 +16,7 @@ func Export(path string) {
|
|||
}
|
||||
|
||||
// Open the database.
|
||||
db, err := bolt.Open(path, 0600)
|
||||
db, err := bolt.Open(path, 0600, nil)
|
||||
if err != nil {
|
||||
fatal(err)
|
||||
return
|
||||
|
|
|
@ -13,7 +13,7 @@ func Get(path, name, key string) {
|
|||
return
|
||||
}
|
||||
|
||||
db, err := bolt.Open(path, 0600)
|
||||
db, err := bolt.Open(path, 0600, nil)
|
||||
if err != nil {
|
||||
fatal(err)
|
||||
return
|
||||
|
|
|
@ -29,7 +29,7 @@ func Import(path string, input string) {
|
|||
|
||||
func importBuckets(path string, root []*rawMessage) {
|
||||
// Open the database.
|
||||
db, err := bolt.Open(path, 0600)
|
||||
db, err := bolt.Open(path, 0600, nil)
|
||||
if err != nil {
|
||||
fatal(err)
|
||||
return
|
||||
|
|
|
@ -23,7 +23,7 @@ func TestImport(t *testing.T) {
|
|||
assert.Equal(t, ``, output)
|
||||
|
||||
// Open database and verify contents.
|
||||
db, err := bolt.Open(path, 0600)
|
||||
db, err := bolt.Open(path, 0600, nil)
|
||||
assert.NoError(t, err)
|
||||
db.View(func(tx *bolt.Tx) error {
|
||||
assert.NotNil(t, tx.Bucket([]byte("empty")))
|
||||
|
|
|
@ -13,7 +13,7 @@ func Info(path string) {
|
|||
return
|
||||
}
|
||||
|
||||
db, err := bolt.Open(path, 0600)
|
||||
db, err := bolt.Open(path, 0600, nil)
|
||||
if err != nil {
|
||||
fatal(err)
|
||||
return
|
||||
|
|
|
@ -13,7 +13,7 @@ func Keys(path, name string) {
|
|||
return
|
||||
}
|
||||
|
||||
db, err := bolt.Open(path, 0600)
|
||||
db, err := bolt.Open(path, 0600, nil)
|
||||
if err != nil {
|
||||
fatal(err)
|
||||
return
|
||||
|
|
|
@ -14,7 +14,7 @@ func open(fn func(*bolt.DB, string)) {
|
|||
path := tempfile()
|
||||
defer os.RemoveAll(path)
|
||||
|
||||
db, err := bolt.Open(path, 0600)
|
||||
db, err := bolt.Open(path, 0600, nil)
|
||||
if err != nil {
|
||||
panic("db open error: " + err.Error())
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ func Pages(path string) {
|
|||
return
|
||||
}
|
||||
|
||||
db, err := bolt.Open(path, 0600)
|
||||
db, err := bolt.Open(path, 0600, nil)
|
||||
if err != nil {
|
||||
fatal(err)
|
||||
return
|
||||
|
|
|
@ -14,7 +14,7 @@ func Stats(path, prefix string) {
|
|||
return
|
||||
}
|
||||
|
||||
db, err := bolt.Open(path, 0600)
|
||||
db, err := bolt.Open(path, 0600, nil)
|
||||
if err != nil {
|
||||
fatal(err)
|
||||
return
|
||||
|
|
23
db.go
23
db.go
|
@ -8,6 +8,7 @@ import (
|
|||
"runtime/debug"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
|
@ -50,6 +51,10 @@ var (
|
|||
|
||||
// ErrChecksum is returned when either meta page checksum does not match.
|
||||
ErrChecksum = errors.New("checksum error")
|
||||
|
||||
// ErrTimeout is returned when a database cannot obtain an exclusive lock
|
||||
// on the data file after the timeout passed to Open().
|
||||
ErrTimeout = errors.New("timeout")
|
||||
)
|
||||
|
||||
// DB represents a collection of buckets persisted to a file on disk.
|
||||
|
@ -108,9 +113,15 @@ func (db *DB) String() string {
|
|||
|
||||
// Open creates and opens a database at the given path.
|
||||
// If the file does not exist then it will be created automatically.
|
||||
func Open(path string, mode os.FileMode) (*DB, error) {
|
||||
// Passing in nil options will cause Bolt to open the database with the default options.
|
||||
func Open(path string, mode os.FileMode, options *Options) (*DB, error) {
|
||||
var db = &DB{opened: true, FillPercent: DefaultFillPercent}
|
||||
|
||||
// Set default options.
|
||||
if options == nil {
|
||||
options = &Options{}
|
||||
}
|
||||
|
||||
// Open data file and separate sync handler for metadata writes.
|
||||
db.path = path
|
||||
|
||||
|
@ -123,7 +134,7 @@ func Open(path string, mode os.FileMode) (*DB, error) {
|
|||
// Lock file so that other processes using Bolt cannot use the database
|
||||
// at the same time. This would cause corruption since the two processes
|
||||
// would write meta pages and free pages separately.
|
||||
if err := flock(db.file); err != nil {
|
||||
if err := flock(db.file, options.Timeout); err != nil {
|
||||
_ = db.close()
|
||||
return nil, err
|
||||
}
|
||||
|
@ -556,6 +567,14 @@ func (db *DB) allocate(count int) (*page, error) {
|
|||
return p, nil
|
||||
}
|
||||
|
||||
// Options represents the options that can be set when opening a database.
|
||||
type Options struct {
|
||||
// Timeout is the amount of time to wait to obtain a file lock.
|
||||
// When set to zero it will wait indefinitely. This option is only
|
||||
// available on Darwin and Linux.
|
||||
Timeout time.Duration
|
||||
}
|
||||
|
||||
// Stats represents statistics about the database.
|
||||
type Stats struct {
|
||||
// Freelist stats
|
||||
|
|
90
db_test.go
90
db_test.go
|
@ -7,6 +7,7 @@ import (
|
|||
"io/ioutil"
|
||||
"os"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
|
@ -18,31 +19,17 @@ import (
|
|||
|
||||
var statsFlag = flag.Bool("stats", false, "show performance stats")
|
||||
|
||||
// Ensure that a database can be opened without error.
|
||||
func TestOpen(t *testing.T) {
|
||||
f, _ := ioutil.TempFile("", "bolt-")
|
||||
path := f.Name()
|
||||
f.Close()
|
||||
os.Remove(path)
|
||||
defer os.RemoveAll(path)
|
||||
|
||||
db, err := Open(path, 0666)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, db)
|
||||
db.Close()
|
||||
}
|
||||
|
||||
// Ensure that opening a database with a bad path returns an error.
|
||||
func TestOpen_BadPath(t *testing.T) {
|
||||
db, err := Open("/../bad-path", 0666)
|
||||
db, err := Open("/../bad-path", 0666, nil)
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, db)
|
||||
}
|
||||
|
||||
// Ensure that a database can be opened without error.
|
||||
func TestDB_Open(t *testing.T) {
|
||||
func TestOpen(t *testing.T) {
|
||||
withTempPath(func(path string) {
|
||||
db, err := Open(path, 0666)
|
||||
db, err := Open(path, 0666, nil)
|
||||
assert.NotNil(t, db)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, db.Path(), path)
|
||||
|
@ -50,15 +37,60 @@ func TestDB_Open(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
// Ensure that opening an already open database file will timeout.
|
||||
func TestOpen_Timeout(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("timeout not supported on windows")
|
||||
}
|
||||
withTempPath(func(path string) {
|
||||
// Open a data file.
|
||||
db0, err := Open(path, 0666, nil)
|
||||
assert.NotNil(t, db0)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Attempt to open the database again.
|
||||
start := time.Now()
|
||||
db1, err := Open(path, 0666, &Options{Timeout: 100 * time.Millisecond})
|
||||
assert.Nil(t, db1)
|
||||
assert.Equal(t, ErrTimeout, err)
|
||||
assert.True(t, time.Since(start) > 100*time.Millisecond)
|
||||
|
||||
db0.Close()
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure that opening an already open database file will wait until its closed.
|
||||
func TestOpen_Wait(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("timeout not supported on windows")
|
||||
}
|
||||
withTempPath(func(path string) {
|
||||
// Open a data file.
|
||||
db0, err := Open(path, 0666, nil)
|
||||
assert.NotNil(t, db0)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Close it in just a bit.
|
||||
time.AfterFunc(100*time.Millisecond, func() { db0.Close() })
|
||||
|
||||
// Attempt to open the database again.
|
||||
start := time.Now()
|
||||
db1, err := Open(path, 0666, &Options{Timeout: 200 * time.Millisecond})
|
||||
assert.NotNil(t, db1)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, time.Since(start) > 100*time.Millisecond)
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure that a re-opened database is consistent.
|
||||
func TestOpen_Check(t *testing.T) {
|
||||
withTempPath(func(path string) {
|
||||
db, err := Open(path, 0666)
|
||||
db, err := Open(path, 0666, nil)
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, db.View(func(tx *Tx) error { return <-tx.Check() }))
|
||||
db.Close()
|
||||
|
||||
db, err = Open(path, 0666)
|
||||
db, err = Open(path, 0666, nil)
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, db.View(func(tx *Tx) error { return <-tx.Check() }))
|
||||
db.Close()
|
||||
|
@ -68,7 +100,7 @@ func TestOpen_Check(t *testing.T) {
|
|||
// Ensure that the database returns an error if the file handle cannot be open.
|
||||
func TestDB_Open_FileError(t *testing.T) {
|
||||
withTempPath(func(path string) {
|
||||
_, err := Open(path+"/youre-not-my-real-parent", 0666)
|
||||
_, err := Open(path+"/youre-not-my-real-parent", 0666, nil)
|
||||
if err, _ := err.(*os.PathError); assert.Error(t, err) {
|
||||
assert.Equal(t, path+"/youre-not-my-real-parent", err.Path)
|
||||
assert.Equal(t, "open", err.Op)
|
||||
|
@ -84,14 +116,14 @@ func TestDB_Open_MetaInitWriteError(t *testing.T) {
|
|||
// Ensure that a database that is too small returns an error.
|
||||
func TestDB_Open_FileTooSmall(t *testing.T) {
|
||||
withTempPath(func(path string) {
|
||||
db, err := Open(path, 0666)
|
||||
db, err := Open(path, 0666, nil)
|
||||
assert.NoError(t, err)
|
||||
db.Close()
|
||||
|
||||
// corrupt the database
|
||||
assert.NoError(t, os.Truncate(path, int64(os.Getpagesize())))
|
||||
|
||||
db, err = Open(path, 0666)
|
||||
db, err = Open(path, 0666, nil)
|
||||
assert.Equal(t, errors.New("file size too small"), err)
|
||||
})
|
||||
}
|
||||
|
@ -115,7 +147,7 @@ func TestDB_Open_CorruptMeta0(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
|
||||
// Open the database.
|
||||
_, err = Open(path, 0666)
|
||||
_, err = Open(path, 0666, nil)
|
||||
assert.Equal(t, err, errors.New("meta0 error: invalid database"))
|
||||
})
|
||||
}
|
||||
|
@ -124,7 +156,7 @@ func TestDB_Open_CorruptMeta0(t *testing.T) {
|
|||
func TestDB_Open_MetaChecksumError(t *testing.T) {
|
||||
for i := 0; i < 2; i++ {
|
||||
withTempPath(func(path string) {
|
||||
db, err := Open(path, 0600)
|
||||
db, err := Open(path, 0600, nil)
|
||||
pageSize := db.pageSize
|
||||
db.Update(func(tx *Tx) error {
|
||||
_, err := tx.CreateBucket([]byte("widgets"))
|
||||
|
@ -143,7 +175,7 @@ func TestDB_Open_MetaChecksumError(t *testing.T) {
|
|||
f.Close()
|
||||
|
||||
// Reopen the database.
|
||||
_, err = Open(path, 0600)
|
||||
_, err = Open(path, 0600, nil)
|
||||
if assert.Error(t, err) {
|
||||
if i == 0 {
|
||||
assert.Equal(t, "meta0 error: checksum error", err.Error())
|
||||
|
@ -387,7 +419,7 @@ func TestDB_DoubleFree(t *testing.T) {
|
|||
|
||||
func ExampleDB_Update() {
|
||||
// Open the database.
|
||||
db, _ := Open(tempfile(), 0666)
|
||||
db, _ := Open(tempfile(), 0666, nil)
|
||||
defer os.Remove(db.Path())
|
||||
defer db.Close()
|
||||
|
||||
|
@ -418,7 +450,7 @@ func ExampleDB_Update() {
|
|||
|
||||
func ExampleDB_View() {
|
||||
// Open the database.
|
||||
db, _ := Open(tempfile(), 0666)
|
||||
db, _ := Open(tempfile(), 0666, nil)
|
||||
defer os.Remove(db.Path())
|
||||
defer db.Close()
|
||||
|
||||
|
@ -444,7 +476,7 @@ func ExampleDB_View() {
|
|||
|
||||
func ExampleDB_Begin_ReadOnly() {
|
||||
// Open the database.
|
||||
db, _ := Open(tempfile(), 0666)
|
||||
db, _ := Open(tempfile(), 0666, nil)
|
||||
defer os.Remove(db.Path())
|
||||
defer db.Close()
|
||||
|
||||
|
@ -494,7 +526,7 @@ func withTempPath(fn func(string)) {
|
|||
// withOpenDB executes a function with an already opened database.
|
||||
func withOpenDB(fn func(*DB, string)) {
|
||||
withTempPath(func(path string) {
|
||||
db, err := Open(path, 0666)
|
||||
db, err := Open(path, 0666, nil)
|
||||
if err != nil {
|
||||
panic("cannot open db: " + err.Error())
|
||||
}
|
||||
|
|
|
@ -301,7 +301,7 @@ func TestTx_CopyFile(t *testing.T) {
|
|||
|
||||
assert.NoError(t, db.View(func(tx *Tx) error { return tx.CopyFile(dest, 0600) }))
|
||||
|
||||
db2, err := Open(dest, 0600)
|
||||
db2, err := Open(dest, 0600, nil)
|
||||
assert.NoError(t, err)
|
||||
defer db2.Close()
|
||||
|
||||
|
@ -366,7 +366,7 @@ func TestTx_CopyFile_Error_Normal(t *testing.T) {
|
|||
|
||||
func ExampleTx_Rollback() {
|
||||
// Open the database.
|
||||
db, _ := Open(tempfile(), 0666)
|
||||
db, _ := Open(tempfile(), 0666, nil)
|
||||
defer os.Remove(db.Path())
|
||||
defer db.Close()
|
||||
|
||||
|
@ -400,7 +400,7 @@ func ExampleTx_Rollback() {
|
|||
|
||||
func ExampleTx_CopyFile() {
|
||||
// Open the database.
|
||||
db, _ := Open(tempfile(), 0666)
|
||||
db, _ := Open(tempfile(), 0666, nil)
|
||||
defer os.Remove(db.Path())
|
||||
defer db.Close()
|
||||
|
||||
|
@ -417,7 +417,7 @@ func ExampleTx_CopyFile() {
|
|||
defer os.Remove(toFile)
|
||||
|
||||
// Open the cloned database.
|
||||
db2, _ := Open(toFile, 0666)
|
||||
db2, _ := Open(toFile, 0666, nil)
|
||||
defer db2.Close()
|
||||
|
||||
// Ensure that the key exists in the copy.
|
||||
|
|
Loading…
Reference in New Issue