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
16// FileType represent a file type.
17type FileType int
18
19// File types.
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
43// Common error.
44var (
45	ErrInvalidFile = errors.New("leveldb/storage: invalid file for argument")
46	ErrLocked      = errors.New("leveldb/storage: already locked")
47	ErrClosed      = errors.New("leveldb/storage: closed")
48)
49
50// ErrCorrupted is the type that wraps errors that indicate corruption of
51// a file. Package storage has its own type instead of using
52// errors.ErrCorrupted to prevent circular import.
53type ErrCorrupted struct {
54	Fd  FileDesc
55	Err error
56}
57
58func isCorrupted(err error) bool {
59	switch err.(type) {
60	case *ErrCorrupted:
61		return true
62	}
63	return false
64}
65
66func (e *ErrCorrupted) Error() string {
67	if !e.Fd.Zero() {
68		return fmt.Sprintf("%v [file=%v]", e.Err, e.Fd)
69	}
70	return e.Err.Error()
71}
72
73// Syncer is the interface that wraps basic Sync method.
74type Syncer interface {
75	// Sync commits the current contents of the file to stable storage.
76	Sync() error
77}
78
79// Reader is the interface that groups the basic Read, Seek, ReadAt and Close
80// methods.
81type Reader interface {
82	io.ReadSeeker
83	io.ReaderAt
84	io.Closer
85}
86
87// Writer is the interface that groups the basic Write, Sync and Close
88// methods.
89type Writer interface {
90	io.WriteCloser
91	Syncer
92}
93
94// Locker is the interface that wraps Unlock method.
95type Locker interface {
96	Unlock()
97}
98
99// FileDesc is a 'file descriptor'.
100type FileDesc struct {
101	Type FileType
102	Num  int64
103}
104
105func (fd FileDesc) String() string {
106	switch fd.Type {
107	case TypeManifest:
108		return fmt.Sprintf("MANIFEST-%06d", fd.Num)
109	case TypeJournal:
110		return fmt.Sprintf("%06d.log", fd.Num)
111	case TypeTable:
112		return fmt.Sprintf("%06d.ldb", fd.Num)
113	case TypeTemp:
114		return fmt.Sprintf("%06d.tmp", fd.Num)
115	default:
116		return fmt.Sprintf("%#x-%d", fd.Type, fd.Num)
117	}
118}
119
120// Zero returns true if fd == (FileDesc{}).
121func (fd FileDesc) Zero() bool {
122	return fd == (FileDesc{})
123}
124
125// FileDescOk returns true if fd is a valid 'file descriptor'.
126func FileDescOk(fd FileDesc) bool {
127	switch fd.Type {
128	case TypeManifest:
129	case TypeJournal:
130	case TypeTable:
131	case TypeTemp:
132	default:
133		return false
134	}
135	return fd.Num >= 0
136}
137
138// Storage is the storage. A storage instance must be safe for concurrent use.
139type Storage interface {
140	// Lock locks the storage. Any subsequent attempt to call Lock will fail
141	// until the last lock released.
142	// Caller should call Unlock method after use.
143	Lock() (Locker, error)
144
145	// Log logs a string. This is used for logging.
146	// An implementation may write to a file, stdout or simply do nothing.
147	Log(str string)
148
149	// SetMeta store 'file descriptor' that can later be acquired using GetMeta
150	// method. The 'file descriptor' should point to a valid file.
151	// SetMeta should be implemented in such way that changes should happen
152	// atomically.
153	SetMeta(fd FileDesc) error
154
155	// GetMeta returns 'file descriptor' stored in meta. The 'file descriptor'
156	// can be updated using SetMeta method.
157	// Returns os.ErrNotExist if meta doesn't store any 'file descriptor', or
158	// 'file descriptor' point to nonexistent file.
159	GetMeta() (FileDesc, error)
160
161	// List returns file descriptors that match the given file types.
162	// The file types may be OR'ed together.
163	List(ft FileType) ([]FileDesc, error)
164
165	// Open opens file with the given 'file descriptor' read-only.
166	// Returns os.ErrNotExist error if the file does not exist.
167	// Returns ErrClosed if the underlying storage is closed.
168	Open(fd FileDesc) (Reader, error)
169
170	// Create creates file with the given 'file descriptor', truncate if already
171	// exist and opens write-only.
172	// Returns ErrClosed if the underlying storage is closed.
173	Create(fd FileDesc) (Writer, error)
174
175	// Remove removes file with the given 'file descriptor'.
176	// Returns ErrClosed if the underlying storage is closed.
177	Remove(fd FileDesc) error
178
179	// Rename renames file from oldfd to newfd.
180	// Returns ErrClosed if the underlying storage is closed.
181	Rename(oldfd, newfd FileDesc) error
182
183	// Close closes the storage.
184	// It is valid to call Close multiple times. Other methods should not be
185	// called after the storage has been closed.
186	Close() error
187}
188