作者: 谢瑞阳 10225101483 徐翔宇 10225101535

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