小组成员: 曹可心-10223903406 朴祉燕-10224602413
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.

760 lines
20 KiB

Release 1.18 Changes are: * Update version number to 1.18 * Replace the basic fprintf call with a call to fwrite in order to work around the apparent compiler optimization/rewrite failure that we are seeing with the new toolchain/iOS SDKs provided with Xcode6 and iOS8. * Fix ALL the header guards. * Createed a README.md with the LevelDB project description. * A new CONTRIBUTING file. * Don't implicitly convert uint64_t to size_t or int. Either preserve it as uint64_t, or explicitly cast. This fixes MSVC warnings about possible value truncation when compiling this code in Chromium. * Added a DumpFile() library function that encapsulates the guts of the "leveldbutil dump" command. This will allow clients to dump data to their log files instead of stdout. It will also allow clients to supply their own environment. * leveldb: Remove unused function 'ConsumeChar'. * leveldbutil: Remove unused member variables from WriteBatchItemPrinter. * OpenBSD, NetBSD and DragonflyBSD have _LITTLE_ENDIAN, so define PLATFORM_IS_LITTLE_ENDIAN like on FreeBSD. This fixes: * issue #143 * issue #198 * issue #249 * Switch from <cstdatomic> to <atomic>. The former never made it into the standard and doesn't exist in modern gcc versions at all. The later contains everything that leveldb was using from the former. This problem was noticed when porting to Portable Native Client where no memory barrier is defined. The fact that <cstdatomic> is missing normally goes unnoticed since memory barriers are defined for most architectures. * Make Hash() treat its input as unsigned. Before this change LevelDB files from platforms with different signedness of char were not compatible. This change fixes: issue #243 * Verify checksums of index/meta/filter blocks when paranoid_checks set. * Invoke all tools for iOS with xcrun. (This was causing problems with the new XCode 5.1.1 image on pulse.) * include <sys/stat.h> only once, and fix the following linter warning: "Found C system header after C++ system header" * When encountering a corrupted table file, return Status::Corruption instead of Status::InvalidArgument. * Support cygwin as build platform, patch is from https://code.google.com/p/leveldb/issues/detail?id=188 * Fix typo, merge patch from https://code.google.com/p/leveldb/issues/detail?id=159 * Fix typos and comments, and address the following two issues: * issue #166 * issue #241 * Add missing db synchronize after "fillseq" in the benchmark. * Removed unused variable in SeekRandom: value (issue #201)
10 years ago
Release 1.18 Changes are: * Update version number to 1.18 * Replace the basic fprintf call with a call to fwrite in order to work around the apparent compiler optimization/rewrite failure that we are seeing with the new toolchain/iOS SDKs provided with Xcode6 and iOS8. * Fix ALL the header guards. * Createed a README.md with the LevelDB project description. * A new CONTRIBUTING file. * Don't implicitly convert uint64_t to size_t or int. Either preserve it as uint64_t, or explicitly cast. This fixes MSVC warnings about possible value truncation when compiling this code in Chromium. * Added a DumpFile() library function that encapsulates the guts of the "leveldbutil dump" command. This will allow clients to dump data to their log files instead of stdout. It will also allow clients to supply their own environment. * leveldb: Remove unused function 'ConsumeChar'. * leveldbutil: Remove unused member variables from WriteBatchItemPrinter. * OpenBSD, NetBSD and DragonflyBSD have _LITTLE_ENDIAN, so define PLATFORM_IS_LITTLE_ENDIAN like on FreeBSD. This fixes: * issue #143 * issue #198 * issue #249 * Switch from <cstdatomic> to <atomic>. The former never made it into the standard and doesn't exist in modern gcc versions at all. The later contains everything that leveldb was using from the former. This problem was noticed when porting to Portable Native Client where no memory barrier is defined. The fact that <cstdatomic> is missing normally goes unnoticed since memory barriers are defined for most architectures. * Make Hash() treat its input as unsigned. Before this change LevelDB files from platforms with different signedness of char were not compatible. This change fixes: issue #243 * Verify checksums of index/meta/filter blocks when paranoid_checks set. * Invoke all tools for iOS with xcrun. (This was causing problems with the new XCode 5.1.1 image on pulse.) * include <sys/stat.h> only once, and fix the following linter warning: "Found C system header after C++ system header" * When encountering a corrupted table file, return Status::Corruption instead of Status::InvalidArgument. * Support cygwin as build platform, patch is from https://code.google.com/p/leveldb/issues/detail?id=188 * Fix typo, merge patch from https://code.google.com/p/leveldb/issues/detail?id=159 * Fix typos and comments, and address the following two issues: * issue #166 * issue #241 * Add missing db synchronize after "fillseq" in the benchmark. * Removed unused variable in SeekRandom: value (issue #201)
10 years ago
  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 <dirent.h>
  5. #include <errno.h>
  6. #include <fcntl.h>
  7. #include <pthread.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <sys/mman.h>
  11. #include <sys/resource.h>
  12. #include <sys/stat.h>
  13. #include <sys/time.h>
  14. #include <sys/types.h>
  15. #include <time.h>
  16. #include <unistd.h>
  17. #include <atomic>
  18. #include <cstring>
  19. #include <limits>
  20. #include <queue>
  21. #include <set>
  22. #include <thread>
  23. #include "leveldb/env.h"
  24. #include "leveldb/slice.h"
  25. #include "port/port.h"
  26. #include "port/thread_annotations.h"
  27. #include "util/logging.h"
  28. #include "util/mutexlock.h"
  29. #include "util/posix_logger.h"
  30. #include "util/env_posix_test_helper.h"
  31. // HAVE_FDATASYNC is defined in the auto-generated port_config.h, which is
  32. // included by port_stdcxx.h.
  33. #if !HAVE_FDATASYNC
  34. #define fdatasync fsync
  35. #endif // !HAVE_FDATASYNC
  36. namespace leveldb {
  37. namespace {
  38. static int open_read_only_file_limit = -1;
  39. static int mmap_limit = -1;
  40. constexpr const size_t kWritableFileBufferSize = 65536;
  41. static Status PosixError(const std::string& context, int err_number) {
  42. if (err_number == ENOENT) {
  43. return Status::NotFound(context, strerror(err_number));
  44. } else {
  45. return Status::IOError(context, strerror(err_number));
  46. }
  47. }
  48. // Helper class to limit resource usage to avoid exhaustion.
  49. // Currently used to limit read-only file descriptors and mmap file usage
  50. // so that we do not run out of file descriptors or virtual memory, or run into
  51. // kernel performance problems for very large databases.
  52. class Limiter {
  53. public:
  54. // Limit maximum number of resources to |max_acquires|.
  55. Limiter(int max_acquires) : acquires_allowed_(max_acquires) {}
  56. Limiter(const Limiter&) = delete;
  57. Limiter operator=(const Limiter&) = delete;
  58. // If another resource is available, acquire it and return true.
  59. // Else return false.
  60. bool Acquire() {
  61. int old_acquires_allowed =
  62. acquires_allowed_.fetch_sub(1, std::memory_order_relaxed);
  63. if (old_acquires_allowed > 0)
  64. return true;
  65. acquires_allowed_.fetch_add(1, std::memory_order_relaxed);
  66. return false;
  67. }
  68. // Release a resource acquired by a previous call to Acquire() that returned
  69. // true.
  70. void Release() {
  71. acquires_allowed_.fetch_add(1, std::memory_order_relaxed);
  72. }
  73. private:
  74. // The number of available resources.
  75. //
  76. // This is a counter and is not tied to the invariants of any other class, so
  77. // it can be operated on safely using std::memory_order_relaxed.
  78. std::atomic<int> acquires_allowed_;
  79. };
  80. class PosixSequentialFile: public SequentialFile {
  81. private:
  82. std::string filename_;
  83. int fd_;
  84. public:
  85. PosixSequentialFile(const std::string& fname, int fd)
  86. : filename_(fname), fd_(fd) {}
  87. virtual ~PosixSequentialFile() { close(fd_); }
  88. virtual Status Read(size_t n, Slice* result, char* scratch) {
  89. Status s;
  90. while (true) {
  91. ssize_t r = read(fd_, scratch, n);
  92. if (r < 0) {
  93. if (errno == EINTR) {
  94. continue; // Retry
  95. }
  96. s = PosixError(filename_, errno);
  97. break;
  98. }
  99. *result = Slice(scratch, r);
  100. break;
  101. }
  102. return s;
  103. }
  104. virtual Status Skip(uint64_t n) {
  105. if (lseek(fd_, n, SEEK_CUR) == static_cast<off_t>(-1)) {
  106. return PosixError(filename_, errno);
  107. }
  108. return Status::OK();
  109. }
  110. };
  111. // pread() based random-access
  112. class PosixRandomAccessFile: public RandomAccessFile {
  113. private:
  114. std::string filename_;
  115. bool temporary_fd_; // If true, fd_ is -1 and we open on every read.
  116. int fd_;
  117. Limiter* limiter_;
  118. public:
  119. PosixRandomAccessFile(const std::string& fname, int fd, Limiter* limiter)
  120. : filename_(fname), fd_(fd), limiter_(limiter) {
  121. temporary_fd_ = !limiter->Acquire();
  122. if (temporary_fd_) {
  123. // Open file on every access.
  124. close(fd_);
  125. fd_ = -1;
  126. }
  127. }
  128. virtual ~PosixRandomAccessFile() {
  129. if (!temporary_fd_) {
  130. close(fd_);
  131. limiter_->Release();
  132. }
  133. }
  134. virtual Status Read(uint64_t offset, size_t n, Slice* result,
  135. char* scratch) const {
  136. int fd = fd_;
  137. if (temporary_fd_) {
  138. fd = open(filename_.c_str(), O_RDONLY);
  139. if (fd < 0) {
  140. return PosixError(filename_, errno);
  141. }
  142. }
  143. Status s;
  144. ssize_t r = pread(fd, scratch, n, static_cast<off_t>(offset));
  145. *result = Slice(scratch, (r < 0) ? 0 : r);
  146. if (r < 0) {
  147. // An error: return a non-ok status
  148. s = PosixError(filename_, errno);
  149. }
  150. if (temporary_fd_) {
  151. // Close the temporary file descriptor opened earlier.
  152. close(fd);
  153. }
  154. return s;
  155. }
  156. };
  157. // mmap() based random-access
  158. class PosixMmapReadableFile: public RandomAccessFile {
  159. private:
  160. std::string filename_;
  161. void* mmapped_region_;
  162. size_t length_;
  163. Limiter* limiter_;
  164. public:
  165. // base[0,length-1] contains the mmapped contents of the file.
  166. PosixMmapReadableFile(const std::string& fname, void* base, size_t length,
  167. Limiter* limiter)
  168. : filename_(fname), mmapped_region_(base), length_(length),
  169. limiter_(limiter) {
  170. }
  171. virtual ~PosixMmapReadableFile() {
  172. munmap(mmapped_region_, length_);
  173. limiter_->Release();
  174. }
  175. virtual Status Read(uint64_t offset, size_t n, Slice* result,
  176. char* scratch) const {
  177. Status s;
  178. if (offset + n > length_) {
  179. *result = Slice();
  180. s = PosixError(filename_, EINVAL);
  181. } else {
  182. *result = Slice(reinterpret_cast<char*>(mmapped_region_) + offset, n);
  183. }
  184. return s;
  185. }
  186. };
  187. class PosixWritableFile final : public WritableFile {
  188. public:
  189. PosixWritableFile(std::string filename, int fd)
  190. : pos_(0), fd_(fd), is_manifest_(IsManifest(filename)),
  191. filename_(std::move(filename)), dirname_(Dirname(filename_)) {}
  192. ~PosixWritableFile() override {
  193. if (fd_ >= 0) {
  194. // Ignoring any potential errors
  195. Close();
  196. }
  197. }
  198. Status Append(const Slice& data) override {
  199. size_t write_size = data.size();
  200. const char* write_data = data.data();
  201. // Fit as much as possible into buffer.
  202. size_t copy_size = std::min(write_size, kWritableFileBufferSize - pos_);
  203. std::memcpy(buf_ + pos_, write_data, copy_size);
  204. write_data += copy_size;
  205. write_size -= copy_size;
  206. pos_ += copy_size;
  207. if (write_size == 0) {
  208. return Status::OK();
  209. }
  210. // Can't fit in buffer, so need to do at least one write.
  211. Status status = FlushBuffer();
  212. if (!status.ok()) {
  213. return status;
  214. }
  215. // Small writes go to buffer, large writes are written directly.
  216. if (write_size < kWritableFileBufferSize) {
  217. std::memcpy(buf_, write_data, write_size);
  218. pos_ = write_size;
  219. return Status::OK();
  220. }
  221. return WriteUnbuffered(write_data, write_size);
  222. }
  223. Status Close() override {
  224. Status status = FlushBuffer();
  225. const int close_result = ::close(fd_);
  226. if (close_result < 0 && status.ok()) {
  227. status = PosixError(filename_, errno);
  228. }
  229. fd_ = -1;
  230. return status;
  231. }
  232. Status Flush() override {
  233. return FlushBuffer();
  234. }
  235. Status Sync() override {
  236. // Ensure new files referred to by the manifest are in the filesystem.
  237. //
  238. // This needs to happen before the manifest file is flushed to disk, to
  239. // avoid crashing in a state where the manifest refers to files that are not
  240. // yet on disk.
  241. Status status = SyncDirIfManifest();
  242. if (!status.ok()) {
  243. return status;
  244. }
  245. status = FlushBuffer();
  246. if (status.ok() && ::fdatasync(fd_) != 0) {
  247. status = PosixError(filename_, errno);
  248. }
  249. return status;
  250. }
  251. private:
  252. Status FlushBuffer() {
  253. Status status = WriteUnbuffered(buf_, pos_);
  254. pos_ = 0;
  255. return status;
  256. }
  257. Status WriteUnbuffered(const char* data, size_t size) {
  258. while (size > 0) {
  259. ssize_t write_result = ::write(fd_, data, size);
  260. if (write_result < 0) {
  261. if (errno == EINTR) {
  262. continue; // Retry
  263. }
  264. return PosixError(filename_, errno);
  265. }
  266. data += write_result;
  267. size -= write_result;
  268. }
  269. return Status::OK();
  270. }
  271. Status SyncDirIfManifest() {
  272. Status status;
  273. if (!is_manifest_) {
  274. return status;
  275. }
  276. int fd = ::open(dirname_.c_str(), O_RDONLY);
  277. if (fd < 0) {
  278. status = PosixError(dirname_, errno);
  279. } else {
  280. if (::fsync(fd) < 0) {
  281. status = PosixError(dirname_, errno);
  282. }
  283. ::close(fd);
  284. }
  285. return status;
  286. }
  287. // Returns the directory name in a path pointing to a file.
  288. //
  289. // Returns "." if the path does not contain any directory separator.
  290. static std::string Dirname(const std::string& filename) {
  291. std::string::size_type separator_pos = filename.rfind('/');
  292. if (separator_pos == std::string::npos) {
  293. return std::string(".");
  294. }
  295. // The filename component should not contain a path separator. If it does,
  296. // the splitting was done incorrectly.
  297. assert(filename.find('/', separator_pos + 1) == std::string::npos);
  298. return filename.substr(0, separator_pos);
  299. }
  300. // Extracts the file name from a path pointing to a file.
  301. //
  302. // The returned Slice points to |filename|'s data buffer, so it is only valid
  303. // while |filename| is alive and unchanged.
  304. static Slice Basename(const std::string& filename) {
  305. std::string::size_type separator_pos = filename.rfind('/');
  306. if (separator_pos == std::string::npos) {
  307. return Slice(filename);
  308. }
  309. // The filename component should not contain a path separator. If it does,
  310. // the splitting was done incorrectly.
  311. assert(filename.find('/', separator_pos + 1) == std::string::npos);
  312. return Slice(filename.data() + separator_pos + 1,
  313. filename.length() - separator_pos - 1);
  314. }
  315. // True if the given file is a manifest file.
  316. static bool IsManifest(const std::string& filename) {
  317. return Basename(filename).starts_with("MANIFEST");
  318. }
  319. // buf_[0, pos_ - 1] contains data to be written to fd_.
  320. char buf_[kWritableFileBufferSize];
  321. size_t pos_;
  322. int fd_;
  323. const bool is_manifest_; // True if the file's name starts with MANIFEST.
  324. const std::string filename_;
  325. const std::string dirname_; // The directory of filename_.
  326. };
  327. static int LockOrUnlock(int fd, bool lock) {
  328. errno = 0;
  329. struct flock f;
  330. memset(&f, 0, sizeof(f));
  331. f.l_type = (lock ? F_WRLCK : F_UNLCK);
  332. f.l_whence = SEEK_SET;
  333. f.l_start = 0;
  334. f.l_len = 0; // Lock/unlock entire file
  335. return fcntl(fd, F_SETLK, &f);
  336. }
  337. class PosixFileLock : public FileLock {
  338. public:
  339. int fd_;
  340. std::string name_;
  341. };
  342. // Set of locked files. We keep a separate set instead of just
  343. // relying on fcntrl(F_SETLK) since fcntl(F_SETLK) does not provide
  344. // any protection against multiple uses from the same process.
  345. class PosixLockTable {
  346. private:
  347. port::Mutex mu_;
  348. std::set<std::string> locked_files_ GUARDED_BY(mu_);
  349. public:
  350. bool Insert(const std::string& fname) LOCKS_EXCLUDED(mu_) {
  351. MutexLock l(&mu_);
  352. return locked_files_.insert(fname).second;
  353. }
  354. void Remove(const std::string& fname) LOCKS_EXCLUDED(mu_) {
  355. MutexLock l(&mu_);
  356. locked_files_.erase(fname);
  357. }
  358. };
  359. class PosixEnv : public Env {
  360. public:
  361. PosixEnv();
  362. virtual ~PosixEnv() {
  363. char msg[] = "Destroying Env::Default()\n";
  364. fwrite(msg, 1, sizeof(msg), stderr);
  365. abort();
  366. }
  367. virtual Status NewSequentialFile(const std::string& fname,
  368. SequentialFile** result) {
  369. int fd = open(fname.c_str(), O_RDONLY);
  370. if (fd < 0) {
  371. *result = nullptr;
  372. return PosixError(fname, errno);
  373. } else {
  374. *result = new PosixSequentialFile(fname, fd);
  375. return Status::OK();
  376. }
  377. }
  378. virtual Status NewRandomAccessFile(const std::string& fname,
  379. RandomAccessFile** result) {
  380. *result = nullptr;
  381. Status s;
  382. int fd = open(fname.c_str(), O_RDONLY);
  383. if (fd < 0) {
  384. s = PosixError(fname, errno);
  385. } else if (mmap_limit_.Acquire()) {
  386. uint64_t size;
  387. s = GetFileSize(fname, &size);
  388. if (s.ok()) {
  389. void* base = mmap(nullptr, size, PROT_READ, MAP_SHARED, fd, 0);
  390. if (base != MAP_FAILED) {
  391. *result = new PosixMmapReadableFile(fname, base, size, &mmap_limit_);
  392. } else {
  393. s = PosixError(fname, errno);
  394. }
  395. }
  396. close(fd);
  397. if (!s.ok()) {
  398. mmap_limit_.Release();
  399. }
  400. } else {
  401. *result = new PosixRandomAccessFile(fname, fd, &fd_limit_);
  402. }
  403. return s;
  404. }
  405. virtual Status NewWritableFile(const std::string& fname,
  406. WritableFile** result) {
  407. Status s;
  408. int fd = open(fname.c_str(), O_TRUNC | O_WRONLY | O_CREAT, 0644);
  409. if (fd < 0) {
  410. *result = nullptr;
  411. s = PosixError(fname, errno);
  412. } else {
  413. *result = new PosixWritableFile(fname, fd);
  414. }
  415. return s;
  416. }
  417. virtual Status NewAppendableFile(const std::string& fname,
  418. WritableFile** result) {
  419. Status s;
  420. int fd = open(fname.c_str(), O_APPEND | O_WRONLY | O_CREAT, 0644);
  421. if (fd < 0) {
  422. *result = nullptr;
  423. s = PosixError(fname, errno);
  424. } else {
  425. *result = new PosixWritableFile(fname, fd);
  426. }
  427. return s;
  428. }
  429. virtual bool FileExists(const std::string& fname) {
  430. return access(fname.c_str(), F_OK) == 0;
  431. }
  432. virtual Status GetChildren(const std::string& dir,
  433. std::vector<std::string>* result) {
  434. result->clear();
  435. DIR* d = opendir(dir.c_str());
  436. if (d == nullptr) {
  437. return PosixError(dir, errno);
  438. }
  439. struct dirent* entry;
  440. while ((entry = readdir(d)) != nullptr) {
  441. result->push_back(entry->d_name);
  442. }
  443. closedir(d);
  444. return Status::OK();
  445. }
  446. virtual Status DeleteFile(const std::string& fname) {
  447. Status result;
  448. if (unlink(fname.c_str()) != 0) {
  449. result = PosixError(fname, errno);
  450. }
  451. return result;
  452. }
  453. virtual Status CreateDir(const std::string& name) {
  454. Status result;
  455. if (mkdir(name.c_str(), 0755) != 0) {
  456. result = PosixError(name, errno);
  457. }
  458. return result;
  459. }
  460. virtual Status DeleteDir(const std::string& name) {
  461. Status result;
  462. if (rmdir(name.c_str()) != 0) {
  463. result = PosixError(name, errno);
  464. }
  465. return result;
  466. }
  467. virtual Status GetFileSize(const std::string& fname, uint64_t* size) {
  468. Status s;
  469. struct stat sbuf;
  470. if (stat(fname.c_str(), &sbuf) != 0) {
  471. *size = 0;
  472. s = PosixError(fname, errno);
  473. } else {
  474. *size = sbuf.st_size;
  475. }
  476. return s;
  477. }
  478. virtual Status RenameFile(const std::string& src, const std::string& target) {
  479. Status result;
  480. if (rename(src.c_str(), target.c_str()) != 0) {
  481. result = PosixError(src, errno);
  482. }
  483. return result;
  484. }
  485. virtual Status LockFile(const std::string& fname, FileLock** lock) {
  486. *lock = nullptr;
  487. Status result;
  488. int fd = open(fname.c_str(), O_RDWR | O_CREAT, 0644);
  489. if (fd < 0) {
  490. result = PosixError(fname, errno);
  491. } else if (!locks_.Insert(fname)) {
  492. close(fd);
  493. result = Status::IOError("lock " + fname, "already held by process");
  494. } else if (LockOrUnlock(fd, true) == -1) {
  495. result = PosixError("lock " + fname, errno);
  496. close(fd);
  497. locks_.Remove(fname);
  498. } else {
  499. PosixFileLock* my_lock = new PosixFileLock;
  500. my_lock->fd_ = fd;
  501. my_lock->name_ = fname;
  502. *lock = my_lock;
  503. }
  504. return result;
  505. }
  506. virtual Status UnlockFile(FileLock* lock) {
  507. PosixFileLock* my_lock = reinterpret_cast<PosixFileLock*>(lock);
  508. Status result;
  509. if (LockOrUnlock(my_lock->fd_, false) == -1) {
  510. result = PosixError("unlock", errno);
  511. }
  512. locks_.Remove(my_lock->name_);
  513. close(my_lock->fd_);
  514. delete my_lock;
  515. return result;
  516. }
  517. virtual void Schedule(void (*function)(void*), void* arg);
  518. virtual void StartThread(void (*function)(void* arg), void* arg);
  519. virtual Status GetTestDirectory(std::string* result) {
  520. const char* env = getenv("TEST_TMPDIR");
  521. if (env && env[0] != '\0') {
  522. *result = env;
  523. } else {
  524. char buf[100];
  525. snprintf(buf, sizeof(buf), "/tmp/leveldbtest-%d", int(geteuid()));
  526. *result = buf;
  527. }
  528. // Directory may already exist
  529. CreateDir(*result);
  530. return Status::OK();
  531. }
  532. virtual Status NewLogger(const std::string& fname, Logger** result) {
  533. FILE* f = fopen(fname.c_str(), "w");
  534. if (f == nullptr) {
  535. *result = nullptr;
  536. return PosixError(fname, errno);
  537. } else {
  538. *result = new PosixLogger(f);
  539. return Status::OK();
  540. }
  541. }
  542. virtual uint64_t NowMicros() {
  543. struct timeval tv;
  544. gettimeofday(&tv, nullptr);
  545. return static_cast<uint64_t>(tv.tv_sec) * 1000000 + tv.tv_usec;
  546. }
  547. virtual void SleepForMicroseconds(int micros) {
  548. usleep(micros);
  549. }
  550. private:
  551. void BackgroundThreadMain();
  552. static void BackgroundThreadEntryPoint(PosixEnv* env) {
  553. env->BackgroundThreadMain();
  554. }
  555. // Stores the work item data in a Schedule() call.
  556. //
  557. // Instances are constructed on the thread calling Schedule() and used on the
  558. // background thread.
  559. //
  560. // This structure is thread-safe beacuse it is immutable.
  561. struct BackgroundWorkItem {
  562. explicit BackgroundWorkItem(void (*function)(void* arg), void* arg)
  563. : function(function), arg(arg) {}
  564. void (* const function)(void*);
  565. void* const arg;
  566. };
  567. port::Mutex background_work_mutex_;
  568. port::CondVar background_work_cv_ GUARDED_BY(background_work_mutex_);
  569. bool started_background_thread_ GUARDED_BY(background_work_mutex_);
  570. std::queue<BackgroundWorkItem> background_work_queue_
  571. GUARDED_BY(background_work_mutex_);
  572. PosixLockTable locks_;
  573. Limiter mmap_limit_;
  574. Limiter fd_limit_;
  575. };
  576. // Return the maximum number of concurrent mmaps.
  577. static int MaxMmaps() {
  578. if (mmap_limit >= 0) {
  579. return mmap_limit;
  580. }
  581. // Up to 1000 mmaps for 64-bit binaries; none for smaller pointer sizes.
  582. mmap_limit = sizeof(void*) >= 8 ? 1000 : 0;
  583. return mmap_limit;
  584. }
  585. // Return the maximum number of read-only files to keep open.
  586. static intptr_t MaxOpenFiles() {
  587. if (open_read_only_file_limit >= 0) {
  588. return open_read_only_file_limit;
  589. }
  590. struct rlimit rlim;
  591. if (getrlimit(RLIMIT_NOFILE, &rlim)) {
  592. // getrlimit failed, fallback to hard-coded default.
  593. open_read_only_file_limit = 50;
  594. } else if (rlim.rlim_cur == RLIM_INFINITY) {
  595. open_read_only_file_limit = std::numeric_limits<int>::max();
  596. } else {
  597. // Allow use of 20% of available file descriptors for read-only files.
  598. open_read_only_file_limit = rlim.rlim_cur / 5;
  599. }
  600. return open_read_only_file_limit;
  601. }
  602. PosixEnv::PosixEnv()
  603. : background_work_cv_(&background_work_mutex_),
  604. started_background_thread_(false),
  605. mmap_limit_(MaxMmaps()),
  606. fd_limit_(MaxOpenFiles()) {
  607. }
  608. void PosixEnv::Schedule(
  609. void (*background_work_function)(void* background_work_arg),
  610. void* background_work_arg) {
  611. MutexLock lock(&background_work_mutex_);
  612. // Start the background thread, if we haven't done so already.
  613. if (!started_background_thread_) {
  614. started_background_thread_ = true;
  615. std::thread background_thread(PosixEnv::BackgroundThreadEntryPoint, this);
  616. background_thread.detach();
  617. }
  618. // If the queue is empty, the background thread may be waiting for work.
  619. if (background_work_queue_.empty()) {
  620. background_work_cv_.Signal();
  621. }
  622. background_work_queue_.emplace(background_work_function, background_work_arg);
  623. }
  624. void PosixEnv::BackgroundThreadMain() {
  625. while (true) {
  626. background_work_mutex_.Lock();
  627. // Wait until there is work to be done.
  628. while (background_work_queue_.empty()) {
  629. background_work_cv_.Wait();
  630. }
  631. assert(!background_work_queue_.empty());
  632. auto background_work_function =
  633. background_work_queue_.front().function;
  634. void* background_work_arg = background_work_queue_.front().arg;
  635. background_work_queue_.pop();
  636. background_work_mutex_.Unlock();
  637. background_work_function(background_work_arg);
  638. }
  639. }
  640. } // namespace
  641. void PosixEnv::StartThread(void (*thread_main)(void* thread_main_arg),
  642. void* thread_main_arg) {
  643. std::thread new_thread(thread_main, thread_main_arg);
  644. new_thread.detach();
  645. }
  646. static pthread_once_t once = PTHREAD_ONCE_INIT;
  647. static Env* default_env;
  648. static void InitDefaultEnv() { default_env = new PosixEnv; }
  649. void EnvPosixTestHelper::SetReadOnlyFDLimit(int limit) {
  650. assert(default_env == nullptr);
  651. open_read_only_file_limit = limit;
  652. }
  653. void EnvPosixTestHelper::SetReadOnlyMMapLimit(int limit) {
  654. assert(default_env == nullptr);
  655. mmap_limit = limit;
  656. }
  657. Env* Env::Default() {
  658. pthread_once(&once, InitDefaultEnv);
  659. return default_env;
  660. }
  661. } // namespace leveldb