小组成员:谢瑞阳、徐翔宇
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.

613 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/message_loop.h"
  12. #include "base/platform_file.h"
  13. #include "base/process_util.h"
  14. #include "base/ref_counted.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 "include/env.h"
  22. #include "include/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. extern "C" {
  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. };
  127. class ChromiumRandomAccessFile: public RandomAccessFile {
  128. private:
  129. std::string filename_;
  130. uint64_t size_;
  131. ::base::PlatformFile file_;
  132. public:
  133. ChromiumRandomAccessFile(const std::string& fname, uint64_t size,
  134. ::base::PlatformFile file)
  135. : filename_(fname), size_(size), file_(file) { }
  136. virtual ~ChromiumRandomAccessFile() { ::base::ClosePlatformFile(file_); }
  137. virtual uint64_t Size() const { return size_; }
  138. virtual Status Read(uint64_t offset, size_t n, Slice* result,
  139. char* scratch) const {
  140. Status s;
  141. int r = ::base::ReadPlatformFile(file_, offset, scratch, n);
  142. *result = Slice(scratch, (r < 0) ? 0 : r);
  143. if (r < 0) {
  144. // An error: return a non-ok status
  145. s = Status::IOError(filename_, "Could not preform read");
  146. }
  147. return s;
  148. }
  149. };
  150. class ChromiumWritableFile : public WritableFile {
  151. private:
  152. std::string filename_;
  153. FILE* file_;
  154. public:
  155. ChromiumWritableFile(const std::string& fname, FILE* f)
  156. : filename_(fname), file_(f) { }
  157. ~ChromiumWritableFile() {
  158. if (file_ != NULL) {
  159. // Ignoring any potential errors
  160. fclose(file_);
  161. }
  162. }
  163. virtual Status Append(const Slice& data) {
  164. size_t r = fwrite_unlocked(data.data(), 1, data.size(), file_);
  165. Status result;
  166. if (r != data.size()) {
  167. result = Status::IOError(filename_, strerror(errno));
  168. }
  169. return result;
  170. }
  171. virtual Status Close() {
  172. Status result;
  173. if (fclose(file_) != 0) {
  174. result = Status::IOError(filename_, strerror(errno));
  175. }
  176. file_ = NULL;
  177. return result;
  178. }
  179. virtual Status Flush() {
  180. Status result;
  181. if (fflush_unlocked(file_) != 0) {
  182. result = Status::IOError(filename_, strerror(errno));
  183. }
  184. return result;
  185. }
  186. virtual Status Sync() {
  187. Status result;
  188. if ((fflush_unlocked(file_) != 0) ||
  189. (fdatasync(fileno(file_)) != 0)) {
  190. result = Status::IOError(filename_, strerror(errno));
  191. }
  192. return result;
  193. }
  194. };
  195. class ChromiumFileLock : public FileLock {
  196. public:
  197. ::base::PlatformFile file_;
  198. };
  199. class ChromiumEnv : public Env {
  200. public:
  201. ChromiumEnv();
  202. virtual ~ChromiumEnv() {
  203. fprintf(stderr, "Destroying Env::Default()\n");
  204. exit(1);
  205. }
  206. virtual Status NewSequentialFile(const std::string& fname,
  207. SequentialFile** result) {
  208. FILE* f = fopen(fname.c_str(), "rb");
  209. if (f == NULL) {
  210. *result = NULL;
  211. return Status::IOError(fname, strerror(errno));
  212. } else {
  213. *result = new ChromiumSequentialFile(fname, f);
  214. return Status::OK();
  215. }
  216. }
  217. virtual Status NewRandomAccessFile(const std::string& fname,
  218. RandomAccessFile** result) {
  219. int flags = ::base::PLATFORM_FILE_READ | ::base::PLATFORM_FILE_OPEN;
  220. bool created;
  221. ::base::PlatformFileError error_code;
  222. ::base::PlatformFile file = ::base::CreatePlatformFile(
  223. CreateFilePath(fname), flags, &created, &error_code);
  224. if (error_code != ::base::PLATFORM_FILE_OK) {
  225. *result = NULL;
  226. return Status::IOError(fname, PlatformFileErrorString(error_code));
  227. }
  228. ::base::PlatformFileInfo info;
  229. if (!::base::GetPlatformFileInfo(file, &info)) {
  230. *result = NULL;
  231. ::base::ClosePlatformFile(file);
  232. return Status::IOError(fname, PlatformFileErrorString(error_code));
  233. }
  234. *result = new ChromiumRandomAccessFile(fname, info.size, file);
  235. return Status::OK();
  236. }
  237. virtual Status NewWritableFile(const std::string& fname,
  238. WritableFile** result) {
  239. *result = NULL;
  240. FILE* f = fopen(fname.c_str(), "wb");
  241. if (f == NULL) {
  242. return Status::IOError(fname, strerror(errno));
  243. } else {
  244. *result = new ChromiumWritableFile(fname, f);
  245. return Status::OK();
  246. }
  247. }
  248. virtual bool FileExists(const std::string& fname) {
  249. return ::file_util::PathExists(CreateFilePath(fname));
  250. }
  251. virtual Status GetChildren(const std::string& dir,
  252. std::vector<std::string>* result) {
  253. result->clear();
  254. ::file_util::FileEnumerator iter(
  255. CreateFilePath(dir), false, ::file_util::FileEnumerator::FILES);
  256. ::FilePath current = iter.Next();
  257. while (!current.empty()) {
  258. result->push_back(FilePathToString(current.BaseName()));
  259. current = iter.Next();
  260. }
  261. // TODO(jorlow): Unfortunately, the FileEnumerator swallows errors, so
  262. // we'll always return OK. Maybe manually check for error
  263. // conditions like the file not existing?
  264. return Status::OK();
  265. }
  266. virtual Status DeleteFile(const std::string& fname) {
  267. Status result;
  268. // TODO(jorlow): Should we assert this is a file?
  269. if (!::file_util::Delete(CreateFilePath(fname), false)) {
  270. result = Status::IOError(fname, "Could not delete file.");
  271. }
  272. return result;
  273. };
  274. virtual Status CreateDir(const std::string& name) {
  275. Status result;
  276. if (!::file_util::CreateDirectory(CreateFilePath(name))) {
  277. result = Status::IOError(name, "Could not create directory.");
  278. }
  279. return result;
  280. };
  281. virtual Status DeleteDir(const std::string& name) {
  282. Status result;
  283. // TODO(jorlow): Should we assert this is a directory?
  284. if (!::file_util::Delete(CreateFilePath(name), false)) {
  285. result = Status::IOError(name, "Could not delete directory.");
  286. }
  287. return result;
  288. };
  289. virtual Status GetFileSize(const std::string& fname, uint64_t* size) {
  290. Status s;
  291. int64 signed_size;
  292. if (!::file_util::GetFileSize(CreateFilePath(fname), &signed_size)) {
  293. *size = 0;
  294. s = Status::IOError(fname, "Could not determine file size.");
  295. } else {
  296. *size = static_cast<uint64_t>(signed_size);
  297. }
  298. return s;
  299. }
  300. virtual Status RenameFile(const std::string& src, const std::string& dst) {
  301. Status result;
  302. if (!::file_util::ReplaceFile(CreateFilePath(src), CreateFilePath(dst))) {
  303. result = Status::IOError(src, "Could not rename file.");
  304. }
  305. return result;
  306. }
  307. virtual Status LockFile(const std::string& fname, FileLock** lock) {
  308. *lock = NULL;
  309. Status result;
  310. int flags = ::base::PLATFORM_FILE_OPEN_ALWAYS |
  311. ::base::PLATFORM_FILE_READ |
  312. ::base::PLATFORM_FILE_WRITE |
  313. ::base::PLATFORM_FILE_EXCLUSIVE_READ |
  314. ::base::PLATFORM_FILE_EXCLUSIVE_WRITE;
  315. bool created;
  316. ::base::PlatformFileError error_code;
  317. ::base::PlatformFile file = ::base::CreatePlatformFile(
  318. CreateFilePath(fname), flags, &created, &error_code);
  319. if (error_code != ::base::PLATFORM_FILE_OK) {
  320. result = Status::IOError(fname, PlatformFileErrorString(error_code));
  321. } else {
  322. ChromiumFileLock* my_lock = new ChromiumFileLock;
  323. my_lock->file_ = file;
  324. *lock = my_lock;
  325. }
  326. return result;
  327. }
  328. virtual Status UnlockFile(FileLock* lock) {
  329. ChromiumFileLock* my_lock = reinterpret_cast<ChromiumFileLock*>(lock);
  330. Status result;
  331. if (!::base::ClosePlatformFile(my_lock->file_)) {
  332. result = Status::IOError("Could not close lock file.");
  333. }
  334. delete my_lock;
  335. return result;
  336. }
  337. virtual void Schedule(void (*function)(void*), void* arg);
  338. virtual void StartThread(void (*function)(void* arg), void* arg);
  339. virtual std::string UserIdentifier() {
  340. #if defined(OS_WIN)
  341. std::wstring user_sid;
  342. bool ret = ::base::win::GetUserSidString(&user_sid);
  343. DCHECK(ret);
  344. return UTF16ToUTF8(user_sid);
  345. #else
  346. char buf[100];
  347. snprintf(buf, sizeof(buf), "%d", int(geteuid()));
  348. return buf;
  349. #endif
  350. }
  351. virtual Status GetTestDirectory(std::string* path) {
  352. mu_.Acquire();
  353. if (test_directory_.empty()) {
  354. if (!::file_util::CreateNewTempDirectory(kLevelDBTestDirectoryPrefix,
  355. &test_directory_)) {
  356. mu_.Release();
  357. return Status::IOError("Could not create temp directory.");
  358. }
  359. }
  360. *path = FilePathToString(test_directory_);
  361. mu_.Release();
  362. return Status::OK();
  363. }
  364. virtual void Logv(WritableFile* info_log, const char* format, va_list ap) {
  365. // TODO(jorlow): We may want to just use Chromium's built in logging.
  366. uint64_t thread_id = 0;
  367. // Coppied from base/logging.cc.
  368. #if defined(OS_WIN)
  369. thread_id = GetCurrentThreadId();
  370. #elif defined(OS_MACOSX)
  371. thread_id = mach_thread_self();
  372. #elif defined(OS_LINUX)
  373. thread_id = syscall(__NR_gettid);
  374. #elif defined(OS_FREEBSD) || defined(OS_NACL)
  375. // TODO(BSD): find a better thread ID
  376. pthread_t tid = pthread_self();
  377. memcpy(&thread_id, &tid, min(sizeof(r), sizeof(tid)));
  378. #endif
  379. // We try twice: the first time with a fixed-size stack allocated buffer,
  380. // and the second time with a much larger dynamically allocated buffer.
  381. char buffer[500];
  382. for (int iter = 0; iter < 2; iter++) {
  383. char* base;
  384. int bufsize;
  385. if (iter == 0) {
  386. bufsize = sizeof(buffer);
  387. base = buffer;
  388. } else {
  389. bufsize = 30000;
  390. base = new char[bufsize];
  391. }
  392. char* p = base;
  393. char* limit = base + bufsize;
  394. ::base::Time::Exploded t;
  395. ::base::Time::Now().LocalExplode(&t);
  396. p += snprintf(p, limit - p,
  397. "%04d/%02d/%02d-%02d:%02d:%02d.%06d %llx ",
  398. t.year,
  399. t.month,
  400. t.day_of_month,
  401. t.hour,
  402. t.minute,
  403. t.second,
  404. static_cast<int>(t.millisecond) * 1000,
  405. static_cast<long long unsigned int>(thread_id));
  406. // Print the message
  407. if (p < limit) {
  408. va_list backup_ap;
  409. va_copy(backup_ap, ap);
  410. p += vsnprintf(p, limit - p, format, backup_ap);
  411. va_end(backup_ap);
  412. }
  413. // Truncate to available space if necessary
  414. if (p >= limit) {
  415. if (iter == 0) {
  416. continue; // Try again with larger buffer
  417. } else {
  418. p = limit - 1;
  419. }
  420. }
  421. // Add newline if necessary
  422. if (p == base || p[-1] != '\n') {
  423. *p++ = '\n';
  424. }
  425. assert(p <= limit);
  426. info_log->Append(Slice(base, p - base));
  427. info_log->Flush();
  428. if (base != buffer) {
  429. delete[] base;
  430. }
  431. break;
  432. }
  433. }
  434. virtual int AppendLocalTimeToBuffer(char* buffer, size_t size) {
  435. ::base::Time::Exploded t;
  436. ::base::Time::Now().LocalExplode(&t);
  437. return snprintf(buffer, size,
  438. "%04d/%02d/%02d-%02d:%02d:%02d.%06d",
  439. t.year,
  440. t.month,
  441. t.day_of_month,
  442. t.hour,
  443. t.minute,
  444. t.second,
  445. static_cast<int>(t.millisecond) * 1000);
  446. }
  447. virtual uint64_t NowMicros() {
  448. return ::base::TimeTicks::HighResNow().ToInternalValue();
  449. }
  450. virtual void SleepForMicroseconds(int micros) {
  451. // Round up to the next millisecond.
  452. ::base::PlatformThread::Sleep((micros + 999) / 1000);
  453. }
  454. private:
  455. // BGThread() is the body of the background thread
  456. void BGThread();
  457. static void BGThreadWrapper(void* arg) {
  458. reinterpret_cast<ChromiumEnv*>(arg)->BGThread();
  459. }
  460. FilePath test_directory_;
  461. size_t page_size_;
  462. ::base::Lock mu_;
  463. ::base::ConditionVariable bgsignal_;
  464. bool started_bgthread_;
  465. // Entry per Schedule() call
  466. struct BGItem { void* arg; void (*function)(void*); };
  467. typedef std::deque<BGItem> BGQueue;
  468. BGQueue queue_;
  469. };
  470. ChromiumEnv::ChromiumEnv()
  471. : page_size_(::base::SysInfo::VMAllocationGranularity()),
  472. bgsignal_(&mu_),
  473. started_bgthread_(false) {
  474. #if defined(OS_MACOSX)
  475. ::base::EnableTerminationOnHeapCorruption();
  476. ::base::EnableTerminationOnOutOfMemory();
  477. #endif // OS_MACOSX
  478. }
  479. class Thread : public ::base::PlatformThread::Delegate {
  480. public:
  481. Thread(void (*function)(void* arg), void* arg)
  482. : function_(function), arg_(arg) {
  483. ::base::PlatformThreadHandle handle;
  484. bool success = ::base::PlatformThread::Create(0, this, &handle);
  485. DCHECK(success);
  486. }
  487. virtual ~Thread() {}
  488. virtual void ThreadMain() {
  489. (*function_)(arg_);
  490. delete this;
  491. }
  492. private:
  493. void (*function_)(void* arg);
  494. void* arg_;
  495. };
  496. void ChromiumEnv::Schedule(void (*function)(void*), void* arg) {
  497. mu_.Acquire();
  498. // Start background thread if necessary
  499. if (!started_bgthread_) {
  500. started_bgthread_ = true;
  501. StartThread(&ChromiumEnv::BGThreadWrapper, this);
  502. }
  503. // If the queue is currently empty, the background thread may currently be
  504. // waiting.
  505. if (queue_.empty()) {
  506. bgsignal_.Signal();
  507. }
  508. // Add to priority queue
  509. queue_.push_back(BGItem());
  510. queue_.back().function = function;
  511. queue_.back().arg = arg;
  512. mu_.Release();
  513. }
  514. void ChromiumEnv::BGThread() {
  515. while (true) {
  516. // Wait until there is an item that is ready to run
  517. mu_.Acquire();
  518. while (queue_.empty()) {
  519. bgsignal_.Wait();
  520. }
  521. void (*function)(void*) = queue_.front().function;
  522. void* arg = queue_.front().arg;
  523. queue_.pop_front();
  524. mu_.Release();
  525. (*function)(arg);
  526. }
  527. }
  528. void ChromiumEnv::StartThread(void (*function)(void* arg), void* arg) {
  529. new Thread(function, arg); // Will self-delete.
  530. }
  531. ::base::LazyInstance<ChromiumEnv, ::base::LeakyLazyInstanceTraits<ChromiumEnv> >
  532. default_env(::base::LINKER_INITIALIZED);
  533. }
  534. Env* Env::Default() {
  535. return default_env.Pointer();
  536. }
  537. }