2014-07-06 14:46:48 +02:00
|
|
|
// 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"
|
|
|
|
|
|
|
|
"github.com/syndtr/goleveldb/leveldb/util"
|
|
|
|
)
|
|
|
|
|
|
|
|
type FileType uint32
|
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
|
|
|
var (
|
|
|
|
ErrInvalidFile = errors.New("leveldb/storage: invalid file for argument")
|
|
|
|
ErrLocked = errors.New("leveldb/storage: already locked")
|
|
|
|
ErrClosed = errors.New("leveldb/storage: closed")
|
|
|
|
)
|
|
|
|
|
2015-08-18 08:56:07 +02:00
|
|
|
// 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 {
|
|
|
|
File *FileInfo
|
|
|
|
Err error
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *ErrCorrupted) Error() string {
|
|
|
|
if e.File != nil {
|
|
|
|
return fmt.Sprintf("%v [file=%v]", e.Err, e.File)
|
|
|
|
} else {
|
|
|
|
return e.Err.Error()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-06 14:46:48 +02:00
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2014-07-23 08:31:36 +02:00
|
|
|
// File is the file. A file instance must be goroutine-safe.
|
2014-07-06 14:46:48 +02:00
|
|
|
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)
|
|
|
|
|
|
|
|
// Replace replaces file with newfile.
|
|
|
|
// Returns ErrClosed if the underlying storage is closed.
|
|
|
|
Replace(newfile File) error
|
|
|
|
|
|
|
|
// Type returns the file type
|
|
|
|
Type() FileType
|
|
|
|
|
|
|
|
// Num returns the file number.
|
|
|
|
Num() uint64
|
|
|
|
|
|
|
|
// Remove removes the file.
|
|
|
|
// Returns ErrClosed if the underlying storage is closed.
|
|
|
|
Remove() error
|
|
|
|
}
|
|
|
|
|
2014-07-23 08:31:36 +02:00
|
|
|
// Storage is the storage. A storage instance must be goroutine-safe.
|
2014-07-06 14:46:48 +02:00
|
|
|
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)
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
|
|
|
// 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 manifest
|
|
|
|
// file does not exist.
|
|
|
|
GetManifest() (File, 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
|
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|
2014-11-18 13:24:42 +01:00
|
|
|
|
|
|
|
// FileInfo wraps basic file info.
|
|
|
|
type FileInfo struct {
|
|
|
|
Type FileType
|
|
|
|
Num uint64
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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()}
|
|
|
|
}
|