作者: 韩晨旭 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.

564 lines
16 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. #include "util/posix_logger.h"
  26. #if defined(OS_WIN)
  27. #include <io.h>
  28. #include "base/win/win_util.h"
  29. #endif
  30. #if defined(OS_MACOSX) || defined(OS_WIN)
  31. // The following are glibc-specific
  32. namespace {
  33. size_t fread_unlocked(void *ptr, size_t size, size_t n, FILE *file) {
  34. return fread(ptr, size, n, file);
  35. }
  36. size_t fwrite_unlocked(const void *ptr, size_t size, size_t n, FILE *file) {
  37. return fwrite(ptr, size, n, file);
  38. }
  39. int fflush_unlocked(FILE *file) {
  40. return fflush(file);
  41. }
  42. int fdatasync(int fildes) {
  43. #if defined(OS_WIN)
  44. return _commit(fildes);
  45. #else
  46. return fsync(fildes);
  47. #endif
  48. }
  49. }
  50. #endif
  51. namespace leveldb {
  52. namespace {
  53. class Thread;
  54. static const ::FilePath::CharType kLevelDBTestDirectoryPrefix[]
  55. = FILE_PATH_LITERAL("leveldb-test-");
  56. ::FilePath CreateFilePath(const std::string& file_path) {
  57. #if defined(OS_WIN)
  58. return FilePath(UTF8ToUTF16(file_path));
  59. #else
  60. return FilePath(file_path);
  61. #endif
  62. }
  63. std::string FilePathToString(const ::FilePath& file_path) {
  64. #if defined(OS_WIN)
  65. return UTF16ToUTF8(file_path.value());
  66. #else
  67. return file_path.value();
  68. #endif
  69. }
  70. // TODO(jorlow): This should be moved into Chromium's base.
  71. const char* PlatformFileErrorString(const ::base::PlatformFileError& error) {
  72. switch (error) {
  73. case ::base::PLATFORM_FILE_ERROR_FAILED:
  74. return "Opening file failed.";
  75. case ::base::PLATFORM_FILE_ERROR_IN_USE:
  76. return "File currently in use.";
  77. case ::base::PLATFORM_FILE_ERROR_EXISTS:
  78. return "File already exists.";
  79. case ::base::PLATFORM_FILE_ERROR_NOT_FOUND:
  80. return "File not found.";
  81. case ::base::PLATFORM_FILE_ERROR_ACCESS_DENIED:
  82. return "Access denied.";
  83. case ::base::PLATFORM_FILE_ERROR_TOO_MANY_OPENED:
  84. return "Too many files open.";
  85. case ::base::PLATFORM_FILE_ERROR_NO_MEMORY:
  86. return "Out of memory.";
  87. case ::base::PLATFORM_FILE_ERROR_NO_SPACE:
  88. return "No space left on drive.";
  89. case ::base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY:
  90. return "Not a directory.";
  91. case ::base::PLATFORM_FILE_ERROR_INVALID_OPERATION:
  92. return "Invalid operation.";
  93. case ::base::PLATFORM_FILE_ERROR_SECURITY:
  94. return "Security error.";
  95. case ::base::PLATFORM_FILE_ERROR_ABORT:
  96. return "File operation aborted.";
  97. case ::base::PLATFORM_FILE_ERROR_NOT_A_FILE:
  98. return "The supplied path was not a file.";
  99. case ::base::PLATFORM_FILE_ERROR_NOT_EMPTY:
  100. return "The file was not empty.";
  101. }
  102. NOTIMPLEMENTED();
  103. return "Unknown error.";
  104. }
  105. class ChromiumSequentialFile: public SequentialFile {
  106. private:
  107. std::string filename_;
  108. FILE* file_;
  109. public:
  110. ChromiumSequentialFile(const std::string& fname, FILE* f)
  111. : filename_(fname), file_(f) { }
  112. virtual ~ChromiumSequentialFile() { fclose(file_); }
  113. virtual Status Read(size_t n, Slice* result, char* scratch) {
  114. Status s;
  115. size_t r = fread_unlocked(scratch, 1, n, file_);
  116. *result = Slice(scratch, r);
  117. if (r < n) {
  118. if (feof(file_)) {
  119. // We leave status as ok if we hit the end of the file
  120. } else {
  121. // A partial read with an error: return a non-ok status
  122. s = Status::IOError(filename_, strerror(errno));
  123. }
  124. }
  125. return s;
  126. }
  127. virtual Status Skip(uint64_t n) {
  128. if (fseek(file_, n, SEEK_CUR)) {
  129. return Status::IOError(filename_, strerror(errno));
  130. }
  131. return Status::OK();
  132. }
  133. };
  134. class ChromiumRandomAccessFile: public RandomAccessFile {
  135. private:
  136. std::string filename_;
  137. ::base::PlatformFile file_;
  138. public:
  139. ChromiumRandomAccessFile(const std::string& fname, ::base::PlatformFile file)
  140. : filename_(fname), file_(file) { }
  141. virtual ~ChromiumRandomAccessFile() { ::base::ClosePlatformFile(file_); }
  142. virtual Status Read(uint64_t offset, size_t n, Slice* result,
  143. char* scratch) const {
  144. Status s;
  145. int r = ::base::ReadPlatformFile(file_, offset, scratch, n);
  146. *result = Slice(scratch, (r < 0) ? 0 : r);
  147. if (r < 0) {
  148. // An error: return a non-ok status
  149. s = Status::IOError(filename_, "Could not preform read");
  150. }
  151. return s;
  152. }
  153. };
  154. class ChromiumWritableFile : public WritableFile {
  155. private:
  156. std::string filename_;
  157. FILE* file_;
  158. public:
  159. ChromiumWritableFile(const std::string& fname, FILE* f)
  160. : filename_(fname), file_(f) { }
  161. ~ChromiumWritableFile() {
  162. if (file_ != NULL) {
  163. // Ignoring any potential errors
  164. fclose(file_);
  165. }
  166. }
  167. virtual Status Append(const Slice& data) {
  168. size_t r = fwrite_unlocked(data.data(), 1, data.size(), file_);
  169. Status result;
  170. if (r != data.size()) {
  171. result = Status::IOError(filename_, strerror(errno));
  172. }
  173. return result;
  174. }
  175. virtual Status Close() {
  176. Status result;
  177. if (fclose(file_) != 0) {
  178. result = Status::IOError(filename_, strerror(errno));
  179. }
  180. file_ = NULL;
  181. return result;
  182. }
  183. virtual Status Flush() {
  184. Status result;
  185. if (fflush_unlocked(file_) != 0) {
  186. result = Status::IOError(filename_, strerror(errno));
  187. }
  188. return result;
  189. }
  190. virtual Status Sync() {
  191. Status result;
  192. if ((fflush_unlocked(file_) != 0) ||
  193. (fdatasync(fileno(file_)) != 0)) {
  194. result = Status::IOError(filename_, strerror(errno));
  195. }
  196. return result;
  197. }
  198. };
  199. class ChromiumFileLock : public FileLock {
  200. public:
  201. ::base::PlatformFile file_;
  202. };
  203. class ChromiumEnv : public Env {
  204. public:
  205. ChromiumEnv();
  206. virtual ~ChromiumEnv() {
  207. fprintf(stderr, "Destroying Env::Default()\n");
  208. exit(1);
  209. }
  210. virtual Status NewSequentialFile(const std::string& fname,
  211. SequentialFile** result) {
  212. FILE* f = fopen(fname.c_str(), "rb");
  213. if (f == NULL) {
  214. *result = NULL;
  215. return Status::IOError(fname, strerror(errno));
  216. } else {
  217. *result = new ChromiumSequentialFile(fname, f);
  218. return Status::OK();
  219. }
  220. }
  221. virtual Status NewRandomAccessFile(const std::string& fname,
  222. RandomAccessFile** result) {
  223. int flags = ::base::PLATFORM_FILE_READ | ::base::PLATFORM_FILE_OPEN;
  224. bool created;
  225. ::base::PlatformFileError error_code;
  226. ::base::PlatformFile file = ::base::CreatePlatformFile(
  227. CreateFilePath(fname), flags, &created, &error_code);
  228. if (error_code != ::base::PLATFORM_FILE_OK) {
  229. *result = NULL;
  230. return Status::IOError(fname, PlatformFileErrorString(error_code));
  231. }
  232. *result = new ChromiumRandomAccessFile(fname, 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_t 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. mu_.Acquire();
  351. if (test_directory_.empty()) {
  352. if (!::file_util::CreateNewTempDirectory(kLevelDBTestDirectoryPrefix,
  353. &test_directory_)) {
  354. mu_.Release();
  355. return Status::IOError("Could not create temp directory.");
  356. }
  357. }
  358. *path = FilePathToString(test_directory_);
  359. mu_.Release();
  360. return Status::OK();
  361. }
  362. // TODO(user,user): Use Chromium's built-in logging?
  363. static uint64_t gettid() {
  364. uint64_t thread_id = 0;
  365. // Coppied from base/logging.cc.
  366. #if defined(OS_WIN)
  367. thread_id = GetCurrentThreadId();
  368. #elif defined(OS_MACOSX)
  369. thread_id = mach_thread_self();
  370. #elif defined(OS_LINUX)
  371. thread_id = syscall(__NR_gettid);
  372. #elif defined(OS_FREEBSD) || defined(OS_NACL)
  373. // TODO(BSD): find a better thread ID
  374. pthread_t tid = pthread_self();
  375. memcpy(&thread_id, &tid, min(sizeof(r), sizeof(tid)));
  376. #endif
  377. return thread_id;
  378. }
  379. virtual Status NewLogger(const std::string& fname, Logger** result) {
  380. FILE* f = fopen(fname.c_str(), "w");
  381. if (f == NULL) {
  382. *result = NULL;
  383. return Status::IOError(fname, strerror(errno));
  384. } else {
  385. *result = new PosixLogger(f, &ChromiumEnv::gettid);
  386. return Status::OK();
  387. }
  388. }
  389. virtual int AppendLocalTimeToBuffer(char* buffer, size_t size) {
  390. ::base::Time::Exploded t;
  391. ::base::Time::Now().LocalExplode(&t);
  392. return snprintf(buffer, size,
  393. "%04d/%02d/%02d-%02d:%02d:%02d.%06d",
  394. t.year,
  395. t.month,
  396. t.day_of_month,
  397. t.hour,
  398. t.minute,
  399. t.second,
  400. static_cast<int>(t.millisecond) * 1000);
  401. }
  402. virtual uint64_t NowMicros() {
  403. return ::base::TimeTicks::HighResNow().ToInternalValue();
  404. }
  405. virtual void SleepForMicroseconds(int micros) {
  406. // Round up to the next millisecond.
  407. ::base::PlatformThread::Sleep((micros + 999) / 1000);
  408. }
  409. private:
  410. // BGThread() is the body of the background thread
  411. void BGThread();
  412. static void BGThreadWrapper(void* arg) {
  413. reinterpret_cast<ChromiumEnv*>(arg)->BGThread();
  414. }
  415. FilePath test_directory_;
  416. size_t page_size_;
  417. ::base::Lock mu_;
  418. ::base::ConditionVariable bgsignal_;
  419. bool started_bgthread_;
  420. // Entry per Schedule() call
  421. struct BGItem { void* arg; void (*function)(void*); };
  422. typedef std::deque<BGItem> BGQueue;
  423. BGQueue queue_;
  424. };
  425. ChromiumEnv::ChromiumEnv()
  426. : page_size_(::base::SysInfo::VMAllocationGranularity()),
  427. bgsignal_(&mu_),
  428. started_bgthread_(false) {
  429. #if defined(OS_MACOSX)
  430. ::base::EnableTerminationOnHeapCorruption();
  431. ::base::EnableTerminationOnOutOfMemory();
  432. #endif // OS_MACOSX
  433. }
  434. class Thread : public ::base::PlatformThread::Delegate {
  435. public:
  436. Thread(void (*function)(void* arg), void* arg)
  437. : function_(function), arg_(arg) {
  438. ::base::PlatformThreadHandle handle;
  439. bool success = ::base::PlatformThread::Create(0, this, &handle);
  440. DCHECK(success);
  441. }
  442. virtual ~Thread() {}
  443. virtual void ThreadMain() {
  444. (*function_)(arg_);
  445. delete this;
  446. }
  447. private:
  448. void (*function_)(void* arg);
  449. void* arg_;
  450. };
  451. void ChromiumEnv::Schedule(void (*function)(void*), void* arg) {
  452. mu_.Acquire();
  453. // Start background thread if necessary
  454. if (!started_bgthread_) {
  455. started_bgthread_ = true;
  456. StartThread(&ChromiumEnv::BGThreadWrapper, this);
  457. }
  458. // If the queue is currently empty, the background thread may currently be
  459. // waiting.
  460. if (queue_.empty()) {
  461. bgsignal_.Signal();
  462. }
  463. // Add to priority queue
  464. queue_.push_back(BGItem());
  465. queue_.back().function = function;
  466. queue_.back().arg = arg;
  467. mu_.Release();
  468. }
  469. void ChromiumEnv::BGThread() {
  470. while (true) {
  471. // Wait until there is an item that is ready to run
  472. mu_.Acquire();
  473. while (queue_.empty()) {
  474. bgsignal_.Wait();
  475. }
  476. void (*function)(void*) = queue_.front().function;
  477. void* arg = queue_.front().arg;
  478. queue_.pop_front();
  479. mu_.Release();
  480. (*function)(arg);
  481. }
  482. }
  483. void ChromiumEnv::StartThread(void (*function)(void* arg), void* arg) {
  484. new Thread(function, arg); // Will self-delete.
  485. }
  486. ::base::LazyInstance<ChromiumEnv, ::base::LeakyLazyInstanceTraits<ChromiumEnv> >
  487. default_env(::base::LINKER_INITIALIZED);
  488. }
  489. Env* Env::Default() {
  490. return default_env.Pointer();
  491. }
  492. }