vendor: upgrade coreos/bbolt to v1.3.1-coreos.2

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
This commit is contained in:
Gyu-Ho Lee 2017-09-27 15:28:52 -07:00
parent 398e6ba2a6
commit 8f6a0ee26c
7 changed files with 106 additions and 76 deletions

View File

@ -13,29 +13,32 @@ import (
// flock acquires an advisory lock on a file descriptor. // flock acquires an advisory lock on a file descriptor.
func flock(db *DB, mode os.FileMode, exclusive bool, timeout time.Duration) error { func flock(db *DB, mode os.FileMode, exclusive bool, timeout time.Duration) error {
var t time.Time var t time.Time
for { if timeout != 0 {
// 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() t = time.Now()
} else if timeout > 0 && time.Since(t) > timeout {
return ErrTimeout
} }
flag := syscall.LOCK_SH fd := db.file.Fd()
flag := syscall.LOCK_NB
if exclusive { if exclusive {
flag = syscall.LOCK_EX flag |= syscall.LOCK_EX
} else {
flag |= syscall.LOCK_SH
} }
for {
// Otherwise attempt to obtain an exclusive lock. // Attempt to obtain an exclusive lock.
err := syscall.Flock(int(db.file.Fd()), flag|syscall.LOCK_NB) err := syscall.Flock(int(fd), flag)
if err == nil { if err == nil {
return nil return nil
} else if err != syscall.EWOULDBLOCK { } else if err != syscall.EWOULDBLOCK {
return err return err
} }
// If we timed out then return an error.
if timeout != 0 && time.Since(t) > timeout-flockRetryTimeout {
return ErrTimeout
}
// Wait for a bit and try again. // Wait for a bit and try again.
time.Sleep(50 * time.Millisecond) time.Sleep(flockRetryTimeout)
} }
} }

View File

@ -13,34 +13,33 @@ import (
// flock acquires an advisory lock on a file descriptor. // flock acquires an advisory lock on a file descriptor.
func flock(db *DB, mode os.FileMode, exclusive bool, timeout time.Duration) error { func flock(db *DB, mode os.FileMode, exclusive bool, timeout time.Duration) error {
var t time.Time var t time.Time
for { if timeout != 0 {
// 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() t = time.Now()
} else if timeout > 0 && time.Since(t) > timeout {
return ErrTimeout
} }
var lock syscall.Flock_t fd := db.file.Fd()
lock.Start = 0 var lockType int16
lock.Len = 0
lock.Pid = 0
lock.Whence = 0
lock.Pid = 0
if exclusive { if exclusive {
lock.Type = syscall.F_WRLCK lockType = syscall.F_WRLCK
} else { } else {
lock.Type = syscall.F_RDLCK lockType = syscall.F_RDLCK
} }
err := syscall.FcntlFlock(db.file.Fd(), syscall.F_SETLK, &lock) for {
// Attempt to obtain an exclusive lock.
lock := syscall.Flock_t{Type: lockType}
err := syscall.FcntlFlock(fd, syscall.F_SETLK, &lock)
if err == nil { if err == nil {
return nil return nil
} else if err != syscall.EAGAIN { } else if err != syscall.EAGAIN {
return err return err
} }
// If we timed out then return an error.
if timeout != 0 && time.Since(t) > timeout-flockRetryTimeout {
return ErrTimeout
}
// Wait for a bit and try again. // Wait for a bit and try again.
time.Sleep(50 * time.Millisecond) time.Sleep(flockRetryTimeout)
} }
} }

View File

@ -59,29 +59,30 @@ func flock(db *DB, mode os.FileMode, exclusive bool, timeout time.Duration) erro
db.lockfile = f db.lockfile = f
var t time.Time var t time.Time
for { if timeout != 0 {
// 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() t = time.Now()
} else if timeout > 0 && time.Since(t) > timeout {
return ErrTimeout
} }
fd := db.file.Fd()
var flag uint32 = flagLockFailImmediately var flag uint32 = flagLockFailImmediately
if exclusive { if exclusive {
flag |= flagLockExclusive flag |= flagLockExclusive
} }
for {
err := lockFileEx(syscall.Handle(db.lockfile.Fd()), flag, 0, 1, 0, &syscall.Overlapped{}) // Attempt to obtain an exclusive lock.
err := lockFileEx(syscall.Handle(fd), flag, 0, 1, 0, &syscall.Overlapped{})
if err == nil { if err == nil {
return nil return nil
} else if err != errLockViolation { } else if err != errLockViolation {
return err return err
} }
// If we timed oumercit then return an error.
if timeout != 0 && time.Since(t) > timeout-flockRetryTimeout {
return ErrTimeout
}
// Wait for a bit and try again. // Wait for a bit and try again.
time.Sleep(50 * time.Millisecond) time.Sleep(flockRetryTimeout)
} }
} }

