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 (e *ErrCorrupted) Error() string {
59	if !e.Fd.Zero() {
60		return fmt.Sprintf("%v [file=%v]", e.Err, e.Fd)
61	}
62	return e.Err.Error()
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// Locker is the interface that wraps Unlock method.
87type Locker interface {
88	Unlock()
89}
90
91// FileDesc is a 'file descriptor'.
92type FileDesc struct {
93	Type FileType
94	Num  int64
95}
96
97func (fd FileDesc) String() string {
98	switch fd.Type {
99	case TypeManifest:
100		return fmt.Sprintf("MANIFEST-%06d", fd.Num)
101	case TypeJournal:
102		return fmt.Sprintf("%06d.log", fd.Num)
103	case TypeTable:
104		return fmt.Sprintf("%06d.ldb", fd.Num)
105	case TypeTemp:
106		return fmt.Sprintf("%06d.tmp", fd.Num)
107	default:
108		return fmt.Sprintf("%#x-%d", fd.Type, fd.Num)
109	}
110}
111
112// Zero returns true if fd == (FileDesc{}).
113func (fd FileDesc) Zero() bool {
114	return fd == (FileDesc{})
115}
116
117// FileDescOk returns true if fd is a valid 'file descriptor'.
118func FileDescOk(fd FileDesc) bool {
119	switch fd.Type {
120	case TypeManifest:
121	case TypeJournal:
122	case TypeTable:
123	case TypeTemp:
124	default:
125		return false
126	}
127	return fd.Num >= 0
128}
129
130// Storage is the storage. A storage instance must be safe for concurrent use.
131type Storage interface {
132	// Lock locks the storage. Any subsequent attempt to call Lock will fail
133	// until the last lock released.
134	// Caller should call Unlock method after use.
135	Lock() (Locker, error)
136
137	// Log logs a string. This is used for logging.
138	// An implementation may write to a file, stdout or simply do nothing.
139	Log(str string)
140
141	// SetMeta store 'file descriptor' that can later be acquired using GetMeta
142	// method. The 'file descriptor' should point to a valid file.
143	// SetMeta should be implemented in such way that changes should happen
144	// atomically.
145	SetMeta(fd FileDesc) error
146
147	// GetMeta returns 'file descriptor' stored in meta. The 'file descriptor'
148	// can be updated using SetMeta method.
149	// Returns os.ErrNotExist if meta doesn't store any 'file descriptor', or
150	// 'file descriptor' point to nonexistent file.
151	GetMeta() (FileDesc, error)
152
153	// List returns file descriptors that match the given file types.
154	// The file types may be OR'ed together.
155	List(ft FileType) ([]FileDesc, error)
156
157	// Open opens file with the given 'file descriptor' read-only.
158	// Returns os.ErrNotExist error if the file does not exist.
159	// Returns ErrClosed if the underlying storage is closed.
160	Open(fd FileDesc) (Reader, error)
161
162	// Create creates file with the given 'file descriptor', truncate if already
163	// exist and opens write-only.
164	// Returns ErrClosed if the underlying storage is closed.
165	Create(fd FileDesc) (Writer, error)
166
167	// Remove removes file with the given 'file descriptor'.
168	// Returns ErrClosed if the underlying storage is closed.
169	Remove(fd FileDesc) error
170
171	// Rename renames file from oldfd to newfd.
172	// Returns ErrClosed if the underlying storage is closed.
173	Rename(oldfd, newfd FileDesc) error
174
175	// Close closes the storage.
176	// It is valid to call Close multiple times. Other methods should not be
177	// called after the storage has been closed.
178	Close() error
179}
180