1179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
2179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org// Use of this source code is governed by a BSD-style license that can be
3179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org// found in the LICENSE file. See the AUTHORS file for names of contributors.
4179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
5179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include <deque>
629c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org#include <set>
7179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include <dirent.h>
8179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include <errno.h>
9179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include <fcntl.h>
10179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include <pthread.h>
11179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include <stdio.h>
12179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include <stdlib.h>
13179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include <string.h>
14179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include <sys/mman.h>
15179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include <sys/stat.h>
16179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include <sys/time.h>
17179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include <sys/types.h>
18179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include <time.h>
19179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include <unistd.h>
20179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#if defined(LEVELDB_PLATFORM_ANDROID)
21179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include <sys/stat.h>
22179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#endif
23fbd97aa4c5325eace57d24b89845b9581bac9324jorlow@chromium.org#include "leveldb/env.h"
24fbd97aa4c5325eace57d24b89845b9581bac9324jorlow@chromium.org#include "leveldb/slice.h"
25179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include "port/port.h"
26179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include "util/logging.h"
2729c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org#include "util/mutexlock.h"
28f65a55c8d0744b95be29a65d06b59b22b012f37bgabor@google.com#include "util/posix_logger.h"
29179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
30179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgnamespace leveldb {
31179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
32179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgnamespace {
33179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
34917b88dd720b6e658c1fd7812bc61c605f315124gabor@google.comstatic Status IOError(const std::string& context, int err_number) {
35917b88dd720b6e658c1fd7812bc61c605f315124gabor@google.com  return Status::IOError(context, strerror(err_number));
36917b88dd720b6e658c1fd7812bc61c605f315124gabor@google.com}
37917b88dd720b6e658c1fd7812bc61c605f315124gabor@google.com
38179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgclass PosixSequentialFile: public SequentialFile {
39179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org private:
40179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  std::string filename_;
41179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  FILE* file_;
42179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
43179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org public:
44179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  PosixSequentialFile(const std::string& fname, FILE* f)
45179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      : filename_(fname), file_(f) { }
46179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  virtual ~PosixSequentialFile() { fclose(file_); }
47179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
48179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  virtual Status Read(size_t n, Slice* result, char* scratch) {
49179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    Status s;
50179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    size_t r = fread_unlocked(scratch, 1, n, file_);
51179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    *result = Slice(scratch, r);
52179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    if (r < n) {
53179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      if (feof(file_)) {
54179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org        // We leave status as ok if we hit the end of the file
55179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      } else {
56179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org        // A partial read with an error: return a non-ok status
57917b88dd720b6e658c1fd7812bc61c605f315124gabor@google.com        s = IOError(filename_, errno);
58179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      }
59179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    }
60179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    return s;
61179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
62a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org
63a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org  virtual Status Skip(uint64_t n) {
64a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org    if (fseek(file_, n, SEEK_CUR)) {
65917b88dd720b6e658c1fd7812bc61c605f315124gabor@google.com      return IOError(filename_, errno);
66a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org    }
67a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org    return Status::OK();
68a5b4129c0a8c01158cde2244a5811f15b9d45ec0dgrogan@chromium.org  }
69179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org};
70179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
71e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com// pread() based random-access
72179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgclass PosixRandomAccessFile: public RandomAccessFile {
73179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org private:
74179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  std::string filename_;
75179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  int fd_;
76179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
77179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org public:
78f85ede82f8c27a00c3120f67fbab89b2a89fe987jorlow@chromium.org  PosixRandomAccessFile(const std::string& fname, int fd)
79f85ede82f8c27a00c3120f67fbab89b2a89fe987jorlow@chromium.org      : filename_(fname), fd_(fd) { }
80179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  virtual ~PosixRandomAccessFile() { close(fd_); }
81179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
82179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  virtual Status Read(uint64_t offset, size_t n, Slice* result,
83179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org                      char* scratch) const {
84179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    Status s;
85179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    ssize_t r = pread(fd_, scratch, n, static_cast<off_t>(offset));
86179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    *result = Slice(scratch, (r < 0) ? 0 : r);
87179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    if (r < 0) {
88179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      // An error: return a non-ok status
89917b88dd720b6e658c1fd7812bc61c605f315124gabor@google.com      s = IOError(filename_, errno);
90179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    }
91179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    return s;
92179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
93179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org};
94179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
9529c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org// Helper class to limit mmap file usage so that we do not end up
9629c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org// running out virtual memory or running into kernel performance
9729c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org// problems for very large databases.
9829c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.orgclass MmapLimiter {
9929c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org public:
10029c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org  // Up to 1000 mmaps for 64-bit binaries; none for smaller pointer sizes.
10129c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org  MmapLimiter() {
10229c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org    SetAllowed(sizeof(void*) >= 8 ? 1000 : 0);
10329c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org  }
10429c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org
10529c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org  // If another mmap slot is available, acquire it and return true.
10629c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org  // Else return false.
10729c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org  bool Acquire() {
10829c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org    if (GetAllowed() <= 0) {
10929c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org      return false;
11029c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org    }
11129c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org    MutexLock l(&mu_);
11229c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org    intptr_t x = GetAllowed();
11329c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org    if (x <= 0) {
11429c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org      return false;
11529c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org    } else {
11629c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org      SetAllowed(x - 1);
11729c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org      return true;
11829c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org    }
11929c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org  }
12029c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org
12129c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org  // Release a slot acquired by a previous call to Acquire() that returned true.
12229c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org  void Release() {
12329c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org    MutexLock l(&mu_);
12429c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org    SetAllowed(GetAllowed() + 1);
12529c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org  }
12629c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org
12729c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org private:
12829c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org  port::Mutex mu_;
12929c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org  port::AtomicPointer allowed_;
13029c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org
13129c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org  intptr_t GetAllowed() const {
13229c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org    return reinterpret_cast<intptr_t>(allowed_.Acquire_Load());
13329c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org  }
13429c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org
13529c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org  // REQUIRES: mu_ must be held
13629c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org  void SetAllowed(intptr_t v) {
13729c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org    allowed_.Release_Store(reinterpret_cast<void*>(v));
13829c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org  }
13929c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org
14029c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org  MmapLimiter(const MmapLimiter&);
14129c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org  void operator=(const MmapLimiter&);
14229c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org};
14329c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org
144e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com// mmap() based random-access
145e83668fa64e932a64712c99398be0acfe75367afsanjay@google.comclass PosixMmapReadableFile: public RandomAccessFile {
146e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com private:
147e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com  std::string filename_;
148e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com  void* mmapped_region_;
149e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com  size_t length_;
15029c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org  MmapLimiter* limiter_;
151e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com
152e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com public:
153e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com  // base[0,length-1] contains the mmapped contents of the file.
15429c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org  PosixMmapReadableFile(const std::string& fname, void* base, size_t length,
15529c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org                        MmapLimiter* limiter)
15629c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org      : filename_(fname), mmapped_region_(base), length_(length),
15729c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org        limiter_(limiter) {
15829c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org  }
15929c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org
16029c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org  virtual ~PosixMmapReadableFile() {
16129c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org    munmap(mmapped_region_, length_);
16229c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org    limiter_->Release();
16329c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org  }
164e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com
165e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com  virtual Status Read(uint64_t offset, size_t n, Slice* result,
166e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com                      char* scratch) const {
167e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com    Status s;
168e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com    if (offset + n > length_) {
169e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com      *result = Slice();
170e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com      s = IOError(filename_, EINVAL);
171e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com    } else {
172e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com      *result = Slice(reinterpret_cast<char*>(mmapped_region_) + offset, n);
173e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com    }
174e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com    return s;
175e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com  }
176e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com};
177e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com
1784935bf087b28aa308c0a820720b85ef695e236aedgrogan@chromium.orgclass PosixWritableFile : public WritableFile {
179179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org private:
180179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  std::string filename_;
1814935bf087b28aa308c0a820720b85ef695e236aedgrogan@chromium.org  FILE* file_;
182179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
183179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org public:
1844935bf087b28aa308c0a820720b85ef695e236aedgrogan@chromium.org  PosixWritableFile(const std::string& fname, FILE* f)
1854935bf087b28aa308c0a820720b85ef695e236aedgrogan@chromium.org      : filename_(fname), file_(f) { }
1864935bf087b28aa308c0a820720b85ef695e236aedgrogan@chromium.org
1874935bf087b28aa308c0a820720b85ef695e236aedgrogan@chromium.org  ~PosixWritableFile() {
1884935bf087b28aa308c0a820720b85ef695e236aedgrogan@chromium.org    if (file_ != NULL) {
1894935bf087b28aa308c0a820720b85ef695e236aedgrogan@chromium.org      // Ignoring any potential errors
1904935bf087b28aa308c0a820720b85ef695e236aedgrogan@chromium.org      fclose(file_);
191179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    }
192179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
193179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
194179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  virtual Status Append(const Slice& data) {
1954935bf087b28aa308c0a820720b85ef695e236aedgrogan@chromium.org    size_t r = fwrite_unlocked(data.data(), 1, data.size(), file_);
1964935bf087b28aa308c0a820720b85ef695e236aedgrogan@chromium.org    if (r != data.size()) {
1974935bf087b28aa308c0a820720b85ef695e236aedgrogan@chromium.org      return IOError(filename_, errno);
198179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    }
199179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    return Status::OK();
200179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
201179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
202179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  virtual Status Close() {
2034935bf087b28aa308c0a820720b85ef695e236aedgrogan@chromium.org    Status result;
2044935bf087b28aa308c0a820720b85ef695e236aedgrogan@chromium.org    if (fclose(file_) != 0) {
2054935bf087b28aa308c0a820720b85ef695e236aedgrogan@chromium.org      result = IOError(filename_, errno);
206179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    }
2074935bf087b28aa308c0a820720b85ef695e236aedgrogan@chromium.org    file_ = NULL;
2084935bf087b28aa308c0a820720b85ef695e236aedgrogan@chromium.org    return result;
209179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
210179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
211179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  virtual Status Flush() {
2124935bf087b28aa308c0a820720b85ef695e236aedgrogan@chromium.org    if (fflush_unlocked(file_) != 0) {
2134935bf087b28aa308c0a820720b85ef695e236aedgrogan@chromium.org      return IOError(filename_, errno);
2144935bf087b28aa308c0a820720b85ef695e236aedgrogan@chromium.org    }
215179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    return Status::OK();
216179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
217179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
21808595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org  Status SyncDirIfManifest() {
21908595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org    const char* f = filename_.c_str();
22008595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org    const char* sep = strrchr(f, '/');
22108595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org    Slice basename;
22208595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org    std::string dir;
22308595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org    if (sep == NULL) {
22408595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org      dir = ".";
22508595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org      basename = f;
22608595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org    } else {
22708595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org      dir = std::string(f, sep - f);
22808595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org      basename = sep + 1;
22908595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org    }
230179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    Status s;
23108595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org    if (basename.starts_with("MANIFEST")) {
23208595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org      int fd = open(dir.c_str(), O_RDONLY);
23308595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org      if (fd < 0) {
23408595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org        s = IOError(dir, errno);
23508595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org      } else {
23608595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org        if (fsync(fd) < 0) {
23708595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org          s = IOError(dir, errno);
23808595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org        }
23908595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org        close(fd);
24008595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org      }
24108595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org    }
24208595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org    return s;
24308595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org  }
24408595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org
24508595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org  virtual Status Sync() {
24608595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org    // Ensure new files referred to by the manifest are in the filesystem.
24708595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org    Status s = SyncDirIfManifest();
24808595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org    if (!s.ok()) {
24908595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org      return s;
25008595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org    }
2514935bf087b28aa308c0a820720b85ef695e236aedgrogan@chromium.org    if (fflush_unlocked(file_) != 0 ||
2524935bf087b28aa308c0a820720b85ef695e236aedgrogan@chromium.org        fdatasync(fileno(file_)) != 0) {
2534935bf087b28aa308c0a820720b85ef695e236aedgrogan@chromium.org      s = Status::IOError(filename_, strerror(errno));
254179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    }
255179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    return s;
256179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
257179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org};
258179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
259179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgstatic int LockOrUnlock(int fd, bool lock) {
260179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  errno = 0;
261179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  struct flock f;
262179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  memset(&f, 0, sizeof(f));
263179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  f.l_type = (lock ? F_WRLCK : F_UNLCK);
264179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  f.l_whence = SEEK_SET;
265179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  f.l_start = 0;
266179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  f.l_len = 0;        // Lock/unlock entire file
267179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  return fcntl(fd, F_SETLK, &f);
268179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org}
269179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
270179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgclass PosixFileLock : public FileLock {
271179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org public:
272179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  int fd_;
27329c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org  std::string name_;
27429c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org};
27529c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org
27629c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org// Set of locked files.  We keep a separate set instead of just
27729c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org// relying on fcntrl(F_SETLK) since fcntl(F_SETLK) does not provide
27829c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org// any protection against multiple uses from the same process.
27929c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.orgclass PosixLockTable {
28029c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org private:
28129c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org  port::Mutex mu_;
28229c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org  std::set<std::string> locked_files_;
28329c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org public:
28429c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org  bool Insert(const std::string& fname) {
28529c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org    MutexLock l(&mu_);
28629c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org    return locked_files_.insert(fname).second;
28729c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org  }
28829c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org  void Remove(const std::string& fname) {
28929c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org    MutexLock l(&mu_);
29029c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org    locked_files_.erase(fname);
29129c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org  }
292179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org};
293179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
294179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgclass PosixEnv : public Env {
295179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org public:
296179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  PosixEnv();
297179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  virtual ~PosixEnv() {
298179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    fprintf(stderr, "Destroying Env::Default()\n");
299bd534e2d9ba35e6ada9afe854ad0dbcef3f27c4fdgrogan@chromium.org    abort();
300179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
301179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
302179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  virtual Status NewSequentialFile(const std::string& fname,
303179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org                                   SequentialFile** result) {
304179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    FILE* f = fopen(fname.c_str(), "r");
305179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    if (f == NULL) {
306179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      *result = NULL;
307917b88dd720b6e658c1fd7812bc61c605f315124gabor@google.com      return IOError(fname, errno);
308179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    } else {
309179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      *result = new PosixSequentialFile(fname, f);
310179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      return Status::OK();
311179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    }
312179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
313179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
314179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  virtual Status NewRandomAccessFile(const std::string& fname,
315179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org                                     RandomAccessFile** result) {
316e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com    *result = NULL;
317e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com    Status s;
318179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    int fd = open(fname.c_str(), O_RDONLY);
319179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    if (fd < 0) {
320e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com      s = IOError(fname, errno);
32129c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org    } else if (mmap_limit_.Acquire()) {
322e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com      uint64_t size;
323e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com      s = GetFileSize(fname, &size);
324e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com      if (s.ok()) {
325e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com        void* base = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
326e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com        if (base != MAP_FAILED) {
32729c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org          *result = new PosixMmapReadableFile(fname, base, size, &mmap_limit_);
328e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com        } else {
329e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com          s = IOError(fname, errno);
330e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com        }
331e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com      }
332e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com      close(fd);
33329c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org      if (!s.ok()) {
33429c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org        mmap_limit_.Release();
33529c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org      }
336e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com    } else {
337e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com      *result = new PosixRandomAccessFile(fname, fd);
338179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    }
339e83668fa64e932a64712c99398be0acfe75367afsanjay@google.com    return s;
340179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
341179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
342179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  virtual Status NewWritableFile(const std::string& fname,
343179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org                                 WritableFile** result) {
344179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    Status s;
3454935bf087b28aa308c0a820720b85ef695e236aedgrogan@chromium.org    FILE* f = fopen(fname.c_str(), "w");
3464935bf087b28aa308c0a820720b85ef695e236aedgrogan@chromium.org    if (f == NULL) {
347179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      *result = NULL;
348917b88dd720b6e658c1fd7812bc61c605f315124gabor@google.com      s = IOError(fname, errno);
349179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    } else {
3504935bf087b28aa308c0a820720b85ef695e236aedgrogan@chromium.org      *result = new PosixWritableFile(fname, f);
351179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    }
352179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    return s;
353179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
354179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
355179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  virtual bool FileExists(const std::string& fname) {
356179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    return access(fname.c_str(), F_OK) == 0;
357179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
358179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
359179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  virtual Status GetChildren(const std::string& dir,
360179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org                             std::vector<std::string>* result) {
361179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    result->clear();
362179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    DIR* d = opendir(dir.c_str());
363179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    if (d == NULL) {
364917b88dd720b6e658c1fd7812bc61c605f315124gabor@google.com      return IOError(dir, errno);
365179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    }
366179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    struct dirent* entry;
367179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    while ((entry = readdir(d)) != NULL) {
368179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      result->push_back(entry->d_name);
369179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    }
370179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    closedir(d);
371179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    return Status::OK();
372179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
373179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
374179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  virtual Status DeleteFile(const std::string& fname) {
375179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    Status result;
376179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    if (unlink(fname.c_str()) != 0) {
377917b88dd720b6e658c1fd7812bc61c605f315124gabor@google.com      result = IOError(fname, errno);
378179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    }
379179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    return result;
38011042098fe3e5a16ad70c388bb5914a907ae3faedgrogan@chromium.org  }
381179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
382179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  virtual Status CreateDir(const std::string& name) {
383179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    Status result;
384179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    if (mkdir(name.c_str(), 0755) != 0) {
385917b88dd720b6e658c1fd7812bc61c605f315124gabor@google.com      result = IOError(name, errno);
386179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    }
387179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    return result;
38811042098fe3e5a16ad70c388bb5914a907ae3faedgrogan@chromium.org  }
389179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
390179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  virtual Status DeleteDir(const std::string& name) {
391179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    Status result;
392179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    if (rmdir(name.c_str()) != 0) {
393917b88dd720b6e658c1fd7812bc61c605f315124gabor@google.com      result = IOError(name, errno);
394179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    }
395179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    return result;
39611042098fe3e5a16ad70c388bb5914a907ae3faedgrogan@chromium.org  }
397179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
398179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  virtual Status GetFileSize(const std::string& fname, uint64_t* size) {
399179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    Status s;
400179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    struct stat sbuf;
401179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    if (stat(fname.c_str(), &sbuf) != 0) {
402179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      *size = 0;
403917b88dd720b6e658c1fd7812bc61c605f315124gabor@google.com      s = IOError(fname, errno);
404179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    } else {
405179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      *size = sbuf.st_size;
406179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    }
407179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    return s;
408179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
409179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
410179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  virtual Status RenameFile(const std::string& src, const std::string& target) {
411179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    Status result;
412179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    if (rename(src.c_str(), target.c_str()) != 0) {
413917b88dd720b6e658c1fd7812bc61c605f315124gabor@google.com      result = IOError(src, errno);
414179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    }
415179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    return result;
416179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
417179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
418179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  virtual Status LockFile(const std::string& fname, FileLock** lock) {
419179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    *lock = NULL;
420179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    Status result;
421179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    int fd = open(fname.c_str(), O_RDWR | O_CREAT, 0644);
422179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    if (fd < 0) {
423917b88dd720b6e658c1fd7812bc61c605f315124gabor@google.com      result = IOError(fname, errno);
42429c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org    } else if (!locks_.Insert(fname)) {
42529c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org      close(fd);
42629c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org      result = Status::IOError("lock " + fname, "already held by process");
427179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    } else if (LockOrUnlock(fd, true) == -1) {
428917b88dd720b6e658c1fd7812bc61c605f315124gabor@google.com      result = IOError("lock " + fname, errno);
429179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      close(fd);
43029c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org      locks_.Remove(fname);
431179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    } else {
432179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      PosixFileLock* my_lock = new PosixFileLock;
433179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      my_lock->fd_ = fd;
43429c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org      my_lock->name_ = fname;
435179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      *lock = my_lock;
436179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    }
437179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    return result;
438179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
439179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
440179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  virtual Status UnlockFile(FileLock* lock) {
441179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    PosixFileLock* my_lock = reinterpret_cast<PosixFileLock*>(lock);
442179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    Status result;
443179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    if (LockOrUnlock(my_lock->fd_, false) == -1) {
444917b88dd720b6e658c1fd7812bc61c605f315124gabor@google.com      result = IOError("unlock", errno);
445179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    }
44629c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org    locks_.Remove(my_lock->name_);
447179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    close(my_lock->fd_);
448179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    delete my_lock;
449179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    return result;
450179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
451179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
452179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  virtual void Schedule(void (*function)(void*), void* arg);
453179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
454179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  virtual void StartThread(void (*function)(void* arg), void* arg);
455179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
456179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  virtual Status GetTestDirectory(std::string* result) {
457179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    const char* env = getenv("TEST_TMPDIR");
458179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    if (env && env[0] != '\0') {
459179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      *result = env;
460179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    } else {
461179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      char buf[100];
462179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      snprintf(buf, sizeof(buf), "/tmp/leveldbtest-%d", int(geteuid()));
463179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      *result = buf;
464179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    }
465179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    // Directory may already exist
466179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    CreateDir(*result);
467179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    return Status::OK();
468179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
469179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
470f65a55c8d0744b95be29a65d06b59b22b012f37bgabor@google.com  static uint64_t gettid() {
471179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    pthread_t tid = pthread_self();
472179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    uint64_t thread_id = 0;
47384744ee8e3e568ca5b24eabf31be706d69d80c4djorlow@chromium.org    memcpy(&thread_id, &tid, std::min(sizeof(thread_id), sizeof(tid)));
474f65a55c8d0744b95be29a65d06b59b22b012f37bgabor@google.com    return thread_id;
475f65a55c8d0744b95be29a65d06b59b22b012f37bgabor@google.com  }
476179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
477f65a55c8d0744b95be29a65d06b59b22b012f37bgabor@google.com  virtual Status NewLogger(const std::string& fname, Logger** result) {
478f65a55c8d0744b95be29a65d06b59b22b012f37bgabor@google.com    FILE* f = fopen(fname.c_str(), "w");
479f65a55c8d0744b95be29a65d06b59b22b012f37bgabor@google.com    if (f == NULL) {
480f65a55c8d0744b95be29a65d06b59b22b012f37bgabor@google.com      *result = NULL;
481f65a55c8d0744b95be29a65d06b59b22b012f37bgabor@google.com      return IOError(fname, errno);
482f65a55c8d0744b95be29a65d06b59b22b012f37bgabor@google.com    } else {
483f65a55c8d0744b95be29a65d06b59b22b012f37bgabor@google.com      *result = new PosixLogger(f, &PosixEnv::gettid);
484f65a55c8d0744b95be29a65d06b59b22b012f37bgabor@google.com      return Status::OK();
485179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    }
486179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
487179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
488179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  virtual uint64_t NowMicros() {
489179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    struct timeval tv;
490179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    gettimeofday(&tv, NULL);
491179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    return static_cast<uint64_t>(tv.tv_sec) * 1000000 + tv.tv_usec;
492179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
493179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
494179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  virtual void SleepForMicroseconds(int micros) {
495179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    usleep(micros);
496179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
497179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
498179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org private:
499179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  void PthreadCall(const char* label, int result) {
500179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    if (result != 0) {
501179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      fprintf(stderr, "pthread %s: %s\n", label, strerror(result));
502bd534e2d9ba35e6ada9afe854ad0dbcef3f27c4fdgrogan@chromium.org      abort();
503179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    }
504179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
505179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
506179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  // BGThread() is the body of the background thread
507179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  void BGThread();
508179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  static void* BGThreadWrapper(void* arg) {
509179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    reinterpret_cast<PosixEnv*>(arg)->BGThread();
510179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    return NULL;
511179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
512179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
513179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  pthread_mutex_t mu_;
514179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  pthread_cond_t bgsignal_;
515179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  pthread_t bgthread_;
516179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  bool started_bgthread_;
517179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
518179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  // Entry per Schedule() call
519179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  struct BGItem { void* arg; void (*function)(void*); };
520179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  typedef std::deque<BGItem> BGQueue;
521179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  BGQueue queue_;
52229c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org
52329c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org  PosixLockTable locks_;
52429c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org  MmapLimiter mmap_limit_;
525179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org};
526179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
5274935bf087b28aa308c0a820720b85ef695e236aedgrogan@chromium.orgPosixEnv::PosixEnv() : started_bgthread_(false) {
528179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  PthreadCall("mutex_init", pthread_mutex_init(&mu_, NULL));
529179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  PthreadCall("cvar_init", pthread_cond_init(&bgsignal_, NULL));
530179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org}
531179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
532179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgvoid PosixEnv::Schedule(void (*function)(void*), void* arg) {
533179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  PthreadCall("lock", pthread_mutex_lock(&mu_));
534179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
535179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  // Start background thread if necessary
536179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  if (!started_bgthread_) {
537179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    started_bgthread_ = true;
538179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    PthreadCall(
539179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org        "create thread",
540179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org        pthread_create(&bgthread_, NULL,  &PosixEnv::BGThreadWrapper, this));
541179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
542179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
543179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  // If the queue is currently empty, the background thread may currently be
544179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  // waiting.
545179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  if (queue_.empty()) {
546179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    PthreadCall("signal", pthread_cond_signal(&bgsignal_));
547179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
548179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
549179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  // Add to priority queue
550179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  queue_.push_back(BGItem());
551179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  queue_.back().function = function;
552179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  queue_.back().arg = arg;
553179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
554179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  PthreadCall("unlock", pthread_mutex_unlock(&mu_));
555179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org}
556179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
557179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgvoid PosixEnv::BGThread() {
558179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  while (true) {
559179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    // Wait until there is an item that is ready to run
560179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    PthreadCall("lock", pthread_mutex_lock(&mu_));
561179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    while (queue_.empty()) {
562179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      PthreadCall("wait", pthread_cond_wait(&bgsignal_, &mu_));
563179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    }
564179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
565179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    void (*function)(void*) = queue_.front().function;
566179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    void* arg = queue_.front().arg;
567179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    queue_.pop_front();
568179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
569179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    PthreadCall("unlock", pthread_mutex_unlock(&mu_));
570179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    (*function)(arg);
571179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
572179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org}
573179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
574179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgnamespace {
575179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgstruct StartThreadState {
576179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  void (*user_function)(void*);
577179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  void* arg;
578179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org};
579179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org}
580179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgstatic void* StartThreadWrapper(void* arg) {
581179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  StartThreadState* state = reinterpret_cast<StartThreadState*>(arg);
582179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  state->user_function(state->arg);
583179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  delete state;
584179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  return NULL;
585179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org}
586179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
587179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgvoid PosixEnv::StartThread(void (*function)(void* arg), void* arg) {
588179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  pthread_t t;
589179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  StartThreadState* state = new StartThreadState;
590179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  state->user_function = function;
591179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  state->arg = arg;
592179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  PthreadCall("start thread",
593179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org              pthread_create(&t, NULL,  &StartThreadWrapper, state));
594179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org}
595179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
59645b9940be332834440bd5299419f396e38085ebehans@chromium.org}  // namespace
597179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
598179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgstatic pthread_once_t once = PTHREAD_ONCE_INIT;
599179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgstatic Env* default_env;
600179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgstatic void InitDefaultEnv() { default_env = new PosixEnv; }
601179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
602179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgEnv* Env::Default() {
603179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  pthread_once(&once, InitDefaultEnv);
604179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  return default_env;
605179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org}
606179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
60745b9940be332834440bd5299419f396e38085ebehans@chromium.org}  // namespace leveldb
608