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