作者: 韩晨旭 10225101440 李畅 10225102463
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.

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