mock_env.cc 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062
  1. // Copyright (c) 2011-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. // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
  7. // Use of this source code is governed by a BSD-style license that can be
  8. // found in the LICENSE file. See the AUTHORS file for names of contributors.
  9. #include "env/mock_env.h"
  10. #include <algorithm>
  11. #include <chrono>
  12. #include "env/emulated_clock.h"
  13. #include "file/filename.h"
  14. #include "port/sys_time.h"
  15. #include "rocksdb/file_system.h"
  16. #include "rocksdb/utilities/options_type.h"
  17. #include "test_util/sync_point.h"
  18. #include "util/cast_util.h"
  19. #include "util/hash.h"
  20. #include "util/random.h"
  21. #include "util/rate_limiter_impl.h"
  22. #include "util/string_util.h"
  23. namespace ROCKSDB_NAMESPACE {
  24. namespace {
  25. int64_t MaybeCurrentTime(const std::shared_ptr<SystemClock>& clock) {
  26. int64_t time = 1337346000; // arbitrary fallback default
  27. clock->GetCurrentTime(&time).PermitUncheckedError();
  28. return time;
  29. }
  30. static std::unordered_map<std::string, OptionTypeInfo> time_elapse_type_info = {
  31. {"time_elapse_only_sleep",
  32. {0, OptionType::kBoolean, OptionVerificationType::kNormal,
  33. OptionTypeFlags::kCompareNever,
  34. [](const ConfigOptions& /*opts*/, const std::string& /*name*/,
  35. const std::string& value, void* addr) {
  36. auto clock = static_cast<EmulatedSystemClock*>(addr);
  37. clock->SetTimeElapseOnlySleep(ParseBoolean("", value));
  38. return Status::OK();
  39. },
  40. [](const ConfigOptions& /*opts*/, const std::string& /*name*/,
  41. const void* addr, std::string* value) {
  42. const auto clock = static_cast<const EmulatedSystemClock*>(addr);
  43. *value = clock->IsTimeElapseOnlySleep() ? "true" : "false";
  44. return Status::OK();
  45. },
  46. nullptr}},
  47. };
  48. static std::unordered_map<std::string, OptionTypeInfo> mock_sleep_type_info = {
  49. {"mock_sleep",
  50. {0, OptionType::kBoolean, OptionVerificationType::kNormal,
  51. OptionTypeFlags::kCompareNever,
  52. [](const ConfigOptions& /*opts*/, const std::string& /*name*/,
  53. const std::string& value, void* addr) {
  54. auto clock = static_cast<EmulatedSystemClock*>(addr);
  55. clock->SetMockSleep(ParseBoolean("", value));
  56. return Status::OK();
  57. },
  58. [](const ConfigOptions& /*opts*/, const std::string& /*name*/,
  59. const void* addr, std::string* value) {
  60. const auto clock = static_cast<const EmulatedSystemClock*>(addr);
  61. *value = clock->IsMockSleepEnabled() ? "true" : "false";
  62. return Status::OK();
  63. },
  64. nullptr}},
  65. };
  66. } // namespace
  67. EmulatedSystemClock::EmulatedSystemClock(
  68. const std::shared_ptr<SystemClock>& base, bool time_elapse_only_sleep)
  69. : SystemClockWrapper(base),
  70. maybe_starting_time_(MaybeCurrentTime(base)),
  71. time_elapse_only_sleep_(time_elapse_only_sleep),
  72. no_slowdown_(time_elapse_only_sleep) {
  73. RegisterOptions("", this, &time_elapse_type_info);
  74. RegisterOptions("", this, &mock_sleep_type_info);
  75. }
  76. class MemFile {
  77. public:
  78. explicit MemFile(SystemClock* clock, const std::string& fn,
  79. bool _is_lock_file = false)
  80. : clock_(clock),
  81. fn_(fn),
  82. refs_(0),
  83. is_lock_file_(_is_lock_file),
  84. locked_(false),
  85. size_(0),
  86. modified_time_(Now()),
  87. rnd_(Lower32of64(GetSliceNPHash64(fn))),
  88. fsynced_bytes_(0) {}
  89. // No copying allowed.
  90. MemFile(const MemFile&) = delete;
  91. void operator=(const MemFile&) = delete;
  92. void Ref() {
  93. MutexLock lock(&mutex_);
  94. ++refs_;
  95. }
  96. bool is_lock_file() const { return is_lock_file_; }
  97. bool Lock() {
  98. assert(is_lock_file_);
  99. MutexLock lock(&mutex_);
  100. if (locked_) {
  101. return false;
  102. } else {
  103. locked_ = true;
  104. return true;
  105. }
  106. }
  107. void Unlock() {
  108. assert(is_lock_file_);
  109. MutexLock lock(&mutex_);
  110. locked_ = false;
  111. }
  112. void Unref() {
  113. bool do_delete = false;
  114. {
  115. MutexLock lock(&mutex_);
  116. --refs_;
  117. assert(refs_ >= 0);
  118. if (refs_ <= 0) {
  119. do_delete = true;
  120. }
  121. }
  122. if (do_delete) {
  123. delete this;
  124. }
  125. }
  126. uint64_t Size() const { return size_; }
  127. void Truncate(size_t size, const IOOptions& /*options*/,
  128. IODebugContext* /*dbg*/) {
  129. MutexLock lock(&mutex_);
  130. if (size < size_) {
  131. data_.resize(size);
  132. size_ = size;
  133. }
  134. }
  135. void CorruptBuffer() {
  136. if (fsynced_bytes_ >= size_) {
  137. return;
  138. }
  139. uint64_t buffered_bytes = size_ - fsynced_bytes_;
  140. uint64_t start =
  141. fsynced_bytes_ + rnd_.Uniform(static_cast<int>(buffered_bytes));
  142. uint64_t end = std::min(start + 512, size_.load());
  143. MutexLock lock(&mutex_);
  144. for (uint64_t pos = start; pos < end; ++pos) {
  145. data_[static_cast<size_t>(pos)] = static_cast<char>(rnd_.Uniform(256));
  146. }
  147. }
  148. IOStatus Read(uint64_t offset, size_t n, const IOOptions& /*options*/,
  149. Slice* result, char* scratch, IODebugContext* /*dbg*/) const {
  150. {
  151. IOStatus s;
  152. TEST_SYNC_POINT_CALLBACK("MemFile::Read:IOStatus", &s);
  153. if (!s.ok()) {
  154. // with sync point only
  155. *result = Slice();
  156. return s;
  157. }
  158. }
  159. MutexLock lock(&mutex_);
  160. const uint64_t available = Size() - std::min(Size(), offset);
  161. size_t offset_ = static_cast<size_t>(offset);
  162. if (n > available) {
  163. n = static_cast<size_t>(available);
  164. }
  165. if (n == 0) {
  166. *result = Slice();
  167. return IOStatus::OK();
  168. }
  169. if (scratch) {
  170. memcpy(scratch, &(data_[offset_]), n);
  171. *result = Slice(scratch, n);
  172. } else {
  173. *result = Slice(&(data_[offset_]), n);
  174. }
  175. return IOStatus::OK();
  176. }
  177. IOStatus Write(uint64_t offset, const Slice& data,
  178. const IOOptions& /*options*/, IODebugContext* /*dbg*/) {
  179. MutexLock lock(&mutex_);
  180. size_t offset_ = static_cast<size_t>(offset);
  181. if (offset + data.size() > data_.size()) {
  182. data_.resize(offset_ + data.size());
  183. }
  184. data_.replace(offset_, data.size(), data.data(), data.size());
  185. size_ = data_.size();
  186. modified_time_ = Now();
  187. return IOStatus::OK();
  188. }
  189. IOStatus Append(const Slice& data, const IOOptions& /*options*/,
  190. IODebugContext* /*dbg*/) {
  191. MutexLock lock(&mutex_);
  192. data_.append(data.data(), data.size());
  193. size_ = data_.size();
  194. modified_time_ = Now();
  195. return IOStatus::OK();
  196. }
  197. IOStatus Fsync(const IOOptions& /*options*/, IODebugContext* /*dbg*/) {
  198. fsynced_bytes_ = size_.load();
  199. return IOStatus::OK();
  200. }
  201. uint64_t ModifiedTime() const { return modified_time_; }
  202. private:
  203. uint64_t Now() {
  204. int64_t unix_time = 0;
  205. auto s = clock_->GetCurrentTime(&unix_time);
  206. assert(s.ok());
  207. return static_cast<uint64_t>(unix_time);
  208. }
  209. // Private since only Unref() should be used to delete it.
  210. ~MemFile() { assert(refs_ == 0); }
  211. SystemClock* clock_;
  212. const std::string fn_;
  213. mutable port::Mutex mutex_;
  214. int refs_;
  215. bool is_lock_file_;
  216. bool locked_;
  217. // Data written into this file, all bytes before fsynced_bytes are
  218. // persistent.
  219. std::string data_;
  220. std::atomic<uint64_t> size_;
  221. std::atomic<uint64_t> modified_time_;
  222. Random rnd_;
  223. std::atomic<uint64_t> fsynced_bytes_;
  224. };
  225. namespace {
  226. class MockSequentialFile : public FSSequentialFile {
  227. public:
  228. explicit MockSequentialFile(MemFile* file, const FileOptions& opts)
  229. : file_(file),
  230. use_direct_io_(opts.use_direct_reads),
  231. use_mmap_read_(opts.use_mmap_reads),
  232. pos_(0) {
  233. file_->Ref();
  234. }
  235. ~MockSequentialFile() override { file_->Unref(); }
  236. IOStatus Read(size_t n, const IOOptions& options, Slice* result,
  237. char* scratch, IODebugContext* dbg) override {
  238. IOStatus s = file_->Read(pos_, n, options, result,
  239. (use_mmap_read_) ? nullptr : scratch, dbg);
  240. if (s.ok()) {
  241. pos_ += result->size();
  242. }
  243. return s;
  244. }
  245. bool use_direct_io() const override { return use_direct_io_; }
  246. IOStatus Skip(uint64_t n) override {
  247. if (pos_ > file_->Size()) {
  248. return IOStatus::IOError("pos_ > file_->Size()");
  249. }
  250. const uint64_t available = file_->Size() - pos_;
  251. if (n > available) {
  252. n = available;
  253. }
  254. pos_ += static_cast<size_t>(n);
  255. return IOStatus::OK();
  256. }
  257. private:
  258. MemFile* file_;
  259. bool use_direct_io_;
  260. bool use_mmap_read_;
  261. size_t pos_;
  262. };
  263. class MockRandomAccessFile : public FSRandomAccessFile {
  264. public:
  265. explicit MockRandomAccessFile(MemFile* file, const FileOptions& opts)
  266. : file_(file),
  267. use_direct_io_(opts.use_direct_reads),
  268. use_mmap_read_(opts.use_mmap_reads) {
  269. file_->Ref();
  270. }
  271. ~MockRandomAccessFile() override { file_->Unref(); }
  272. bool use_direct_io() const override { return use_direct_io_; }
  273. IOStatus Prefetch(uint64_t /*offset*/, size_t /*n*/,
  274. const IOOptions& /*options*/,
  275. IODebugContext* /*dbg*/) override {
  276. return IOStatus::OK();
  277. }
  278. IOStatus Read(uint64_t offset, size_t n, const IOOptions& options,
  279. Slice* result, char* scratch,
  280. IODebugContext* dbg) const override {
  281. if (use_mmap_read_) {
  282. return file_->Read(offset, n, options, result, nullptr, dbg);
  283. } else {
  284. return file_->Read(offset, n, options, result, scratch, dbg);
  285. }
  286. }
  287. IOStatus GetFileSize(uint64_t* size) override {
  288. *size = file_->Size();
  289. return IOStatus::OK();
  290. }
  291. private:
  292. MemFile* file_;
  293. bool use_direct_io_;
  294. bool use_mmap_read_;
  295. };
  296. class MockRandomRWFile : public FSRandomRWFile {
  297. public:
  298. explicit MockRandomRWFile(MemFile* file) : file_(file) { file_->Ref(); }
  299. ~MockRandomRWFile() override { file_->Unref(); }
  300. IOStatus Write(uint64_t offset, const Slice& data, const IOOptions& options,
  301. IODebugContext* dbg) override {
  302. return file_->Write(offset, data, options, dbg);
  303. }
  304. IOStatus Read(uint64_t offset, size_t n, const IOOptions& options,
  305. Slice* result, char* scratch,
  306. IODebugContext* dbg) const override {
  307. return file_->Read(offset, n, options, result, scratch, dbg);
  308. }
  309. IOStatus Close(const IOOptions& options, IODebugContext* dbg) override {
  310. return file_->Fsync(options, dbg);
  311. }
  312. IOStatus Flush(const IOOptions& /*options*/,
  313. IODebugContext* /*dbg*/) override {
  314. return IOStatus::OK();
  315. }
  316. IOStatus Sync(const IOOptions& options, IODebugContext* dbg) override {
  317. return file_->Fsync(options, dbg);
  318. }
  319. private:
  320. MemFile* file_;
  321. };
  322. class MockWritableFile : public FSWritableFile {
  323. public:
  324. MockWritableFile(MemFile* file, const FileOptions& opts)
  325. : file_(file),
  326. use_direct_io_(opts.use_direct_writes),
  327. rate_limiter_(opts.rate_limiter) {
  328. file_->Ref();
  329. }
  330. ~MockWritableFile() override { file_->Unref(); }
  331. bool use_direct_io() const override { return false && use_direct_io_; }
  332. using FSWritableFile::Append;
  333. IOStatus Append(const Slice& data, const IOOptions& options,
  334. IODebugContext* dbg) override {
  335. size_t bytes_written = 0;
  336. while (bytes_written < data.size()) {
  337. auto bytes = RequestToken(data.size() - bytes_written);
  338. IOStatus s = file_->Append(Slice(data.data() + bytes_written, bytes),
  339. options, dbg);
  340. if (!s.ok()) {
  341. return s;
  342. }
  343. bytes_written += bytes;
  344. }
  345. return IOStatus::OK();
  346. }
  347. using FSWritableFile::PositionedAppend;
  348. IOStatus PositionedAppend(const Slice& data, uint64_t /*offset*/,
  349. const IOOptions& options,
  350. IODebugContext* dbg) override {
  351. assert(use_direct_io_);
  352. return Append(data, options, dbg);
  353. }
  354. IOStatus Truncate(uint64_t size, const IOOptions& options,
  355. IODebugContext* dbg) override {
  356. file_->Truncate(static_cast<size_t>(size), options, dbg);
  357. return IOStatus::OK();
  358. }
  359. IOStatus Close(const IOOptions& options, IODebugContext* dbg) override {
  360. return file_->Fsync(options, dbg);
  361. }
  362. IOStatus Flush(const IOOptions& /*options*/,
  363. IODebugContext* /*dbg*/) override {
  364. return IOStatus::OK();
  365. }
  366. IOStatus Sync(const IOOptions& options, IODebugContext* dbg) override {
  367. return file_->Fsync(options, dbg);
  368. }
  369. uint64_t GetFileSize(const IOOptions& /*options*/,
  370. IODebugContext* /*dbg*/) override {
  371. return file_->Size();
  372. }
  373. private:
  374. inline size_t RequestToken(size_t bytes) {
  375. if (rate_limiter_ && io_priority_ < Env::IO_TOTAL) {
  376. bytes = std::min(
  377. bytes, static_cast<size_t>(rate_limiter_->GetSingleBurstBytes()));
  378. rate_limiter_->Request(bytes, io_priority_);
  379. }
  380. return bytes;
  381. }
  382. MemFile* file_;
  383. bool use_direct_io_;
  384. RateLimiter* rate_limiter_;
  385. };
  386. class MockEnvDirectory : public FSDirectory {
  387. public:
  388. IOStatus Fsync(const IOOptions& /*options*/,
  389. IODebugContext* /*dbg*/) override {
  390. return IOStatus::OK();
  391. }
  392. IOStatus Close(const IOOptions& /*options*/,
  393. IODebugContext* /*dbg*/) override {
  394. return IOStatus::OK();
  395. }
  396. };
  397. class MockEnvFileLock : public FileLock {
  398. public:
  399. explicit MockEnvFileLock(const std::string& fname) : fname_(fname) {}
  400. std::string FileName() const { return fname_; }
  401. private:
  402. const std::string fname_;
  403. };
  404. class TestMemLogger : public Logger {
  405. private:
  406. std::unique_ptr<FSWritableFile> file_;
  407. std::atomic_size_t log_size_;
  408. static const uint64_t flush_every_seconds_ = 5;
  409. std::atomic_uint_fast64_t last_flush_micros_;
  410. SystemClock* clock_;
  411. IOOptions options_;
  412. IODebugContext* dbg_;
  413. std::atomic<bool> flush_pending_;
  414. public:
  415. TestMemLogger(std::unique_ptr<FSWritableFile> f, SystemClock* clock,
  416. const IOOptions& options, IODebugContext* dbg,
  417. const InfoLogLevel log_level = InfoLogLevel::ERROR_LEVEL)
  418. : Logger(log_level),
  419. file_(std::move(f)),
  420. log_size_(0),
  421. last_flush_micros_(0),
  422. clock_(clock),
  423. options_(options),
  424. dbg_(dbg),
  425. flush_pending_(false) {}
  426. ~TestMemLogger() override = default;
  427. void Flush() override {
  428. if (flush_pending_) {
  429. flush_pending_ = false;
  430. }
  431. last_flush_micros_ = clock_->NowMicros();
  432. }
  433. using Logger::Logv;
  434. void Logv(const char* format, va_list ap) override {
  435. // We try twice: the first time with a fixed-size stack allocated buffer,
  436. // and the second time with a much larger dynamically allocated buffer.
  437. char buffer[500];
  438. for (int iter = 0; iter < 2; iter++) {
  439. char* base;
  440. int bufsize;
  441. if (iter == 0) {
  442. bufsize = sizeof(buffer);
  443. base = buffer;
  444. } else {
  445. bufsize = 30000;
  446. base = new char[bufsize];
  447. }
  448. char* p = base;
  449. char* limit = base + bufsize;
  450. port::TimeVal now_tv;
  451. port::GetTimeOfDay(&now_tv, nullptr);
  452. const time_t seconds = now_tv.tv_sec;
  453. struct tm t;
  454. memset(&t, 0, sizeof(t));
  455. struct tm* ret __attribute__((__unused__));
  456. ret = port::LocalTimeR(&seconds, &t);
  457. assert(ret);
  458. p += snprintf(p, limit - p, "%04d/%02d/%02d-%02d:%02d:%02d.%06d ",
  459. t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour,
  460. t.tm_min, t.tm_sec, static_cast<int>(now_tv.tv_usec));
  461. // Print the message
  462. if (p < limit) {
  463. va_list backup_ap;
  464. va_copy(backup_ap, ap);
  465. p += vsnprintf(p, limit - p, format, backup_ap);
  466. va_end(backup_ap);
  467. }
  468. // Truncate to available space if necessary
  469. if (p >= limit) {
  470. if (iter == 0) {
  471. continue; // Try again with larger buffer
  472. } else {
  473. p = limit - 1;
  474. }
  475. }
  476. // Add newline if necessary
  477. if (p == base || p[-1] != '\n') {
  478. *p++ = '\n';
  479. }
  480. assert(p <= limit);
  481. const size_t write_size = p - base;
  482. Status s = file_->Append(Slice(base, write_size), options_, dbg_);
  483. if (s.ok()) {
  484. flush_pending_ = true;
  485. log_size_ += write_size;
  486. }
  487. uint64_t now_micros =
  488. static_cast<uint64_t>(now_tv.tv_sec) * 1000000 + now_tv.tv_usec;
  489. if (now_micros - last_flush_micros_ >= flush_every_seconds_ * 1000000) {
  490. flush_pending_ = false;
  491. last_flush_micros_ = now_micros;
  492. }
  493. if (base != buffer) {
  494. delete[] base;
  495. }
  496. break;
  497. }
  498. }
  499. size_t GetLogFileSize() const override { return log_size_; }
  500. };
  501. static std::unordered_map<std::string, OptionTypeInfo> mock_fs_type_info = {
  502. {"supports_direct_io",
  503. {0, OptionType::kBoolean, OptionVerificationType::kNormal,
  504. OptionTypeFlags::kNone}},
  505. };
  506. } // namespace
  507. MockFileSystem::MockFileSystem(const std::shared_ptr<SystemClock>& clock,
  508. bool supports_direct_io)
  509. : system_clock_(clock), supports_direct_io_(supports_direct_io) {
  510. clock_ = system_clock_.get();
  511. RegisterOptions("", &supports_direct_io_, &mock_fs_type_info);
  512. }
  513. MockFileSystem::~MockFileSystem() {
  514. for (auto i = file_map_.begin(); i != file_map_.end(); ++i) {
  515. i->second->Unref();
  516. }
  517. }
  518. Status MockFileSystem::PrepareOptions(const ConfigOptions& options) {
  519. Status s = FileSystem::PrepareOptions(options);
  520. if (s.ok() && system_clock_ == SystemClock::Default()) {
  521. system_clock_ = options.env->GetSystemClock();
  522. clock_ = system_clock_.get();
  523. }
  524. return s;
  525. }
  526. IOStatus MockFileSystem::GetAbsolutePath(const std::string& db_path,
  527. const IOOptions& /*options*/,
  528. std::string* output_path,
  529. IODebugContext* /*dbg*/) {
  530. *output_path = NormalizeMockPath(db_path);
  531. if (output_path->at(0) != '/') {
  532. return IOStatus::NotSupported("GetAbsolutePath");
  533. } else {
  534. return IOStatus::OK();
  535. }
  536. }
  537. std::string MockFileSystem::NormalizeMockPath(const std::string& path) {
  538. std::string p = NormalizePath(path);
  539. if (p.back() == kFilePathSeparator && p.size() > 1) {
  540. p.pop_back();
  541. }
  542. return p;
  543. }
  544. // Partial implementation of the FileSystem interface.
  545. IOStatus MockFileSystem::NewSequentialFile(
  546. const std::string& fname, const FileOptions& file_opts,
  547. std::unique_ptr<FSSequentialFile>* result, IODebugContext* /*dbg*/) {
  548. auto fn = NormalizeMockPath(fname);
  549. MutexLock lock(&mutex_);
  550. if (file_map_.find(fn) == file_map_.end()) {
  551. *result = nullptr;
  552. return IOStatus::PathNotFound(fn);
  553. }
  554. auto* f = file_map_[fn];
  555. if (f->is_lock_file()) {
  556. return IOStatus::InvalidArgument(fn, "Cannot open a lock file.");
  557. } else if (file_opts.use_direct_reads && !supports_direct_io_) {
  558. return IOStatus::NotSupported("Direct I/O Not Supported");
  559. } else {
  560. result->reset(new MockSequentialFile(f, file_opts));
  561. return IOStatus::OK();
  562. }
  563. }
  564. IOStatus MockFileSystem::NewRandomAccessFile(
  565. const std::string& fname, const FileOptions& file_opts,
  566. std::unique_ptr<FSRandomAccessFile>* result, IODebugContext* /*dbg*/) {
  567. auto fn = NormalizeMockPath(fname);
  568. MutexLock lock(&mutex_);
  569. if (file_map_.find(fn) == file_map_.end()) {
  570. *result = nullptr;
  571. return IOStatus::PathNotFound(fn);
  572. }
  573. auto* f = file_map_[fn];
  574. if (f->is_lock_file()) {
  575. return IOStatus::InvalidArgument(fn, "Cannot open a lock file.");
  576. } else if (file_opts.use_direct_reads && !supports_direct_io_) {
  577. return IOStatus::NotSupported("Direct I/O Not Supported");
  578. } else {
  579. result->reset(new MockRandomAccessFile(f, file_opts));
  580. return IOStatus::OK();
  581. }
  582. }
  583. IOStatus MockFileSystem::NewRandomRWFile(
  584. const std::string& fname, const FileOptions& /*file_opts*/,
  585. std::unique_ptr<FSRandomRWFile>* result, IODebugContext* /*dbg*/) {
  586. auto fn = NormalizeMockPath(fname);
  587. MutexLock lock(&mutex_);
  588. if (file_map_.find(fn) == file_map_.end()) {
  589. *result = nullptr;
  590. return IOStatus::PathNotFound(fn);
  591. }
  592. auto* f = file_map_[fn];
  593. if (f->is_lock_file()) {
  594. return IOStatus::InvalidArgument(fn, "Cannot open a lock file.");
  595. }
  596. result->reset(new MockRandomRWFile(f));
  597. return IOStatus::OK();
  598. }
  599. IOStatus MockFileSystem::ReuseWritableFile(
  600. const std::string& fname, const std::string& old_fname,
  601. const FileOptions& options, std::unique_ptr<FSWritableFile>* result,
  602. IODebugContext* dbg) {
  603. auto s = RenameFile(old_fname, fname, IOOptions(), dbg);
  604. if (!s.ok()) {
  605. return s;
  606. } else {
  607. result->reset();
  608. return NewWritableFile(fname, options, result, dbg);
  609. }
  610. }
  611. IOStatus MockFileSystem::NewWritableFile(
  612. const std::string& fname, const FileOptions& file_opts,
  613. std::unique_ptr<FSWritableFile>* result, IODebugContext* /*dbg*/) {
  614. auto fn = NormalizeMockPath(fname);
  615. MutexLock lock(&mutex_);
  616. if (file_map_.find(fn) != file_map_.end()) {
  617. DeleteFileInternal(fn);
  618. }
  619. MemFile* file = new MemFile(clock_, fn, false);
  620. file->Ref();
  621. file_map_[fn] = file;
  622. if (file_opts.use_direct_writes && !supports_direct_io_) {
  623. return IOStatus::NotSupported("Direct I/O Not Supported");
  624. } else {
  625. result->reset(new MockWritableFile(file, file_opts));
  626. return IOStatus::OK();
  627. }
  628. }
  629. IOStatus MockFileSystem::ReopenWritableFile(
  630. const std::string& fname, const FileOptions& file_opts,
  631. std::unique_ptr<FSWritableFile>* result, IODebugContext* /*dbg*/) {
  632. auto fn = NormalizeMockPath(fname);
  633. MutexLock lock(&mutex_);
  634. MemFile* file = nullptr;
  635. if (file_map_.find(fn) == file_map_.end()) {
  636. file = new MemFile(clock_, fn, false);
  637. // Only take a reference when we create the file objectt
  638. file->Ref();
  639. file_map_[fn] = file;
  640. } else {
  641. file = file_map_[fn];
  642. }
  643. if (file_opts.use_direct_writes && !supports_direct_io_) {
  644. return IOStatus::NotSupported("Direct I/O Not Supported");
  645. } else {
  646. result->reset(new MockWritableFile(file, file_opts));
  647. return IOStatus::OK();
  648. }
  649. }
  650. IOStatus MockFileSystem::NewDirectory(const std::string& /*name*/,
  651. const IOOptions& /*io_opts*/,
  652. std::unique_ptr<FSDirectory>* result,
  653. IODebugContext* /*dbg*/) {
  654. result->reset(new MockEnvDirectory());
  655. return IOStatus::OK();
  656. }
  657. IOStatus MockFileSystem::FileExists(const std::string& fname,
  658. const IOOptions& /*io_opts*/,
  659. IODebugContext* /*dbg*/) {
  660. auto fn = NormalizeMockPath(fname);
  661. MutexLock lock(&mutex_);
  662. if (file_map_.find(fn) != file_map_.end()) {
  663. // File exists
  664. return IOStatus::OK();
  665. }
  666. // Now also check if fn exists as a dir
  667. for (const auto& iter : file_map_) {
  668. const std::string& filename = iter.first;
  669. if (filename.size() >= fn.size() + 1 && filename[fn.size()] == '/' &&
  670. Slice(filename).starts_with(Slice(fn))) {
  671. return IOStatus::OK();
  672. }
  673. }
  674. return IOStatus::NotFound();
  675. }
  676. bool MockFileSystem::GetChildrenInternal(const std::string& dir,
  677. std::vector<std::string>* result) {
  678. auto d = NormalizeMockPath(dir);
  679. bool found_dir = false;
  680. result->clear();
  681. for (const auto& iter : file_map_) {
  682. const std::string& filename = iter.first;
  683. if (filename == d) {
  684. found_dir = true;
  685. } else if (filename.size() >= d.size() + 1 && filename[d.size()] == '/' &&
  686. Slice(filename).starts_with(Slice(d))) {
  687. found_dir = true;
  688. size_t next_slash = filename.find('/', d.size() + 1);
  689. if (next_slash != std::string::npos) {
  690. result->push_back(
  691. filename.substr(d.size() + 1, next_slash - d.size() - 1));
  692. } else {
  693. result->push_back(filename.substr(d.size() + 1));
  694. }
  695. }
  696. }
  697. result->erase(std::unique(result->begin(), result->end()), result->end());
  698. return found_dir;
  699. }
  700. IOStatus MockFileSystem::GetChildren(const std::string& dir,
  701. const IOOptions& /*options*/,
  702. std::vector<std::string>* result,
  703. IODebugContext* /*dbg*/) {
  704. MutexLock lock(&mutex_);
  705. bool found_dir = GetChildrenInternal(dir, result);
  706. #ifndef __clang_analyzer__
  707. return found_dir ? IOStatus::OK() : IOStatus::NotFound(dir);
  708. #else
  709. return found_dir ? IOStatus::OK() : IOStatus::NotFound();
  710. #endif
  711. }
  712. void MockFileSystem::DeleteFileInternal(const std::string& fname) {
  713. assert(fname == NormalizeMockPath(fname));
  714. const auto& pair = file_map_.find(fname);
  715. if (pair != file_map_.end()) {
  716. pair->second->Unref();
  717. file_map_.erase(fname);
  718. }
  719. }
  720. IOStatus MockFileSystem::DeleteFile(const std::string& fname,
  721. const IOOptions& /*options*/,
  722. IODebugContext* /*dbg*/) {
  723. auto fn = NormalizeMockPath(fname);
  724. MutexLock lock(&mutex_);
  725. if (file_map_.find(fn) == file_map_.end()) {
  726. return IOStatus::PathNotFound(fn);
  727. }
  728. DeleteFileInternal(fn);
  729. return IOStatus::OK();
  730. }
  731. IOStatus MockFileSystem::Truncate(const std::string& fname, size_t size,
  732. const IOOptions& options,
  733. IODebugContext* dbg) {
  734. auto fn = NormalizeMockPath(fname);
  735. MutexLock lock(&mutex_);
  736. auto iter = file_map_.find(fn);
  737. if (iter == file_map_.end()) {
  738. return IOStatus::PathNotFound(fn);
  739. }
  740. iter->second->Truncate(size, options, dbg);
  741. return IOStatus::OK();
  742. }
  743. IOStatus MockFileSystem::CreateDir(const std::string& dirname,
  744. const IOOptions& /*options*/,
  745. IODebugContext* /*dbg*/) {
  746. auto dn = NormalizeMockPath(dirname);
  747. MutexLock lock(&mutex_);
  748. if (file_map_.find(dn) == file_map_.end()) {
  749. MemFile* file = new MemFile(clock_, dn, false);
  750. file->Ref();
  751. file_map_[dn] = file;
  752. } else {
  753. return IOStatus::IOError();
  754. }
  755. return IOStatus::OK();
  756. }
  757. IOStatus MockFileSystem::CreateDirIfMissing(const std::string& dirname,
  758. const IOOptions& options,
  759. IODebugContext* dbg) {
  760. CreateDir(dirname, options, dbg).PermitUncheckedError();
  761. return IOStatus::OK();
  762. }
  763. IOStatus MockFileSystem::DeleteDir(const std::string& dirname,
  764. const IOOptions& /*options*/,
  765. IODebugContext* /*dbg*/) {
  766. auto dir = NormalizeMockPath(dirname);
  767. MutexLock lock(&mutex_);
  768. if (file_map_.find(dir) == file_map_.end()) {
  769. return IOStatus::PathNotFound(dir);
  770. } else {
  771. std::vector<std::string> children;
  772. if (GetChildrenInternal(dir, &children)) {
  773. for (const auto& child : children) {
  774. DeleteFileInternal(child);
  775. }
  776. }
  777. DeleteFileInternal(dir);
  778. return IOStatus::OK();
  779. }
  780. }
  781. IOStatus MockFileSystem::GetFileSize(const std::string& fname,
  782. const IOOptions& /*options*/,
  783. uint64_t* file_size,
  784. IODebugContext* /*dbg*/) {
  785. auto fn = NormalizeMockPath(fname);
  786. TEST_SYNC_POINT_CALLBACK("MockFileSystem::GetFileSize:CheckFileType", &fn);
  787. MutexLock lock(&mutex_);
  788. auto iter = file_map_.find(fn);
  789. if (iter == file_map_.end()) {
  790. return IOStatus::PathNotFound(fn);
  791. }
  792. *file_size = iter->second->Size();
  793. return IOStatus::OK();
  794. }
  795. IOStatus MockFileSystem::GetFileModificationTime(const std::string& fname,
  796. const IOOptions& /*options*/,
  797. uint64_t* time,
  798. IODebugContext* /*dbg*/) {
  799. auto fn = NormalizeMockPath(fname);
  800. MutexLock lock(&mutex_);
  801. auto iter = file_map_.find(fn);
  802. if (iter == file_map_.end()) {
  803. return IOStatus::PathNotFound(fn);
  804. }
  805. *time = iter->second->ModifiedTime();
  806. return IOStatus::OK();
  807. }
  808. bool MockFileSystem::RenameFileInternal(const std::string& src,
  809. const std::string& dest) {
  810. if (file_map_.find(src) == file_map_.end()) {
  811. return false;
  812. } else {
  813. std::vector<std::string> children;
  814. if (GetChildrenInternal(src, &children)) {
  815. for (const auto& child : children) {
  816. RenameFileInternal(src + "/" + child, dest + "/" + child);
  817. }
  818. }
  819. DeleteFileInternal(dest);
  820. file_map_[dest] = file_map_[src];
  821. file_map_.erase(src);
  822. return true;
  823. }
  824. }
  825. IOStatus MockFileSystem::RenameFile(const std::string& src,
  826. const std::string& dest,
  827. const IOOptions& /*options*/,
  828. IODebugContext* /*dbg*/) {
  829. auto s = NormalizeMockPath(src);
  830. auto t = NormalizeMockPath(dest);
  831. MutexLock lock(&mutex_);
  832. bool found = RenameFileInternal(s, t);
  833. if (!found) {
  834. return IOStatus::PathNotFound(s);
  835. } else {
  836. return IOStatus::OK();
  837. }
  838. }
  839. IOStatus MockFileSystem::LinkFile(const std::string& src,
  840. const std::string& dest,
  841. const IOOptions& /*options*/,
  842. IODebugContext* /*dbg*/) {
  843. auto s = NormalizeMockPath(src);
  844. auto t = NormalizeMockPath(dest);
  845. MutexLock lock(&mutex_);
  846. if (file_map_.find(s) == file_map_.end()) {
  847. return IOStatus::PathNotFound(s);
  848. }
  849. DeleteFileInternal(t);
  850. file_map_[t] = file_map_[s];
  851. file_map_[t]->Ref(); // Otherwise it might get deleted when noone uses s
  852. return IOStatus::OK();
  853. }
  854. IOStatus MockFileSystem::NewLogger(const std::string& fname,
  855. const IOOptions& io_opts,
  856. std::shared_ptr<Logger>* result,
  857. IODebugContext* dbg) {
  858. auto fn = NormalizeMockPath(fname);
  859. MutexLock lock(&mutex_);
  860. auto iter = file_map_.find(fn);
  861. MemFile* file = nullptr;
  862. if (iter == file_map_.end()) {
  863. file = new MemFile(clock_, fn, false);
  864. file->Ref();
  865. file_map_[fn] = file;
  866. } else {
  867. file = iter->second;
  868. }
  869. std::unique_ptr<FSWritableFile> f(new MockWritableFile(file, FileOptions()));
  870. result->reset(new TestMemLogger(std::move(f), clock_, io_opts, dbg));
  871. return IOStatus::OK();
  872. }
  873. IOStatus MockFileSystem::LockFile(const std::string& fname,
  874. const IOOptions& /*options*/,
  875. FileLock** flock, IODebugContext* /*dbg*/) {
  876. auto fn = NormalizeMockPath(fname);
  877. {
  878. MutexLock lock(&mutex_);
  879. if (file_map_.find(fn) != file_map_.end()) {
  880. if (!file_map_[fn]->is_lock_file()) {
  881. return IOStatus::InvalidArgument(fname, "Not a lock file.");
  882. }
  883. if (!file_map_[fn]->Lock()) {
  884. return IOStatus::IOError(fn, "lock is already held.");
  885. }
  886. } else {
  887. auto* file = new MemFile(clock_, fn, true);
  888. file->Ref();
  889. file->Lock();
  890. file_map_[fn] = file;
  891. }
  892. }
  893. *flock = new MockEnvFileLock(fn);
  894. return IOStatus::OK();
  895. }
  896. IOStatus MockFileSystem::UnlockFile(FileLock* flock,
  897. const IOOptions& /*options*/,
  898. IODebugContext* /*dbg*/) {
  899. std::string fn = static_cast_with_check<MockEnvFileLock>(flock)->FileName();
  900. {
  901. MutexLock lock(&mutex_);
  902. if (file_map_.find(fn) != file_map_.end()) {
  903. if (!file_map_[fn]->is_lock_file()) {
  904. return IOStatus::InvalidArgument(fn, "Not a lock file.");
  905. }
  906. file_map_[fn]->Unlock();
  907. }
  908. }
  909. delete flock;
  910. return IOStatus::OK();
  911. }
  912. IOStatus MockFileSystem::GetTestDirectory(const IOOptions& /*options*/,
  913. std::string* path,
  914. IODebugContext* /*dbg*/) {
  915. *path = "/test";
  916. return IOStatus::OK();
  917. }
  918. Status MockFileSystem::CorruptBuffer(const std::string& fname) {
  919. auto fn = NormalizeMockPath(fname);
  920. MutexLock lock(&mutex_);
  921. auto iter = file_map_.find(fn);
  922. if (iter == file_map_.end()) {
  923. return Status::IOError(fn, "File not found");
  924. }
  925. iter->second->CorruptBuffer();
  926. return Status::OK();
  927. }
  928. MockEnv::MockEnv(Env* env, const std::shared_ptr<FileSystem>& fs,
  929. const std::shared_ptr<SystemClock>& clock)
  930. : CompositeEnvWrapper(env, fs, clock) {}
  931. MockEnv* MockEnv::Create(Env* env) {
  932. auto clock =
  933. std::make_shared<EmulatedSystemClock>(env->GetSystemClock(), true);
  934. return MockEnv::Create(env, clock);
  935. }
  936. MockEnv* MockEnv::Create(Env* env, const std::shared_ptr<SystemClock>& clock) {
  937. auto fs = std::make_shared<MockFileSystem>(clock);
  938. return new MockEnv(env, fs, clock);
  939. }
  940. Status MockEnv::CorruptBuffer(const std::string& fname) {
  941. auto mock = static_cast_with_check<MockFileSystem>(GetFileSystem().get());
  942. return mock->CorruptBuffer(fname);
  943. }
  944. // This is to maintain the behavior before swithcing from InMemoryEnv to MockEnv
  945. Env* NewMemEnv(Env* base_env) { return MockEnv::Create(base_env); }
  946. } // namespace ROCKSDB_NAMESPACE