// Copyright (c) 2012, Suryandaru Triandana // 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 provides storage abstraction for LevelDB. package storage import ( "errors" "fmt" "io" "github.com/syndtr/goleveldb/leveldb/util" ) type FileType int const ( TypeManifest FileType = 1 << iota TypeJournal TypeTable TypeTemp TypeAll = TypeManifest | TypeJournal | TypeTable | TypeTemp ) func (t FileType) String() string { switch t { case TypeManifest: return "manifest" case TypeJournal: return "journal" case TypeTable: return "table" case TypeTemp: return "temp" } return fmt.Sprintf("", t) } var ( ErrInvalidFile = errors.New("leveldb/storage: invalid file for argument") ErrLocked = errors.New("leveldb/storage: already locked") 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. Sync() error } // Reader is the interface that groups the basic Read, Seek, ReadAt and Close // methods. type Reader interface { io.ReadSeeker io.ReaderAt io.Closer } // Writer is the interface that groups the basic Write, Sync and Close // methods. type Writer interface { io.WriteCloser Syncer } type Lock interface { util.Releaser } // FileDesc is a file descriptor. type FileDesc struct { Type FileType Num int64 } 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) } } // Nil returns true if fd == (FileDesc{}). func (fd FileDesc) Nil() bool { return fd == (FileDesc{}) } // 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. 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() (Lock, error) // Log logs a string. This is used for logging. // An implementation may write to a file, stdout or simply do nothing. Log(str string) // 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 // 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) // List returns fds that match the given file types. // The file types may be OR'ed together. List(ft FileType) ([]FileDesc, 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) // 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) // Remove removes file with the given fd. // Returns ErrClosed if the underlying storage is closed. Remove(fd FileDesc) error // Rename renames file from oldfd to newfd. // Returns ErrClosed if the underlying storage is closed. Rename(oldfd, newfd FileDesc) 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 }