aboutsummaryrefslogtreecommitdiffstats
path: root/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage
diff options
context:
space:
mode:
Diffstat (limited to 'Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage')
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage.go565
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_plan9.go17
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_solaris.go25
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_test.go142
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_unix.go37
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_windows.go17
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/mem_storage.go207
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/mem_storage_test.go66
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/storage.go154
9 files changed, 582 insertions, 648 deletions
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage.go
index 46cc9d070..cbe1dc103 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage.go
@@ -17,11 +17,12 @@ import (
"strings"
"sync"
"time"
-
- "github.com/syndtr/goleveldb/leveldb/util"
)
-var errFileOpen = errors.New("leveldb/storage: file still open")
+var (
+ errFileOpen = errors.New("leveldb/storage: file still open")
+ errReadOnly = errors.New("leveldb/storage: storage is read-only")
+)
type fileLock interface {
release() error
@@ -32,40 +33,52 @@ type fileStorageLock struct {
}
func (lock *fileStorageLock) Release() {
- fs := lock.fs
- fs.mu.Lock()
- defer fs.mu.Unlock()
- if fs.slock == lock {
- fs.slock = nil
+ if lock.fs != nil {
+ lock.fs.mu.Lock()
+ defer lock.fs.mu.Unlock()
+ if lock.fs.slock == lock {
+ lock.fs.slock = nil
+ }
}
- return
}
+const logSizeThreshold = 1024 * 1024 // 1 MiB
+
// fileStorage is a file-system backed storage.
type fileStorage struct {
- path string
-
- mu sync.Mutex
- flock fileLock
- slock *fileStorageLock
- logw *os.File
- buf []byte
+ path string
+ readOnly bool
+
+ mu sync.Mutex
+ flock fileLock
+ slock *fileStorageLock
+ logw *os.File
+ logSize int64
+ buf []byte
// Opened file counter; if open < 0 means closed.
open int
day int
}
// OpenFile returns a new filesytem-backed storage implementation with the given
-// path. This also hold a file lock, so any subsequent attempt to open the same
-// path will fail.
+// path. This also acquire a file lock, so any subsequent attempt to open the
+// same path will fail.
//
// The storage must be closed after use, by calling Close method.
-func OpenFile(path string) (Storage, error) {
- if err := os.MkdirAll(path, 0755); err != nil {
+func OpenFile(path string, readOnly bool) (Storage, error) {
+ if fi, err := os.Stat(path); err == nil {
+ if !fi.IsDir() {
+ return nil, fmt.Errorf("leveldb/storage: open %s: not a directory", path)
+ }
+ } else if os.IsNotExist(err) && !readOnly {
+ if err := os.MkdirAll(path, 0755); err != nil {
+ return nil, err
+ }
+ } else {
return nil, err
}
- flock, err := newFileLock(filepath.Join(path, "LOCK"))
+ flock, err := newFileLock(filepath.Join(path, "LOCK"), readOnly)
if err != nil {
return nil, err
}
@@ -76,23 +89,42 @@ func OpenFile(path string) (Storage, error) {
}
}()
- rename(filepath.Join(path, "LOG"), filepath.Join(path, "LOG.old"))
- logw, err := os.OpenFile(filepath.Join(path, "LOG"), os.O_WRONLY|os.O_CREATE, 0644)
- if err != nil {
- return nil, err
+ var (
+ logw *os.File
+ logSize int64
+ )
+ if !readOnly {
+ logw, err = os.OpenFile(filepath.Join(path, "LOG"), os.O_WRONLY|os.O_CREATE, 0644)
+ if err != nil {
+ return nil, err
+ }
+ logSize, err = logw.Seek(0, os.SEEK_END)
+ if err != nil {
+ logw.Close()
+ return nil, err
+ }
}
- fs := &fileStorage{path: path, flock: flock, logw: logw}
+ fs := &fileStorage{
+ path: path,
+ readOnly: readOnly,
+ flock: flock,
+ logw: logw,
+ logSize: logSize,
+ }
runtime.SetFinalizer(fs, (*fileStorage).Close)
return fs, nil
}
-func (fs *fileStorage) Lock() (util.Releaser, error) {
+func (fs *fileStorage) Lock() (Lock, error) {
fs.mu.Lock()
defer fs.mu.Unlock()
if fs.open < 0 {
return nil, ErrClosed
}
+ if fs.readOnly {
+ return &fileStorageLock{}, nil
+ }
if fs.slock != nil {
return nil, ErrLocked
}
@@ -101,7 +133,7 @@ func (fs *fileStorage) Lock() (util.Releaser, error) {
}
func itoa(buf []byte, i int, wid int) []byte {
- var u uint = uint(i)
+ u := uint(i)
if u == 0 && wid <= 1 {
return append(buf, '0')
}
@@ -126,6 +158,22 @@ func (fs *fileStorage) printDay(t time.Time) {
}
func (fs *fileStorage) doLog(t time.Time, str string) {
+ if fs.logSize > logSizeThreshold {
+ // Rotate log file.
+ fs.logw.Close()
+ fs.logw = nil
+ fs.logSize = 0
+ rename(filepath.Join(fs.path, "LOG"), filepath.Join(fs.path, "LOG.old"))
+ }
+ if fs.logw == nil {
+ var err error
+ fs.logw, err = os.OpenFile(filepath.Join(fs.path, "LOG"), os.O_WRONLY|os.O_CREATE, 0644)
+ if err != nil {
+ return
+ }
+ // Force printDay on new log file.
+ fs.day = 0
+ }
fs.printDay(t)
hour, min, sec := t.Clock()
msec := t.Nanosecond() / 1e3
@@ -145,65 +193,71 @@ func (fs *fileStorage) doLog(t time.Time, str string) {
}
func (fs *fileStorage) Log(str string) {
- t := time.Now()
- fs.mu.Lock()
- defer fs.mu.Unlock()
- if fs.open < 0 {
- return
+ if !fs.readOnly {
+ t := time.Now()
+ fs.mu.Lock()
+ defer fs.mu.Unlock()
+ if fs.open < 0 {
+ return
+ }
+ fs.doLog(t, str)
}
- fs.doLog(t, str)
}
func (fs *fileStorage) log(str string) {
- fs.doLog(time.Now(), str)
+ if !fs.readOnly {
+ fs.doLog(time.Now(), str)
+ }
}
-func (fs *fileStorage) GetFile(num uint64, t FileType) File {
- return &file{fs: fs, num: num, t: t}
-}
+func (fs *fileStorage) SetMeta(fd FileDesc) (err error) {
+ if !FileDescOk(fd) {
+ return ErrInvalidFile
+ }
+ if fs.readOnly {
+ return errReadOnly
+ }
-func (fs *fileStorage) GetFiles(t FileType) (ff []File, err error) {
fs.mu.Lock()
defer fs.mu.Unlock()
if fs.open < 0 {
- return nil, ErrClosed
+ return ErrClosed
}
- dir, err := os.Open(fs.path)
+ defer func() {
+ if err != nil {
+ fs.log(fmt.Sprintf("CURRENT: %v", err))
+ }
+ }()
+ path := fmt.Sprintf("%s.%d", filepath.Join(fs.path, "CURRENT"), fd.Num)
+ w, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
return
}
- fnn, err := dir.Readdirnames(0)
- // Close the dir first before checking for Readdirnames error.
- if err := dir.Close(); err != nil {
- fs.log(fmt.Sprintf("close dir: %v", err))
+ _, err = fmt.Fprintln(w, fsGenName(fd))
+ // Close the file first.
+ if cerr := w.Close(); cerr != nil {
+ fs.log(fmt.Sprintf("close CURRENT.%d: %v", fd.Num, cerr))
}
if err != nil {
return
}
- f := &file{fs: fs}
- for _, fn := range fnn {
- if f.parse(fn) && (f.t&t) != 0 {
- ff = append(ff, f)
- f = &file{fs: fs}
- }
- }
- return
+ return rename(path, filepath.Join(fs.path, "CURRENT"))
}
-func (fs *fileStorage) GetManifest() (f File, err error) {
+func (fs *fileStorage) GetMeta() (fd FileDesc, err error) {
fs.mu.Lock()
defer fs.mu.Unlock()
if fs.open < 0 {
- return nil, ErrClosed
+ return FileDesc{}, ErrClosed
}
dir, err := os.Open(fs.path)
if err != nil {
return
}
- fnn, err := dir.Readdirnames(0)
+ names, err := dir.Readdirnames(0)
// Close the dir first before checking for Readdirnames error.
- if err := dir.Close(); err != nil {
- fs.log(fmt.Sprintf("close dir: %v", err))
+ if ce := dir.Close(); ce != nil {
+ fs.log(fmt.Sprintf("close dir: %v", ce))
}
if err != nil {
return
@@ -212,55 +266,64 @@ func (fs *fileStorage) GetManifest() (f File, err error) {
var rem []string
var pend bool
var cerr error
- for _, fn := range fnn {
- if strings.HasPrefix(fn, "CURRENT") {
- pend1 := len(fn) > 7
+ for _, name := range names {
+ if strings.HasPrefix(name, "CURRENT") {
+ pend1 := len(name) > 7
+ var pendNum int64
// Make sure it is valid name for a CURRENT file, otherwise skip it.
if pend1 {
- if fn[7] != '.' || len(fn) < 9 {
- fs.log(fmt.Sprintf("skipping %s: invalid file name", fn))
+ if name[7] != '.' || len(name) < 9 {
+ fs.log(fmt.Sprintf("skipping %s: invalid file name", name))
continue
}
- if _, e1 := strconv.ParseUint(fn[8:], 10, 0); e1 != nil {
- fs.log(fmt.Sprintf("skipping %s: invalid file num: %v", fn, e1))
+ var e1 error
+ if pendNum, e1 = strconv.ParseInt(name[8:], 10, 0); e1 != nil {
+ fs.log(fmt.Sprintf("skipping %s: invalid file num: %v", name, e1))
continue
}
}
- path := filepath.Join(fs.path, fn)
+ path := filepath.Join(fs.path, name)
r, e1 := os.OpenFile(path, os.O_RDONLY, 0)
if e1 != nil {
- return nil, e1
+ return FileDesc{}, e1
}
b, e1 := ioutil.ReadAll(r)
if e1 != nil {
r.Close()
- return nil, e1
+ return FileDesc{}, e1
}
- f1 := &file{fs: fs}
- if len(b) < 1 || b[len(b)-1] != '\n' || !f1.parse(string(b[:len(b)-1])) {
- fs.log(fmt.Sprintf("skipping %s: corrupted or incomplete", fn))
+ var fd1 FileDesc
+ if len(b) < 1 || b[len(b)-1] != '\n' || !fsParseNamePtr(string(b[:len(b)-1]), &fd1) {
+ fs.log(fmt.Sprintf("skipping %s: corrupted or incomplete", name))
if pend1 {
- rem = append(rem, fn)
+ rem = append(rem, name)
}
if !pend1 || cerr == nil {
- cerr = fmt.Errorf("leveldb/storage: corrupted or incomplete %s file", fn)
+ metaFd, _ := fsParseName(name)
+ cerr = &ErrCorrupted{
+ Fd: metaFd,
+ Err: errors.New("leveldb/storage: corrupted or incomplete meta file"),
+ }
}
- } else if f != nil && f1.Num() < f.Num() {
- fs.log(fmt.Sprintf("skipping %s: obsolete", fn))
+ } else if pend1 && pendNum != fd1.Num {
+ fs.log(fmt.Sprintf("skipping %s: inconsistent pending-file num: %d vs %d", name, pendNum, fd1.Num))
+ rem = append(rem, name)
+ } else if fd1.Num < fd.Num {
+ fs.log(fmt.Sprintf("skipping %s: obsolete", name))
if pend1 {
- rem = append(rem, fn)
+ rem = append(rem, name)
}
} else {
- f = f1
+ fd = fd1
pend = pend1
}
if err := r.Close(); err != nil {
- fs.log(fmt.Sprintf("close %s: %v", fn, err))
+ fs.log(fmt.Sprintf("close %s: %v", name, err))
}
}
}
// Don't remove any files if there is no valid CURRENT file.
- if f == nil {
+ if fd.Nil() {
if cerr != nil {
err = cerr
} else {
@@ -268,267 +331,253 @@ func (fs *fileStorage) GetManifest() (f File, err error) {
}
return
}
- // Rename pending CURRENT file to an effective CURRENT.
- if pend {
- path := fmt.Sprintf("%s.%d", filepath.Join(fs.path, "CURRENT"), f.Num())
- if err := rename(path, filepath.Join(fs.path, "CURRENT")); err != nil {
- fs.log(fmt.Sprintf("CURRENT.%d -> CURRENT: %v", f.Num(), err))
+ if !fs.readOnly {
+ // Rename pending CURRENT file to an effective CURRENT.
+ if pend {
+ path := fmt.Sprintf("%s.%d", filepath.Join(fs.path, "CURRENT"), fd.Num)
+ if err := rename(path, filepath.Join(fs.path, "CURRENT")); err != nil {
+ fs.log(fmt.Sprintf("CURRENT.%d -> CURRENT: %v", fd.Num, err))
+ }
}
- }
- // Remove obsolete or incomplete pending CURRENT files.
- for _, fn := range rem {
- path := filepath.Join(fs.path, fn)
- if err := os.Remove(path); err != nil {
- fs.log(fmt.Sprintf("remove %s: %v", fn, err))
+ // Remove obsolete or incomplete pending CURRENT files.
+ for _, name := range rem {
+ path := filepath.Join(fs.path, name)
+ if err := os.Remove(path); err != nil {
+ fs.log(fmt.Sprintf("remove %s: %v", name, err))
+ }
}
}
return
}
-func (fs *fileStorage) SetManifest(f File) (err error) {
+func (fs *fileStorage) List(ft FileType) (fds []FileDesc, err error) {
fs.mu.Lock()
defer fs.mu.Unlock()
if fs.open < 0 {
- return ErrClosed
- }
- f2, ok := f.(*file)
- if !ok || f2.t != TypeManifest {
- return ErrInvalidFile
+ return nil, ErrClosed
}
- defer func() {
- if err != nil {
- fs.log(fmt.Sprintf("CURRENT: %v", err))
- }
- }()
- path := fmt.Sprintf("%s.%d", filepath.Join(fs.path, "CURRENT"), f2.Num())
- w, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
+ dir, err := os.Open(fs.path)
if err != nil {
- return err
+ return
}
- _, err = fmt.Fprintln(w, f2.name())
- // Close the file first.
- if err := w.Close(); err != nil {
- fs.log(fmt.Sprintf("close CURRENT.%d: %v", f2.num, err))
+ names, err := dir.Readdirnames(0)
+ // Close the dir first before checking for Readdirnames error.
+ if cerr := dir.Close(); cerr != nil {
+ fs.log(fmt.Sprintf("close dir: %v", cerr))
}
- if err != nil {
- return err
+ if err == nil {
+ for _, name := range names {
+ if fd, ok := fsParseName(name); ok && fd.Type&ft != 0 {
+ fds = append(fds, fd)
+ }
+ }
}
- return rename(path, filepath.Join(fs.path, "CURRENT"))
+ return
}
-func (fs *fileStorage) Close() error {
+func (fs *fileStorage) Open(fd FileDesc) (Reader, error) {
+ if !FileDescOk(fd) {
+ return nil, ErrInvalidFile
+ }
+
fs.mu.Lock()
defer fs.mu.Unlock()
if fs.open < 0 {
- return ErrClosed
- }
- // Clear the finalizer.
- runtime.SetFinalizer(fs, nil)
-
- if fs.open > 0 {
- fs.log(fmt.Sprintf("refuse to close, %d files still open", fs.open))
- return fmt.Errorf("leveldb/storage: cannot close, %d files still open", fs.open)
+ return nil, ErrClosed
}
- fs.open = -1
- e1 := fs.logw.Close()
- err := fs.flock.release()
- if err == nil {
- err = e1
+ of, err := os.OpenFile(filepath.Join(fs.path, fsGenName(fd)), os.O_RDONLY, 0)
+ if err != nil {
+ if fsHasOldName(fd) && os.IsNotExist(err) {
+ of, err = os.OpenFile(filepath.Join(fs.path, fsGenOldName(fd)), os.O_RDONLY, 0)
+ if err == nil {
+ goto ok
+ }
+ }
+ return nil, err
}
- return err
-}
-
-type fileWrap struct {
- *os.File
- f *file
+ok:
+ fs.open++
+ return &fileWrap{File: of, fs: fs, fd: fd}, nil
}
-func (fw fileWrap) Sync() error {
- if err := fw.File.Sync(); err != nil {
- return err
+func (fs *fileStorage) Create(fd FileDesc) (Writer, error) {
+ if !FileDescOk(fd) {
+ return nil, ErrInvalidFile
}
- if fw.f.Type() == TypeManifest {
- // Also sync parent directory if file type is manifest.
- // See: https://code.google.com/p/leveldb/issues/detail?id=190.
- if err := syncDir(fw.f.fs.path); err != nil {
- return err
- }
+ if fs.readOnly {
+ return nil, errReadOnly
}
- return nil
-}
-func (fw fileWrap) Close() error {
- f := fw.f
- f.fs.mu.Lock()
- defer f.fs.mu.Unlock()
- if !f.open {
- return ErrClosed
+ fs.mu.Lock()
+ defer fs.mu.Unlock()
+ if fs.open < 0 {
+ return nil, ErrClosed
}
- f.open = false
- f.fs.open--
- err := fw.File.Close()
+ of, err := os.OpenFile(filepath.Join(fs.path, fsGenName(fd)), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
- f.fs.log(fmt.Sprintf("close %s.%d: %v", f.Type(), f.Num(), err))
+ return nil, err
}
- return err
+ fs.open++
+ return &fileWrap{File: of, fs: fs, fd: fd}, nil
}
-type file struct {
- fs *fileStorage
- num uint64
- t FileType
- open bool
-}
-
-func (f *file) Open() (Reader, error) {
- f.fs.mu.Lock()
- defer f.fs.mu.Unlock()
- if f.fs.open < 0 {
- return nil, ErrClosed
+func (fs *fileStorage) Remove(fd FileDesc) error {
+ if !FileDescOk(fd) {
+ return ErrInvalidFile
}
- if f.open {
- return nil, errFileOpen
+ if fs.readOnly {
+ return errReadOnly
}
- of, err := os.OpenFile(f.path(), os.O_RDONLY, 0)
+
+ fs.mu.Lock()
+ defer fs.mu.Unlock()
+ if fs.open < 0 {
+ return ErrClosed
+ }
+ err := os.Remove(filepath.Join(fs.path, fsGenName(fd)))
if err != nil {
- if f.hasOldName() && os.IsNotExist(err) {
- of, err = os.OpenFile(f.oldPath(), os.O_RDONLY, 0)
- if err == nil {
- goto ok
+ if fsHasOldName(fd) && os.IsNotExist(err) {
+ if e1 := os.Remove(filepath.Join(fs.path, fsGenOldName(fd))); !os.IsNotExist(e1) {
+ fs.log(fmt.Sprintf("remove %s: %v (old name)", fd, err))
+ err = e1
}
+ } else {
+ fs.log(fmt.Sprintf("remove %s: %v", fd, err))
}
- return nil, err
}
-ok:
- f.open = true
- f.fs.open++
- return fileWrap{of, f}, nil
+ return err
}
-func (f *file) Create() (Writer, error) {
- f.fs.mu.Lock()
- defer f.fs.mu.Unlock()
- if f.fs.open < 0 {
- return nil, ErrClosed
+func (fs *fileStorage) Rename(oldfd, newfd FileDesc) error {
+ if !FileDescOk(oldfd) || !FileDescOk(newfd) {
+ return ErrInvalidFile
}
- if f.open {
- return nil, errFileOpen
+ if oldfd == newfd {
+ return nil
}
- of, err := os.OpenFile(f.path(), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
- if err != nil {
- return nil, err
+ if fs.readOnly {
+ return errReadOnly
}
- f.open = true
- f.fs.open++
- return fileWrap{of, f}, nil
+
+ fs.mu.Lock()
+ defer fs.mu.Unlock()
+ if fs.open < 0 {
+ return ErrClosed
+ }
+ return rename(filepath.Join(fs.path, fsGenName(oldfd)), filepath.Join(fs.path, fsGenName(newfd)))
}
-func (f *file) Replace(newfile File) error {
- f.fs.mu.Lock()
- defer f.fs.mu.Unlock()
- if f.fs.open < 0 {
+func (fs *fileStorage) Close() error {
+ fs.mu.Lock()
+ defer fs.mu.Unlock()
+ if fs.open < 0 {
return ErrClosed
}
- newfile2, ok := newfile.(*file)
- if !ok {
- return ErrInvalidFile
+ // Clear the finalizer.
+ runtime.SetFinalizer(fs, nil)
+
+ if fs.open > 0 {
+ fs.log(fmt.Sprintf("close: warning, %d files still open", fs.open))
}
- if f.open || newfile2.open {
- return errFileOpen
+ fs.open = -1
+ if fs.logw != nil {
+ fs.logw.Close()
}
- return rename(newfile2.path(), f.path())
+ return fs.flock.release()
}
-func (f *file) Type() FileType {
- return f.t
+type fileWrap struct {
+ *os.File
+ fs *fileStorage
+ fd FileDesc
+ closed bool
}
-func (f *file) Num() uint64 {
- return f.num
+func (fw *fileWrap) Sync() error {
+ if err := fw.File.Sync(); err != nil {
+ return err
+ }
+ if fw.fd.Type == TypeManifest {
+ // Also sync parent directory if file type is manifest.
+ // See: https://code.google.com/p/leveldb/issues/detail?id=190.
+ if err := syncDir(fw.fs.path); err != nil {
+ fw.fs.log(fmt.Sprintf("syncDir: %v", err))
+ return err
+ }
+ }
+ return nil
}
-func (f *file) Remove() error {
- f.fs.mu.Lock()
- defer f.fs.mu.Unlock()
- if f.fs.open < 0 {
+func (fw *fileWrap) Close() error {
+ fw.fs.mu.Lock()
+ defer fw.fs.mu.Unlock()
+ if fw.closed {
return ErrClosed
}
- if f.open {
- return errFileOpen
- }
- err := os.Remove(f.path())
+ fw.closed = true
+ fw.fs.open--
+ err := fw.File.Close()
if err != nil {
- f.fs.log(fmt.Sprintf("remove %s.%d: %v", f.Type(), f.Num(), err))
- }
- // Also try remove file with old name, just in case.
- if f.hasOldName() {
- if e1 := os.Remove(f.oldPath()); !os.IsNotExist(e1) {
- f.fs.log(fmt.Sprintf("remove %s.%d: %v (old name)", f.Type(), f.Num(), err))
- err = e1
- }
+ fw.fs.log(fmt.Sprintf("close %s: %v", fw.fd, err))
}
return err
}
-func (f *file) hasOldName() bool {
- return f.t == TypeTable
-}
-
-func (f *file) oldName() string {
- switch f.t {
- case TypeTable:
- return fmt.Sprintf("%06d.sst", f.num)
- }
- return f.name()
-}
-
-func (f *file) oldPath() string {
- return filepath.Join(f.fs.path, f.oldName())
-}
-
-func (f *file) name() string {
- switch f.t {
+func fsGenName(fd FileDesc) string {
+ switch fd.Type {
case TypeManifest:
- return fmt.Sprintf("MANIFEST-%06d", f.num)
+ return fmt.Sprintf("MANIFEST-%06d", fd.Num)
case TypeJournal:
- return fmt.Sprintf("%06d.log", f.num)
+ return fmt.Sprintf("%06d.log", fd.Num)
case TypeTable:
- return fmt.Sprintf("%06d.ldb", f.num)
+ return fmt.Sprintf("%06d.ldb", fd.Num)
case TypeTemp:
- return fmt.Sprintf("%06d.tmp", f.num)
+ return fmt.Sprintf("%06d.tmp", fd.Num)
default:
panic("invalid file type")
}
}
-func (f *file) path() string {
- return filepath.Join(f.fs.path, f.name())
+func fsHasOldName(fd FileDesc) bool {
+ return fd.Type == TypeTable
}
-func (f *file) parse(name string) bool {
- var num uint64
+func fsGenOldName(fd FileDesc) string {
+ switch fd.Type {
+ case TypeTable:
+ return fmt.Sprintf("%06d.sst", fd.Num)
+ }
+ return fsGenName(fd)
+}
+
+func fsParseName(name string) (fd FileDesc, ok bool) {
var tail string
- _, err := fmt.Sscanf(name, "%d.%s", &num, &tail)
+ _, err := fmt.Sscanf(name, "%d.%s", &fd.Num, &tail)
if err == nil {
switch tail {
case "log":
- f.t = TypeJournal
+ fd.Type = TypeJournal
case "ldb", "sst":
- f.t = TypeTable
+ fd.Type = TypeTable
case "tmp":
- f.t = TypeTemp
+ fd.Type = TypeTemp
default:
- return false
+ return
}
- f.num = num
- return true
+ return fd, true
}
- n, _ := fmt.Sscanf(name, "MANIFEST-%d%s", &num, &tail)
+ n, _ := fmt.Sscanf(name, "MANIFEST-%d%s", &fd.Num, &tail)
if n == 1 {
- f.t = TypeManifest
- f.num = num
- return true
+ fd.Type = TypeManifest
+ return fd, true
}
+ return
+}
- return false
+func fsParseNamePtr(name string, fd *FileDesc) bool {
+ _fd, ok := fsParseName(name)
+ if fd != nil {
+ *fd = _fd
+ }
+ return ok
}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_plan9.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_plan9.go
index 42940d769..bab62bfce 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_plan9.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_plan9.go
@@ -19,8 +19,21 @@ func (fl *plan9FileLock) release() error {
return fl.f.Close()
}
-func newFileLock(path string) (fl fileLock, err error) {
- f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, os.ModeExclusive|0644)
+func newFileLock(path string, readOnly bool) (fl fileLock, err error) {
+ var (
+ flag int
+ perm os.FileMode
+ )
+ if readOnly {
+ flag = os.O_RDONLY
+ } else {
+ flag = os.O_RDWR
+ perm = os.ModeExclusive
+ }
+ f, err := os.OpenFile(path, flag, perm)
+ if os.IsNotExist(err) {
+ f, err = os.OpenFile(path, flag|os.O_CREATE, perm|0644)
+ }
if err != nil {
return
}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_solaris.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_solaris.go
index 102031bfd..79901ee4a 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_solaris.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_solaris.go
@@ -18,18 +18,27 @@ type unixFileLock struct {
}
func (fl *unixFileLock) release() error {
- if err := setFileLock(fl.f, false); err != nil {
+ if err := setFileLock(fl.f, false, false); err != nil {
return err
}
return fl.f.Close()
}
-func newFileLock(path string) (fl fileLock, err error) {
- f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0644)
+func newFileLock(path string, readOnly bool) (fl fileLock, err error) {
+ var flag int
+ if readOnly {
+ flag = os.O_RDONLY
+ } else {
+ flag = os.O_RDWR
+ }
+ f, err := os.OpenFile(path, flag, 0)
+ if os.IsNotExist(err) {
+ f, err = os.OpenFile(path, flag|os.O_CREATE, 0644)
+ }
if err != nil {
return
}
- err = setFileLock(f, true)
+ err = setFileLock(f, readOnly, true)
if err != nil {
f.Close()
return
@@ -38,7 +47,7 @@ func newFileLock(path string) (fl fileLock, err error) {
return
}
-func setFileLock(f *os.File, lock bool) error {
+func setFileLock(f *os.File, readOnly, lock bool) error {
flock := syscall.Flock_t{
Type: syscall.F_UNLCK,
Start: 0,
@@ -46,7 +55,11 @@ func setFileLock(f *os.File, lock bool) error {
Whence: 1,
}
if lock {
- flock.Type = syscall.F_WRLCK
+ if readOnly {
+ flock.Type = syscall.F_RDLCK
+ } else {
+ flock.Type = syscall.F_WRLCK
+ }
}
return syscall.FcntlFlock(f.Fd(), syscall.F_SETLK, &flock)
}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_test.go
deleted file mode 100644
index 92abcbb7d..000000000
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_test.go
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
-// All rights reserved.
-//
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package storage
-
-import (
- "fmt"
- "os"
- "path/filepath"
- "testing"
-)
-
-var cases = []struct {
- oldName []string
- name string
- ftype FileType
- num uint64
-}{
- {nil, "000100.log", TypeJournal, 100},
- {nil, "000000.log", TypeJournal, 0},
- {[]string{"000000.sst"}, "000000.ldb", TypeTable, 0},
- {nil, "MANIFEST-000002", TypeManifest, 2},
- {nil, "MANIFEST-000007", TypeManifest, 7},
- {nil, "18446744073709551615.log", TypeJournal, 18446744073709551615},
- {nil, "000100.tmp", TypeTemp, 100},
-}
-
-var invalidCases = []string{
- "",
- "foo",
- "foo-dx-100.log",
- ".log",
- "",
- "manifest",
- "CURREN",
- "CURRENTX",
- "MANIFES",
- "MANIFEST",
- "MANIFEST-",
- "XMANIFEST-3",
- "MANIFEST-3x",
- "LOC",
- "LOCKx",
- "LO",
- "LOGx",
- "18446744073709551616.log",
- "184467440737095516150.log",
- "100",
- "100.",
- "100.lop",
-}
-
-func TestFileStorage_CreateFileName(t *testing.T) {
- for _, c := range cases {
- f := &file{num: c.num, t: c.ftype}
- if f.name() != c.name {
- t.Errorf("invalid filename got '%s', want '%s'", f.name(), c.name)
- }
- }
-}
-
-func TestFileStorage_ParseFileName(t *testing.T) {
- for _, c := range cases {
- for _, name := range append([]string{c.name}, c.oldName...) {
- f := new(file)
- if !f.parse(name) {
- t.Errorf("cannot parse filename '%s'", name)
- continue
- }
- if f.Type() != c.ftype {
- t.Errorf("filename '%s' invalid type got '%d', want '%d'", name, f.Type(), c.ftype)
- }
- if f.Num() != c.num {
- t.Errorf("filename '%s' invalid number got '%d', want '%d'", name, f.Num(), c.num)
- }
- }
- }
-}
-
-func TestFileStorage_InvalidFileName(t *testing.T) {
- for _, name := range invalidCases {
- f := new(file)
- if f.parse(name) {
- t.Errorf("filename '%s' should be invalid", name)
- }
- }
-}
-
-func TestFileStorage_Locking(t *testing.T) {
- path := filepath.Join(os.TempDir(), fmt.Sprintf("goleveldbtestfd-%d", os.Getuid()))
-
- _, err := os.Stat(path)
- if err == nil {
- err = os.RemoveAll(path)
- if err != nil {
- t.Fatal("RemoveAll: got error: ", err)
- }
- }
-
- p1, err := OpenFile(path)
- if err != nil {
- t.Fatal("OpenFile(1): got error: ", err)
- }
-
- defer os.RemoveAll(path)
-
- p2, err := OpenFile(path)
- if err != nil {
- t.Logf("OpenFile(2): got error: %s (expected)", err)
- } else {
- p2.Close()
- p1.Close()
- t.Fatal("OpenFile(2): expect error")
- }
-
- p1.Close()
-
- p3, err := OpenFile(path)
- if err != nil {
- t.Fatal("OpenFile(3): got error: ", err)
- }
- defer p3.Close()
-
- l, err := p3.Lock()
- if err != nil {
- t.Fatal("storage lock failed(1): ", err)
- }
- _, err = p3.Lock()
- if err == nil {
- t.Fatal("expect error for second storage lock attempt")
- } else {
- t.Logf("storage lock got error: %s (expected)", err)
- }
- l.Release()
- _, err = p3.Lock()
- if err != nil {
- t.Fatal("storage lock failed(2): ", err)
- }
-}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_unix.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_unix.go
index d0a604b7a..7e2991537 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_unix.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_unix.go
@@ -18,18 +18,27 @@ type unixFileLock struct {
}
func (fl *unixFileLock) release() error {
- if err := setFileLock(fl.f, false); err != nil {
+ if err := setFileLock(fl.f, false, false); err != nil {
return err
}
return fl.f.Close()
}
-func newFileLock(path string) (fl fileLock, err error) {
- f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0644)
+func newFileLock(path string, readOnly bool) (fl fileLock, err error) {
+ var flag int
+ if readOnly {
+ flag = os.O_RDONLY
+ } else {
+ flag = os.O_RDWR
+ }
+ f, err := os.OpenFile(path, flag, 0)
+ if os.IsNotExist(err) {
+ f, err = os.OpenFile(path, flag|os.O_CREATE, 0644)
+ }
if err != nil {
return
}
- err = setFileLock(f, true)
+ err = setFileLock(f, readOnly, true)
if err != nil {
f.Close()
return
@@ -38,10 +47,14 @@ func newFileLock(path string) (fl fileLock, err error) {
return
}
-func setFileLock(f *os.File, lock bool) error {
+func setFileLock(f *os.File, readOnly, lock bool) error {
how := syscall.LOCK_UN
if lock {
- how = syscall.LOCK_EX
+ if readOnly {
+ how = syscall.LOCK_SH
+ } else {
+ how = syscall.LOCK_EX
+ }
}
return syscall.Flock(int(f.Fd()), how|syscall.LOCK_NB)
}
@@ -50,13 +63,23 @@ func rename(oldpath, newpath string) error {
return os.Rename(oldpath, newpath)
}
+func isErrInvalid(err error) bool {
+ if err == os.ErrInvalid {
+ return true
+ }
+ if syserr, ok := err.(*os.SyscallError); ok && syserr.Err == syscall.EINVAL {
+ return true
+ }
+ return false
+}
+
func syncDir(name string) error {
f, err := os.Open(name)
if err != nil {
return err
}
defer f.Close()
- if err := f.Sync(); err != nil {
+ if err := f.Sync(); err != nil && !isErrInvalid(err) {
return err
}
return nil
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_windows.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_windows.go
index 50c3c454e..899335fd7 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_windows.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_windows.go
@@ -29,12 +29,22 @@ func (fl *windowsFileLock) release() error {
return syscall.Close(fl.fd)
}
-func newFileLock(path string) (fl fileLock, err error) {
+func newFileLock(path string, readOnly bool) (fl fileLock, err error) {
pathp, err := syscall.UTF16PtrFromString(path)
if err != nil {
return
}
- fd, err := syscall.CreateFile(pathp, syscall.GENERIC_READ|syscall.GENERIC_WRITE, 0, nil, syscall.CREATE_ALWAYS, syscall.FILE_ATTRIBUTE_NORMAL, 0)
+ var access, shareMode uint32
+ if readOnly {
+ access = syscall.GENERIC_READ
+ shareMode = syscall.FILE_SHARE_READ
+ } else {
+ access = syscall.GENERIC_READ | syscall.GENERIC_WRITE
+ }
+ fd, err := syscall.CreateFile(pathp, access, shareMode, nil, syscall.OPEN_EXISTING, syscall.FILE_ATTRIBUTE_NORMAL, 0)
+ if err == syscall.ERROR_FILE_NOT_FOUND {
+ fd, err = syscall.CreateFile(pathp, access, shareMode, nil, syscall.OPEN_ALWAYS, syscall.FILE_ATTRIBUTE_NORMAL, 0)
+ }
if err != nil {
return
}
@@ -47,9 +57,8 @@ func moveFileEx(from *uint16, to *uint16, flags uint32) error {
if r1 == 0 {
if e1 != 0 {
return error(e1)
- } else {
- return syscall.EINVAL
}
+ return syscall.EINVAL
}
return nil
}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/mem_storage.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/mem_storage.go
index fc1c8165d..9b70e1513 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/mem_storage.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/mem_storage.go
@@ -10,8 +10,6 @@ import (
"bytes"
"os"
"sync"
-
- "github.com/syndtr/goleveldb/leveldb/util"
)
const typeShift = 3
@@ -32,10 +30,10 @@ func (lock *memStorageLock) Release() {
// memStorage is a memory-backed storage.
type memStorage struct {
- mu sync.Mutex
- slock *memStorageLock
- files map[uint64]*memFile
- manifest *memFilePtr
+ mu sync.Mutex
+ slock *memStorageLock
+ files map[uint64]*memFile
+ meta FileDesc
}
// NewMemStorage returns a new memory-backed storage implementation.
@@ -45,7 +43,7 @@ func NewMemStorage() Storage {
}
}
-func (ms *memStorage) Lock() (util.Releaser, error) {
+func (ms *memStorage) Lock() (Lock, error) {
ms.mu.Lock()
defer ms.mu.Unlock()
if ms.slock != nil {
@@ -57,147 +55,164 @@ func (ms *memStorage) Lock() (util.Releaser, error) {
func (*memStorage) Log(str string) {}
-func (ms *memStorage) GetFile(num uint64, t FileType) File {
- return &memFilePtr{ms: ms, num: num, t: t}
-}
+func (ms *memStorage) SetMeta(fd FileDesc) error {
+ if !FileDescOk(fd) {
+ return ErrInvalidFile
+ }
-func (ms *memStorage) GetFiles(t FileType) ([]File, error) {
ms.mu.Lock()
- var ff []File
- for x, _ := range ms.files {
- num, mt := x>>typeShift, FileType(x)&TypeAll
- if mt&t == 0 {
- continue
- }
- ff = append(ff, &memFilePtr{ms: ms, num: num, t: mt})
- }
+ ms.meta = fd
ms.mu.Unlock()
- return ff, nil
+ return nil
}
-func (ms *memStorage) GetManifest() (File, error) {
+func (ms *memStorage) GetMeta() (FileDesc, error) {
ms.mu.Lock()
defer ms.mu.Unlock()
- if ms.manifest == nil {
- return nil, os.ErrNotExist
+ if ms.meta.Nil() {
+ return FileDesc{}, os.ErrNotExist
}
- return ms.manifest, nil
+ return ms.meta, nil
}
-func (ms *memStorage) SetManifest(f File) error {
- fm, ok := f.(*memFilePtr)
- if !ok || fm.t != TypeManifest {
- return ErrInvalidFile
- }
+func (ms *memStorage) List(ft FileType) ([]FileDesc, error) {
ms.mu.Lock()
- ms.manifest = fm
+ var fds []FileDesc
+ for x, _ := range ms.files {
+ fd := unpackFile(x)
+ if fd.Type&ft != 0 {
+ fds = append(fds, fd)
+ }
+ }
ms.mu.Unlock()
- return nil
+ return fds, nil
}
-func (*memStorage) Close() error { return nil }
-
-type memReader struct {
- *bytes.Reader
- m *memFile
-}
-
-func (mr *memReader) Close() error {
- return mr.m.Close()
-}
-
-type memFile struct {
- bytes.Buffer
- ms *memStorage
- open bool
-}
-
-func (*memFile) Sync() error { return nil }
-func (m *memFile) Close() error {
- m.ms.mu.Lock()
- m.open = false
- m.ms.mu.Unlock()
- return nil
-}
-
-type memFilePtr struct {
- ms *memStorage
- num uint64
- t FileType
-}
-
-func (p *memFilePtr) x() uint64 {
- return p.Num()<<typeShift | uint64(p.Type())
-}
+func (ms *memStorage) Open(fd FileDesc) (Reader, error) {
+ if !FileDescOk(fd) {
+ return nil, ErrInvalidFile
+ }
-func (p *memFilePtr) Open() (Reader, error) {
- ms := p.ms
ms.mu.Lock()
defer ms.mu.Unlock()
- if m, exist := ms.files[p.x()]; exist {
+ if m, exist := ms.files[packFile(fd)]; exist {
if m.open {
return nil, errFileOpen
}
m.open = true
- return &memReader{Reader: bytes.NewReader(m.Bytes()), m: m}, nil
+ return &memReader{Reader: bytes.NewReader(m.Bytes()), ms: ms, m: m}, nil
}
return nil, os.ErrNotExist
}
-func (p *memFilePtr) Create() (Writer, error) {
- ms := p.ms
+func (ms *memStorage) Create(fd FileDesc) (Writer, error) {
+ if !FileDescOk(fd) {
+ return nil, ErrInvalidFile
+ }
+
+ x := packFile(fd)
ms.mu.Lock()
defer ms.mu.Unlock()
- m, exist := ms.files[p.x()]
+ m, exist := ms.files[x]
if exist {
if m.open {
return nil, errFileOpen
}
m.Reset()
} else {
- m = &memFile{ms: ms}
- ms.files[p.x()] = m
+ m = &memFile{}
+ ms.files[x] = m
}
m.open = true
- return m, nil
+ return &memWriter{memFile: m, ms: ms}, nil
}
-func (p *memFilePtr) Replace(newfile File) error {
- p1, ok := newfile.(*memFilePtr)
- if !ok {
+func (ms *memStorage) Remove(fd FileDesc) error {
+ if !FileDescOk(fd) {
return ErrInvalidFile
}
- ms := p.ms
+
+ x := packFile(fd)
ms.mu.Lock()
defer ms.mu.Unlock()
- m1, exist := ms.files[p1.x()]
+ if _, exist := ms.files[x]; exist {
+ delete(ms.files, x)
+ return nil
+ }
+ return os.ErrNotExist
+}
+
+func (ms *memStorage) Rename(oldfd, newfd FileDesc) error {
+ if FileDescOk(oldfd) || FileDescOk(newfd) {
+ return ErrInvalidFile
+ }
+ if oldfd == newfd {
+ return nil
+ }
+
+ oldx := packFile(oldfd)
+ newx := packFile(newfd)
+ ms.mu.Lock()
+ defer ms.mu.Unlock()
+ oldm, exist := ms.files[oldx]
if !exist {
return os.ErrNotExist
}
- m0, exist := ms.files[p.x()]
- if (exist && m0.open) || m1.open {
+ newm, exist := ms.files[newx]
+ if (exist && newm.open) || oldm.open {
return errFileOpen
}
- delete(ms.files, p1.x())
- ms.files[p.x()] = m1
+ delete(ms.files, oldx)
+ ms.files[newx] = oldm
return nil
}
-func (p *memFilePtr) Type() FileType {
- return p.t
+func (*memStorage) Close() error { return nil }
+
+type memFile struct {
+ bytes.Buffer
+ open bool
}
-func (p *memFilePtr) Num() uint64 {
- return p.num
+type memReader struct {
+ *bytes.Reader
+ ms *memStorage
+ m *memFile
+ closed bool
}
-func (p *memFilePtr) Remove() error {
- ms := p.ms
- ms.mu.Lock()
- defer ms.mu.Unlock()
- if _, exist := ms.files[p.x()]; exist {
- delete(ms.files, p.x())
- return nil
+func (mr *memReader) Close() error {
+ mr.ms.mu.Lock()
+ defer mr.ms.mu.Unlock()
+ if mr.closed {
+ return ErrClosed
}
- return os.ErrNotExist
+ mr.m.open = false
+ return nil
+}
+
+type memWriter struct {
+ *memFile
+ ms *memStorage
+ closed bool
+}
+
+func (*memWriter) Sync() error { return nil }
+
+func (mw *memWriter) Close() error {
+ mw.ms.mu.Lock()
+ defer mw.ms.mu.Unlock()
+ if mw.closed {
+ return ErrClosed
+ }
+ mw.memFile.open = false
+ return nil
+}
+
+func packFile(fd FileDesc) uint64 {
+ return uint64(fd.Num)<<typeShift | uint64(fd.Type)
+}
+
+func unpackFile(x uint64) FileDesc {
+ return FileDesc{FileType(x) & TypeAll, int64(x >> typeShift)}
}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/mem_storage_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/mem_storage_test.go
deleted file mode 100644
index 23bb074b4..000000000
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/mem_storage_test.go
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright (c) 2013, Suryandaru Triandana <syndtr@gmail.com>
-// All rights reserved.
-//
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package storage
-
-import (
- "bytes"
- "testing"
-)
-
-func TestMemStorage(t *testing.T) {
- m := NewMemStorage()
-
- l, err := m.Lock()
- if err != nil {
- t.Fatal("storage lock failed(1): ", err)
- }
- _, err = m.Lock()
- if err == nil {
- t.Fatal("expect error for second storage lock attempt")
- } else {
- t.Logf("storage lock got error: %s (expected)", err)
- }
- l.Release()
- _, err = m.Lock()
- if err != nil {
- t.Fatal("storage lock failed(2): ", err)
- }
-
- f := m.GetFile(1, TypeTable)
- if f.Num() != 1 && f.Type() != TypeTable {
- t.Fatal("invalid file number and type")
- }
- w, _ := f.Create()
- w.Write([]byte("abc"))
- w.Close()
- if ff, _ := m.GetFiles(TypeAll); len(ff) != 1 {
- t.Fatal("invalid GetFiles len")
- }
- buf := new(bytes.Buffer)
- r, err := f.Open()
- if err != nil {
- t.Fatal("Open: got error: ", err)
- }
- buf.ReadFrom(r)
- r.Close()
- if got := buf.String(); got != "abc" {
- t.Fatalf("Read: invalid value, want=abc got=%s", got)
- }
- if _, err := f.Open(); err != nil {
- t.Fatal("Open: got error: ", err)
- }
- if _, err := m.GetFile(1, TypeTable).Open(); err == nil {
- t.Fatal("expecting error")
- }
- f.Remove()
- if ff, _ := m.GetFiles(TypeAll); len(ff) != 0 {
- t.Fatal("invalid GetFiles len", len(ff))
- }
- if _, err := f.Open(); err == nil {
- t.Fatal("expecting error")
- }
-}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/storage.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/storage.go
index 85dd70b06..9b30b6727 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/storage.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/storage.go
@@ -15,7 +15,7 @@ import (
"github.com/syndtr/goleveldb/leveldb/util"
)
-type FileType uint32
+type FileType int
const (
TypeManifest FileType = 1 << iota
@@ -46,6 +46,22 @@ var (
ErrClosed = errors.New("leveldb/storage: closed")
)
+// ErrCorrupted is the type that wraps errors that indicate corruption of
+// a file. Package storage has its own type instead of using
+// errors.ErrCorrupted to prevent circular import.
+type ErrCorrupted struct {
+ Fd FileDesc
+ Err error
+}
+
+func (e *ErrCorrupted) Error() string {
+ if !e.Fd.Nil() {
+ return fmt.Sprintf("%v [file=%v]", e.Err, e.Fd)
+ } else {
+ return e.Err.Error()
+ }
+}
+
// Syncer is the interface that wraps basic Sync method.
type Syncer interface {
// Sync commits the current contents of the file to stable storage.
@@ -67,31 +83,47 @@ type Writer interface {
Syncer
}
-// File is the file. A file instance must be goroutine-safe.
-type File interface {
- // Open opens the file for read. Returns os.ErrNotExist error
- // if the file does not exist.
- // Returns ErrClosed if the underlying storage is closed.
- Open() (r Reader, err error)
-
- // Create creates the file for writting. Truncate the file if
- // already exist.
- // Returns ErrClosed if the underlying storage is closed.
- Create() (w Writer, err error)
+type Lock interface {
+ util.Releaser
+}
- // Replace replaces file with newfile.
- // Returns ErrClosed if the underlying storage is closed.
- Replace(newfile File) error
+// FileDesc is a file descriptor.
+type FileDesc struct {
+ Type FileType
+ Num int64
+}
- // Type returns the file type
- Type() FileType
+func (fd FileDesc) String() string {
+ switch fd.Type {
+ case TypeManifest:
+ return fmt.Sprintf("MANIFEST-%06d", fd.Num)
+ case TypeJournal:
+ return fmt.Sprintf("%06d.log", fd.Num)
+ case TypeTable:
+ return fmt.Sprintf("%06d.ldb", fd.Num)
+ case TypeTemp:
+ return fmt.Sprintf("%06d.tmp", fd.Num)
+ default:
+ return fmt.Sprintf("%#x-%d", fd.Type, fd.Num)
+ }
+}
- // Num returns the file number.
- Num() uint64
+// Nil returns true if fd == (FileDesc{}).
+func (fd FileDesc) Nil() bool {
+ return fd == (FileDesc{})
+}
- // Remove removes the file.
- // Returns ErrClosed if the underlying storage is closed.
- Remove() error
+// FileDescOk returns true if fd is a valid file descriptor.
+func FileDescOk(fd FileDesc) bool {
+ switch fd.Type {
+ case TypeManifest:
+ case TypeJournal:
+ case TypeTable:
+ case TypeTemp:
+ default:
+ return false
+ }
+ return fd.Num >= 0
}
// Storage is the storage. A storage instance must be goroutine-safe.
@@ -99,59 +131,47 @@ type Storage interface {
// Lock locks the storage. Any subsequent attempt to call Lock will fail
// until the last lock released.
// After use the caller should call the Release method.
- Lock() (l util.Releaser, err error)
+ Lock() (Lock, error)
- // Log logs a string. This is used for logging. An implementation
- // may write to a file, stdout or simply do nothing.
+ // Log logs a string. This is used for logging.
+ // An implementation may write to a file, stdout or simply do nothing.
Log(str string)
- // GetFile returns a file for the given number and type. GetFile will never
- // returns nil, even if the underlying storage is closed.
- GetFile(num uint64, t FileType) File
+ // SetMeta sets to point to the given fd, which then can be acquired using
+ // GetMeta method.
+ // SetMeta should be implemented in such way that changes should happened
+ // atomically.
+ SetMeta(fd FileDesc) error
- // GetFiles returns a slice of files that match the given file types.
- // The file types may be OR'ed together.
- GetFiles(t FileType) ([]File, error)
+ // GetManifest returns a manifest file.
+ // Returns os.ErrNotExist if meta doesn't point to any fd, or point to fd
+ // that doesn't exist.
+ GetMeta() (FileDesc, error)
- // GetManifest returns a manifest file. Returns os.ErrNotExist if manifest
- // file does not exist.
- GetManifest() (File, error)
+ // List returns fds that match the given file types.
+ // The file types may be OR'ed together.
+ List(ft FileType) ([]FileDesc, error)
- // SetManifest sets the given file as manifest file. The given file should
- // be a manifest file type or error will be returned.
- SetManifest(f File) error
+ // Open opens file with the given fd read-only.
+ // Returns os.ErrNotExist error if the file does not exist.
+ // Returns ErrClosed if the underlying storage is closed.
+ Open(fd FileDesc) (Reader, error)
- // Close closes the storage. It is valid to call Close multiple times.
- // Other methods should not be called after the storage has been closed.
- Close() error
-}
+ // Create creates file with the given fd, truncate if already exist and
+ // opens write-only.
+ // Returns ErrClosed if the underlying storage is closed.
+ Create(fd FileDesc) (Writer, error)
-// FileInfo wraps basic file info.
-type FileInfo struct {
- Type FileType
- Num uint64
-}
+ // Remove removes file with the given fd.
+ // Returns ErrClosed if the underlying storage is closed.
+ Remove(fd FileDesc) error
-func (fi FileInfo) String() string {
- switch fi.Type {
- case TypeManifest:
- return fmt.Sprintf("MANIFEST-%06d", fi.Num)
- case TypeJournal:
- return fmt.Sprintf("%06d.log", fi.Num)
- case TypeTable:
- return fmt.Sprintf("%06d.ldb", fi.Num)
- case TypeTemp:
- return fmt.Sprintf("%06d.tmp", fi.Num)
- default:
- return fmt.Sprintf("%#x-%d", fi.Type, fi.Num)
- }
-}
+ // Rename renames file from oldfd to newfd.
+ // Returns ErrClosed if the underlying storage is closed.
+ Rename(oldfd, newfd FileDesc) error
-// NewFileInfo creates new FileInfo from the given File. It will returns nil
-// if File is nil.
-func NewFileInfo(f File) *FileInfo {
- if f == nil {
- return nil
- }
- return &FileInfo{f.Type(), f.Num()}
+ // Close closes the storage.
+ // It is valid to call Close multiple times. Other methods should not be
+ // called after the storage has been closed.
+ Close() error
}