187 lines
4.7 KiB
Go
187 lines
4.7 KiB
Go
// 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 provides storage abstraction for LevelDB.
|
|
package storage
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
)
|
|
|
|
// FileType represent a file type.
|
|
type FileType int
|
|
|
|
// File types.
|
|
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("<unknown:%d>", t)
|
|
}
|
|
|
|
// Common error.
|
|
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 isCorrupted(err error) bool {
|
|
switch err.(type) {
|
|
case *ErrCorrupted:
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (e *ErrCorrupted) Error() string {
|
|
if !e.Fd.Zero() {
|
|
return fmt.Sprintf("%v [file=%v]", e.Err, e.Fd)
|
|
}
|
|
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
|
|
}
|
|
|
|
// Locker is the interface that wraps Unlock method.
|
|
type Locker interface {
|
|
Unlock()
|
|
}
|
|
|
|
// 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)
|
|
}
|
|
}
|
|
|
|
// Zero returns true if fd == (FileDesc{}).
|
|
func (fd FileDesc) Zero() 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 safe for concurrent use.
|
|
type Storage interface {
|
|
// Lock locks the storage. Any subsequent attempt to call Lock will fail
|
|
// until the last lock released.
|
|
// Caller should call Unlock method after use.
|
|
Lock() (Locker, 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 store 'file descriptor' that can later be acquired using GetMeta
|
|
// method. The 'file descriptor' should point to a valid file.
|
|
// SetMeta should be implemented in such way that changes should happen
|
|
// atomically.
|
|
SetMeta(fd FileDesc) error
|
|
|
|
// GetMeta returns 'file descriptor' stored in meta. The 'file descriptor'
|
|
// can be updated using SetMeta method.
|
|
// Returns os.ErrNotExist if meta doesn't store any 'file descriptor', or
|
|
// 'file descriptor' point to nonexistent file.
|
|
GetMeta() (FileDesc, error)
|
|
|
|
// List returns file descriptors 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 'file descriptor' 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 'file descriptor', 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 'file descriptor'.
|
|
// 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
|
|
}
|