]>
Commit | Line | Data |
---|---|---|
f67539c2 TL |
1 | // Copyright (c) 2019-present, Facebook, Inc. All rights reserved. |
2 | // This source code is licensed under both the GPLv2 (found in the | |
3 | // COPYING file in the root directory) and Apache 2.0 License | |
4 | // (found in the LICENSE.Apache file in the root directory). | |
5 | // | |
6 | // A FileSystem is an interface used by the rocksdb implementation to access | |
7 | // storage functionality like the filesystem etc. Callers | |
8 | // may wish to provide a custom FileSystem object when opening a database to | |
9 | // get fine gain control; e.g., to rate limit file system operations. | |
10 | // | |
11 | // All FileSystem implementations are safe for concurrent access from | |
12 | // multiple threads without any external synchronization. | |
13 | // | |
14 | // WARNING: Since this is a new interface, it is expected that there will be | |
15 | // some changes as storage systems are ported over. | |
16 | ||
17 | #pragma once | |
18 | ||
19 | #include <stdint.h> | |
1e59de90 | 20 | |
f67539c2 TL |
21 | #include <chrono> |
22 | #include <cstdarg> | |
23 | #include <functional> | |
24 | #include <limits> | |
25 | #include <memory> | |
26 | #include <sstream> | |
27 | #include <string> | |
1e59de90 | 28 | #include <unordered_map> |
f67539c2 | 29 | #include <vector> |
1e59de90 TL |
30 | |
31 | #include "rocksdb/customizable.h" | |
f67539c2 TL |
32 | #include "rocksdb/env.h" |
33 | #include "rocksdb/io_status.h" | |
34 | #include "rocksdb/options.h" | |
1e59de90 | 35 | #include "rocksdb/table.h" |
f67539c2 TL |
36 | #include "rocksdb/thread_status.h" |
37 | ||
38 | namespace ROCKSDB_NAMESPACE { | |
39 | ||
40 | class FileLock; | |
41 | class FSDirectory; | |
42 | class FSRandomAccessFile; | |
43 | class FSRandomRWFile; | |
44 | class FSSequentialFile; | |
45 | class FSWritableFile; | |
46 | class Logger; | |
47 | class Slice; | |
48 | struct ImmutableDBOptions; | |
49 | struct MutableDBOptions; | |
50 | class RateLimiter; | |
1e59de90 | 51 | struct ConfigOptions; |
f67539c2 TL |
52 | |
53 | using AccessPattern = RandomAccessFile::AccessPattern; | |
54 | using FileAttributes = Env::FileAttributes; | |
55 | ||
1e59de90 | 56 | // DEPRECATED |
f67539c2 TL |
57 | // Priority of an IO request. This is a hint and does not guarantee any |
58 | // particular QoS. | |
59 | // IO_LOW - Typically background reads/writes such as compaction/flush | |
60 | // IO_HIGH - Typically user reads/synchronous WAL writes | |
61 | enum class IOPriority : uint8_t { | |
62 | kIOLow, | |
63 | kIOHigh, | |
64 | kIOTotal, | |
65 | }; | |
66 | ||
67 | // Type of the data begin read/written. It can be passed down as a flag | |
68 | // for the FileSystem implementation to optionally handle different types in | |
69 | // different ways | |
70 | enum class IOType : uint8_t { | |
71 | kData, | |
72 | kFilter, | |
73 | kIndex, | |
74 | kMetadata, | |
75 | kWAL, | |
76 | kManifest, | |
77 | kLog, | |
78 | kUnknown, | |
79 | kInvalid, | |
80 | }; | |
81 | ||
82 | // Per-request options that can be passed down to the FileSystem | |
83 | // implementation. These are hints and are not necessarily guaranteed to be | |
84 | // honored. More hints can be added here in the future to indicate things like | |
85 | // storage media (HDD/SSD) to be used, replication level etc. | |
86 | struct IOOptions { | |
20effc67 TL |
87 | // Timeout for the operation in microseconds |
88 | std::chrono::microseconds timeout; | |
f67539c2 | 89 | |
1e59de90 | 90 | // DEPRECATED |
f67539c2 TL |
91 | // Priority - high or low |
92 | IOPriority prio; | |
93 | ||
1e59de90 TL |
94 | // Priority used to charge rate limiter configured in file system level (if |
95 | // any) | |
96 | // Limitation: right now RocksDB internal does not consider this | |
97 | // rate_limiter_priority | |
98 | Env::IOPriority rate_limiter_priority; | |
99 | ||
f67539c2 TL |
100 | // Type of data being read/written |
101 | IOType type; | |
20effc67 | 102 | |
1e59de90 TL |
103 | // EXPERIMENTAL |
104 | // An option map that's opaque to RocksDB. It can be used to implement a | |
105 | // custom contract between a FileSystem user and the provider. This is only | |
106 | // useful in cases where a RocksDB user directly uses the FileSystem or file | |
107 | // object for their own purposes, and wants to pass extra options to APIs | |
108 | // such as NewRandomAccessFile and NewWritableFile. | |
109 | std::unordered_map<std::string, std::string> property_bag; | |
110 | ||
111 | // Force directory fsync, some file systems like btrfs may skip directory | |
112 | // fsync, set this to force the fsync | |
113 | bool force_dir_fsync; | |
114 | ||
115 | // Can be used by underlying file systems to skip recursing through sub | |
116 | // directories and list only files in GetChildren API. | |
117 | bool do_not_recurse; | |
118 | ||
119 | IOOptions() : IOOptions(false) {} | |
120 | ||
121 | explicit IOOptions(bool force_dir_fsync_) | |
122 | : timeout(std::chrono::microseconds::zero()), | |
123 | prio(IOPriority::kIOLow), | |
124 | rate_limiter_priority(Env::IO_TOTAL), | |
125 | type(IOType::kUnknown), | |
126 | force_dir_fsync(force_dir_fsync_), | |
127 | do_not_recurse(false) {} | |
128 | }; | |
129 | ||
130 | struct DirFsyncOptions { | |
131 | enum FsyncReason : uint8_t { | |
132 | kNewFileSynced, | |
133 | kFileRenamed, | |
134 | kDirRenamed, | |
135 | kFileDeleted, | |
136 | kDefault, | |
137 | } reason; | |
138 | ||
139 | std::string renamed_new_name; // for kFileRenamed | |
140 | // add other options for other FsyncReason | |
141 | ||
142 | DirFsyncOptions(); | |
143 | ||
144 | explicit DirFsyncOptions(std::string file_renamed_new_name); | |
145 | ||
146 | explicit DirFsyncOptions(FsyncReason fsync_reason); | |
f67539c2 TL |
147 | }; |
148 | ||
149 | // File scope options that control how a file is opened/created and accessed | |
150 | // while its open. We may add more options here in the future such as | |
151 | // redundancy level, media to use etc. | |
152 | struct FileOptions : EnvOptions { | |
153 | // Embedded IOOptions to control the parameters for any IOs that need | |
154 | // to be issued for the file open/creation | |
155 | IOOptions io_options; | |
156 | ||
1e59de90 TL |
157 | // EXPERIMENTAL |
158 | // The feature is in development and is subject to change. | |
159 | // When creating a new file, set the temperature of the file so that | |
160 | // underlying file systems can put it with appropriate storage media and/or | |
161 | // coding. | |
162 | Temperature temperature = Temperature::kUnknown; | |
163 | ||
164 | // The checksum type that is used to calculate the checksum value for | |
165 | // handoff during file writes. | |
166 | ChecksumType handoff_checksum_type; | |
167 | ||
168 | FileOptions() : EnvOptions(), handoff_checksum_type(ChecksumType::kCRC32c) {} | |
f67539c2 TL |
169 | |
170 | FileOptions(const DBOptions& opts) | |
1e59de90 | 171 | : EnvOptions(opts), handoff_checksum_type(ChecksumType::kCRC32c) {} |
f67539c2 TL |
172 | |
173 | FileOptions(const EnvOptions& opts) | |
1e59de90 | 174 | : EnvOptions(opts), handoff_checksum_type(ChecksumType::kCRC32c) {} |
20effc67 TL |
175 | |
176 | FileOptions(const FileOptions& opts) | |
1e59de90 TL |
177 | : EnvOptions(opts), |
178 | io_options(opts.io_options), | |
179 | temperature(opts.temperature), | |
180 | handoff_checksum_type(opts.handoff_checksum_type) {} | |
20effc67 | 181 | |
1e59de90 | 182 | FileOptions& operator=(const FileOptions&) = default; |
f67539c2 TL |
183 | }; |
184 | ||
185 | // A structure to pass back some debugging information from the FileSystem | |
186 | // implementation to RocksDB in case of an IO error | |
187 | struct IODebugContext { | |
188 | // file_path to be filled in by RocksDB in case of an error | |
189 | std::string file_path; | |
190 | ||
191 | // A map of counter names to values - set by the FileSystem implementation | |
192 | std::map<std::string, uint64_t> counters; | |
193 | ||
194 | // To be set by the FileSystem implementation | |
195 | std::string msg; | |
196 | ||
1e59de90 TL |
197 | // To be set by the underlying FileSystem implementation. |
198 | std::string request_id; | |
199 | ||
200 | // In order to log required information in IO tracing for different | |
201 | // operations, Each bit in trace_data stores which corresponding info from | |
202 | // IODebugContext will be added in the trace. Foreg, if trace_data = 1, it | |
203 | // means bit at position 0 is set so TraceData::kRequestID (request_id) will | |
204 | // be logged in the trace record. | |
205 | // | |
206 | enum TraceData : char { | |
207 | // The value of each enum represents the bitwise position for | |
208 | // that information in trace_data which will be used by IOTracer for | |
209 | // tracing. Make sure to add them sequentially. | |
210 | kRequestID = 0, | |
211 | }; | |
212 | uint64_t trace_data = 0; | |
213 | ||
f67539c2 TL |
214 | IODebugContext() {} |
215 | ||
216 | void AddCounter(std::string& name, uint64_t value) { | |
217 | counters.emplace(name, value); | |
218 | } | |
219 | ||
1e59de90 TL |
220 | // Called by underlying file system to set request_id and log request_id in |
221 | // IOTracing. | |
222 | void SetRequestId(const std::string& _request_id) { | |
223 | request_id = _request_id; | |
224 | trace_data |= (1 << TraceData::kRequestID); | |
225 | } | |
226 | ||
f67539c2 TL |
227 | std::string ToString() { |
228 | std::ostringstream ss; | |
229 | ss << file_path << ", "; | |
230 | for (auto counter : counters) { | |
231 | ss << counter.first << " = " << counter.second << ","; | |
232 | } | |
233 | ss << msg; | |
234 | return ss.str(); | |
235 | } | |
236 | }; | |
237 | ||
1e59de90 TL |
238 | // A function pointer type for custom destruction of void pointer passed to |
239 | // ReadAsync API. RocksDB/caller is responsible for deleting the void pointer | |
240 | // allocated by FS in ReadAsync API. | |
241 | using IOHandleDeleter = std::function<void(void*)>; | |
242 | ||
f67539c2 TL |
243 | // The FileSystem, FSSequentialFile, FSRandomAccessFile, FSWritableFile, |
244 | // FSRandomRWFileclass, and FSDIrectory classes define the interface between | |
245 | // RocksDB and storage systems, such as Posix filesystems, | |
246 | // remote filesystems etc. | |
247 | // The interface allows for fine grained control of individual IO operations, | |
248 | // such as setting a timeout, prioritization, hints on data placement, | |
249 | // different handling based on type of IO etc. | |
250 | // This is accomplished by passing an instance of IOOptions to every | |
251 | // API call that can potentially perform IO. Additionally, each such API is | |
252 | // passed a pointer to a IODebugContext structure that can be used by the | |
253 | // storage system to include troubleshooting information. The return values | |
254 | // of the APIs is of type IOStatus, which can indicate an error code/sub-code, | |
255 | // as well as metadata about the error such as its scope and whether its | |
256 | // retryable. | |
1e59de90 TL |
257 | // NewCompositeEnv can be used to create an Env with a custom FileSystem for |
258 | // DBOptions::env. | |
259 | // | |
260 | // Exceptions MUST NOT propagate out of overridden functions into RocksDB, | |
261 | // because RocksDB is not exception-safe. This could cause undefined behavior | |
262 | // including data loss, unreported corruption, deadlocks, and more. | |
263 | class FileSystem : public Customizable { | |
f67539c2 TL |
264 | public: |
265 | FileSystem(); | |
266 | ||
267 | // No copying allowed | |
268 | FileSystem(const FileSystem&) = delete; | |
269 | ||
270 | virtual ~FileSystem(); | |
271 | ||
f67539c2 | 272 | static const char* Type() { return "FileSystem"; } |
1e59de90 | 273 | static const char* kDefaultName() { return "DefaultFileSystem"; } |
f67539c2 TL |
274 | |
275 | // Loads the FileSystem specified by the input value into the result | |
1e59de90 TL |
276 | // The CreateFromString alternative should be used; this method may be |
277 | // deprecated in a future release. | |
f67539c2 TL |
278 | static Status Load(const std::string& value, |
279 | std::shared_ptr<FileSystem>* result); | |
280 | ||
1e59de90 TL |
281 | // Loads the FileSystem specified by the input value into the result |
282 | // @see Customizable for a more detailed description of the parameters and | |
283 | // return codes | |
284 | // @param config_options Controls how the FileSystem is loaded | |
285 | // @param value The name and optional properties describing the file system | |
286 | // to load. | |
287 | // @param result On success, returns the loaded FileSystem | |
288 | // @return OK if the FileSystem was successfully loaded. | |
289 | // @return not-OK if the load failed. | |
290 | static Status CreateFromString(const ConfigOptions& options, | |
291 | const std::string& value, | |
292 | std::shared_ptr<FileSystem>* result); | |
293 | ||
294 | // Return a default FileSystem suitable for the current operating | |
295 | // system. | |
f67539c2 TL |
296 | static std::shared_ptr<FileSystem> Default(); |
297 | ||
20effc67 TL |
298 | // Handles the event when a new DB or a new ColumnFamily starts using the |
299 | // specified data paths. | |
300 | // | |
301 | // The data paths might be shared by different DBs or ColumnFamilies, | |
302 | // so RegisterDbPaths might be called with the same data paths. | |
303 | // For example, when CreateColumnFamily is called multiple times with the same | |
304 | // data path, RegisterDbPaths will also be called with the same data path. | |
305 | // | |
306 | // If the return status is ok, then the paths must be correspondingly | |
307 | // called in UnregisterDbPaths; | |
308 | // otherwise this method should have no side effect, and UnregisterDbPaths | |
309 | // do not need to be called for the paths. | |
310 | // | |
311 | // Different implementations may take different actions. | |
312 | // By default, it's a no-op and returns Status::OK. | |
313 | virtual Status RegisterDbPaths(const std::vector<std::string>& /*paths*/) { | |
314 | return Status::OK(); | |
315 | } | |
316 | // Handles the event a DB or a ColumnFamily stops using the specified data | |
317 | // paths. | |
318 | // | |
319 | // It should be called corresponding to each successful RegisterDbPaths. | |
320 | // | |
321 | // Different implementations may take different actions. | |
322 | // By default, it's a no-op and returns Status::OK. | |
323 | virtual Status UnregisterDbPaths(const std::vector<std::string>& /*paths*/) { | |
324 | return Status::OK(); | |
325 | } | |
326 | ||
f67539c2 TL |
327 | // Create a brand new sequentially-readable file with the specified name. |
328 | // On success, stores a pointer to the new file in *result and returns OK. | |
329 | // On failure stores nullptr in *result and returns non-OK. If the file does | |
330 | // not exist, returns a non-OK status. | |
331 | // | |
332 | // The returned file will only be accessed by one thread at a time. | |
333 | virtual IOStatus NewSequentialFile(const std::string& fname, | |
334 | const FileOptions& file_opts, | |
335 | std::unique_ptr<FSSequentialFile>* result, | |
336 | IODebugContext* dbg) = 0; | |
337 | ||
338 | // Create a brand new random access read-only file with the | |
339 | // specified name. On success, stores a pointer to the new file in | |
340 | // *result and returns OK. On failure stores nullptr in *result and | |
341 | // returns non-OK. If the file does not exist, returns a non-OK | |
342 | // status. | |
343 | // | |
344 | // The returned file may be concurrently accessed by multiple threads. | |
345 | virtual IOStatus NewRandomAccessFile( | |
346 | const std::string& fname, const FileOptions& file_opts, | |
1e59de90 | 347 | std::unique_ptr<FSRandomAccessFile>* result, IODebugContext* dbg) = 0; |
f67539c2 TL |
348 | // These values match Linux definition |
349 | // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/fcntl.h#n56 | |
350 | enum WriteLifeTimeHint { | |
351 | kWLTHNotSet = 0, // No hint information set | |
352 | kWLTHNone, // No hints about write life time | |
353 | kWLTHShort, // Data written has a short life time | |
354 | kWLTHMedium, // Data written has a medium life time | |
355 | kWLTHLong, // Data written has a long life time | |
356 | kWLTHExtreme, // Data written has an extremely long life time | |
357 | }; | |
358 | ||
359 | // Create an object that writes to a new file with the specified | |
360 | // name. Deletes any existing file with the same name and creates a | |
361 | // new file. On success, stores a pointer to the new file in | |
362 | // *result and returns OK. On failure stores nullptr in *result and | |
363 | // returns non-OK. | |
364 | // | |
365 | // The returned file will only be accessed by one thread at a time. | |
366 | virtual IOStatus NewWritableFile(const std::string& fname, | |
367 | const FileOptions& file_opts, | |
368 | std::unique_ptr<FSWritableFile>* result, | |
369 | IODebugContext* dbg) = 0; | |
370 | ||
1e59de90 TL |
371 | // Create an object that writes to a file with the specified name. |
372 | // `FSWritableFile::Append()`s will append after any existing content. If the | |
373 | // file does not already exist, creates it. | |
374 | // | |
375 | // On success, stores a pointer to the file in *result and returns OK. On | |
376 | // failure stores nullptr in *result and returns non-OK. | |
f67539c2 TL |
377 | // |
378 | // The returned file will only be accessed by one thread at a time. | |
379 | virtual IOStatus ReopenWritableFile( | |
380 | const std::string& /*fname*/, const FileOptions& /*options*/, | |
381 | std::unique_ptr<FSWritableFile>* /*result*/, IODebugContext* /*dbg*/) { | |
20effc67 | 382 | return IOStatus::NotSupported("ReopenWritableFile"); |
f67539c2 TL |
383 | } |
384 | ||
385 | // Reuse an existing file by renaming it and opening it as writable. | |
386 | virtual IOStatus ReuseWritableFile(const std::string& fname, | |
387 | const std::string& old_fname, | |
388 | const FileOptions& file_opts, | |
389 | std::unique_ptr<FSWritableFile>* result, | |
20effc67 | 390 | IODebugContext* dbg); |
f67539c2 TL |
391 | |
392 | // Open `fname` for random read and write, if file doesn't exist the file | |
393 | // will be created. On success, stores a pointer to the new file in | |
394 | // *result and returns OK. On failure returns non-OK. | |
395 | // | |
396 | // The returned file will only be accessed by one thread at a time. | |
397 | virtual IOStatus NewRandomRWFile(const std::string& /*fname*/, | |
398 | const FileOptions& /*options*/, | |
399 | std::unique_ptr<FSRandomRWFile>* /*result*/, | |
400 | IODebugContext* /*dbg*/) { | |
401 | return IOStatus::NotSupported( | |
402 | "RandomRWFile is not implemented in this FileSystem"); | |
403 | } | |
404 | ||
405 | // Opens `fname` as a memory-mapped file for read and write (in-place updates | |
406 | // only, i.e., no appends). On success, stores a raw buffer covering the whole | |
407 | // file in `*result`. The file must exist prior to this call. | |
408 | virtual IOStatus NewMemoryMappedFileBuffer( | |
409 | const std::string& /*fname*/, | |
410 | std::unique_ptr<MemoryMappedFileBuffer>* /*result*/) { | |
411 | return IOStatus::NotSupported( | |
412 | "MemoryMappedFileBuffer is not implemented in this FileSystem"); | |
413 | } | |
414 | ||
415 | // Create an object that represents a directory. Will fail if directory | |
416 | // doesn't exist. If the directory exists, it will open the directory | |
417 | // and create a new Directory object. | |
418 | // | |
419 | // On success, stores a pointer to the new Directory in | |
420 | // *result and returns OK. On failure stores nullptr in *result and | |
421 | // returns non-OK. | |
422 | virtual IOStatus NewDirectory(const std::string& name, | |
423 | const IOOptions& io_opts, | |
424 | std::unique_ptr<FSDirectory>* result, | |
425 | IODebugContext* dbg) = 0; | |
426 | ||
427 | // Returns OK if the named file exists. | |
428 | // NotFound if the named file does not exist, | |
429 | // the calling process does not have permission to determine | |
430 | // whether this file exists, or if the path is invalid. | |
431 | // IOError if an IO Error was encountered | |
432 | virtual IOStatus FileExists(const std::string& fname, | |
433 | const IOOptions& options, | |
434 | IODebugContext* dbg) = 0; | |
435 | ||
436 | // Store in *result the names of the children of the specified directory. | |
437 | // The names are relative to "dir". | |
438 | // Original contents of *results are dropped. | |
439 | // Returns OK if "dir" exists and "*result" contains its children. | |
440 | // NotFound if "dir" does not exist, the calling process does not have | |
441 | // permission to access "dir", or if "dir" is invalid. | |
442 | // IOError if an IO Error was encountered | |
443 | virtual IOStatus GetChildren(const std::string& dir, const IOOptions& options, | |
444 | std::vector<std::string>* result, | |
445 | IODebugContext* dbg) = 0; | |
446 | ||
447 | // Store in *result the attributes of the children of the specified directory. | |
448 | // In case the implementation lists the directory prior to iterating the files | |
449 | // and files are concurrently deleted, the deleted files will be omitted from | |
450 | // result. | |
451 | // The name attributes are relative to "dir". | |
452 | // Original contents of *results are dropped. | |
453 | // Returns OK if "dir" exists and "*result" contains its children. | |
454 | // NotFound if "dir" does not exist, the calling process does not have | |
455 | // permission to access "dir", or if "dir" is invalid. | |
456 | // IOError if an IO Error was encountered | |
457 | virtual IOStatus GetChildrenFileAttributes( | |
458 | const std::string& dir, const IOOptions& options, | |
459 | std::vector<FileAttributes>* result, IODebugContext* dbg) { | |
460 | assert(result != nullptr); | |
461 | std::vector<std::string> child_fnames; | |
462 | IOStatus s = GetChildren(dir, options, &child_fnames, dbg); | |
463 | if (!s.ok()) { | |
464 | return s; | |
465 | } | |
466 | result->resize(child_fnames.size()); | |
467 | size_t result_size = 0; | |
468 | for (size_t i = 0; i < child_fnames.size(); ++i) { | |
469 | const std::string path = dir + "/" + child_fnames[i]; | |
470 | if (!(s = GetFileSize(path, options, &(*result)[result_size].size_bytes, | |
471 | dbg)) | |
472 | .ok()) { | |
473 | if (FileExists(path, options, dbg).IsNotFound()) { | |
474 | // The file may have been deleted since we listed the directory | |
475 | continue; | |
476 | } | |
477 | return s; | |
478 | } | |
479 | (*result)[result_size].name = std::move(child_fnames[i]); | |
480 | result_size++; | |
481 | } | |
482 | result->resize(result_size); | |
483 | return IOStatus::OK(); | |
484 | } | |
485 | ||
1e59de90 TL |
486 | // This seems to clash with a macro on Windows, so #undef it here |
487 | #ifdef DeleteFile | |
488 | #undef DeleteFile | |
489 | #endif | |
f67539c2 TL |
490 | // Delete the named file. |
491 | virtual IOStatus DeleteFile(const std::string& fname, | |
492 | const IOOptions& options, | |
493 | IODebugContext* dbg) = 0; | |
494 | ||
495 | // Truncate the named file to the specified size. | |
496 | virtual IOStatus Truncate(const std::string& /*fname*/, size_t /*size*/, | |
497 | const IOOptions& /*options*/, | |
498 | IODebugContext* /*dbg*/) { | |
1e59de90 TL |
499 | return IOStatus::NotSupported( |
500 | "Truncate is not supported for this FileSystem"); | |
f67539c2 TL |
501 | } |
502 | ||
503 | // Create the specified directory. Returns error if directory exists. | |
504 | virtual IOStatus CreateDir(const std::string& dirname, | |
505 | const IOOptions& options, IODebugContext* dbg) = 0; | |
506 | ||
507 | // Creates directory if missing. Return Ok if it exists, or successful in | |
508 | // Creating. | |
509 | virtual IOStatus CreateDirIfMissing(const std::string& dirname, | |
510 | const IOOptions& options, | |
511 | IODebugContext* dbg) = 0; | |
512 | ||
513 | // Delete the specified directory. | |
514 | virtual IOStatus DeleteDir(const std::string& dirname, | |
515 | const IOOptions& options, IODebugContext* dbg) = 0; | |
516 | ||
517 | // Store the size of fname in *file_size. | |
518 | virtual IOStatus GetFileSize(const std::string& fname, | |
519 | const IOOptions& options, uint64_t* file_size, | |
520 | IODebugContext* dbg) = 0; | |
521 | ||
522 | // Store the last modification time of fname in *file_mtime. | |
523 | virtual IOStatus GetFileModificationTime(const std::string& fname, | |
524 | const IOOptions& options, | |
525 | uint64_t* file_mtime, | |
526 | IODebugContext* dbg) = 0; | |
527 | // Rename file src to target. | |
528 | virtual IOStatus RenameFile(const std::string& src, const std::string& target, | |
529 | const IOOptions& options, | |
530 | IODebugContext* dbg) = 0; | |
531 | ||
532 | // Hard Link file src to target. | |
533 | virtual IOStatus LinkFile(const std::string& /*src*/, | |
534 | const std::string& /*target*/, | |
535 | const IOOptions& /*options*/, | |
536 | IODebugContext* /*dbg*/) { | |
1e59de90 TL |
537 | return IOStatus::NotSupported( |
538 | "LinkFile is not supported for this FileSystem"); | |
f67539c2 TL |
539 | } |
540 | ||
541 | virtual IOStatus NumFileLinks(const std::string& /*fname*/, | |
542 | const IOOptions& /*options*/, | |
543 | uint64_t* /*count*/, IODebugContext* /*dbg*/) { | |
544 | return IOStatus::NotSupported( | |
545 | "Getting number of file links is not supported for this FileSystem"); | |
546 | } | |
547 | ||
548 | virtual IOStatus AreFilesSame(const std::string& /*first*/, | |
549 | const std::string& /*second*/, | |
550 | const IOOptions& /*options*/, bool* /*res*/, | |
551 | IODebugContext* /*dbg*/) { | |
1e59de90 TL |
552 | return IOStatus::NotSupported( |
553 | "AreFilesSame is not supported for this FileSystem"); | |
f67539c2 TL |
554 | } |
555 | ||
556 | // Lock the specified file. Used to prevent concurrent access to | |
557 | // the same db by multiple processes. On failure, stores nullptr in | |
558 | // *lock and returns non-OK. | |
559 | // | |
560 | // On success, stores a pointer to the object that represents the | |
561 | // acquired lock in *lock and returns OK. The caller should call | |
562 | // UnlockFile(*lock) to release the lock. If the process exits, | |
563 | // the lock will be automatically released. | |
564 | // | |
565 | // If somebody else already holds the lock, finishes immediately | |
566 | // with a failure. I.e., this call does not wait for existing locks | |
567 | // to go away. | |
568 | // | |
569 | // May create the named file if it does not already exist. | |
570 | virtual IOStatus LockFile(const std::string& fname, const IOOptions& options, | |
571 | FileLock** lock, IODebugContext* dbg) = 0; | |
572 | ||
573 | // Release the lock acquired by a previous successful call to LockFile. | |
574 | // REQUIRES: lock was returned by a successful LockFile() call | |
575 | // REQUIRES: lock has not already been unlocked. | |
576 | virtual IOStatus UnlockFile(FileLock* lock, const IOOptions& options, | |
577 | IODebugContext* dbg) = 0; | |
578 | ||
579 | // *path is set to a temporary directory that can be used for testing. It may | |
580 | // or many not have just been created. The directory may or may not differ | |
581 | // between runs of the same process, but subsequent calls will return the | |
582 | // same directory. | |
583 | virtual IOStatus GetTestDirectory(const IOOptions& options, std::string* path, | |
584 | IODebugContext* dbg) = 0; | |
585 | ||
586 | // Create and returns a default logger (an instance of EnvLogger) for storing | |
1e59de90 | 587 | // informational messages. Derived classes can override to provide custom |
f67539c2 TL |
588 | // logger. |
589 | virtual IOStatus NewLogger(const std::string& fname, const IOOptions& io_opts, | |
590 | std::shared_ptr<Logger>* result, | |
1e59de90 | 591 | IODebugContext* dbg); |
f67539c2 TL |
592 | |
593 | // Get full directory name for this db. | |
594 | virtual IOStatus GetAbsolutePath(const std::string& db_path, | |
595 | const IOOptions& options, | |
596 | std::string* output_path, | |
597 | IODebugContext* dbg) = 0; | |
598 | ||
20effc67 TL |
599 | // Sanitize the FileOptions. Typically called by a FileOptions/EnvOptions |
600 | // copy constructor | |
601 | virtual void SanitizeFileOptions(FileOptions* /*opts*/) const {} | |
602 | ||
f67539c2 TL |
603 | // OptimizeForLogRead will create a new FileOptions object that is a copy of |
604 | // the FileOptions in the parameters, but is optimized for reading log files. | |
605 | virtual FileOptions OptimizeForLogRead(const FileOptions& file_options) const; | |
606 | ||
607 | // OptimizeForManifestRead will create a new FileOptions object that is a copy | |
608 | // of the FileOptions in the parameters, but is optimized for reading manifest | |
609 | // files. | |
610 | virtual FileOptions OptimizeForManifestRead( | |
611 | const FileOptions& file_options) const; | |
612 | ||
613 | // OptimizeForLogWrite will create a new FileOptions object that is a copy of | |
614 | // the FileOptions in the parameters, but is optimized for writing log files. | |
615 | // Default implementation returns the copy of the same object. | |
616 | virtual FileOptions OptimizeForLogWrite(const FileOptions& file_options, | |
1e59de90 | 617 | const DBOptions& db_options) const; |
f67539c2 TL |
618 | |
619 | // OptimizeForManifestWrite will create a new FileOptions object that is a | |
620 | // copy of the FileOptions in the parameters, but is optimized for writing | |
621 | // manifest files. Default implementation returns the copy of the same | |
622 | // object. | |
623 | virtual FileOptions OptimizeForManifestWrite( | |
624 | const FileOptions& file_options) const; | |
625 | ||
626 | // OptimizeForCompactionTableWrite will create a new FileOptions object that | |
627 | // is a copy of the FileOptions in the parameters, but is optimized for | |
628 | // writing table files. | |
629 | virtual FileOptions OptimizeForCompactionTableWrite( | |
630 | const FileOptions& file_options, | |
631 | const ImmutableDBOptions& immutable_ops) const; | |
632 | ||
633 | // OptimizeForCompactionTableRead will create a new FileOptions object that | |
634 | // is a copy of the FileOptions in the parameters, but is optimized for | |
635 | // reading table files. | |
636 | virtual FileOptions OptimizeForCompactionTableRead( | |
637 | const FileOptions& file_options, | |
638 | const ImmutableDBOptions& db_options) const; | |
639 | ||
1e59de90 TL |
640 | // OptimizeForBlobFileRead will create a new FileOptions object that |
641 | // is a copy of the FileOptions in the parameters, but is optimized for | |
642 | // reading blob files. | |
643 | virtual FileOptions OptimizeForBlobFileRead( | |
644 | const FileOptions& file_options, | |
645 | const ImmutableDBOptions& db_options) const; | |
646 | ||
f67539c2 TL |
647 | // This seems to clash with a macro on Windows, so #undef it here |
648 | #ifdef GetFreeSpace | |
649 | #undef GetFreeSpace | |
650 | #endif | |
651 | ||
652 | // Get the amount of free disk space | |
653 | virtual IOStatus GetFreeSpace(const std::string& /*path*/, | |
654 | const IOOptions& /*options*/, | |
655 | uint64_t* /*diskfree*/, | |
656 | IODebugContext* /*dbg*/) { | |
20effc67 | 657 | return IOStatus::NotSupported("GetFreeSpace"); |
f67539c2 TL |
658 | } |
659 | ||
20effc67 TL |
660 | virtual IOStatus IsDirectory(const std::string& /*path*/, |
661 | const IOOptions& options, bool* is_dir, | |
662 | IODebugContext* /*dgb*/) = 0; | |
663 | ||
1e59de90 TL |
664 | // EXPERIMENTAL |
665 | // Poll for completion of read IO requests. The Poll() method should call the | |
666 | // callback functions to indicate completion of read requests. | |
667 | // Underlying FS is required to support Poll API. Poll implementation should | |
668 | // ensure that the callback gets called at IO completion, and return only | |
669 | // after the callback has been called. | |
670 | // If Poll returns partial results for any reads, its caller reponsibility to | |
671 | // call Read or ReadAsync in order to get the remaining bytes. | |
672 | // | |
673 | // Default implementation is to return IOStatus::OK. | |
674 | ||
675 | virtual IOStatus Poll(std::vector<void*>& /*io_handles*/, | |
676 | size_t /*min_completions*/) { | |
677 | return IOStatus::OK(); | |
678 | } | |
679 | ||
680 | // EXPERIMENTAL | |
681 | // Abort the read IO requests submitted asynchronously. Underlying FS is | |
682 | // required to support AbortIO API. AbortIO implementation should ensure that | |
683 | // the all the read requests related to io_handles should be aborted and | |
684 | // it shouldn't call the callback for these io_handles. | |
685 | // | |
686 | // Default implementation is to return IOStatus::OK. | |
687 | virtual IOStatus AbortIO(std::vector<void*>& /*io_handles*/) { | |
688 | return IOStatus::OK(); | |
689 | } | |
690 | ||
f67539c2 TL |
691 | // If you're adding methods here, remember to add them to EnvWrapper too. |
692 | ||
693 | private: | |
694 | void operator=(const FileSystem&); | |
695 | }; | |
696 | ||
697 | // A file abstraction for reading sequentially through a file | |
698 | class FSSequentialFile { | |
699 | public: | |
700 | FSSequentialFile() {} | |
701 | ||
702 | virtual ~FSSequentialFile() {} | |
703 | ||
704 | // Read up to "n" bytes from the file. "scratch[0..n-1]" may be | |
705 | // written by this routine. Sets "*result" to the data that was | |
706 | // read (including if fewer than "n" bytes were successfully read). | |
707 | // May set "*result" to point at data in "scratch[0..n-1]", so | |
708 | // "scratch[0..n-1]" must be live when "*result" is used. | |
709 | // If an error was encountered, returns a non-OK status. | |
710 | // | |
1e59de90 TL |
711 | // After call, result->size() < n only if end of file has been |
712 | // reached (or non-OK status). Read might fail if called again after | |
713 | // first result->size() < n. | |
714 | // | |
f67539c2 TL |
715 | // REQUIRES: External synchronization |
716 | virtual IOStatus Read(size_t n, const IOOptions& options, Slice* result, | |
717 | char* scratch, IODebugContext* dbg) = 0; | |
718 | ||
719 | // Skip "n" bytes from the file. This is guaranteed to be no | |
720 | // slower that reading the same data, but may be faster. | |
721 | // | |
722 | // If end of file is reached, skipping will stop at the end of the | |
723 | // file, and Skip will return OK. | |
724 | // | |
725 | // REQUIRES: External synchronization | |
726 | virtual IOStatus Skip(uint64_t n) = 0; | |
727 | ||
728 | // Indicates the upper layers if the current SequentialFile implementation | |
729 | // uses direct IO. | |
730 | virtual bool use_direct_io() const { return false; } | |
731 | ||
732 | // Use the returned alignment value to allocate | |
733 | // aligned buffer for Direct I/O | |
734 | virtual size_t GetRequiredBufferAlignment() const { return kDefaultPageSize; } | |
735 | ||
736 | // Remove any kind of caching of data from the offset to offset+length | |
737 | // of this file. If the length is 0, then it refers to the end of file. | |
738 | // If the system is not caching the file contents, then this is a noop. | |
739 | virtual IOStatus InvalidateCache(size_t /*offset*/, size_t /*length*/) { | |
740 | return IOStatus::NotSupported("InvalidateCache not supported."); | |
741 | } | |
742 | ||
743 | // Positioned Read for direct I/O | |
744 | // If Direct I/O enabled, offset, n, and scratch should be properly aligned | |
745 | virtual IOStatus PositionedRead(uint64_t /*offset*/, size_t /*n*/, | |
746 | const IOOptions& /*options*/, | |
747 | Slice* /*result*/, char* /*scratch*/, | |
748 | IODebugContext* /*dbg*/) { | |
20effc67 | 749 | return IOStatus::NotSupported("PositionedRead"); |
f67539c2 TL |
750 | } |
751 | ||
1e59de90 TL |
752 | // EXPERIMENTAL |
753 | // When available, returns the actual temperature for the file. This is | |
754 | // useful in case some outside process moves a file from one tier to another, | |
755 | // though the temperature is generally expected not to change while a file is | |
756 | // open. | |
757 | virtual Temperature GetTemperature() const { return Temperature::kUnknown; } | |
758 | ||
f67539c2 TL |
759 | // If you're adding methods here, remember to add them to |
760 | // SequentialFileWrapper too. | |
761 | }; | |
762 | ||
1e59de90 | 763 | // A read IO request structure for use in MultiRead and asynchronous Read APIs. |
f67539c2 | 764 | struct FSReadRequest { |
1e59de90 | 765 | // Input parameter that represents the file offset in bytes. |
f67539c2 TL |
766 | uint64_t offset; |
767 | ||
1e59de90 TL |
768 | // Input parameter that represents the length to read in bytes. `result` only |
769 | // returns fewer bytes if end of file is hit (or `status` is not OK). | |
f67539c2 TL |
770 | size_t len; |
771 | ||
1e59de90 TL |
772 | // A buffer that MultiRead() can optionally place data in. It can |
773 | // ignore this and allocate its own buffer. | |
774 | // The lifecycle of scratch will be until IO is completed. | |
775 | // | |
776 | // In case of asynchronous reads, its an output parameter and it will be | |
777 | // maintained until callback has been called. Scratch is allocated by RocksDB | |
778 | // and will be passed to underlying FileSystem. | |
f67539c2 TL |
779 | char* scratch; |
780 | ||
781 | // Output parameter set by MultiRead() to point to the data buffer, and | |
782 | // the number of valid bytes | |
1e59de90 TL |
783 | // |
784 | // In case of asynchronous reads, this output parameter is set by Async Read | |
785 | // APIs to point to the data buffer, and | |
786 | // the number of valid bytes. | |
787 | // Slice result should point to scratch i.e the data should | |
788 | // always be read into scratch. | |
f67539c2 TL |
789 | Slice result; |
790 | ||
1e59de90 TL |
791 | // Output parameter set by underlying FileSystem that represents status of |
792 | // read request. | |
f67539c2 TL |
793 | IOStatus status; |
794 | }; | |
795 | ||
796 | // A file abstraction for randomly reading the contents of a file. | |
797 | class FSRandomAccessFile { | |
798 | public: | |
799 | FSRandomAccessFile() {} | |
800 | ||
801 | virtual ~FSRandomAccessFile() {} | |
802 | ||
803 | // Read up to "n" bytes from the file starting at "offset". | |
804 | // "scratch[0..n-1]" may be written by this routine. Sets "*result" | |
805 | // to the data that was read (including if fewer than "n" bytes were | |
806 | // successfully read). May set "*result" to point at data in | |
807 | // "scratch[0..n-1]", so "scratch[0..n-1]" must be live when | |
808 | // "*result" is used. If an error was encountered, returns a non-OK | |
809 | // status. | |
810 | // | |
1e59de90 TL |
811 | // After call, result->size() < n only if end of file has been |
812 | // reached (or non-OK status). Read might fail if called again after | |
813 | // first result->size() < n. | |
814 | // | |
f67539c2 TL |
815 | // Safe for concurrent use by multiple threads. |
816 | // If Direct I/O enabled, offset, n, and scratch should be aligned properly. | |
817 | virtual IOStatus Read(uint64_t offset, size_t n, const IOOptions& options, | |
818 | Slice* result, char* scratch, | |
819 | IODebugContext* dbg) const = 0; | |
820 | ||
821 | // Readahead the file starting from offset by n bytes for caching. | |
20effc67 TL |
822 | // If it's not implemented (default: `NotSupported`), RocksDB will create |
823 | // internal prefetch buffer to improve read performance. | |
f67539c2 TL |
824 | virtual IOStatus Prefetch(uint64_t /*offset*/, size_t /*n*/, |
825 | const IOOptions& /*options*/, | |
826 | IODebugContext* /*dbg*/) { | |
20effc67 | 827 | return IOStatus::NotSupported("Prefetch"); |
f67539c2 TL |
828 | } |
829 | ||
830 | // Read a bunch of blocks as described by reqs. The blocks can | |
831 | // optionally be read in parallel. This is a synchronous call, i.e it | |
832 | // should return after all reads have completed. The reads will be | |
1e59de90 TL |
833 | // non-overlapping but can be in any order. If the function return Status |
834 | // is not ok, status of individual requests will be ignored and return | |
835 | // status will be assumed for all read requests. The function return status | |
836 | // is only meant for errors that occur before processing individual read | |
837 | // requests. | |
f67539c2 TL |
838 | virtual IOStatus MultiRead(FSReadRequest* reqs, size_t num_reqs, |
839 | const IOOptions& options, IODebugContext* dbg) { | |
840 | assert(reqs != nullptr); | |
841 | for (size_t i = 0; i < num_reqs; ++i) { | |
842 | FSReadRequest& req = reqs[i]; | |
843 | req.status = | |
844 | Read(req.offset, req.len, options, &req.result, req.scratch, dbg); | |
845 | } | |
846 | return IOStatus::OK(); | |
847 | } | |
848 | ||
849 | // Tries to get an unique ID for this file that will be the same each time | |
850 | // the file is opened (and will stay the same while the file is open). | |
851 | // Furthermore, it tries to make this ID at most "max_size" bytes. If such an | |
852 | // ID can be created this function returns the length of the ID and places it | |
853 | // in "id"; otherwise, this function returns 0, in which case "id" | |
854 | // may not have been modified. | |
855 | // | |
856 | // This function guarantees, for IDs from a given environment, two unique ids | |
857 | // cannot be made equal to each other by adding arbitrary bytes to one of | |
858 | // them. That is, no unique ID is the prefix of another. | |
859 | // | |
860 | // This function guarantees that the returned ID will not be interpretable as | |
861 | // a single varint. | |
862 | // | |
863 | // Note: these IDs are only valid for the duration of the process. | |
864 | virtual size_t GetUniqueId(char* /*id*/, size_t /*max_size*/) const { | |
865 | return 0; // Default implementation to prevent issues with backwards | |
866 | // compatibility. | |
867 | }; | |
868 | ||
869 | enum AccessPattern { kNormal, kRandom, kSequential, kWillNeed, kWontNeed }; | |
870 | ||
871 | virtual void Hint(AccessPattern /*pattern*/) {} | |
872 | ||
873 | // Indicates the upper layers if the current RandomAccessFile implementation | |
874 | // uses direct IO. | |
875 | virtual bool use_direct_io() const { return false; } | |
876 | ||
877 | // Use the returned alignment value to allocate | |
878 | // aligned buffer for Direct I/O | |
879 | virtual size_t GetRequiredBufferAlignment() const { return kDefaultPageSize; } | |
880 | ||
881 | // Remove any kind of caching of data from the offset to offset+length | |
882 | // of this file. If the length is 0, then it refers to the end of file. | |
883 | // If the system is not caching the file contents, then this is a noop. | |
884 | virtual IOStatus InvalidateCache(size_t /*offset*/, size_t /*length*/) { | |
885 | return IOStatus::NotSupported("InvalidateCache not supported."); | |
886 | } | |
887 | ||
1e59de90 TL |
888 | // EXPERIMENTAL |
889 | // This API reads the requested data in FSReadRequest asynchronously. This is | |
890 | // a asynchronous call, i.e it should return after submitting the request. | |
891 | // | |
892 | // When the read request is completed, callback function specified in cb | |
893 | // should be called with arguments cb_arg and the result populated in | |
894 | // FSReadRequest with result and status fileds updated by FileSystem. | |
895 | // cb_arg should be used by the callback to track the original request | |
896 | // submitted. | |
897 | // | |
898 | // This API should also populate io_handle which should be used by | |
899 | // underlying FileSystem to store the context in order to distinguish the read | |
900 | // requests at their side and provide the custom deletion function in del_fn. | |
901 | // RocksDB guarantees that the del_fn for io_handle will be called after | |
902 | // receiving the callback. Furthermore, RocksDB guarantees that if it calls | |
903 | // the Poll API for this io_handle, del_fn will be called after the Poll | |
904 | // returns. RocksDB is responsible for managing the lifetime of io_handle. | |
905 | // | |
906 | // req contains the request offset and size passed as input parameter of read | |
907 | // request and result and status fields are output parameter set by underlying | |
908 | // FileSystem. The data should always be read into scratch field. | |
909 | // | |
910 | // Default implementation is to read the data synchronously. | |
911 | virtual IOStatus ReadAsync( | |
912 | FSReadRequest& req, const IOOptions& opts, | |
913 | std::function<void(const FSReadRequest&, void*)> cb, void* cb_arg, | |
914 | void** /*io_handle*/, IOHandleDeleter* /*del_fn*/, IODebugContext* dbg) { | |
915 | req.status = | |
916 | Read(req.offset, req.len, opts, &(req.result), req.scratch, dbg); | |
917 | cb(req, cb_arg); | |
918 | return IOStatus::OK(); | |
919 | } | |
920 | ||
921 | // EXPERIMENTAL | |
922 | // When available, returns the actual temperature for the file. This is | |
923 | // useful in case some outside process moves a file from one tier to another, | |
924 | // though the temperature is generally expected not to change while a file is | |
925 | // open. | |
926 | virtual Temperature GetTemperature() const { return Temperature::kUnknown; } | |
927 | ||
f67539c2 TL |
928 | // If you're adding methods here, remember to add them to |
929 | // RandomAccessFileWrapper too. | |
930 | }; | |
931 | ||
20effc67 | 932 | // A data structure brings the data verification information, which is |
1e59de90 | 933 | // used together with data being written to a file. |
20effc67 TL |
934 | struct DataVerificationInfo { |
935 | // checksum of the data being written. | |
936 | Slice checksum; | |
937 | }; | |
938 | ||
f67539c2 TL |
939 | // A file abstraction for sequential writing. The implementation |
940 | // must provide buffering since callers may append small fragments | |
941 | // at a time to the file. | |
942 | class FSWritableFile { | |
943 | public: | |
944 | FSWritableFile() | |
945 | : last_preallocated_block_(0), | |
946 | preallocation_block_size_(0), | |
947 | io_priority_(Env::IO_TOTAL), | |
948 | write_hint_(Env::WLTH_NOT_SET), | |
949 | strict_bytes_per_sync_(false) {} | |
950 | ||
951 | explicit FSWritableFile(const FileOptions& options) | |
952 | : last_preallocated_block_(0), | |
953 | preallocation_block_size_(0), | |
954 | io_priority_(Env::IO_TOTAL), | |
955 | write_hint_(Env::WLTH_NOT_SET), | |
956 | strict_bytes_per_sync_(options.strict_bytes_per_sync) {} | |
957 | ||
958 | virtual ~FSWritableFile() {} | |
959 | ||
960 | // Append data to the end of the file | |
1e59de90 | 961 | // Note: A WritableFile object must support either Append or |
f67539c2 TL |
962 | // PositionedAppend, so the users cannot mix the two. |
963 | virtual IOStatus Append(const Slice& data, const IOOptions& options, | |
964 | IODebugContext* dbg) = 0; | |
965 | ||
1e59de90 | 966 | // Append data with verification information. |
20effc67 | 967 | // Note that this API change is experimental and it might be changed in |
1e59de90 TL |
968 | // the future. Currently, RocksDB only generates crc32c based checksum for |
969 | // the file writes when the checksum handoff option is set. | |
970 | // Expected behavior: if the handoff_checksum_type in FileOptions (currently, | |
971 | // ChecksumType::kCRC32C is set as default) is not supported by this | |
972 | // FSWritableFile, the information in DataVerificationInfo can be ignored | |
973 | // (i.e. does not perform checksum verification). | |
20effc67 TL |
974 | virtual IOStatus Append(const Slice& data, const IOOptions& options, |
975 | const DataVerificationInfo& /* verification_info */, | |
976 | IODebugContext* dbg) { | |
977 | return Append(data, options, dbg); | |
978 | } | |
979 | ||
f67539c2 TL |
980 | // PositionedAppend data to the specified offset. The new EOF after append |
981 | // must be larger than the previous EOF. This is to be used when writes are | |
982 | // not backed by OS buffers and hence has to always start from the start of | |
983 | // the sector. The implementation thus needs to also rewrite the last | |
984 | // partial sector. | |
985 | // Note: PositionAppend does not guarantee moving the file offset after the | |
986 | // write. A WritableFile object must support either Append or | |
987 | // PositionedAppend, so the users cannot mix the two. | |
988 | // | |
989 | // PositionedAppend() can only happen on the page/sector boundaries. For that | |
990 | // reason, if the last write was an incomplete sector we still need to rewind | |
991 | // back to the nearest sector/page and rewrite the portion of it with whatever | |
992 | // we need to add. We need to keep where we stop writing. | |
993 | // | |
994 | // PositionedAppend() can only write whole sectors. For that reason we have to | |
995 | // pad with zeros for the last write and trim the file when closing according | |
996 | // to the position we keep in the previous step. | |
997 | // | |
998 | // PositionedAppend() requires aligned buffer to be passed in. The alignment | |
999 | // required is queried via GetRequiredBufferAlignment() | |
1000 | virtual IOStatus PositionedAppend(const Slice& /* data */, | |
1001 | uint64_t /* offset */, | |
1002 | const IOOptions& /*options*/, | |
1003 | IODebugContext* /*dbg*/) { | |
20effc67 TL |
1004 | return IOStatus::NotSupported("PositionedAppend"); |
1005 | } | |
1006 | ||
20effc67 TL |
1007 | // PositionedAppend data with verification information. |
1008 | // Note that this API change is experimental and it might be changed in | |
1e59de90 TL |
1009 | // the future. Currently, RocksDB only generates crc32c based checksum for |
1010 | // the file writes when the checksum handoff option is set. | |
1011 | // Expected behavior: if the handoff_checksum_type in FileOptions (currently, | |
1012 | // ChecksumType::kCRC32C is set as default) is not supported by this | |
1013 | // FSWritableFile, the information in DataVerificationInfo can be ignored | |
1014 | // (i.e. does not perform checksum verification). | |
20effc67 TL |
1015 | virtual IOStatus PositionedAppend( |
1016 | const Slice& /* data */, uint64_t /* offset */, | |
1017 | const IOOptions& /*options*/, | |
1018 | const DataVerificationInfo& /* verification_info */, | |
1019 | IODebugContext* /*dbg*/) { | |
1020 | return IOStatus::NotSupported("PositionedAppend"); | |
f67539c2 TL |
1021 | } |
1022 | ||
1023 | // Truncate is necessary to trim the file to the correct size | |
1024 | // before closing. It is not always possible to keep track of the file | |
1025 | // size due to whole pages writes. The behavior is undefined if called | |
1026 | // with other writes to follow. | |
1027 | virtual IOStatus Truncate(uint64_t /*size*/, const IOOptions& /*options*/, | |
1028 | IODebugContext* /*dbg*/) { | |
1029 | return IOStatus::OK(); | |
1030 | } | |
1e59de90 TL |
1031 | virtual IOStatus Close(const IOOptions& /*options*/, |
1032 | IODebugContext* /*dbg*/) = 0; | |
1033 | ||
f67539c2 TL |
1034 | virtual IOStatus Flush(const IOOptions& options, IODebugContext* dbg) = 0; |
1035 | virtual IOStatus Sync(const IOOptions& options, | |
1036 | IODebugContext* dbg) = 0; // sync data | |
1037 | ||
1038 | /* | |
1039 | * Sync data and/or metadata as well. | |
1040 | * By default, sync only data. | |
1041 | * Override this method for environments where we need to sync | |
1042 | * metadata as well. | |
1043 | */ | |
1044 | virtual IOStatus Fsync(const IOOptions& options, IODebugContext* dbg) { | |
1045 | return Sync(options, dbg); | |
1046 | } | |
1047 | ||
1048 | // true if Sync() and Fsync() are safe to call concurrently with Append() | |
1049 | // and Flush(). | |
1050 | virtual bool IsSyncThreadSafe() const { return false; } | |
1051 | ||
1052 | // Indicates the upper layers if the current WritableFile implementation | |
1053 | // uses direct IO. | |
1054 | virtual bool use_direct_io() const { return false; } | |
1055 | ||
1056 | // Use the returned alignment value to allocate | |
1057 | // aligned buffer for Direct I/O | |
1058 | virtual size_t GetRequiredBufferAlignment() const { return kDefaultPageSize; } | |
1059 | ||
1060 | virtual void SetWriteLifeTimeHint(Env::WriteLifeTimeHint hint) { | |
1061 | write_hint_ = hint; | |
1062 | } | |
1063 | ||
1e59de90 TL |
1064 | /* |
1065 | * If rate limiting is enabled, change the file-granularity priority used in | |
1066 | * rate-limiting writes. | |
1067 | * | |
1068 | * In the presence of finer-granularity priority such as | |
1069 | * `WriteOptions::rate_limiter_priority`, this file-granularity priority may | |
1070 | * be overridden by a non-Env::IO_TOTAL finer-granularity priority and used as | |
1071 | * a fallback for Env::IO_TOTAL finer-granularity priority. | |
1072 | * | |
1073 | * If rate limiting is not enabled, this call has no effect. | |
1074 | */ | |
f67539c2 TL |
1075 | virtual void SetIOPriority(Env::IOPriority pri) { io_priority_ = pri; } |
1076 | ||
1077 | virtual Env::IOPriority GetIOPriority() { return io_priority_; } | |
1078 | ||
1079 | virtual Env::WriteLifeTimeHint GetWriteLifeTimeHint() { return write_hint_; } | |
1080 | /* | |
1081 | * Get the size of valid data in the file. | |
1082 | */ | |
1083 | virtual uint64_t GetFileSize(const IOOptions& /*options*/, | |
1084 | IODebugContext* /*dbg*/) { | |
1085 | return 0; | |
1086 | } | |
1087 | ||
1088 | /* | |
1089 | * Get and set the default pre-allocation block size for writes to | |
1090 | * this file. If non-zero, then Allocate will be used to extend the | |
1091 | * underlying storage of a file (generally via fallocate) if the Env | |
1092 | * instance supports it. | |
1093 | */ | |
1094 | virtual void SetPreallocationBlockSize(size_t size) { | |
1095 | preallocation_block_size_ = size; | |
1096 | } | |
1097 | ||
1098 | virtual void GetPreallocationStatus(size_t* block_size, | |
1099 | size_t* last_allocated_block) { | |
1100 | *last_allocated_block = last_preallocated_block_; | |
1101 | *block_size = preallocation_block_size_; | |
1102 | } | |
1103 | ||
1104 | // For documentation, refer to RandomAccessFile::GetUniqueId() | |
1105 | virtual size_t GetUniqueId(char* /*id*/, size_t /*max_size*/) const { | |
1106 | return 0; // Default implementation to prevent issues with backwards | |
1107 | } | |
1108 | ||
1109 | // Remove any kind of caching of data from the offset to offset+length | |
1110 | // of this file. If the length is 0, then it refers to the end of file. | |
1111 | // If the system is not caching the file contents, then this is a noop. | |
1112 | // This call has no effect on dirty pages in the cache. | |
1113 | virtual IOStatus InvalidateCache(size_t /*offset*/, size_t /*length*/) { | |
1114 | return IOStatus::NotSupported("InvalidateCache not supported."); | |
1115 | } | |
1116 | ||
1117 | // Sync a file range with disk. | |
1118 | // offset is the starting byte of the file range to be synchronized. | |
1119 | // nbytes specifies the length of the range to be synchronized. | |
1120 | // This asks the OS to initiate flushing the cached data to disk, | |
1121 | // without waiting for completion. | |
1122 | // Default implementation does nothing. | |
1123 | virtual IOStatus RangeSync(uint64_t /*offset*/, uint64_t /*nbytes*/, | |
1124 | const IOOptions& options, IODebugContext* dbg) { | |
1125 | if (strict_bytes_per_sync_) { | |
1126 | return Sync(options, dbg); | |
1127 | } | |
1128 | return IOStatus::OK(); | |
1129 | } | |
1130 | ||
1131 | // PrepareWrite performs any necessary preparation for a write | |
1132 | // before the write actually occurs. This allows for pre-allocation | |
1133 | // of space on devices where it can result in less file | |
1134 | // fragmentation and/or less waste from over-zealous filesystem | |
1135 | // pre-allocation. | |
1136 | virtual void PrepareWrite(size_t offset, size_t len, const IOOptions& options, | |
1137 | IODebugContext* dbg) { | |
1138 | if (preallocation_block_size_ == 0) { | |
1139 | return; | |
1140 | } | |
1141 | // If this write would cross one or more preallocation blocks, | |
1142 | // determine what the last preallocation block necessary to | |
1143 | // cover this write would be and Allocate to that point. | |
1144 | const auto block_size = preallocation_block_size_; | |
1145 | size_t new_last_preallocated_block = | |
1146 | (offset + len + block_size - 1) / block_size; | |
1147 | if (new_last_preallocated_block > last_preallocated_block_) { | |
1148 | size_t num_spanned_blocks = | |
1149 | new_last_preallocated_block - last_preallocated_block_; | |
1150 | Allocate(block_size * last_preallocated_block_, | |
20effc67 TL |
1151 | block_size * num_spanned_blocks, options, dbg) |
1152 | .PermitUncheckedError(); | |
f67539c2 TL |
1153 | last_preallocated_block_ = new_last_preallocated_block; |
1154 | } | |
1155 | } | |
1156 | ||
1157 | // Pre-allocates space for a file. | |
1158 | virtual IOStatus Allocate(uint64_t /*offset*/, uint64_t /*len*/, | |
1159 | const IOOptions& /*options*/, | |
1160 | IODebugContext* /*dbg*/) { | |
1161 | return IOStatus::OK(); | |
1162 | } | |
1163 | ||
1164 | // If you're adding methods here, remember to add them to | |
1165 | // WritableFileWrapper too. | |
1166 | ||
1167 | protected: | |
1168 | size_t preallocation_block_size() { return preallocation_block_size_; } | |
1169 | ||
1170 | private: | |
1171 | size_t last_preallocated_block_; | |
1172 | size_t preallocation_block_size_; | |
1173 | // No copying allowed | |
1174 | FSWritableFile(const FSWritableFile&); | |
1175 | void operator=(const FSWritableFile&); | |
1176 | ||
1177 | protected: | |
1178 | Env::IOPriority io_priority_; | |
1179 | Env::WriteLifeTimeHint write_hint_; | |
1180 | const bool strict_bytes_per_sync_; | |
1181 | }; | |
1182 | ||
1183 | // A file abstraction for random reading and writing. | |
1184 | class FSRandomRWFile { | |
1185 | public: | |
1186 | FSRandomRWFile() {} | |
1187 | ||
1188 | virtual ~FSRandomRWFile() {} | |
1189 | ||
1190 | // Indicates if the class makes use of direct I/O | |
1191 | // If false you must pass aligned buffer to Write() | |
1192 | virtual bool use_direct_io() const { return false; } | |
1193 | ||
1194 | // Use the returned alignment value to allocate | |
1195 | // aligned buffer for Direct I/O | |
1196 | virtual size_t GetRequiredBufferAlignment() const { return kDefaultPageSize; } | |
1197 | ||
1198 | // Write bytes in `data` at offset `offset`, Returns Status::OK() on success. | |
1199 | // Pass aligned buffer when use_direct_io() returns true. | |
1200 | virtual IOStatus Write(uint64_t offset, const Slice& data, | |
1201 | const IOOptions& options, IODebugContext* dbg) = 0; | |
1202 | ||
1203 | // Read up to `n` bytes starting from offset `offset` and store them in | |
1204 | // result, provided `scratch` size should be at least `n`. | |
1e59de90 TL |
1205 | // |
1206 | // After call, result->size() < n only if end of file has been | |
1207 | // reached (or non-OK status). Read might fail if called again after | |
1208 | // first result->size() < n. | |
1209 | // | |
f67539c2 TL |
1210 | // Returns Status::OK() on success. |
1211 | virtual IOStatus Read(uint64_t offset, size_t n, const IOOptions& options, | |
1212 | Slice* result, char* scratch, | |
1213 | IODebugContext* dbg) const = 0; | |
1214 | ||
1215 | virtual IOStatus Flush(const IOOptions& options, IODebugContext* dbg) = 0; | |
1216 | ||
1217 | virtual IOStatus Sync(const IOOptions& options, IODebugContext* dbg) = 0; | |
1218 | ||
1219 | virtual IOStatus Fsync(const IOOptions& options, IODebugContext* dbg) { | |
1220 | return Sync(options, dbg); | |
1221 | } | |
1222 | ||
1223 | virtual IOStatus Close(const IOOptions& options, IODebugContext* dbg) = 0; | |
1224 | ||
1e59de90 TL |
1225 | // EXPERIMENTAL |
1226 | // When available, returns the actual temperature for the file. This is | |
1227 | // useful in case some outside process moves a file from one tier to another, | |
1228 | // though the temperature is generally expected not to change while a file is | |
1229 | // open. | |
1230 | virtual Temperature GetTemperature() const { return Temperature::kUnknown; } | |
1231 | ||
f67539c2 TL |
1232 | // If you're adding methods here, remember to add them to |
1233 | // RandomRWFileWrapper too. | |
1234 | ||
1235 | // No copying allowed | |
1236 | FSRandomRWFile(const RandomRWFile&) = delete; | |
1237 | FSRandomRWFile& operator=(const RandomRWFile&) = delete; | |
1238 | }; | |
1239 | ||
1240 | // MemoryMappedFileBuffer object represents a memory-mapped file's raw buffer. | |
1241 | // Subclasses should release the mapping upon destruction. | |
1242 | class FSMemoryMappedFileBuffer { | |
1243 | public: | |
1244 | FSMemoryMappedFileBuffer(void* _base, size_t _length) | |
1245 | : base_(_base), length_(_length) {} | |
1246 | ||
1247 | virtual ~FSMemoryMappedFileBuffer() = 0; | |
1248 | ||
1249 | // We do not want to unmap this twice. We can make this class | |
1250 | // movable if desired, however, since | |
1251 | FSMemoryMappedFileBuffer(const FSMemoryMappedFileBuffer&) = delete; | |
1252 | FSMemoryMappedFileBuffer& operator=(const FSMemoryMappedFileBuffer&) = delete; | |
1253 | ||
1254 | void* GetBase() const { return base_; } | |
1255 | size_t GetLen() const { return length_; } | |
1256 | ||
1257 | protected: | |
1258 | void* base_; | |
1259 | const size_t length_; | |
1260 | }; | |
1261 | ||
1262 | // Directory object represents collection of files and implements | |
1263 | // filesystem operations that can be executed on directories. | |
1264 | class FSDirectory { | |
1265 | public: | |
1266 | virtual ~FSDirectory() {} | |
1267 | // Fsync directory. Can be called concurrently from multiple threads. | |
1268 | virtual IOStatus Fsync(const IOOptions& options, IODebugContext* dbg) = 0; | |
1269 | ||
1e59de90 TL |
1270 | // FsyncWithDirOptions after renaming a file. Depends on the filesystem, it |
1271 | // may fsync directory or just the renaming file (e.g. btrfs). By default, it | |
1272 | // just calls directory fsync. | |
1273 | virtual IOStatus FsyncWithDirOptions( | |
1274 | const IOOptions& options, IODebugContext* dbg, | |
1275 | const DirFsyncOptions& /*dir_fsync_options*/) { | |
1276 | return Fsync(options, dbg); | |
1277 | } | |
1278 | ||
1279 | // Close directory | |
1280 | virtual IOStatus Close(const IOOptions& /*options*/, | |
1281 | IODebugContext* /*dbg*/) { | |
1282 | return IOStatus::NotSupported("Close"); | |
1283 | } | |
1284 | ||
f67539c2 TL |
1285 | virtual size_t GetUniqueId(char* /*id*/, size_t /*max_size*/) const { |
1286 | return 0; | |
1287 | } | |
1288 | ||
1289 | // If you're adding methods here, remember to add them to | |
1290 | // DirectoryWrapper too. | |
1291 | }; | |
1292 | ||
1293 | // Below are helpers for wrapping most of the classes in this file. | |
1294 | // They forward all calls to another instance of the class. | |
1295 | // Useful when wrapping the default implementations. | |
1296 | // Typical usage is to inherit your wrapper from *Wrapper, e.g.: | |
1297 | // | |
1298 | // class MySequentialFileWrapper : public | |
1299 | // ROCKSDB_NAMESPACE::FSSequentialFileWrapper { | |
1300 | // public: | |
1301 | // MySequentialFileWrapper(ROCKSDB_NAMESPACE::FSSequentialFile* target): | |
1302 | // ROCKSDB_NAMESPACE::FSSequentialFileWrapper(target) {} | |
1303 | // Status Read(size_t n, FileSystem::IOOptions& options, Slice* result, | |
1304 | // char* scratch, FileSystem::IODebugContext* dbg) override { | |
1305 | // cout << "Doing a read of size " << n << "!" << endl; | |
1306 | // return ROCKSDB_NAMESPACE::FSSequentialFileWrapper::Read(n, options, | |
1307 | // result, | |
1308 | // scratch, dbg); | |
1309 | // } | |
1310 | // // All other methods are forwarded to target_ automatically. | |
1311 | // }; | |
1312 | // | |
1313 | // This is often more convenient than inheriting the class directly because | |
1314 | // (a) Don't have to override and forward all methods - the Wrapper will | |
1315 | // forward everything you're not explicitly overriding. | |
1316 | // (b) Don't need to update the wrapper when more methods are added to the | |
1317 | // rocksdb class. Unless you actually want to override the behavior. | |
1318 | // (And unless rocksdb people forgot to update the *Wrapper class.) | |
1319 | ||
1320 | // An implementation of Env that forwards all calls to another Env. | |
1321 | // May be useful to clients who wish to override just part of the | |
1322 | // functionality of another Env. | |
1323 | class FileSystemWrapper : public FileSystem { | |
1324 | public: | |
1325 | // Initialize an EnvWrapper that delegates all calls to *t | |
1e59de90 | 1326 | explicit FileSystemWrapper(const std::shared_ptr<FileSystem>& t); |
f67539c2 TL |
1327 | ~FileSystemWrapper() override {} |
1328 | ||
1329 | // Return the target to which this Env forwards all calls | |
20effc67 | 1330 | FileSystem* target() const { return target_.get(); } |
f67539c2 TL |
1331 | |
1332 | // The following text is boilerplate that forwards all methods to target() | |
1e59de90 | 1333 | IOStatus NewSequentialFile(const std::string& f, const FileOptions& file_opts, |
f67539c2 TL |
1334 | std::unique_ptr<FSSequentialFile>* r, |
1335 | IODebugContext* dbg) override { | |
1336 | return target_->NewSequentialFile(f, file_opts, r, dbg); | |
1337 | } | |
1338 | IOStatus NewRandomAccessFile(const std::string& f, | |
1339 | const FileOptions& file_opts, | |
1340 | std::unique_ptr<FSRandomAccessFile>* r, | |
1341 | IODebugContext* dbg) override { | |
1342 | return target_->NewRandomAccessFile(f, file_opts, r, dbg); | |
1343 | } | |
1344 | IOStatus NewWritableFile(const std::string& f, const FileOptions& file_opts, | |
1345 | std::unique_ptr<FSWritableFile>* r, | |
1346 | IODebugContext* dbg) override { | |
1347 | return target_->NewWritableFile(f, file_opts, r, dbg); | |
1348 | } | |
1349 | IOStatus ReopenWritableFile(const std::string& fname, | |
1350 | const FileOptions& file_opts, | |
1351 | std::unique_ptr<FSWritableFile>* result, | |
1352 | IODebugContext* dbg) override { | |
1353 | return target_->ReopenWritableFile(fname, file_opts, result, dbg); | |
1354 | } | |
1355 | IOStatus ReuseWritableFile(const std::string& fname, | |
1356 | const std::string& old_fname, | |
1357 | const FileOptions& file_opts, | |
1358 | std::unique_ptr<FSWritableFile>* r, | |
1359 | IODebugContext* dbg) override { | |
1e59de90 | 1360 | return target_->ReuseWritableFile(fname, old_fname, file_opts, r, dbg); |
f67539c2 TL |
1361 | } |
1362 | IOStatus NewRandomRWFile(const std::string& fname, | |
1363 | const FileOptions& file_opts, | |
1364 | std::unique_ptr<FSRandomRWFile>* result, | |
1365 | IODebugContext* dbg) override { | |
1366 | return target_->NewRandomRWFile(fname, file_opts, result, dbg); | |
1367 | } | |
1368 | IOStatus NewMemoryMappedFileBuffer( | |
1369 | const std::string& fname, | |
1370 | std::unique_ptr<MemoryMappedFileBuffer>* result) override { | |
1371 | return target_->NewMemoryMappedFileBuffer(fname, result); | |
1372 | } | |
1373 | IOStatus NewDirectory(const std::string& name, const IOOptions& io_opts, | |
1374 | std::unique_ptr<FSDirectory>* result, | |
1375 | IODebugContext* dbg) override { | |
1376 | return target_->NewDirectory(name, io_opts, result, dbg); | |
1377 | } | |
1378 | IOStatus FileExists(const std::string& f, const IOOptions& io_opts, | |
1379 | IODebugContext* dbg) override { | |
1380 | return target_->FileExists(f, io_opts, dbg); | |
1381 | } | |
1382 | IOStatus GetChildren(const std::string& dir, const IOOptions& io_opts, | |
1383 | std::vector<std::string>* r, | |
1384 | IODebugContext* dbg) override { | |
1385 | return target_->GetChildren(dir, io_opts, r, dbg); | |
1386 | } | |
1387 | IOStatus GetChildrenFileAttributes(const std::string& dir, | |
1388 | const IOOptions& options, | |
1389 | std::vector<FileAttributes>* result, | |
1390 | IODebugContext* dbg) override { | |
1391 | return target_->GetChildrenFileAttributes(dir, options, result, dbg); | |
1392 | } | |
1393 | IOStatus DeleteFile(const std::string& f, const IOOptions& options, | |
1394 | IODebugContext* dbg) override { | |
1395 | return target_->DeleteFile(f, options, dbg); | |
1396 | } | |
1397 | IOStatus Truncate(const std::string& fname, size_t size, | |
1398 | const IOOptions& options, IODebugContext* dbg) override { | |
1399 | return target_->Truncate(fname, size, options, dbg); | |
1400 | } | |
1401 | IOStatus CreateDir(const std::string& d, const IOOptions& options, | |
1402 | IODebugContext* dbg) override { | |
1403 | return target_->CreateDir(d, options, dbg); | |
1404 | } | |
1405 | IOStatus CreateDirIfMissing(const std::string& d, const IOOptions& options, | |
1406 | IODebugContext* dbg) override { | |
1407 | return target_->CreateDirIfMissing(d, options, dbg); | |
1408 | } | |
1409 | IOStatus DeleteDir(const std::string& d, const IOOptions& options, | |
1410 | IODebugContext* dbg) override { | |
1411 | return target_->DeleteDir(d, options, dbg); | |
1412 | } | |
1413 | IOStatus GetFileSize(const std::string& f, const IOOptions& options, | |
1414 | uint64_t* s, IODebugContext* dbg) override { | |
1415 | return target_->GetFileSize(f, options, s, dbg); | |
1416 | } | |
1417 | ||
1418 | IOStatus GetFileModificationTime(const std::string& fname, | |
1419 | const IOOptions& options, | |
1420 | uint64_t* file_mtime, | |
1421 | IODebugContext* dbg) override { | |
1422 | return target_->GetFileModificationTime(fname, options, file_mtime, dbg); | |
1423 | } | |
1424 | ||
1425 | IOStatus GetAbsolutePath(const std::string& db_path, const IOOptions& options, | |
1426 | std::string* output_path, | |
1427 | IODebugContext* dbg) override { | |
1428 | return target_->GetAbsolutePath(db_path, options, output_path, dbg); | |
1429 | } | |
1430 | ||
1431 | IOStatus RenameFile(const std::string& s, const std::string& t, | |
1432 | const IOOptions& options, IODebugContext* dbg) override { | |
1433 | return target_->RenameFile(s, t, options, dbg); | |
1434 | } | |
1435 | ||
1436 | IOStatus LinkFile(const std::string& s, const std::string& t, | |
1437 | const IOOptions& options, IODebugContext* dbg) override { | |
1438 | return target_->LinkFile(s, t, options, dbg); | |
1439 | } | |
1440 | ||
1441 | IOStatus NumFileLinks(const std::string& fname, const IOOptions& options, | |
1442 | uint64_t* count, IODebugContext* dbg) override { | |
1443 | return target_->NumFileLinks(fname, options, count, dbg); | |
1444 | } | |
1445 | ||
1446 | IOStatus AreFilesSame(const std::string& first, const std::string& second, | |
1447 | const IOOptions& options, bool* res, | |
1448 | IODebugContext* dbg) override { | |
1449 | return target_->AreFilesSame(first, second, options, res, dbg); | |
1450 | } | |
1451 | ||
1452 | IOStatus LockFile(const std::string& f, const IOOptions& options, | |
1453 | FileLock** l, IODebugContext* dbg) override { | |
1454 | return target_->LockFile(f, options, l, dbg); | |
1455 | } | |
1456 | ||
1457 | IOStatus UnlockFile(FileLock* l, const IOOptions& options, | |
1458 | IODebugContext* dbg) override { | |
1459 | return target_->UnlockFile(l, options, dbg); | |
1460 | } | |
1461 | ||
1462 | IOStatus GetTestDirectory(const IOOptions& options, std::string* path, | |
1463 | IODebugContext* dbg) override { | |
1464 | return target_->GetTestDirectory(options, path, dbg); | |
1465 | } | |
1466 | IOStatus NewLogger(const std::string& fname, const IOOptions& options, | |
1467 | std::shared_ptr<Logger>* result, | |
1468 | IODebugContext* dbg) override { | |
1469 | return target_->NewLogger(fname, options, result, dbg); | |
1470 | } | |
1471 | ||
20effc67 TL |
1472 | void SanitizeFileOptions(FileOptions* opts) const override { |
1473 | target_->SanitizeFileOptions(opts); | |
1474 | } | |
1475 | ||
f67539c2 | 1476 | FileOptions OptimizeForLogRead( |
1e59de90 | 1477 | const FileOptions& file_options) const override { |
f67539c2 TL |
1478 | return target_->OptimizeForLogRead(file_options); |
1479 | } | |
1480 | FileOptions OptimizeForManifestRead( | |
1481 | const FileOptions& file_options) const override { | |
1482 | return target_->OptimizeForManifestRead(file_options); | |
1483 | } | |
1484 | FileOptions OptimizeForLogWrite(const FileOptions& file_options, | |
1e59de90 | 1485 | const DBOptions& db_options) const override { |
f67539c2 TL |
1486 | return target_->OptimizeForLogWrite(file_options, db_options); |
1487 | } | |
1488 | FileOptions OptimizeForManifestWrite( | |
1489 | const FileOptions& file_options) const override { | |
1490 | return target_->OptimizeForManifestWrite(file_options); | |
1491 | } | |
1492 | FileOptions OptimizeForCompactionTableWrite( | |
1493 | const FileOptions& file_options, | |
1494 | const ImmutableDBOptions& immutable_ops) const override { | |
1495 | return target_->OptimizeForCompactionTableWrite(file_options, | |
1496 | immutable_ops); | |
1497 | } | |
1498 | FileOptions OptimizeForCompactionTableRead( | |
1499 | const FileOptions& file_options, | |
1500 | const ImmutableDBOptions& db_options) const override { | |
1501 | return target_->OptimizeForCompactionTableRead(file_options, db_options); | |
1502 | } | |
1e59de90 TL |
1503 | FileOptions OptimizeForBlobFileRead( |
1504 | const FileOptions& file_options, | |
1505 | const ImmutableDBOptions& db_options) const override { | |
1506 | return target_->OptimizeForBlobFileRead(file_options, db_options); | |
1507 | } | |
f67539c2 TL |
1508 | IOStatus GetFreeSpace(const std::string& path, const IOOptions& options, |
1509 | uint64_t* diskfree, IODebugContext* dbg) override { | |
1510 | return target_->GetFreeSpace(path, options, diskfree, dbg); | |
1511 | } | |
20effc67 TL |
1512 | IOStatus IsDirectory(const std::string& path, const IOOptions& options, |
1513 | bool* is_dir, IODebugContext* dbg) override { | |
1514 | return target_->IsDirectory(path, options, is_dir, dbg); | |
1515 | } | |
f67539c2 | 1516 | |
1e59de90 TL |
1517 | const Customizable* Inner() const override { return target_.get(); } |
1518 | Status PrepareOptions(const ConfigOptions& options) override; | |
1519 | #ifndef ROCKSDB_LITE | |
1520 | std::string SerializeOptions(const ConfigOptions& config_options, | |
1521 | const std::string& header) const override; | |
1522 | #endif // ROCKSDB_LITE | |
1523 | ||
1524 | virtual IOStatus Poll(std::vector<void*>& io_handles, | |
1525 | size_t min_completions) override { | |
1526 | return target_->Poll(io_handles, min_completions); | |
1527 | } | |
1528 | ||
1529 | virtual IOStatus AbortIO(std::vector<void*>& io_handles) override { | |
1530 | return target_->AbortIO(io_handles); | |
1531 | } | |
1532 | ||
1533 | protected: | |
20effc67 | 1534 | std::shared_ptr<FileSystem> target_; |
f67539c2 TL |
1535 | }; |
1536 | ||
1537 | class FSSequentialFileWrapper : public FSSequentialFile { | |
1538 | public: | |
1e59de90 TL |
1539 | // Creates a FileWrapper around the input File object and without |
1540 | // taking ownership of the object | |
20effc67 TL |
1541 | explicit FSSequentialFileWrapper(FSSequentialFile* t) : target_(t) {} |
1542 | ||
1543 | FSSequentialFile* target() const { return target_; } | |
f67539c2 TL |
1544 | |
1545 | IOStatus Read(size_t n, const IOOptions& options, Slice* result, | |
1546 | char* scratch, IODebugContext* dbg) override { | |
1547 | return target_->Read(n, options, result, scratch, dbg); | |
1548 | } | |
1549 | IOStatus Skip(uint64_t n) override { return target_->Skip(n); } | |
1550 | bool use_direct_io() const override { return target_->use_direct_io(); } | |
1551 | size_t GetRequiredBufferAlignment() const override { | |
1552 | return target_->GetRequiredBufferAlignment(); | |
1553 | } | |
1554 | IOStatus InvalidateCache(size_t offset, size_t length) override { | |
1555 | return target_->InvalidateCache(offset, length); | |
1556 | } | |
1557 | IOStatus PositionedRead(uint64_t offset, size_t n, const IOOptions& options, | |
1558 | Slice* result, char* scratch, | |
1559 | IODebugContext* dbg) override { | |
1560 | return target_->PositionedRead(offset, n, options, result, scratch, dbg); | |
1561 | } | |
1e59de90 TL |
1562 | Temperature GetTemperature() const override { |
1563 | return target_->GetTemperature(); | |
1564 | } | |
f67539c2 TL |
1565 | |
1566 | private: | |
1567 | FSSequentialFile* target_; | |
1568 | }; | |
1569 | ||
1e59de90 TL |
1570 | class FSSequentialFileOwnerWrapper : public FSSequentialFileWrapper { |
1571 | public: | |
1572 | // Creates a FileWrapper around the input File object and takes | |
1573 | // ownership of the object | |
1574 | explicit FSSequentialFileOwnerWrapper(std::unique_ptr<FSSequentialFile>&& t) | |
1575 | : FSSequentialFileWrapper(t.get()), guard_(std::move(t)) {} | |
1576 | ||
1577 | private: | |
1578 | std::unique_ptr<FSSequentialFile> guard_; | |
1579 | }; | |
1580 | ||
f67539c2 TL |
1581 | class FSRandomAccessFileWrapper : public FSRandomAccessFile { |
1582 | public: | |
1e59de90 TL |
1583 | // Creates a FileWrapper around the input File object and without |
1584 | // taking ownership of the object | |
20effc67 TL |
1585 | explicit FSRandomAccessFileWrapper(FSRandomAccessFile* t) : target_(t) {} |
1586 | ||
1587 | FSRandomAccessFile* target() const { return target_; } | |
f67539c2 TL |
1588 | |
1589 | IOStatus Read(uint64_t offset, size_t n, const IOOptions& options, | |
1590 | Slice* result, char* scratch, | |
1591 | IODebugContext* dbg) const override { | |
1592 | return target_->Read(offset, n, options, result, scratch, dbg); | |
1593 | } | |
1594 | IOStatus MultiRead(FSReadRequest* reqs, size_t num_reqs, | |
1595 | const IOOptions& options, IODebugContext* dbg) override { | |
1596 | return target_->MultiRead(reqs, num_reqs, options, dbg); | |
1597 | } | |
1598 | IOStatus Prefetch(uint64_t offset, size_t n, const IOOptions& options, | |
1599 | IODebugContext* dbg) override { | |
1600 | return target_->Prefetch(offset, n, options, dbg); | |
1601 | } | |
1602 | size_t GetUniqueId(char* id, size_t max_size) const override { | |
1603 | return target_->GetUniqueId(id, max_size); | |
1604 | }; | |
1605 | void Hint(AccessPattern pattern) override { target_->Hint(pattern); } | |
1606 | bool use_direct_io() const override { return target_->use_direct_io(); } | |
1607 | size_t GetRequiredBufferAlignment() const override { | |
1608 | return target_->GetRequiredBufferAlignment(); | |
1609 | } | |
1610 | IOStatus InvalidateCache(size_t offset, size_t length) override { | |
1611 | return target_->InvalidateCache(offset, length); | |
1612 | } | |
1e59de90 TL |
1613 | IOStatus ReadAsync(FSReadRequest& req, const IOOptions& opts, |
1614 | std::function<void(const FSReadRequest&, void*)> cb, | |
1615 | void* cb_arg, void** io_handle, IOHandleDeleter* del_fn, | |
1616 | IODebugContext* dbg) override { | |
1617 | return target()->ReadAsync(req, opts, cb, cb_arg, io_handle, del_fn, dbg); | |
1618 | } | |
1619 | Temperature GetTemperature() const override { | |
1620 | return target_->GetTemperature(); | |
1621 | } | |
f67539c2 TL |
1622 | |
1623 | private: | |
1e59de90 | 1624 | std::unique_ptr<FSRandomAccessFile> guard_; |
f67539c2 TL |
1625 | FSRandomAccessFile* target_; |
1626 | }; | |
1627 | ||
1e59de90 TL |
1628 | class FSRandomAccessFileOwnerWrapper : public FSRandomAccessFileWrapper { |
1629 | public: | |
1630 | // Creates a FileWrapper around the input File object and takes | |
1631 | // ownership of the object | |
1632 | explicit FSRandomAccessFileOwnerWrapper( | |
1633 | std::unique_ptr<FSRandomAccessFile>&& t) | |
1634 | : FSRandomAccessFileWrapper(t.get()), guard_(std::move(t)) {} | |
1635 | ||
1636 | private: | |
1637 | std::unique_ptr<FSRandomAccessFile> guard_; | |
1638 | }; | |
1639 | ||
f67539c2 TL |
1640 | class FSWritableFileWrapper : public FSWritableFile { |
1641 | public: | |
1e59de90 TL |
1642 | // Creates a FileWrapper around the input File object and without |
1643 | // taking ownership of the object | |
f67539c2 TL |
1644 | explicit FSWritableFileWrapper(FSWritableFile* t) : target_(t) {} |
1645 | ||
20effc67 TL |
1646 | FSWritableFile* target() const { return target_; } |
1647 | ||
f67539c2 TL |
1648 | IOStatus Append(const Slice& data, const IOOptions& options, |
1649 | IODebugContext* dbg) override { | |
1650 | return target_->Append(data, options, dbg); | |
1651 | } | |
20effc67 TL |
1652 | IOStatus Append(const Slice& data, const IOOptions& options, |
1653 | const DataVerificationInfo& verification_info, | |
1654 | IODebugContext* dbg) override { | |
1655 | return target_->Append(data, options, verification_info, dbg); | |
1656 | } | |
f67539c2 TL |
1657 | IOStatus PositionedAppend(const Slice& data, uint64_t offset, |
1658 | const IOOptions& options, | |
1659 | IODebugContext* dbg) override { | |
1660 | return target_->PositionedAppend(data, offset, options, dbg); | |
1661 | } | |
20effc67 TL |
1662 | IOStatus PositionedAppend(const Slice& data, uint64_t offset, |
1663 | const IOOptions& options, | |
1664 | const DataVerificationInfo& verification_info, | |
1665 | IODebugContext* dbg) override { | |
1666 | return target_->PositionedAppend(data, offset, options, verification_info, | |
1667 | dbg); | |
1668 | } | |
f67539c2 TL |
1669 | IOStatus Truncate(uint64_t size, const IOOptions& options, |
1670 | IODebugContext* dbg) override { | |
1671 | return target_->Truncate(size, options, dbg); | |
1672 | } | |
1673 | IOStatus Close(const IOOptions& options, IODebugContext* dbg) override { | |
1674 | return target_->Close(options, dbg); | |
1675 | } | |
1676 | IOStatus Flush(const IOOptions& options, IODebugContext* dbg) override { | |
1677 | return target_->Flush(options, dbg); | |
1678 | } | |
1679 | IOStatus Sync(const IOOptions& options, IODebugContext* dbg) override { | |
1680 | return target_->Sync(options, dbg); | |
1681 | } | |
1682 | IOStatus Fsync(const IOOptions& options, IODebugContext* dbg) override { | |
1683 | return target_->Fsync(options, dbg); | |
1684 | } | |
1685 | bool IsSyncThreadSafe() const override { return target_->IsSyncThreadSafe(); } | |
1686 | ||
1687 | bool use_direct_io() const override { return target_->use_direct_io(); } | |
1688 | ||
1689 | size_t GetRequiredBufferAlignment() const override { | |
1690 | return target_->GetRequiredBufferAlignment(); | |
1691 | } | |
1692 | ||
1693 | void SetWriteLifeTimeHint(Env::WriteLifeTimeHint hint) override { | |
1694 | target_->SetWriteLifeTimeHint(hint); | |
1695 | } | |
1696 | ||
1697 | Env::WriteLifeTimeHint GetWriteLifeTimeHint() override { | |
1698 | return target_->GetWriteLifeTimeHint(); | |
1699 | } | |
1700 | ||
1701 | uint64_t GetFileSize(const IOOptions& options, IODebugContext* dbg) override { | |
1702 | return target_->GetFileSize(options, dbg); | |
1703 | } | |
1704 | ||
1705 | void SetPreallocationBlockSize(size_t size) override { | |
1706 | target_->SetPreallocationBlockSize(size); | |
1707 | } | |
1708 | ||
1709 | void GetPreallocationStatus(size_t* block_size, | |
1710 | size_t* last_allocated_block) override { | |
1711 | target_->GetPreallocationStatus(block_size, last_allocated_block); | |
1712 | } | |
1713 | ||
1714 | size_t GetUniqueId(char* id, size_t max_size) const override { | |
1715 | return target_->GetUniqueId(id, max_size); | |
1716 | } | |
1717 | ||
1718 | IOStatus InvalidateCache(size_t offset, size_t length) override { | |
1719 | return target_->InvalidateCache(offset, length); | |
1720 | } | |
1721 | ||
1722 | IOStatus RangeSync(uint64_t offset, uint64_t nbytes, const IOOptions& options, | |
1723 | IODebugContext* dbg) override { | |
1724 | return target_->RangeSync(offset, nbytes, options, dbg); | |
1725 | } | |
1726 | ||
1727 | void PrepareWrite(size_t offset, size_t len, const IOOptions& options, | |
1728 | IODebugContext* dbg) override { | |
1729 | target_->PrepareWrite(offset, len, options, dbg); | |
1730 | } | |
1731 | ||
1732 | IOStatus Allocate(uint64_t offset, uint64_t len, const IOOptions& options, | |
1733 | IODebugContext* dbg) override { | |
1734 | return target_->Allocate(offset, len, options, dbg); | |
1735 | } | |
1736 | ||
1737 | private: | |
1738 | FSWritableFile* target_; | |
1739 | }; | |
1740 | ||
1e59de90 TL |
1741 | class FSWritableFileOwnerWrapper : public FSWritableFileWrapper { |
1742 | public: | |
1743 | // Creates a FileWrapper around the input File object and takes | |
1744 | // ownership of the object | |
1745 | explicit FSWritableFileOwnerWrapper(std::unique_ptr<FSWritableFile>&& t) | |
1746 | : FSWritableFileWrapper(t.get()), guard_(std::move(t)) {} | |
1747 | ||
1748 | private: | |
1749 | std::unique_ptr<FSWritableFile> guard_; | |
1750 | }; | |
1751 | ||
f67539c2 TL |
1752 | class FSRandomRWFileWrapper : public FSRandomRWFile { |
1753 | public: | |
1e59de90 TL |
1754 | // Creates a FileWrapper around the input File object and without |
1755 | // taking ownership of the object | |
20effc67 TL |
1756 | explicit FSRandomRWFileWrapper(FSRandomRWFile* t) : target_(t) {} |
1757 | ||
1758 | FSRandomRWFile* target() const { return target_; } | |
f67539c2 TL |
1759 | |
1760 | bool use_direct_io() const override { return target_->use_direct_io(); } | |
1761 | size_t GetRequiredBufferAlignment() const override { | |
1762 | return target_->GetRequiredBufferAlignment(); | |
1763 | } | |
1764 | IOStatus Write(uint64_t offset, const Slice& data, const IOOptions& options, | |
1765 | IODebugContext* dbg) override { | |
1766 | return target_->Write(offset, data, options, dbg); | |
1767 | } | |
1768 | IOStatus Read(uint64_t offset, size_t n, const IOOptions& options, | |
1769 | Slice* result, char* scratch, | |
1770 | IODebugContext* dbg) const override { | |
1771 | return target_->Read(offset, n, options, result, scratch, dbg); | |
1772 | } | |
1773 | IOStatus Flush(const IOOptions& options, IODebugContext* dbg) override { | |
1774 | return target_->Flush(options, dbg); | |
1775 | } | |
1776 | IOStatus Sync(const IOOptions& options, IODebugContext* dbg) override { | |
1777 | return target_->Sync(options, dbg); | |
1778 | } | |
1779 | IOStatus Fsync(const IOOptions& options, IODebugContext* dbg) override { | |
1780 | return target_->Fsync(options, dbg); | |
1781 | } | |
1782 | IOStatus Close(const IOOptions& options, IODebugContext* dbg) override { | |
1783 | return target_->Close(options, dbg); | |
1784 | } | |
1e59de90 TL |
1785 | Temperature GetTemperature() const override { |
1786 | return target_->GetTemperature(); | |
1787 | } | |
f67539c2 TL |
1788 | |
1789 | private: | |
1790 | FSRandomRWFile* target_; | |
1791 | }; | |
1792 | ||
1e59de90 TL |
1793 | class FSRandomRWFileOwnerWrapper : public FSRandomRWFileWrapper { |
1794 | public: | |
1795 | // Creates a FileWrapper around the input File object and takes | |
1796 | // ownership of the object | |
1797 | explicit FSRandomRWFileOwnerWrapper(std::unique_ptr<FSRandomRWFile>&& t) | |
1798 | : FSRandomRWFileWrapper(t.get()), guard_(std::move(t)) {} | |
1799 | ||
1800 | private: | |
1801 | std::unique_ptr<FSRandomRWFile> guard_; | |
1802 | }; | |
1803 | ||
f67539c2 TL |
1804 | class FSDirectoryWrapper : public FSDirectory { |
1805 | public: | |
1e59de90 TL |
1806 | // Creates a FileWrapper around the input File object and takes |
1807 | // ownership of the object | |
1808 | explicit FSDirectoryWrapper(std::unique_ptr<FSDirectory>&& t) | |
1809 | : guard_(std::move(t)) { | |
1810 | target_ = guard_.get(); | |
1811 | } | |
1812 | ||
1813 | // Creates a FileWrapper around the input File object and without | |
1814 | // taking ownership of the object | |
20effc67 | 1815 | explicit FSDirectoryWrapper(FSDirectory* t) : target_(t) {} |
f67539c2 TL |
1816 | |
1817 | IOStatus Fsync(const IOOptions& options, IODebugContext* dbg) override { | |
1818 | return target_->Fsync(options, dbg); | |
1819 | } | |
1e59de90 TL |
1820 | |
1821 | IOStatus FsyncWithDirOptions( | |
1822 | const IOOptions& options, IODebugContext* dbg, | |
1823 | const DirFsyncOptions& dir_fsync_options) override { | |
1824 | return target_->FsyncWithDirOptions(options, dbg, dir_fsync_options); | |
1825 | } | |
1826 | ||
1827 | IOStatus Close(const IOOptions& options, IODebugContext* dbg) override { | |
1828 | return target_->Close(options, dbg); | |
1829 | } | |
1830 | ||
f67539c2 TL |
1831 | size_t GetUniqueId(char* id, size_t max_size) const override { |
1832 | return target_->GetUniqueId(id, max_size); | |
1833 | } | |
1834 | ||
1835 | private: | |
1e59de90 | 1836 | std::unique_ptr<FSDirectory> guard_; |
f67539c2 TL |
1837 | FSDirectory* target_; |
1838 | }; | |
1839 | ||
20effc67 TL |
1840 | // A utility routine: write "data" to the named file. |
1841 | extern IOStatus WriteStringToFile(FileSystem* fs, const Slice& data, | |
1842 | const std::string& fname, | |
1843 | bool should_sync = false); | |
1844 | ||
f67539c2 | 1845 | // A utility routine: read contents of named file into *data |
20effc67 TL |
1846 | extern IOStatus ReadFileToString(FileSystem* fs, const std::string& fname, |
1847 | std::string* data); | |
f67539c2 TL |
1848 | |
1849 | } // namespace ROCKSDB_NAMESPACE |