You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

612 lines
17 KiB

  1. // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file. See the AUTHORS file for names of contributors.
  4. #include <deque>
  5. #include <errno.h>
  6. #include <stdio.h>
  7. #include "base/at_exit.h"
  8. #include "base/file_path.h"
  9. #include "base/file_util.h"
  10. #include "base/lazy_instance.h"
  11. #include "base/memory/ref_counted.h"
  12. #include "base/message_loop.h"
  13. #include "base/platform_file.h"
  14. #include "base/process_util.h"
  15. #include "base/synchronization/lock.h"
  16. #include "base/sys_info.h"
  17. #include "base/task.h"
  18. #include "base/threading/platform_thread.h"
  19. #include "base/threading/thread.h"
  20. #include "base/utf_string_conversions.h"
  21. #include "leveldb/env.h"
  22. #include "leveldb/slice.h"
  23. #include "port/port.h"
  24. #include "util/logging.h"
  25. #if defined(OS_WIN)
  26. #include <io.h>
  27. #include "base/win/win_util.h"
  28. #endif
  29. #if defined(OS_MACOSX) || defined(OS_WIN)
  30. // The following are glibc-specific
  31. namespace {
  32. size_t fread_unlocked(void *ptr, size_t size, size_t n, FILE *file) {
  33. return fread(ptr, size, n, file);
  34. }
  35. size_t fwrite_unlocked(const void *ptr, size_t size, size_t n, FILE *file) {
  36. return fwrite(ptr, size, n, file);
  37. }
  38. int fflush_unlocked(FILE *file) {
  39. return fflush(file);
  40. }
  41. int fdatasync(int fildes) {
  42. #if defined(OS_WIN)
  43. return _commit(fildes);
  44. #else
  45. return fsync(fildes);
  46. #endif
  47. }
  48. }
  49. #endif
  50. namespace leveldb {
  51. namespace {
  52. class Thread;
  53. static const ::FilePath::CharType kLevelDBTestDirectoryPrefix[]
  54. = FILE_PATH_LITERAL("leveldb-test-");
  55. ::FilePath CreateFilePath(const std::string& file_path) {
  56. #if defined(OS_WIN)
  57. return FilePath(UTF8ToUTF16(file_path));
  58. #else
  59. return FilePath(file_path);
  60. #endif
  61. }
  62. std::string FilePathToString(const ::FilePath& file_path) {
  63. #if defined(OS_WIN)
  64. return UTF16ToUTF8(file_path.value());
  65. #else
  66. return file_path.value();
  67. #endif
  68. }
  69. // TODO(jorlow): This should be moved into Chromium's base.
  70. const char* PlatformFileErrorString(const ::base::PlatformFileError& error) {
  71. switch (error) {
  72. case ::base::PLATFORM_FILE_ERROR_FAILED:
  73. return "Opening file failed.";
  74. case ::base::PLATFORM_FILE_ERROR_IN_USE:
  75. return "File currently in use.";
  76. case ::base::PLATFORM_FILE_ERROR_EXISTS:
  77. return "File already exists.";
  78. case ::base::PLATFORM_FILE_ERROR_NOT_FOUND:
  79. return "File not found.";
  80. case ::base::PLATFORM_FILE_ERROR_ACCESS_DENIED:
  81. return "Access denied.";
  82. case ::base::PLATFORM_FILE_ERROR_TOO_MANY_OPENED:
  83. return "Too many files open.";
  84. case ::base::PLATFORM_FILE_ERROR_NO_MEMORY:
  85. return "Out of memory.";
  86. case ::base::PLATFORM_FILE_ERROR_NO_SPACE:
  87. return "No space left on drive.";
  88. case ::base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY:
  89. return "Not a directory.";
  90. case ::base::PLATFORM_FILE_ERROR_INVALID_OPERATION:
  91. return "Invalid operation.";
  92. case ::base::PLATFORM_FILE_ERROR_SECURITY:
  93. return "Security error.";
  94. case ::base::PLATFORM_FILE_ERROR_ABORT:
  95. return "File operation aborted.";
  96. case ::base::PLATFORM_FILE_ERROR_NOT_A_FILE:
  97. return "The supplied path was not a file.";
  98. case ::base::PLATFORM_FILE_ERROR_NOT_EMPTY:
  99. return "The file was not empty.";
  100. }
  101. NOTIMPLEMENTED();
  102. return "Unknown error.";
  103. }
  104. class ChromiumSequentialFile: public SequentialFile {
  105. private:
  106. std::string filename_;
  107. FILE* file_;
  108. public:
  109. ChromiumSequentialFile(const std::string& fname, FILE* f)
  110. : filename_(fname), file_(f) { }
  111. virtual ~ChromiumSequentialFile() { fclose(file_); }
  112. virtual Status Read(size_t n, Slice* result, char* scratch) {
  113. Status s;
  114. size_t r = fread_unlocked(scratch, 1, n, file_);
  115. *result = Slice(scratch, r);
  116. if (r < n) {
  117. if (feof(file_)) {
  118. // We leave status as ok if we hit the end of the file
  119. } else {
  120. // A partial read with an error: return a non-ok status
  121. s = Status::IOError(filename_, strerror(errno));
  122. }
  123. }
  124. return s;
  125. }
  126. virtual Status Skip(uint64_t n) {
  127. if (fseek(file_, n, SEEK_CUR)) {
  128. return Status::IOError(filename_, strerror(errno));
  129. }
  130. return Status::OK();
  131. }
  132. };
  133. class ChromiumRandomAccessFile: public RandomAccessFile {
  134. private:
  135. std::string filename_;
  136. ::base::PlatformFile file_;
  137. public:
  138. ChromiumRandomAccessFile(const std::string& fname, ::base::PlatformFile file)
  139. : filename_(fname), file_(file) { }
  140. virtual ~ChromiumRandomAccessFile() { ::base::ClosePlatformFile(file_); }
  141. virtual Status Read(uint64_t offset, size_t n, Slice* result,
  142. char* scratch) const {
  143. Status s;
  144. int r = ::base::ReadPlatformFile(file_, offset, scratch, n);
  145. *result = Slice(scratch, (r < 0) ? 0 : r);
  146. if (r < 0) {
  147. // An error: return a non-ok status
  148. s = Status::IOError(filename_, "Could not preform read");
  149. }
  150. return s;
  151. }
  152. };
  153. class ChromiumWritableFile : public WritableFile {
  154. private:
  155. std::string filename_;
  156. FILE* file_;
  157. public:
  158. ChromiumWritableFile(const std::string& fname, FILE* f)
  159. : filename_(fname), file_(f) { }
  160. ~ChromiumWritableFile() {
  161. if (file_ != NULL) {
  162. // Ignoring any potential errors
  163. fclose(file_);
  164. }
  165. }
  166. virtual Status Append(const Slice& data) {
  167. size_t r = fwrite_unlocked(data.data(), 1, data.size(), file_);
  168. Status result;
  169. if (r != data.size()) {
  170. result = Status::IOError(filename_, strerror(errno));
  171. }
  172. return result;
  173. }
  174. virtual Status Close() {
  175. Status result;
  176. if (fclose(file_) != 0) {
  177. result = Status::IOError(filename_, strerror(errno));
  178. }
  179. file_ = NULL;
  180. return result;
  181. }
  182. virtual Status Flush() {
  183. Status result;
  184. if (fflush_unlocked(file_) != 0) {
  185. result = Status::IOError(filename_, strerror(errno));
  186. }
  187. return result;
  188. }
  189. virtual Status Sync() {
  190. Status result;
  191. if ((fflush_unlocked(file_) != 0) ||
  192. (fdatasync(fileno(file_)) != 0)) {
  193. result = Status::IOError(filename_, strerror(errno));
  194. }
  195. return result;
  196. }
  197. };
  198. class ChromiumFileLock : public FileLock {
  199. public:
  200. ::base::PlatformFile file_;
  201. };
  202. class ChromiumEnv : public Env {
  203. public:
  204. ChromiumEnv();
  205. virtual ~ChromiumEnv() {
  206. fprintf(stderr, "Destroying Env::Default()\n");
  207. exit(1);
  208. }
  209. virtual Status NewSequentialFile(const std::string& fname,
  210. SequentialFile** result) {
  211. FILE* f = fopen(fname.c_str(), "rb");
  212. if (f == NULL) {
  213. *result = NULL;
  214. return Status::IOError(fname, strerror(errno));
  215. } else {
  216. *result = new ChromiumSequentialFile(fname, f);
  217. return Status::OK();
  218. }
  219. }
  220. virtual Status NewRandomAccessFile(const std::string& fname,
  221. RandomAccessFile** result) {
  222. int flags = ::base::PLATFORM_FILE_READ | ::base::PLATFORM_FILE_OPEN;
  223. bool created;
  224. ::base::PlatformFileError error_code;
  225. ::base::PlatformFile file = ::base::CreatePlatformFile(
  226. CreateFilePath(fname), flags, &created, &error_code);
  227. if (error_code != ::base::PLATFORM_FILE_OK) {
  228. *result = NULL;
  229. return Status::IOError(fname, PlatformFileErrorString(error_code));
  230. }
  231. *result = new ChromiumRandomAccessFile(fname, file);
  232. return Status::OK();
  233. }
  234. virtual Status NewWritableFile(const std::string& fname,
  235. WritableFile** result) {
  236. *result = NULL;
  237. FILE* f = fopen(fname.c_str(), "wb");
  238. if (f == NULL) {
  239. return Status::IOError(fname, strerror(errno));
  240. } else {
  241. *result = new ChromiumWritableFile(fname, f);
  242. return Status::OK();
  243. }
  244. }
  245. virtual bool FileExists(const std::string& fname) {
  246. return ::file_util::PathExists(CreateFilePath(fname));
  247. }
  248. virtual Status GetChildren(const std::string& dir,
  249. std::vector<std::string>* result) {
  250. result->clear();
  251. ::file_util::FileEnumerator iter(
  252. CreateFilePath(dir), false, ::file_util::FileEnumerator::FILES);
  253. ::FilePath current = iter.Next();
  254. while (!current.empty()) {
  255. result->push_back(FilePathToString(current.BaseName()));
  256. current = iter.Next();
  257. }
  258. // TODO(jorlow): Unfortunately, the FileEnumerator swallows errors, so
  259. // we'll always return OK. Maybe manually check for error
  260. // conditions like the file not existing?
  261. return Status::OK();
  262. }
  263. virtual Status DeleteFile(const std::string& fname) {
  264. Status result;
  265. // TODO(jorlow): Should we assert this is a file?
  266. if (!::file_util::Delete(CreateFilePath(fname), false)) {
  267. result = Status::IOError(fname, "Could not delete file.");
  268. }
  269. return result;
  270. };
  271. virtual Status CreateDir(const std::string& name) {
  272. Status result;
  273. if (!::file_util::CreateDirectory(CreateFilePath(name))) {
  274. result = Status::IOError(name, "Could not create directory.");
  275. }
  276. return result;
  277. };
  278. virtual Status DeleteDir(const std::string& name) {
  279. Status result;
  280. // TODO(jorlow): Should we assert this is a directory?
  281. if (!::file_util::Delete(CreateFilePath(name), false)) {
  282. result = Status::IOError(name, "Could not delete directory.");
  283. }
  284. return result;
  285. };
  286. virtual Status GetFileSize(const std::string& fname, uint64_t* size) {
  287. Status s;
  288. int64_t signed_size;
  289. if (!::file_util::GetFileSize(CreateFilePath(fname), &signed_size)) {
  290. *size = 0;
  291. s = Status::IOError(fname, "Could not determine file size.");
  292. } else {
  293. *size = static_cast<uint64_t>(signed_size);
  294. }
  295. return s;
  296. }
  297. virtual Status RenameFile(const std::string& src, const std::string& dst) {
  298. Status result;
  299. if (!::file_util::ReplaceFile(CreateFilePath(src), CreateFilePath(dst))) {
  300. result = Status::IOError(src, "Could not rename file.");
  301. }
  302. return result;
  303. }
  304. virtual Status LockFile(const std::string& fname, FileLock** lock) {
  305. *lock = NULL;
  306. Status result;
  307. int flags = ::base::PLATFORM_FILE_OPEN_ALWAYS |
  308. ::base::PLATFORM_FILE_READ |
  309. ::base::PLATFORM_FILE_WRITE |
  310. ::base::PLATFORM_FILE_EXCLUSIVE_READ |
  311. ::base::PLATFORM_FILE_EXCLUSIVE_WRITE;
  312. bool created;
  313. ::base::PlatformFileError error_code;
  314. ::base::PlatformFile file = ::base::CreatePlatformFile(
  315. CreateFilePath(fname), flags, &created, &error_code);
  316. if (error_code != ::base::PLATFORM_FILE_OK) {
  317. result = Status::IOError(fname, PlatformFileErrorString(error_code));
  318. } else {
  319. ChromiumFileLock* my_lock = new ChromiumFileLock;
  320. my_lock->file_ = file;
  321. *lock = my_lock;
  322. }
  323. return result;
  324. }
  325. virtual Status UnlockFile(FileLock* lock) {
  326. ChromiumFileLock* my_lock = reinterpret_cast<ChromiumFileLock*>(lock);
  327. Status result;
  328. if (!::base::ClosePlatformFile(my_lock->file_)) {
  329. result = Status::IOError("Could not close lock file.");
  330. }
  331. delete my_lock;
  332. return result;
  333. }
  334. virtual void Schedule(void (*function)(void*), void* arg);
  335. virtual void StartThread(void (*function)(void* arg), void* arg);
  336. virtual std::string UserIdentifier() {
  337. #if defined(OS_WIN)
  338. std::wstring user_sid;
  339. bool ret = ::base::win::GetUserSidString(&user_sid);
  340. DCHECK(ret);
  341. return UTF16ToUTF8(user_sid);
  342. #else
  343. char buf[100];
  344. snprintf(buf, sizeof(buf), "%d", int(geteuid()));
  345. return buf;
  346. #endif
  347. }
  348. virtual Status GetTestDirectory(std::string* path) {
  349. mu_.Acquire();
  350. if (test_directory_.empty()) {
  351. if (!::file_util::CreateNewTempDirectory(kLevelDBTestDirectoryPrefix,
  352. &test_directory_)) {
  353. mu_.Release();
  354. return Status::IOError("Could not create temp directory.");
  355. }
  356. }
  357. *path = FilePathToString(test_directory_);
  358. mu_.Release();
  359. return Status::OK();
  360. }
  361. virtual void Logv(WritableFile* info_log, const char* format, va_list ap) {
  362. // TODO(jorlow): We may want to just use Chromium's built in logging.
  363. uint64_t thread_id = 0;
  364. // Coppied from base/logging.cc.
  365. #if defined(OS_WIN)
  366. thread_id = GetCurrentThreadId();
  367. #elif defined(OS_MACOSX)
  368. thread_id = mach_thread_self();
  369. #elif defined(OS_LINUX)
  370. thread_id = syscall(__NR_gettid);
  371. #elif defined(OS_FREEBSD) || defined(OS_NACL)
  372. // TODO(BSD): find a better thread ID
  373. pthread_t tid = pthread_self();
  374. memcpy(&thread_id, &tid, min(sizeof(r), sizeof(tid)));
  375. #endif
  376. // We try twice: the first time with a fixed-size stack allocated buffer,
  377. // and the second time with a much larger dynamically allocated buffer.
  378. char buffer[500];
  379. for (int iter = 0; iter < 2; iter++) {
  380. char* base;
  381. int bufsize;
  382. if (iter == 0) {
  383. bufsize = sizeof(buffer);
  384. base = buffer;
  385. } else {
  386. bufsize = 30000;
  387. base = new char[bufsize];
  388. }
  389. char* p = base;
  390. char* limit = base + bufsize;
  391. ::base::Time::Exploded t;
  392. ::base::Time::Now().LocalExplode(&t);
  393. p += snprintf(p, limit - p,
  394. "%04d/%02d/%02d-%02d:%02d:%02d.%06d %llx ",
  395. t.year,
  396. t.month,
  397. t.day_of_month,
  398. t.hour,
  399. t.minute,
  400. t.second,
  401. static_cast<int>(t.millisecond) * 1000,
  402. static_cast<long long unsigned int>(thread_id));
  403. // Print the message
  404. if (p < limit) {
  405. va_list backup_ap;
  406. va_copy(backup_ap, ap);
  407. p += vsnprintf(p, limit - p, format, backup_ap);
  408. va_end(backup_ap);
  409. }
  410. // Truncate to available space if necessary
  411. if (p >= limit) {
  412. if (iter == 0) {
  413. continue; // Try again with larger buffer
  414. } else {
  415. p = limit - 1;
  416. }
  417. }
  418. // Add newline if necessary
  419. if (p == base || p[-1] != '\n') {
  420. *p++ = '\n';
  421. }
  422. assert(p <= limit);
  423. info_log->Append(Slice(base, p - base));
  424. info_log->Flush();
  425. if (base != buffer) {
  426. delete[] base;
  427. }
  428. break;
  429. }
  430. }
  431. virtual int AppendLocalTimeToBuffer(char* buffer, size_t size) {
  432. ::base::Time::Exploded t;
  433. ::base::Time::Now().LocalExplode(&t);
  434. return snprintf(buffer, size,
  435. "%04d/%02d/%02d-%02d:%02d:%02d.%06d",
  436. t.year,
  437. t.month,
  438. t.day_of_month,
  439. t.hour,
  440. t.minute,
  441. t.second,
  442. static_cast<int>(t.millisecond) * 1000);
  443. }
  444. virtual uint64_t NowMicros() {
  445. return ::base::TimeTicks::HighResNow().ToInternalValue();
  446. }
  447. virtual void SleepForMicroseconds(int micros) {
  448. // Round up to the next millisecond.
  449. ::base::PlatformThread::Sleep((micros + 999) / 1000);
  450. }
  451. private:
  452. // BGThread() is the body of the background thread
  453. void BGThread();
  454. static void BGThreadWrapper(void* arg) {
  455. reinterpret_cast<ChromiumEnv*>(arg)->BGThread();
  456. }
  457. FilePath test_directory_;
  458. size_t page_size_;
  459. ::base::Lock mu_;
  460. ::base::ConditionVariable bgsignal_;
  461. bool started_bgthread_;
  462. // Entry per Schedule() call
  463. struct BGItem { void* arg; void (*function)(void*); };
  464. typedef std::deque<BGItem> BGQueue;
  465. BGQueue queue_;
  466. };
  467. ChromiumEnv::ChromiumEnv()
  468. : page_size_(::base::SysInfo::VMAllocationGranularity()),
  469. bgsignal_(&mu_),
  470. started_bgthread_(false) {
  471. #if defined(OS_MACOSX)
  472. ::base::EnableTerminationOnHeapCorruption();
  473. ::base::EnableTerminationOnOutOfMemory();
  474. #endif // OS_MACOSX
  475. }
  476. class Thread : public ::base::PlatformThread::Delegate {
  477. public:
  478. Thread(void (*function)(void* arg), void* arg)
  479. : function_(function), arg_(arg) {
  480. ::base::PlatformThreadHandle handle;
  481. bool success = ::base::PlatformThread::Create(0, this, &handle);
  482. DCHECK(success);
  483. }
  484. virtual ~Thread() {}
  485. virtual void ThreadMain() {
  486. (*function_)(arg_);
  487. delete this;
  488. }
  489. private:
  490. void (*function_)(void* arg);
  491. void* arg_;
  492. };
  493. void ChromiumEnv::Schedule(void (*function)(void*), void* arg) {
  494. mu_.Acquire();
  495. // Start background thread if necessary
  496. if (!started_bgthread_) {
  497. started_bgthread_ = true;
  498. StartThread(&ChromiumEnv::BGThreadWrapper, this);
  499. }
  500. // If the queue is currently empty, the background thread may currently be
  501. // waiting.
  502. if (queue_.empty()) {
  503. bgsignal_.Signal();
  504. }
  505. // Add to priority queue
  506. queue_.push_back(BGItem());
  507. queue_.back().function = function;
  508. queue_.back().arg = arg;
  509. mu_.Release();
  510. }
  511. void ChromiumEnv::BGThread() {
  512. while (true) {
  513. // Wait until there is an item that is ready to run
  514. mu_.Acquire();
  515. while (queue_.empty()) {
  516. bgsignal_.Wait();
  517. }
  518. void (*function)(void*) = queue_.front().function;
  519. void* arg = queue_.front().arg;
  520. queue_.pop_front();
  521. mu_.Release();
  522. (*function)(arg);
  523. }
  524. }
  525. void ChromiumEnv::StartThread(void (*function)(void* arg), void* arg) {
  526. new Thread(function, arg); // Will self-delete.
  527. }
  528. ::base::LazyInstance<ChromiumEnv, ::base::LeakyLazyInstanceTraits<ChromiumEnv> >
  529. default_env(::base::LINKER_INITIALIZED);
  530. }
  531. Env* Env::Default() {
  532. return default_env.Pointer();
  533. }
  534. }