diff --git a/third_party/github.com/cznic/exp/dbm/all_test.go b/third_party/github.com/cznic/exp/dbm/all_test.go index eb380e184..8a2308c06 100644 --- a/third_party/github.com/cznic/exp/dbm/all_test.go +++ b/third_party/github.com/cznic/exp/dbm/all_test.go @@ -24,6 +24,7 @@ import ( "time" "camlistore.org/third_party/github.com/cznic/exp/lldb" + "camlistore.org/third_party/github.com/cznic/fileutil" ) var ( @@ -795,7 +796,7 @@ func TestSlice0(t *testing.T) { ga = append(ga, strings.Join(a, ",")) return true, nil }); err != nil { - if err != io.EOF { + if !fileutil.IsEOF(err) { t.Fatal(i, err) } } @@ -2116,7 +2117,7 @@ func TestFileReadAtWriteAt(t *testing.T) { from, to = 0, n2 } n, err := f.ReadAt(b[from:to], int64(from)) - if err != nil && (err != io.EOF && n != 0) { + if err != nil && (!fileutil.IsEOF(err) && n != 0) { t.Error(fsz(), from, to, err) return } diff --git a/third_party/github.com/cznic/exp/dbm/etc.go b/third_party/github.com/cznic/exp/dbm/etc.go index 9ed65d802..76d6f63a6 100644 --- a/third_party/github.com/cznic/exp/dbm/etc.go +++ b/third_party/github.com/cznic/exp/dbm/etc.go @@ -7,10 +7,10 @@ package dbm import ( "bytes" "fmt" - "io" "camlistore.org/third_party/github.com/cznic/exp/lldb" "camlistore.org/third_party/github.com/cznic/mathutil" + "camlistore.org/third_party/github.com/cznic/fileutil" ) type header struct { @@ -149,7 +149,7 @@ func encVal(val interface{}) (r []byte, err error) { } func noEof(e error) (err error) { - if e != io.EOF { + if !fileutil.IsEOF(e) { err = e } return diff --git a/third_party/github.com/cznic/exp/dbm/file.go b/third_party/github.com/cznic/exp/dbm/file.go index aab1f81a2..6b5a8e4c6 100644 --- a/third_party/github.com/cznic/exp/dbm/file.go +++ b/third_party/github.com/cznic/exp/dbm/file.go @@ -11,6 +11,7 @@ import ( "camlistore.org/third_party/github.com/cznic/exp/lldb" "camlistore.org/third_party/github.com/cznic/mathutil" + "camlistore.org/third_party/github.com/cznic/fileutil" ) /* @@ -375,7 +376,7 @@ func (f *File) ReadFrom(r io.Reader) (n int64, err error) { n += int64(rn) } } - if rerr != io.EOF { + if !fileutil.IsEOF(rerr) { err = rerr } return @@ -439,7 +440,7 @@ func (f *File) WriteTo(w io.Writer) (n int64, err error) { n += int64(wn) } } - if rerr != io.EOF { + if !fileutil.IsEOF(rerr) { err = rerr } return diff --git a/third_party/github.com/cznic/exp/lldb/2pc.go b/third_party/github.com/cznic/exp/lldb/2pc.go index f77d9794c..197d79e57 100644 --- a/third_party/github.com/cznic/exp/lldb/2pc.go +++ b/third_party/github.com/cznic/exp/lldb/2pc.go @@ -13,6 +13,7 @@ import ( "io" "os" + "camlistore.org/third_party/github.com/cznic/fileutil" "camlistore.org/third_party/github.com/cznic/mathutil" ) @@ -161,7 +162,7 @@ func NewACIDFiler(db Filer, wal *os.File) (r *ACIDFiler0, err error) { for { k, v, err := enum.current() if err != nil { - if err == io.EOF { + if fileutil.IsEOF(err) { break } @@ -173,7 +174,7 @@ func NewACIDFiler(db Filer, wal *os.File) (r *ACIDFiler0, err error) { } if err = enum.next(); err != nil { - if err == io.EOF { + if fileutil.IsEOF(err) { break } @@ -299,7 +300,7 @@ func (a *ACIDFiler0) recoverDb(db Filer) (err error) { for { k, v, err := enum.current() if err != nil { - if err == io.EOF { + if fileutil.IsEOF(err) { break } @@ -311,7 +312,7 @@ func (a *ACIDFiler0) recoverDb(db Filer) (err error) { } if err = enum.next(); err != nil { - if err == io.EOF { + if fileutil.IsEOF(err) { break } diff --git a/third_party/github.com/cznic/exp/lldb/btree.go b/third_party/github.com/cznic/exp/lldb/btree.go index 628a10a44..438a0824c 100644 --- a/third_party/github.com/cznic/exp/lldb/btree.go +++ b/third_party/github.com/cznic/exp/lldb/btree.go @@ -13,6 +13,7 @@ import ( "strings" "camlistore.org/third_party/github.com/cznic/bufs" + "camlistore.org/third_party/github.com/cznic/fileutil" "camlistore.org/third_party/github.com/cznic/sortutil" ) @@ -184,7 +185,7 @@ func (t *BTree) Dump(w io.Writer) (err error) { err = enum.next() if err != nil { - if err == io.EOF { + if fileutil.IsEOF(err) { err = nil break } diff --git a/third_party/github.com/cznic/exp/lldb/btree_test.go b/third_party/github.com/cznic/exp/lldb/btree_test.go index 715531edd..f60f5e7ff 100644 --- a/third_party/github.com/cznic/exp/lldb/btree_test.go +++ b/third_party/github.com/cznic/exp/lldb/btree_test.go @@ -10,13 +10,13 @@ import ( "encoding/hex" "flag" "fmt" - "io" "math" "math/rand" "os" "runtime" "testing" + "camlistore.org/third_party/github.com/cznic/fileutil" "camlistore.org/third_party/github.com/cznic/mathutil" ) @@ -632,15 +632,15 @@ func TestbTreeNext(t *testing.T) { t.Fatal(err) } - if _, _, err = enum.current(); err != io.EOF { + if _, _, err = enum.current(); !fileutil.IsEOF(err) { t.Fatal(err) } - if err = enum.next(); err != io.EOF { + if err = enum.next(); !fileutil.IsEOF(err) { t.Fatal(err) } - if err = enum.prev(); err != io.EOF { + if err = enum.prev(); !fileutil.IsEOF(err) { t.Fatal(err) } @@ -683,7 +683,7 @@ func TestbTreeNext(t *testing.T) { t.Fatal(err) } - if err = enum.next(); N > 1 && err != io.EOF { + if err = enum.next(); N > 1 && !fileutil.IsEOF(err) { t.Fatal(err) } @@ -697,11 +697,11 @@ func TestbTreeNext(t *testing.T) { } // index: N - if _, _, err = enum.current(); err != io.EOF { + if _, _, err = enum.current(); !fileutil.IsEOF(err) { t.Fatal(err) } - if err = enum.next(); N > 1 && err != io.EOF { + if err = enum.next(); N > 1 && !fileutil.IsEOF(err) { t.Fatal(err) } @@ -727,7 +727,7 @@ func TestbTreeNext(t *testing.T) { switch { case i == N: - if err := enum.next(); err != io.EOF { + if err := enum.next(); !fileutil.IsEOF(err) { t.Fatal(err) } default: @@ -747,15 +747,15 @@ func TestbTreePrev(t *testing.T) { t.Fatal(err) } - if _, _, err = enum.current(); err != io.EOF { + if _, _, err = enum.current(); !fileutil.IsEOF(err) { t.Fatal(err) } - if err = enum.next(); err != io.EOF { + if err = enum.next(); !fileutil.IsEOF(err) { t.Fatal(err) } - if err = enum.prev(); err != io.EOF { + if err = enum.prev(); !fileutil.IsEOF(err) { t.Fatal(err) } @@ -780,7 +780,7 @@ func TestbTreePrev(t *testing.T) { t.Fatal(err) } - if err = enum.prev(); err != io.EOF { + if err = enum.prev(); !fileutil.IsEOF(err) { t.Fatal(err) } @@ -812,7 +812,7 @@ func TestbTreePrev(t *testing.T) { } // index: N - if _, _, err = enum.current(); err != io.EOF { + if _, _, err = enum.current(); !fileutil.IsEOF(err) { t.Fatal(err) } @@ -842,7 +842,7 @@ func TestbTreePrev(t *testing.T) { switch { case i == 1: - if err := enum.prev(); err != io.EOF { + if err := enum.prev(); !fileutil.IsEOF(err) { t.Fatal(err) } default: @@ -1095,7 +1095,7 @@ func TestseekFirst(t *testing.T) { bt := NewBTree(nil) enum, err := bt.seekFirst() - if err != io.EOF { + if !fileutil.IsEOF(err) { t.Fatal(err) } @@ -1106,12 +1106,12 @@ func TestseekFirst(t *testing.T) { } err = enum.prev() - if err != io.EOF { + if !fileutil.IsEOF(err) { t.Fatal(err) } err = enum.next() - if err != io.EOF { + if !fileutil.IsEOF(err) { t.Fatal(err) } @@ -1131,7 +1131,7 @@ func TestseekFirst(t *testing.T) { } err = enum.prev() - if err != io.EOF { + if !fileutil.IsEOF(err) { t.Fatal(err) } @@ -1163,7 +1163,7 @@ func TestseekLast(t *testing.T) { bt := NewBTree(nil) enum, err := bt.seekFirst() - if err != io.EOF { + if !fileutil.IsEOF(err) { t.Fatal(err) } @@ -1174,12 +1174,12 @@ func TestseekLast(t *testing.T) { } err = enum.prev() - if err != io.EOF { + if !fileutil.IsEOF(err) { t.Fatal(err) } err = enum.next() - if err != io.EOF { + if !fileutil.IsEOF(err) { t.Fatal(err) } @@ -1199,7 +1199,7 @@ func TestseekLast(t *testing.T) { } err = enum.next() - if err != io.EOF { + if !fileutil.IsEOF(err) { t.Fatal(err) } @@ -1597,7 +1597,7 @@ func TestBTreeSeekNext(t *testing.T) { k, v, err := en.Next() if err != nil { - if err != io.EOF { + if !fileutil.IsEOF(err) { t.Fatal(i, err) } @@ -1687,7 +1687,7 @@ func TestBTreeSeekPrev(t *testing.T) { k, v, err := en.Prev() if err != nil { - if err != io.EOF { + if !fileutil.IsEOF(err) { t.Fatal(i, err) } diff --git a/third_party/github.com/cznic/exp/lldb/filer_test.go b/third_party/github.com/cznic/exp/lldb/filer_test.go index 73ebffc0f..7378b806c 100644 --- a/third_party/github.com/cznic/exp/lldb/filer_test.go +++ b/third_party/github.com/cznic/exp/lldb/filer_test.go @@ -7,12 +7,13 @@ package lldb import ( "bytes" "encoding/hex" - "io" "io/ioutil" "math/rand" "os" "runtime" "testing" + + "camlistore.org/third_party/github.com/cznic/fileutil" ) // Bench knobs. @@ -284,7 +285,7 @@ func testFilerReadAtWriteAt(t *testing.T, nf newFunc) { from, to = 0, n2 } n, err := f.ReadAt(b[from:to], int64(from)) - if err != nil && (err != io.EOF && n != 0) { + if err != nil && (!fileutil.IsEOF(err) && n != 0) { fsz, err = f.Size() if err != nil { t.Error(err) diff --git a/third_party/github.com/cznic/exp/lldb/memfiler.go b/third_party/github.com/cznic/exp/lldb/memfiler.go index 0019c4189..aefb55cae 100644 --- a/third_party/github.com/cznic/exp/lldb/memfiler.go +++ b/third_party/github.com/cznic/exp/lldb/memfiler.go @@ -79,8 +79,10 @@ package lldb import ( "bytes" "fmt" - "camlistore.org/third_party/github.com/cznic/mathutil" "io" + + "camlistore.org/third_party/github.com/cznic/fileutil" + "camlistore.org/third_party/github.com/cznic/mathutil" ) const ( @@ -213,7 +215,7 @@ func (f *MemFiler) ReadFrom(r io.Reader) (n int64, err error) { n += int64(rn) } } - if rerr != io.EOF { + if !fileutil.IsEOF(rerr) { err = rerr } return @@ -335,7 +337,7 @@ func (f *MemFiler) WriteTo(w io.Writer) (n int64, err error) { n += int64(wn) } } - if rerr != io.EOF { + if !fileutil.IsEOF(rerr) { err = rerr } return diff --git a/third_party/github.com/cznic/exp/lldb/xact.go b/third_party/github.com/cznic/exp/lldb/xact.go index 375d9ea1c..d25f5e258 100644 --- a/third_party/github.com/cznic/exp/lldb/xact.go +++ b/third_party/github.com/cznic/exp/lldb/xact.go @@ -54,6 +54,7 @@ import ( "fmt" "io" + "camlistore.org/third_party/github.com/cznic/fileutil" "camlistore.org/third_party/github.com/cznic/mathutil" ) @@ -151,7 +152,7 @@ func (f *bitFiler) ReadAt(b []byte, off int64) (n int, err error) { pg = &bitPage{} if f.parent != nil { _, err = f.parent.ReadAt(pg.data[:], off&^bfMask) - if err != nil && err != io.EOF { + if err != nil && !fileutil.IsEOF(err) { return } @@ -209,7 +210,7 @@ func (f *bitFiler) WriteAt(b []byte, off int64) (n int, err error) { pg = &bitPage{} if f.parent != nil { _, err = f.parent.ReadAt(pg.data[:], off&^bfMask) - if err != nil && err != io.EOF { + if err != nil && !fileutil.IsEOF(err) { return } diff --git a/third_party/github.com/cznic/exp/lldb/xact_test.go b/third_party/github.com/cznic/exp/lldb/xact_test.go index c2fac8df3..d7da160d1 100644 --- a/third_party/github.com/cznic/exp/lldb/xact_test.go +++ b/third_party/github.com/cznic/exp/lldb/xact_test.go @@ -12,6 +12,7 @@ import ( "math/rand" "testing" + "camlistore.org/third_party/github.com/cznic/fileutil" "camlistore.org/third_party/github.com/cznic/mathutil" ) @@ -182,12 +183,12 @@ func TestRollbackFiler3(t *testing.T) { } n, err := r.ReadAt([]byte{0}, 0) - if n != 0 || err != io.EOF { + if n != 0 || !fileutil.IsEOF(err) { t.Fatal(n, err) } n, err = r.ReadAt([]byte{0}, 1e6) - if n != 0 || err != io.EOF { + if n != 0 || !fileutil.IsEOF(err) { t.Fatal(n, err) } diff --git a/third_party/github.com/cznic/fileutil/fileutil_arm.go b/third_party/github.com/cznic/fileutil/fileutil_arm.go index 77880ef87..2a73719e4 100644 --- a/third_party/github.com/cznic/fileutil/fileutil_arm.go +++ b/third_party/github.com/cznic/fileutil/fileutil_arm.go @@ -7,6 +7,7 @@ package fileutil import ( + "io" "os" ) @@ -21,3 +22,6 @@ func PunchHole(f *os.File, off, len int64) error { func Fadvise(f *os.File, off, len int64, advice FadviseAdvice) error { return nil } + +// IsEOF reports whether err is an EOF condition. +func IsEOF(err error) bool { return err == io.EOF } diff --git a/third_party/github.com/cznic/fileutil/fileutil_darwin.go b/third_party/github.com/cznic/fileutil/fileutil_darwin.go index f73198186..af1c89749 100644 --- a/third_party/github.com/cznic/fileutil/fileutil_darwin.go +++ b/third_party/github.com/cznic/fileutil/fileutil_darwin.go @@ -7,6 +7,7 @@ package fileutil import ( + "io" "os" ) @@ -21,3 +22,6 @@ func PunchHole(f *os.File, off, len int64) error { func Fadvise(f *os.File, off, len int64, advice FadviseAdvice) error { return nil } + +// IsEOF reports whether err is an EOF condition. +func IsEOF(err error) bool { return err == io.EOF } diff --git a/third_party/github.com/cznic/fileutil/fileutil_freebsd.go b/third_party/github.com/cznic/fileutil/fileutil_freebsd.go index e51d57172..b6af553ab 100644 --- a/third_party/github.com/cznic/fileutil/fileutil_freebsd.go +++ b/third_party/github.com/cznic/fileutil/fileutil_freebsd.go @@ -1,23 +1,27 @@ -// Copyright (c) 2011 CZ.NIC z.s.p.o. All rights reserved. +// Copyright (c) 2013 wathiede[0]. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. - -// blame: jnml, labs.nic.cz +// +// [0]: https://github.com/wathiede package fileutil import ( + "io" "os" ) // PunchHole deallocates space inside a file in the byte range starting at -// offset and continuing for len bytes. Unimplemented on FreeBSD +// offset and continuing for len bytes. Unimplemented on FreeBSD. func PunchHole(f *os.File, off, len int64) error { return nil } // Fadvise predeclares an access pattern for file data. See also 'man 2 -// posix_fadvise'. Unimplemented on FreeBSD +// posix_fadvise'. Unimplemented on FreeBSD. func Fadvise(f *os.File, off, len int64, advice FadviseAdvice) error { return nil } + +// IsEOF reports whether err is an EOF condition. +func IsEOF(err error) bool { return err == io.EOF } diff --git a/third_party/github.com/cznic/fileutil/fileutil_linux.go b/third_party/github.com/cznic/fileutil/fileutil_linux.go index 370f57eb4..9b7d523c7 100644 --- a/third_party/github.com/cznic/fileutil/fileutil_linux.go +++ b/third_party/github.com/cznic/fileutil/fileutil_linux.go @@ -8,6 +8,7 @@ package fileutil import ( "bytes" + "io" "io/ioutil" "os" "strconv" @@ -32,6 +33,9 @@ func init() { } tokens := bytes.Split(b, []byte(".")) + if len(tokens) > 3 { + tokens = tokens[:3] + } switch len(tokens) { case 3: // Supported since kernel 2.6.38 @@ -43,7 +47,7 @@ func init() { puncher = func(*os.File, int64, int64) error { return nil } } default: - panic(n) + puncher = func(*os.File, int64, int64) error { return nil } } } @@ -84,3 +88,6 @@ func Fadvise(f *os.File, off, len int64, advice FadviseAdvice) error { 0, 0) return os.NewSyscallError("SYS_FADVISE64", errno) } + +// IsEOF reports whether err is an EOF condition. +func IsEOF(err error) bool { return err == io.EOF } diff --git a/third_party/github.com/cznic/fileutil/fileutil_windows.go b/third_party/github.com/cznic/fileutil/fileutil_windows.go index 3e8c39d6a..e156c1cac 100644 --- a/third_party/github.com/cznic/fileutil/fileutil_windows.go +++ b/third_party/github.com/cznic/fileutil/fileutil_windows.go @@ -5,7 +5,9 @@ package fileutil import ( + "io" "os" + "syscall" ) // PunchHole deallocates space inside a file in the byte range starting at @@ -19,3 +21,14 @@ func PunchHole(f *os.File, off, len int64) error { func Fadvise(f *os.File, off, len int64, advice FadviseAdvice) error { return nil } + +// IsEOF reports whether err is an EOF condition. +func IsEOF(err error) bool { + if err == io.EOF { + return true + } + + // http://social.technet.microsoft.com/Forums/windowsserver/en-US/1a16311b-c625-46cf-830b-6a26af488435/how-to-solve-error-38-0x26-errorhandleeof-using-fsctlgetretrievalpointers + x, ok := err.(*os.PathError) + return ok && x.Op == "read" && x.Err.(syscall.Errno) == 0x26 +} diff --git a/third_party/github.com/cznic/fileutil/storage/probe_test.go b/third_party/github.com/cznic/fileutil/storage/probe_test.go index 29f647965..00eca8ee5 100644 --- a/third_party/github.com/cznic/fileutil/storage/probe_test.go +++ b/third_party/github.com/cznic/fileutil/storage/probe_test.go @@ -38,6 +38,7 @@ func (p *Probe) assert(t *testing.T, msg int, opsRd, opsWr, bytesRd, bytesWr, se } func TestProbe(t *testing.T) { + return //TODO disabled due to atomic.AddInt64 failing on W32 const fn = "test.tmp" store, err := NewFile(fn, os.O_CREATE|os.O_RDWR|os.O_CREATE, 0666) diff --git a/third_party/github.com/cznic/kv/all_test.go b/third_party/github.com/cznic/kv/all_test.go index 58ba9a2d6..de489ba98 100644 --- a/third_party/github.com/cznic/kv/all_test.go +++ b/third_party/github.com/cznic/kv/all_test.go @@ -8,15 +8,17 @@ import ( "encoding/binary" "flag" "fmt" - "io" + "io/ioutil" "math" "os" "path" + "path/filepath" "runtime" "strings" "sync" "testing" + "camlistore.org/third_party/github.com/cznic/fileutil" "camlistore.org/third_party/github.com/cznic/mathutil" ) @@ -146,9 +148,9 @@ func TestName(t *testing.T) { }(db.Name()) if n := db.Name(); n == "" || - !strings.Contains(n, "_testdata/") || - !strings.HasPrefix(path.Base(n), "temp") || - !strings.HasSuffix(path.Base(n), ".db") || + !strings.Contains(n, "_testdata") || + !strings.HasPrefix(filepath.Base(n), "temp") || + !strings.HasSuffix(filepath.Base(n), ".db") || path.Base(n) == "temp.db" { t.Error(n) } @@ -1393,7 +1395,7 @@ func TestSeekNext(t *testing.T) { k, v, err := en.Next() if err != nil { - if err != io.EOF { + if !fileutil.IsEOF(err) { t.Fatal(i, err) } @@ -1487,7 +1489,7 @@ func TestSeekPrev(t *testing.T) { k, v, err := en.Prev() if err != nil { - if err != io.EOF { + if !fileutil.IsEOF(err) { t.Fatal(i, err) } @@ -1808,3 +1810,64 @@ func TestWALName(t *testing.T) { t.Error(n) } } + +func TestCreateWithEmptyWAL(t *testing.T) { + dir, err := ioutil.TempDir("", "kv-test-create") + if err != nil { + t.Fatal(err) + } + + defer os.RemoveAll(dir) + dbName := filepath.Join(dir, "test.db") + var o Options + walName := o.walName(dbName, "") + wal, err := os.Create(walName) + if err != nil { + t.Error(err) + return + } + + wal.Close() + defer os.Remove(walName) + + db, err := Create(dbName, &Options{}) + if err != nil { + t.Error(err) + return + } + + if err = db.Set([]byte("foo"), []byte("bar")); err != nil { + t.Error(err) + } + db.Close() +} + +func TestCreateWithNonEmptyWAL(t *testing.T) { + dir, err := ioutil.TempDir("", "kv-test-create") + if err != nil { + t.Fatal(err) + } + + defer os.RemoveAll(dir) + dbName := filepath.Join(dir, "test.db") + var o Options + walName := o.walName(dbName, "") + wal, err := os.Create(walName) + if err != nil { + t.Error(err) + return + } + + if n, err := wal.Write([]byte{0}); n != 1 || err != nil { + t.Error(n, err) + return + } + + wal.Close() + defer os.Remove(walName) + + if _, err = Create(dbName, &Options{}); err == nil { + t.Error("Unexpected success") + return + } +} diff --git a/third_party/github.com/cznic/kv/etc.go b/third_party/github.com/cznic/kv/etc.go index efdcfdf26..bac0b3771 100644 --- a/third_party/github.com/cznic/kv/etc.go +++ b/third_party/github.com/cznic/kv/etc.go @@ -7,7 +7,8 @@ package kv import ( "bytes" "fmt" - "io" + + "camlistore.org/third_party/github.com/cznic/fileutil" ) type header struct { @@ -48,7 +49,7 @@ func h2b(b []byte, h int64) []byte { } func noEof(e error) (err error) { - if e != io.EOF { + if !fileutil.IsEOF(e) { err = e } return diff --git a/third_party/github.com/cznic/kv/kv.go b/third_party/github.com/cznic/kv/kv.go index a045fdb9b..3339c165b 100644 --- a/third_party/github.com/cznic/kv/kv.go +++ b/third_party/github.com/cznic/kv/kv.go @@ -291,6 +291,13 @@ func (db *DB) Close() (err error) { err = e1 } } + if wal := db.wal; wal != nil { + e := wal.Close() + db.wal = nil + if err == nil { + err = e + } + } return } @@ -664,12 +671,10 @@ func (db *DB) Put(dst, key []byte, upd func(key, old []byte) (new []byte, write return } -// Seek returns an enumerator or an error if any. Normally the enumerator is -// positioned on a KV pair such that 'key' >= KV.key and 'hit' is key == -// KV.key. If 'key' collates after any existing key in the DB then the -// enumerator's position is effectively "after" the last KV pair, but that is -// not an error. However, such enumerator will return err set to io.EOF from -// its Next/Prev methods. +// Seek returns an enumerator positioned on the first key/value pair whose key +// is 'greater than or equal to' the given key. There may be no such pair, in +// which case the Next,Prev methods of the returned enumerator will always +// return io.EOF. // // Seek is atomic and it is safe for concurrent use by multiple goroutines. func (db *DB) Seek(key []byte) (enum *Enumerator, hit bool, err error) { diff --git a/third_party/github.com/cznic/kv/options.go b/third_party/github.com/cznic/kv/options.go index 47e724138..dc9ebde3a 100644 --- a/third_party/github.com/cznic/kv/options.go +++ b/third_party/github.com/cznic/kv/options.go @@ -85,8 +85,9 @@ type Options struct { // used. If it is of zero size then a clean shutdown of the DB is // assumed, otherwise an automatic DB recovery is performed. // - // On creating a new DB the WAL file must not exist. It's not safe to - // write to a WAL file as it may contain unprocessed DB recovery data. + // On creating a new DB the WAL file must not exist or it must be + // empty. It's not safe to write to a non empty WAL file as it may + // contain unprocessed DB recovery data. _WAL string // Time to collect transactions before committing them into the WAL. @@ -142,7 +143,16 @@ func (o *Options) check(dbname string, new, lock bool) (err error) { case true: if o.wal, err = os.OpenFile(o._WAL, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666); err != nil { if os.IsExist(err) { - err = fmt.Errorf("cannot create DB %q: WAL file %q exists", dbname, o._WAL) + fi, e := os.Stat(o._WAL) + if e != nil { + return e + } + + if sz := fi.Size(); sz != 0 { + return fmt.Errorf("cannot create DB %q: non empty WAL file %q (size %d) exists", dbname, o._WAL, sz) + } + + o.wal, err = os.OpenFile(o._WAL, os.O_RDWR, 0666) } return }