View File

@ -40,6 +40,9 @@ const (
// default page size for db is set to the OS page size. // default page size for db is set to the OS page size.
var defaultPageSize = os.Getpagesize() var defaultPageSize = os.Getpagesize()
// The time elapsed between consecutive file locking attempts.
const flockRetryTimeout = 50 * time.Millisecond
// DB represents a collection of buckets persisted to a file on disk. // DB represents a collection of buckets persisted to a file on disk.
// All data access is performed through transactions which can be obtained through the DB. // All data access is performed through transactions which can be obtained through the DB.
// All the functions on DB will return a ErrDatabaseNotOpen if accessed before Open() is called. // All the functions on DB will return a ErrDatabaseNotOpen if accessed before Open() is called.
@ -113,9 +116,11 @@ type DB struct {
opened bool opened bool
rwtx *Tx rwtx *Tx
txs []*Tx txs []*Tx
freelist *freelist
stats Stats stats Stats
freelist *freelist
freelistLoad sync.Once
pagePool sync.Pool pagePool sync.Pool
batchMu sync.Mutex batchMu sync.Mutex
@ -154,12 +159,14 @@ func (db *DB) String() string {
// If the file does not exist then it will be created automatically. // If the file does not exist then it will be created automatically.
// Passing in nil options will cause Bolt to open the database with the default options. // 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) { func Open(path string, mode os.FileMode, options *Options) (*DB, error) {
var db = &DB{opened: true} db := &DB{
opened: true,
}
// Set default options if no options are provided. // Set default options if no options are provided.
if options == nil { if options == nil {
options = DefaultOptions options = DefaultOptions
} }
db.NoSync = options.NoSync
db.NoGrowSync = options.NoGrowSync db.NoGrowSync = options.NoGrowSync
db.MmapFlags = options.MmapFlags db.MmapFlags = options.MmapFlags
db.NoFreelistSync = options.NoFreelistSync db.NoFreelistSync = options.NoFreelistSync
@ -250,20 +257,11 @@ func Open(path string, mode os.FileMode, options *Options) (*DB, error) {
return db, nil return db, nil
} }
db.freelist = newFreelist() db.loadFreelist()
noFreeList := db.meta().freelist == pgidNoFreelist
if noFreeList {
// Reconstruct free list by scanning the DB.
db.freelist.readIDs(db.freepages())
} else {
// Read free list from freelist page.
db.freelist.read(db.page(db.meta().freelist))
}
db.stats.FreePageN = len(db.freelist.ids)
// Flush freelist when transitioning from no sync to sync so // Flush freelist when transitioning from no sync to sync so
// NoFreelistSync unaware boltdb can open the db later. // NoFreelistSync unaware boltdb can open the db later.
if !db.NoFreelistSync && noFreeList { if !db.NoFreelistSync && !db.hasSyncedFreelist() {
tx, err := db.Begin(true) tx, err := db.Begin(true)
if tx != nil { if tx != nil {
err = tx.Commit() err = tx.Commit()
@ -278,6 +276,27 @@ func Open(path string, mode os.FileMode, options *Options) (*DB, error) {
return db, nil return db, nil
} }
// loadFreelist reads the freelist if it is synced, or reconstructs it
// by scanning the DB if it is not synced. It assumes there are no
// concurrent accesses being made to the freelist.
func (db *DB) loadFreelist() {
db.freelistLoad.Do(func() {
db.freelist = newFreelist()
if !db.hasSyncedFreelist() {
// Reconstruct free list by scanning the DB.
db.freelist.readIDs(db.freepages())
} else {
// Read free list from freelist page.
db.freelist.read(db.page(db.meta().freelist))
}
db.stats.FreePageN = len(db.freelist.ids)
})
}
func (db *DB) hasSyncedFreelist() bool {
return db.meta().freelist != pgidNoFreelist
}
// mmap opens the underlying memory-mapped file and initializes the meta references. // mmap opens the underlying memory-mapped file and initializes the meta references.
// minsz is the minimum size that the new mmap can be. // minsz is the minimum size that the new mmap can be.
func (db *DB) mmap(minsz int) error { func (db *DB) mmap(minsz int) error {
@ -683,11 +702,7 @@ func (db *DB) View(fn func(*Tx) error) error {
return err return err
} }
if err := t.Rollback(); err != nil { return t.Rollback()
return err
}
return nil
} }
// Batch calls fn as part of a batch. It behaves similar to Update, // Batch calls fn as part of a batch. It behaves similar to Update,
@ -1008,6 +1023,11 @@ type Options struct {
// PageSize overrides the default OS page size. // PageSize overrides the default OS page size.
PageSize int PageSize int
// NoSync sets the initial value of DB.NoSync. Normally this can just be
// set directly on the DB itself when returned from Open(), but this option
// is useful in APIs which expose Options but not the underlying DB.
NoSync bool
} }
// DefaultOptions represent the options used if nil options are passed into Open(). // DefaultOptions represent the options used if nil options are passed into Open().

View File

@ -317,7 +317,11 @@ func (tx *Tx) WriteTo(w io.Writer) (n int64, err error) {
if err != nil { if err != nil {
return 0, err return 0, err
} }
defer func() { _ = f.Close() }() defer func() {
if cerr := f.Close(); err == nil {
err = cerr
}
}()
// Generate a meta page. We use the same page data for both meta pages. // Generate a meta page. We use the same page data for both meta pages.
buf := make([]byte, tx.db.pageSize) buf := make([]byte, tx.db.pageSize)
@ -345,7 +349,7 @@ func (tx *Tx) WriteTo(w io.Writer) (n int64, err error) {
} }
// Move past the meta pages in the file. // Move past the meta pages in the file.
if _, err := f.Seek(int64(tx.db.pageSize*2), os.SEEK_SET); err != nil { if _, err := f.Seek(int64(tx.db.pageSize*2), io.SeekStart); err != nil {
return n, fmt.Errorf("seek: %s", err) return n, fmt.Errorf("seek: %s", err)
} }
@ -356,7 +360,7 @@ func (tx *Tx) WriteTo(w io.Writer) (n int64, err error) {
return n, err return n, err
} }
return n, f.Close() return n, nil
} }
// CopyFile copies the entire database to file at the given path. // CopyFile copies the entire database to file at the given path.
@ -391,6 +395,9 @@ func (tx *Tx) Check() <-chan error {
} }
func (tx *Tx) check(ch chan error) { func (tx *Tx) check(ch chan error) {
// Force loading free list if opened in ReadOnly mode.
tx.db.loadFreelist()
// Check if any pages are double freed. // Check if any pages are double freed.
freed := make(map[pgid]bool) freed := make(map[pgid]bool)
all := make([]pgid, tx.db.freelist.count()) all := make([]pgid, tx.db.freelist.count())

6
glide.lock generated
View File

@ -1,5 +1,5 @@
hash: 49950d40cee960e66f818746fca6ccaa849c62851d81d0960f6089c3677eec65 hash: 2741432e90b78701658bb5aea14c6a43d1e57d6f2f111e16398f8ce5af500e54
updated: 2017-09-19T14:50:30.702073385+02:00 updated: 2017-09-27T15:28:21.693058-07:00
imports: imports:
- name: github.com/beorn7/perks - name: github.com/beorn7/perks
version: 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9 version: 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9
@ -8,7 +8,7 @@ imports:
- name: github.com/bgentry/speakeasy - name: github.com/bgentry/speakeasy
version: 4aabc24848ce5fd31929f7d1e4ea74d3709c14cd version: 4aabc24848ce5fd31929f7d1e4ea74d3709c14cd
- name: github.com/coreos/bbolt - name: github.com/coreos/bbolt
version: e1c92081e510bb6b2bbfc93e7e6bd0b6dabd3e12 version: 54f6fad6e4859cf6c17d98577f5aab4903c3fdde
- name: github.com/coreos/go-semver - name: github.com/coreos/go-semver
version: 8ab6407b697782a06568d4b7f1db25550ec2e4c6 version: 8ab6407b697782a06568d4b7f1db25550ec2e4c6
subpackages: subpackages:

View File

@ -5,7 +5,7 @@ import:
- package: github.com/bgentry/speakeasy - package: github.com/bgentry/speakeasy
version: v0.1.0 version: v0.1.0
- package: github.com/coreos/bbolt - package: github.com/coreos/bbolt
version: v1.3.1-coreos.1 version: v1.3.1-coreos.2
- package: github.com/coreos/go-semver - package: github.com/coreos/go-semver
version: v0.2.0 version: v0.2.0
subpackages: subpackages: