1// Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com> 2// All rights reserved. 3// 4// Use of this source code is governed by a BSD-style license that can be 5// found in the LICENSE file. 6 7// Package storage provides storage abstraction for LevelDB. 8package storage 9 10import ( 11 "errors" 12 "fmt" 13 "io" 14 15 "github.com/syndtr/goleveldb/leveldb/util" 16) 17 18type FileType uint32 19 20const ( 21 TypeManifest FileType = 1 << iota 22 TypeJournal 23 TypeTable 24 TypeTemp 25 26 TypeAll = TypeManifest | TypeJournal | TypeTable | TypeTemp 27) 28 29func (t FileType) String() string { 30 switch t { 31 case TypeManifest: 32 return "manifest" 33 case TypeJournal: 34 return "journal" 35 case TypeTable: 36 return "table" 37 case TypeTemp: 38 return "temp" 39 } 40 return fmt.Sprintf("<unknown:%d>", t) 41} 42 43var ( 44 ErrInvalidFile = errors.New("leveldb/storage: invalid file for argument") 45 ErrLocked = errors.New("leveldb/storage: already locked") 46 ErrClosed = errors.New("leveldb/storage: closed") 47) 48 49// ErrCorrupted is the type that wraps errors that indicate corruption of 50// a file. Package storage has its own type instead of using 51// errors.ErrCorrupted to prevent circular import. 52type ErrCorrupted struct { 53 File *FileInfo 54 Err error 55} 56 57func (e *ErrCorrupted) Error() string { 58 if e.File != nil { 59 return fmt.Sprintf("%v [file=%v]", e.Err, e.File) 60 } else { 61 return e.Err.Error() 62 } 63} 64 65// Syncer is the interface that wraps basic Sync method. 66type Syncer interface { 67 // Sync commits the current contents of the file to stable storage. 68 Sync() error 69} 70 71// Reader is the interface that groups the basic Read, Seek, ReadAt and Close 72// methods. 73type Reader interface { 74 io.ReadSeeker 75 io.ReaderAt 76 io.Closer 77} 78 79// Writer is the interface that groups the basic Write, Sync and Close 80// methods. 81type Writer interface { 82 io.WriteCloser 83 Syncer 84} 85 86// File is the file. A file instance must be goroutine-safe. 87type File interface { 88 // Open opens the file for read. Returns os.ErrNotExist error 89 // if the file does not exist. 90 // Returns ErrClosed if the underlying storage is closed. 91 Open() (r Reader, err error) 92 93 // Create creates the file for writting. Truncate the file if 94 // already exist. 95 // Returns ErrClosed if the underlying storage is closed. 96 Create() (w Writer, err error) 97 98 // Replace replaces file with newfile. 99 // Returns ErrClosed if the underlying storage is closed. 100 Replace(newfile File) error 101 102 // Type returns the file type 103 Type() FileType 104 105 // Num returns the file number. 106 Num() uint64 107 108 // Remove removes the file. 109 // Returns ErrClosed if the underlying storage is closed. 110 Remove() error 111} 112 113// Storage is the storage. A storage instance must be goroutine-safe. 114type Storage interface { 115 // Lock locks the storage. Any subsequent attempt to call Lock will fail 116 // until the last lock released. 117 // After use the caller should call the Release method. 118 Lock() (l util.Releaser, err error) 119 120 // Log logs a string. This is used for logging. An implementation 121 // may write to a file, stdout or simply do nothing. 122 Log(str string) 123 124 // GetFile returns a file for the given number and type. GetFile will never 125 // returns nil, even if the underlying storage is closed. 126 GetFile(num uint64, t FileType) File 127 128 // GetFiles returns a slice of files that match the given file types. 129 // The file types may be OR'ed together. 130 GetFiles(t FileType) ([]File, error) 131 132 // GetManifest returns a manifest file. Returns os.ErrNotExist if manifest 133 // file does not exist. 134 GetManifest() (File, error) 135 136 // SetManifest sets the given file as manifest file. The given file should 137 // be a manifest file type or error will be returned. 138 SetManifest(f File) error 139 140 // Close closes the storage. It is valid to call Close multiple times. 141 // Other methods should not be called after the storage has been closed. 142 Close() error 143} 144 145// FileInfo wraps basic file info. 146type FileInfo struct { 147 Type FileType 148 Num uint64 149} 150 151func (fi FileInfo) String() string { 152 switch fi.Type { 153 case TypeManifest: 154 return fmt.Sprintf("MANIFEST-%06d", fi.Num) 155 case TypeJournal: 156 return fmt.Sprintf("%06d.log", fi.Num) 157 case TypeTable: 158 return fmt.Sprintf("%06d.ldb", fi.Num) 159 case TypeTemp: 160 return fmt.Sprintf("%06d.tmp", fi.Num) 161 default: 162 return fmt.Sprintf("%#x-%d", fi.Type, fi.Num) 163 } 164} 165 166// NewFileInfo creates new FileInfo from the given File. It will returns nil 167// if File is nil. 168func NewFileInfo(f File) *FileInfo { 169 if f == nil { 170 return nil 171 } 172 return &FileInfo{f.Type(), f.Num()} 173} 174