Coverage Report

Created: 2025-06-10 13:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/bitcoin/src/leveldb/util/env_posix.cc
Line
Count
Source
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
5
#include <dirent.h>
6
#include <fcntl.h>
7
#include <pthread.h>
8
#include <sys/mman.h>
9
#include <sys/resource.h>
10
#include <sys/stat.h>
11
#include <sys/time.h>
12
#include <sys/types.h>
13
#include <unistd.h>
14
15
#include <atomic>
16
#include <cerrno>
17
#include <cstddef>
18
#include <cstdint>
19
#include <cstdio>
20
#include <cstdlib>
21
#include <cstring>
22
#include <limits>
23
#include <queue>
24
#include <set>
25
#include <string>
26
#include <thread>
27
#include <type_traits>
28
#include <utility>
29
30
#include "leveldb/env.h"
31
#include "leveldb/slice.h"
32
#include "leveldb/status.h"
33
#include "port/port.h"
34
#include "port/thread_annotations.h"
35
#include "util/env_posix_test_helper.h"
36
#include "util/posix_logger.h"
37
38
namespace leveldb {
39
40
namespace {
41
42
// Set by EnvPosixTestHelper::SetReadOnlyMMapLimit() and MaxOpenFiles().
43
int g_open_read_only_file_limit = -1;
44
45
// Up to 4096 mmap regions for 64-bit binaries; none for 32-bit.
46
constexpr const int kDefaultMmapLimit = (sizeof(void*) >= 8) ? 4096 : 0;
47
48
// Can be set using EnvPosixTestHelper::SetReadOnlyMMapLimit().
49
int g_mmap_limit = kDefaultMmapLimit;
50
51
// Common flags defined for all posix open operations
52
#if HAVE_O_CLOEXEC
53
constexpr const int kOpenBaseFlags = O_CLOEXEC;
54
#else
55
constexpr const int kOpenBaseFlags = 0;
56
#endif  // defined(HAVE_O_CLOEXEC)
57
58
constexpr const size_t kWritableFileBufferSize = 65536;
59
60
33.2k
Status PosixError(const std::string& context, int error_number) {
61
33.2k
  if (error_number == ENOENT) {
  Branch (61:7): [True: 0, False: 33.2k]
62
0
    return Status::NotFound(context, std::strerror(error_number));
63
33.2k
  } else {
64
33.2k
    return Status::IOError(context, std::strerror(error_number));
65
33.2k
  }
66
33.2k
}
67
68
// Helper class to limit resource usage to avoid exhaustion.
69
// Currently used to limit read-only file descriptors and mmap file usage
70
// so that we do not run out of file descriptors or virtual memory, or run into
71
// kernel performance problems for very large databases.
72
class Limiter {
73
 public:
74
  // Limit maximum number of resources to |max_acquires|.
75
22.1k
  Limiter(int max_acquires) : acquires_allowed_(max_acquires) {}
76
77
  Limiter(const Limiter&) = delete;
78
  Limiter operator=(const Limiter&) = delete;
79
80
  // If another resource is available, acquire it and return true.
81
  // Else return false.
82
24
  bool Acquire() {
83
24
    int old_acquires_allowed =
84
24
        acquires_allowed_.fetch_sub(1, std::memory_order_relaxed);
85
86
24
    if (old_acquires_allowed > 0) return true;
  Branch (86:9): [True: 24, False: 0]
87
88
0
    acquires_allowed_.fetch_add(1, std::memory_order_relaxed);
89
0
    return false;
90
24
  }
91
92
  // Release a resource acquired by a previous call to Acquire() that returned
93
  // true.
94
24
  void Release() { acquires_allowed_.fetch_add(1, std::memory_order_relaxed); }
95
96
 private:
97
  // The number of available resources.
98
  //
99
  // This is a counter and is not tied to the invariants of any other class, so
100
  // it can be operated on safely using std::memory_order_relaxed.
101
  std::atomic<int> acquires_allowed_;
102
};
103
104
// Implements sequential read access in a file using read().
105
//
106
// Instances of this class are thread-friendly but not thread-safe, as required
107
// by the SequentialFile API.
108
class PosixSequentialFile final : public SequentialFile {
109
 public:
110
  PosixSequentialFile(std::string filename, int fd)
111
66.5k
      : fd_(fd), filename_(filename) {}
112
66.5k
  ~PosixSequentialFile() override { close(fd_); }
113
114
99.8k
  Status Read(size_t n, Slice* result, char* scratch) override {
115
99.8k
    Status status;
116
99.8k
    while (true) {
  Branch (116:12): [Folded - Ignored]
117
99.8k
      ::ssize_t read_size = ::read(fd_, scratch, n);
118
99.8k
      if (read_size < 0) {  // Read error.
  Branch (118:11): [True: 0, False: 99.8k]
119
0
        if (errno == EINTR) {
  Branch (119:13): [True: 0, False: 0]
120
0
          continue;  // Retry
121
0
        }
122
0
        status = PosixError(filename_, errno);
123
0
        break;
124
0
      }
125
99.8k
      *result = Slice(scratch, read_size);
126
99.8k
      break;
127
99.8k
    }
128
99.8k
    return status;
129
99.8k
  }
130
131
0
  Status Skip(uint64_t n) override {
132
0
    if (::lseek(fd_, n, SEEK_CUR) == static_cast<off_t>(-1)) {
  Branch (132:9): [True: 0, False: 0]
133
0
      return PosixError(filename_, errno);
134
0
    }
135
0
    return Status::OK();
136
0
  }
137
138
0
  virtual std::string GetName() const override { return filename_; }
139
140
 private:
141
  const int fd_;
142
  const std::string filename_;
143
};
144
145
// Implements random read access in a file using pread().
146
//
147
// Instances of this class are thread-safe, as required by the RandomAccessFile
148
// API. Instances are immutable and Read() only calls thread-safe library
149
// functions.
150
class PosixRandomAccessFile final : public RandomAccessFile {
151
 public:
152
  // The new instance takes ownership of |fd|. |fd_limiter| must outlive this
153
  // instance, and will be used to determine if .
154
  PosixRandomAccessFile(std::string filename, int fd, Limiter* fd_limiter)
155
0
      : has_permanent_fd_(fd_limiter->Acquire()),
156
0
        fd_(has_permanent_fd_ ? fd : -1),
  Branch (156:13): [True: 0, False: 0]
157
0
        fd_limiter_(fd_limiter),
158
0
        filename_(std::move(filename)) {
159
0
    if (!has_permanent_fd_) {
  Branch (159:9): [True: 0, False: 0]
160
0
      assert(fd_ == -1);
  Branch (160:7): [True: 0, False: 0]
161
0
      ::close(fd);  // The file will be opened on every read.
162
0
    }
163
0
  }
164
165
0
  ~PosixRandomAccessFile() override {
166
0
    if (has_permanent_fd_) {
  Branch (166:9): [True: 0, False: 0]
167
0
      assert(fd_ != -1);
  Branch (167:7): [True: 0, False: 0]
168
0
      ::close(fd_);
169
0
      fd_limiter_->Release();
170
0
    }
171
0
  }
172
173
  Status Read(uint64_t offset, size_t n, Slice* result,
174
0
              char* scratch) const override {
175
0
    int fd = fd_;
176
0
    if (!has_permanent_fd_) {
  Branch (176:9): [True: 0, False: 0]
177
0
      fd = ::open(filename_.c_str(), O_RDONLY | kOpenBaseFlags);
178
0
      if (fd < 0) {
  Branch (178:11): [True: 0, False: 0]
179
0
        return PosixError(filename_, errno);
180
0
      }
181
0
    }
182
183
0
    assert(fd != -1);
  Branch (183:5): [True: 0, False: 0]
184
185
0
    Status status;
186
0
    ssize_t read_size = ::pread(fd, scratch, n, static_cast<off_t>(offset));
187
0
    *result = Slice(scratch, (read_size < 0) ? 0 : read_size);
  Branch (187:30): [True: 0, False: 0]
188
0
    if (read_size < 0) {
  Branch (188:9): [True: 0, False: 0]
189
      // An error: return a non-ok status.
190
0
      status = PosixError(filename_, errno);
191
0
    }
192
0
    if (!has_permanent_fd_) {
  Branch (192:9): [True: 0, False: 0]
193
      // Close the temporary file descriptor opened earlier.
194
0
      assert(fd != fd_);
  Branch (194:7): [True: 0, False: 0]
195
0
      ::close(fd);
196
0
    }
197
0
    return status;
198
0
  }
199
200
0
  virtual std::string GetName() const override { return filename_; }
201
202
 private:
203
  const bool has_permanent_fd_;  // If false, the file is opened on every read.
204
  const int fd_;                 // -1 if has_permanent_fd_ is false.
205
  Limiter* const fd_limiter_;
206
  const std::string filename_;
207
};
208
209
// Implements random read access in a file using mmap().
210
//
211
// Instances of this class are thread-safe, as required by the RandomAccessFile
212
// API. Instances are immutable and Read() only calls thread-safe library
213
// functions.
214
class PosixMmapReadableFile final : public RandomAccessFile {
215
 public:
216
  // mmap_base[0, length-1] points to the memory-mapped contents of the file. It
217
  // must be the result of a successful call to mmap(). This instances takes
218
  // over the ownership of the region.
219
  //
220
  // |mmap_limiter| must outlive this instance. The caller must have already
221
  // aquired the right to use one mmap region, which will be released when this
222
  // instance is destroyed.
223
  PosixMmapReadableFile(std::string filename, char* mmap_base, size_t length,
224
                        Limiter* mmap_limiter)
225
24
      : mmap_base_(mmap_base),
226
24
        length_(length),
227
24
        mmap_limiter_(mmap_limiter),
228
24
        filename_(std::move(filename)) {}
229
230
24
  ~PosixMmapReadableFile() override {
231
24
    ::munmap(static_cast<void*>(mmap_base_), length_);
232
24
    mmap_limiter_->Release();
233
24
  }
234
235
  Status Read(uint64_t offset, size_t n, Slice* result,
236
108
              char* scratch) const override {
237
108
    if (offset + n > length_) {
  Branch (237:9): [True: 0, False: 108]
238
0
      *result = Slice();
239
0
      return PosixError(filename_, EINVAL);
240
0
    }
241
242
108
    *result = Slice(mmap_base_ + offset, n);
243
108
    return Status::OK();
244
108
  }
245
246
0
  virtual std::string GetName() const override { return filename_; }
247
248
 private:
249
  char* const mmap_base_;
250
  const size_t length_;
251
  Limiter* const mmap_limiter_;
252
  const std::string filename_;
253
};
254
255
class PosixWritableFile final : public WritableFile {
256
 public:
257
  PosixWritableFile(std::string filename, int fd)
258
166k
      : pos_(0),
259
166k
        fd_(fd),
260
166k
        is_manifest_(IsManifest(filename)),
261
166k
        filename_(std::move(filename)),
262
166k
        dirname_(Dirname(filename_)) {}
263
264
166k
  ~PosixWritableFile() override {
265
166k
    if (fd_ >= 0) {
  Branch (265:9): [True: 66.5k, False: 99.8k]
266
      // Ignoring any potential errors
267
66.5k
      Close();
268
66.5k
    }
269
166k
  }
270
271
4.92M
  Status Append(const Slice& data) override {
272
4.92M
    size_t write_size = data.size();
273
4.92M
    const char* write_data = data.data();
274
275
    // Fit as much as possible into buffer.
276
4.92M
    size_t copy_size = std::min(write_size, kWritableFileBufferSize - pos_);
277
4.92M
    std::memcpy(buf_ + pos_, write_data, copy_size);
278
4.92M
    write_data += copy_size;
279
4.92M
    write_size -= copy_size;
280
4.92M
    pos_ += copy_size;
281
4.92M
    if (write_size == 0) {
  Branch (281:9): [True: 4.92M, False: 0]
282
4.92M
      return Status::OK();
283
4.92M
    }
284
285
    // Can't fit in buffer, so need to do at least one write.
286
0
    Status status = FlushBuffer();
287
0
    if (!status.ok()) {
  Branch (287:9): [True: 0, False: 0]
288
0
      return status;
289
0
    }
290
291
    // Small writes go to buffer, large writes are written directly.
292
0
    if (write_size < kWritableFileBufferSize) {
  Branch (292:9): [True: 0, False: 0]
293
0
      std::memcpy(buf_, write_data, write_size);
294
0
      pos_ = write_size;
295
0
      return Status::OK();
296
0
    }
297
0
    return WriteUnbuffered(write_data, write_size);
298
0
  }
299
300
166k
  Status Close() override {
301
166k
    Status status = FlushBuffer();
302
166k
    const int close_result = ::close(fd_);
303
166k
    if (close_result < 0 && status.ok()) {
  Branch (303:9): [True: 0, False: 166k]
  Branch (303:29): [True: 0, False: 0]
304
0
      status = PosixError(filename_, errno);
305
0
    }
306
166k
    fd_ = -1;
307
166k
    return status;
308
166k
  }
309
310
2.43M
  Status Flush() override { return FlushBuffer(); }
311
312
129k
  Status Sync() override {
313
    // Ensure new files referred to by the manifest are in the filesystem.
314
    //
315
    // This needs to happen before the manifest file is flushed to disk, to
316
    // avoid crashing in a state where the manifest refers to files that are not
317
    // yet on disk.
318
129k
    Status status = SyncDirIfManifest();
319
129k
    if (!status.ok()) {
  Branch (319:9): [True: 0, False: 129k]
320
0
      return status;
321
0
    }
322
323
129k
    status = FlushBuffer();
324
129k
    if (!status.ok()) {
  Branch (324:9): [True: 0, False: 129k]
325
0
      return status;
326
0
    }
327
328
129k
    return SyncFd(fd_, filename_, false);
329
129k
  }
330
331
 private:
332
2.72M
  Status FlushBuffer() {
333
2.72M
    Status status = WriteUnbuffered(buf_, pos_);
334
2.72M
    pos_ = 0;
335
2.72M
    return status;
336
2.72M
  }
337
338
2.72M
  Status WriteUnbuffered(const char* data, size_t size) {
339
5.22M
    while (size > 0) {
  Branch (339:12): [True: 2.49M, False: 2.72M]
340
2.49M
      ssize_t write_result = ::write(fd_, data, size);
341
2.49M
      if (write_result < 0) {
  Branch (341:11): [True: 0, False: 2.49M]
342
0
        if (errno == EINTR) {
  Branch (342:13): [True: 0, False: 0]
343
0
          continue;  // Retry
344
0
        }
345
0
        return PosixError(filename_, errno);
346
0
      }
347
2.49M
      data += write_result;
348
2.49M
      size -= write_result;
349
2.49M
    }
350
2.72M
    return Status::OK();
351
2.72M
  }
352
353
129k
  Status SyncDirIfManifest() {
354
129k
    Status status;
355
129k
    if (!is_manifest_) {
  Branch (355:9): [True: 95.7k, False: 33.3k]
356
95.7k
      return status;
357
95.7k
    }
358
359
33.3k
    int fd = ::open(dirname_.c_str(), O_RDONLY | kOpenBaseFlags);
360
33.3k
    if (fd < 0) {
  Branch (360:9): [True: 0, False: 33.3k]
361
0
      status = PosixError(dirname_, errno);
362
33.3k
    } else {
363
33.3k
      status = SyncFd(fd, dirname_, true);
364
33.3k
      ::close(fd);
365
33.3k
    }
366
33.3k
    return status;
367
129k
  }
368
369
  // Ensures that all the caches associated with the given file descriptor's
370
  // data are flushed all the way to durable media, and can withstand power
371
  // failures.
372
  //
373
  // The path argument is only used to populate the description string in the
374
  // returned Status if an error occurs.
375
162k
  static Status SyncFd(int fd, const std::string& fd_path, bool syncing_dir) {
376
#if HAVE_FULLFSYNC
377
    // On macOS and iOS, fsync() doesn't guarantee durability past power
378
    // failures. fcntl(F_FULLFSYNC) is required for that purpose. Some
379
    // filesystems don't support fcntl(F_FULLFSYNC), and require a fallback to
380
    // fsync().
381
    if (::fcntl(fd, F_FULLFSYNC) == 0) {
382
      return Status::OK();
383
    }
384
#endif  // HAVE_FULLFSYNC
385
386
162k
#if HAVE_FDATASYNC
387
162k
    bool sync_success = ::fdatasync(fd) == 0;
388
#else
389
    bool sync_success = ::fsync(fd) == 0;
390
#endif  // HAVE_FDATASYNC
391
392
162k
    if (sync_success) {
  Branch (392:9): [True: 162k, False: 0]
393
162k
      return Status::OK();
394
162k
    }
395
    // Do not crash if filesystem can't fsync directories
396
    // (see https://github.com/bitcoin/bitcoin/pull/10000)
397
0
    if (syncing_dir && errno == EINVAL) {
  Branch (397:9): [True: 0, False: 0]
  Branch (397:24): [True: 0, False: 0]
398
0
      return Status::OK();
399
0
    }
400
0
    return PosixError(fd_path, errno);
401
0
  }
402
403
  // Returns the directory name in a path pointing to a file.
404
  //
405
  // Returns "." if the path does not contain any directory separator.
406
166k
  static std::string Dirname(const std::string& filename) {
407
166k
    std::string::size_type separator_pos = filename.rfind('/');
408
166k
    if (separator_pos == std::string::npos) {
  Branch (408:9): [True: 0, False: 166k]
409
0
      return std::string(".");
410
0
    }
411
    // The filename component should not contain a path separator. If it does,
412
    // the splitting was done incorrectly.
413
166k
    assert(filename.find('/', separator_pos + 1) == std::string::npos);
  Branch (413:5): [True: 166k, False: 0]
414
415
166k
    return filename.substr(0, separator_pos);
416
166k
  }
417
418
  // Extracts the file name from a path pointing to a file.
419
  //
420
  // The returned Slice points to |filename|'s data buffer, so it is only valid
421
  // while |filename| is alive and unchanged.
422
166k
  static Slice Basename(const std::string& filename) {
423
166k
    std::string::size_type separator_pos = filename.rfind('/');
424
166k
    if (separator_pos == std::string::npos) {
  Branch (424:9): [True: 0, False: 166k]
425
0
      return Slice(filename);
426
0
    }
427
    // The filename component should not contain a path separator. If it does,
428
    // the splitting was done incorrectly.
429
166k
    assert(filename.find('/', separator_pos + 1) == std::string::npos);
  Branch (429:5): [True: 166k, False: 0]
430
431
166k
    return Slice(filename.data() + separator_pos + 1,
432
166k
                 filename.length() - separator_pos - 1);
433
166k
  }
434
435
  // True if the given file is a manifest file.
436
166k
  static bool IsManifest(const std::string& filename) {
437
166k
    return Basename(filename).starts_with("MANIFEST");
438
166k
  }
439
440
0
  virtual std::string GetName() const override { return filename_; }
441
442
  // buf_[0, pos_ - 1] contains data to be written to fd_.
443
  char buf_[kWritableFileBufferSize];
444
  size_t pos_;
445
  int fd_;
446
447
  const bool is_manifest_;  // True if the file's name starts with MANIFEST.
448
  const std::string filename_;
449
  const std::string dirname_;  // The directory of filename_.
450
};
451
452
66.5k
int LockOrUnlock(int fd, bool lock) {
453
66.5k
  errno = 0;
454
66.5k
  struct ::flock file_lock_info;
455
66.5k
  std::memset(&file_lock_info, 0, sizeof(file_lock_info));
456
66.5k
  file_lock_info.l_type = (lock ? F_WRLCK : F_UNLCK);
  Branch (456:28): [True: 33.2k, False: 33.2k]
457
66.5k
  file_lock_info.l_whence = SEEK_SET;
458
66.5k
  file_lock_info.l_start = 0;
459
66.5k
  file_lock_info.l_len = 0;  // Lock/unlock entire file.
460
66.5k
  return ::fcntl(fd, F_SETLK, &file_lock_info);
461
66.5k
}
462
463
// Instances are thread-safe because they are immutable.
464
class PosixFileLock : public FileLock {
465
 public:
466
  PosixFileLock(int fd, std::string filename)
467
33.2k
      : fd_(fd), filename_(std::move(filename)) {}
468
469
66.5k
  int fd() const { return fd_; }
470
33.2k
  const std::string& filename() const { return filename_; }
471
472
 private:
473
  const int fd_;
474
  const std::string filename_;
475
};
476
477
// Tracks the files locked by PosixEnv::LockFile().
478
//
479
// We maintain a separate set instead of relying on fcntl(F_SETLK) because
480
// fcntl(F_SETLK) does not provide any protection against multiple uses from the
481
// same process.
482
//
483
// Instances are thread-safe because all member data is guarded by a mutex.
484
class PosixLockTable {
485
 public:
486
33.2k
  bool Insert(const std::string& fname) LOCKS_EXCLUDED(mu_) {
487
33.2k
    mu_.Lock();
488
33.2k
    bool succeeded = locked_files_.insert(fname).second;
489
33.2k
    mu_.Unlock();
490
33.2k
    return succeeded;
491
33.2k
  }
492
33.2k
  void Remove(const std::string& fname) LOCKS_EXCLUDED(mu_) {
493
33.2k
    mu_.Lock();
494
33.2k
    locked_files_.erase(fname);
495
33.2k
    mu_.Unlock();
496
33.2k
  }
497
498
 private:
499
  port::Mutex mu_;
500
  std::set<std::string> locked_files_ GUARDED_BY(mu_);
501
};
502
503
class PosixEnv : public Env {
504
 public:
505
  PosixEnv();
506
0
  ~PosixEnv() override {
507
0
    static const char msg[] =
508
0
        "PosixEnv singleton destroyed. Unsupported behavior!\n";
509
0
    std::fwrite(msg, 1, sizeof(msg), stderr);
510
0
    std::abort();
511
0
  }
512
513
  Status NewSequentialFile(const std::string& filename,
514
66.5k
                           SequentialFile** result) override {
515
66.5k
    int fd = ::open(filename.c_str(), O_RDONLY | kOpenBaseFlags);
516
66.5k
    if (fd < 0) {
  Branch (516:9): [True: 0, False: 66.5k]
517
0
      *result = nullptr;
518
0
      return PosixError(filename, errno);
519
0
    }
520
521
66.5k
    *result = new PosixSequentialFile(filename, fd);
522
66.5k
    return Status::OK();
523
66.5k
  }
524
525
  Status NewRandomAccessFile(const std::string& filename,
526
24
                             RandomAccessFile** result) override {
527
24
    *result = nullptr;
528
24
    int fd = ::open(filename.c_str(), O_RDONLY | kOpenBaseFlags);
529
24
    if (fd < 0) {
  Branch (529:9): [True: 0, False: 24]
530
0
      return PosixError(filename, errno);
531
0
    }
532
533
24
    if (!mmap_limiter_.Acquire()) {
  Branch (533:9): [True: 0, False: 24]
534
0
      *result = new PosixRandomAccessFile(filename, fd, &fd_limiter_);
535
0
      return Status::OK();
536
0
    }
537
538
24
    uint64_t file_size;
539
24
    Status status = GetFileSize(filename, &file_size);
540
24
    if (status.ok()) {
  Branch (540:9): [True: 24, False: 0]
541
24
      void* mmap_base =
542
24
          ::mmap(/*addr=*/nullptr, file_size, PROT_READ, MAP_SHARED, fd, 0);
543
24
      if (mmap_base != MAP_FAILED) {
  Branch (543:11): [True: 24, False: 0]
544
24
        *result = new PosixMmapReadableFile(filename,
545
24
                                            reinterpret_cast<char*>(mmap_base),
546
24
                                            file_size, &mmap_limiter_);
547
24
      } else {
548
0
        status = PosixError(filename, errno);
549
0
      }
550
24
    }
551
24
    ::close(fd);
552
24
    if (!status.ok()) {
  Branch (552:9): [True: 0, False: 24]
553
0
      mmap_limiter_.Release();
554
0
    }
555
24
    return status;
556
24
  }
557
558
  Status NewWritableFile(const std::string& filename,
559
166k
                         WritableFile** result) override {
560
166k
    int fd = ::open(filename.c_str(),
561
166k
                    O_TRUNC | O_WRONLY | O_CREAT | kOpenBaseFlags, 0644);
562
166k
    if (fd < 0) {
  Branch (562:9): [True: 0, False: 166k]
563
0
      *result = nullptr;
564
0
      return PosixError(filename, errno);
565
0
    }
566
567
166k
    *result = new PosixWritableFile(filename, fd);
568
166k
    return Status::OK();
569
166k
  }
570
571
  Status NewAppendableFile(const std::string& filename,
572
0
                           WritableFile** result) override {
573
0
    int fd = ::open(filename.c_str(),
574
0
                    O_APPEND | O_WRONLY | O_CREAT | kOpenBaseFlags, 0644);
575
0
    if (fd < 0) {
  Branch (575:9): [True: 0, False: 0]
576
0
      *result = nullptr;
577
0
      return PosixError(filename, errno);
578
0
    }
579
580
0
    *result = new PosixWritableFile(filename, fd);
581
0
    return Status::OK();
582
0
  }
583
584
33.2k
  bool FileExists(const std::string& filename) override {
585
33.2k
    return ::access(filename.c_str(), F_OK) == 0;
586
33.2k
  }
587
588
  Status GetChildren(const std::string& directory_path,
589
66.5k
                     std::vector<std::string>* result) override {
590
66.5k
    result->clear();
591
66.5k
    ::DIR* dir = ::opendir(directory_path.c_str());
592
66.5k
    if (dir == nullptr) {
  Branch (592:9): [True: 0, False: 66.5k]
593
0
      return PosixError(directory_path, errno);
594
0
    }
595
66.5k
    struct ::dirent* entry;
596
466k
    while ((entry = ::readdir(dir)) != nullptr) {
  Branch (596:12): [True: 399k, False: 66.5k]
597
399k
      result->emplace_back(entry->d_name);
598
399k
    }
599
66.5k
    ::closedir(dir);
600
66.5k
    return Status::OK();
601
66.5k
  }
602
603
33.3k
  Status DeleteFile(const std::string& filename) override {
604
33.3k
    if (::unlink(filename.c_str()) != 0) {
  Branch (604:9): [True: 0, False: 33.3k]
605
0
      return PosixError(filename, errno);
606
0
    }
607
33.3k
    return Status::OK();
608
33.3k
  }
609
610
33.2k
  Status CreateDir(const std::string& dirname) override {
611
33.2k
    if (::mkdir(dirname.c_str(), 0755) != 0) {
  Branch (611:9): [True: 33.2k, False: 0]
612
33.2k
      return PosixError(dirname, errno);
613
33.2k
    }
614
0
    return Status::OK();
615
33.2k
  }
616
617
0
  Status DeleteDir(const std::string& dirname) override {
618
0
    if (::rmdir(dirname.c_str()) != 0) {
  Branch (618:9): [True: 0, False: 0]
619
0
      return PosixError(dirname, errno);
620
0
    }
621
0
    return Status::OK();
622
0
  }
623
624
24
  Status GetFileSize(const std::string& filename, uint64_t* size) override {
625
24
    struct ::stat file_stat;
626
24
    if (::stat(filename.c_str(), &file_stat) != 0) {
  Branch (626:9): [True: 0, False: 24]
627
0
      *size = 0;
628
0
      return PosixError(filename, errno);
629
0
    }
630
24
    *size = file_stat.st_size;
631
24
    return Status::OK();
632
24
  }
633
634
66.5k
  Status RenameFile(const std::string& from, const std::string& to) override {
635
66.5k
    if (std::rename(from.c_str(), to.c_str()) != 0) {
  Branch (635:9): [True: 0, False: 66.5k]
636
0
      return PosixError(from, errno);
637
0
    }
638
66.5k
    return Status::OK();
639
66.5k
  }
640
641
33.2k
  Status LockFile(const std::string& filename, FileLock** lock) override {
642
33.2k
    *lock = nullptr;
643
644
33.2k
    int fd = ::open(filename.c_str(), O_RDWR | O_CREAT | kOpenBaseFlags, 0644);
645
33.2k
    if (fd < 0) {
  Branch (645:9): [True: 0, False: 33.2k]
646
0
      return PosixError(filename, errno);
647
0
    }
648
649
33.2k
    if (!locks_.Insert(filename)) {
  Branch (649:9): [True: 0, False: 33.2k]
650
0
      ::close(fd);
651
0
      return Status::IOError("lock " + filename, "already held by process");
652
0
    }
653
654
33.2k
    if (LockOrUnlock(fd, true) == -1) {
  Branch (654:9): [True: 0, False: 33.2k]
655
0
      int lock_errno = errno;
656
0
      ::close(fd);
657
0
      locks_.Remove(filename);
658
0
      return PosixError("lock " + filename, lock_errno);
659
0
    }
660
661
33.2k
    *lock = new PosixFileLock(fd, filename);
662
33.2k
    return Status::OK();
663
33.2k
  }
664
665
33.2k
  Status UnlockFile(FileLock* lock) override {
666
33.2k
    PosixFileLock* posix_file_lock = static_cast<PosixFileLock*>(lock);
667
33.2k
    if (LockOrUnlock(posix_file_lock->fd(), false) == -1) {
  Branch (667:9): [True: 0, False: 33.2k]
668
0
      return PosixError("unlock " + posix_file_lock->filename(), errno);
669
0
    }
670
33.2k
    locks_.Remove(posix_file_lock->filename());
671
33.2k
    ::close(posix_file_lock->fd());
672
33.2k
    delete posix_file_lock;
673
33.2k
    return Status::OK();
674
33.2k
  }
675
676
  void Schedule(void (*background_work_function)(void* background_work_arg),
677
                void* background_work_arg) override;
678
679
  void StartThread(void (*thread_main)(void* thread_main_arg),
680
0
                   void* thread_main_arg) override {
681
0
    std::thread new_thread(thread_main, thread_main_arg);
682
0
    new_thread.detach();
683
0
  }
684
685
0
  Status GetTestDirectory(std::string* result) override {
686
0
    const char* env = std::getenv("TEST_TMPDIR");
687
0
    if (env && env[0] != '\0') {
  Branch (687:9): [True: 0, False: 0]
  Branch (687:16): [True: 0, False: 0]
688
0
      *result = env;
689
0
    } else {
690
0
      char buf[100];
691
0
      std::snprintf(buf, sizeof(buf), "/tmp/leveldbtest-%d",
692
0
                    static_cast<int>(::geteuid()));
693
0
      *result = buf;
694
0
    }
695
696
    // The CreateDir status is ignored because the directory may already exist.
697
0
    CreateDir(*result);
698
699
0
    return Status::OK();
700
0
  }
701
702
0
  Status NewLogger(const std::string& filename, Logger** result) override {
703
0
    int fd = ::open(filename.c_str(),
704
0
                    O_APPEND | O_WRONLY | O_CREAT | kOpenBaseFlags, 0644);
705
0
    if (fd < 0) {
  Branch (705:9): [True: 0, False: 0]
706
0
      *result = nullptr;
707
0
      return PosixError(filename, errno);
708
0
    }
709
710
0
    std::FILE* fp = ::fdopen(fd, "w");
711
0
    if (fp == nullptr) {
  Branch (711:9): [True: 0, False: 0]
712
0
      ::close(fd);
713
0
      *result = nullptr;
714
0
      return PosixError(filename, errno);
715
0
    } else {
716
0
      *result = new PosixLogger(fp);
717
0
      return Status::OK();
718
0
    }
719
0
  }
720
721
48
  uint64_t NowMicros() override {
722
48
    static constexpr uint64_t kUsecondsPerSecond = 1000000;
723
48
    struct ::timeval tv;
724
48
    ::gettimeofday(&tv, nullptr);
725
48
    return static_cast<uint64_t>(tv.tv_sec) * kUsecondsPerSecond + tv.tv_usec;
726
48
  }
727
728
0
  void SleepForMicroseconds(int micros) override {
729
0
    std::this_thread::sleep_for(std::chrono::microseconds(micros));
730
0
  }
731
732
 private:
733
  void BackgroundThreadMain();
734
735
24
  static void BackgroundThreadEntryPoint(PosixEnv* env) {
736
24
    env->BackgroundThreadMain();
737
24
  }
738
739
  // Stores the work item data in a Schedule() call.
740
  //
741
  // Instances are constructed on the thread calling Schedule() and used on the
742
  // background thread.
743
  //
744
  // This structure is thread-safe beacuse it is immutable.
745
  struct BackgroundWorkItem {
746
    explicit BackgroundWorkItem(void (*function)(void* arg), void* arg)
747
24
        : function(function), arg(arg) {}
748
749
    void (*const function)(void*);
750
    void* const arg;
751
  };
752
753
  port::Mutex background_work_mutex_;
754
  port::CondVar background_work_cv_ GUARDED_BY(background_work_mutex_);
755
  bool started_background_thread_ GUARDED_BY(background_work_mutex_);
756
757
  std::queue<BackgroundWorkItem> background_work_queue_
758
      GUARDED_BY(background_work_mutex_);
759
760
  PosixLockTable locks_;  // Thread-safe.
761
  Limiter mmap_limiter_;  // Thread-safe.
762
  Limiter fd_limiter_;    // Thread-safe.
763
};
764
765
// Return the maximum number of concurrent mmaps.
766
11.0k
int MaxMmaps() { return g_mmap_limit; }
767
768
// Return the maximum number of read-only files to keep open.
769
11.0k
int MaxOpenFiles() {
770
11.0k
  if (g_open_read_only_file_limit >= 0) {
  Branch (770:7): [True: 0, False: 11.0k]
771
0
    return g_open_read_only_file_limit;
772
0
  }
773
11.0k
  struct ::rlimit rlim;
774
11.0k
  if (::getrlimit(RLIMIT_NOFILE, &rlim)) {
  Branch (774:7): [True: 0, False: 11.0k]
775
    // getrlimit failed, fallback to hard-coded default.
776
0
    g_open_read_only_file_limit = 50;
777
11.0k
  } else if (rlim.rlim_cur == RLIM_INFINITY) {
  Branch (777:14): [True: 0, False: 11.0k]
778
0
    g_open_read_only_file_limit = std::numeric_limits<int>::max();
779
11.0k
  } else {
780
    // Allow use of 20% of available file descriptors for read-only files.
781
11.0k
    g_open_read_only_file_limit = rlim.rlim_cur / 5;
782
11.0k
  }
783
11.0k
  return g_open_read_only_file_limit;
784
11.0k
}
785
786
}  // namespace
787
788
PosixEnv::PosixEnv()
789
11.0k
    : background_work_cv_(&background_work_mutex_),
790
11.0k
      started_background_thread_(false),
791
11.0k
      mmap_limiter_(MaxMmaps()),
792
11.0k
      fd_limiter_(MaxOpenFiles()) {}
793
794
void PosixEnv::Schedule(
795
    void (*background_work_function)(void* background_work_arg),
796
24
    void* background_work_arg) {
797
24
  background_work_mutex_.Lock();
798
799
  // Start the background thread, if we haven't done so already.
800
24
  if (!started_background_thread_) {
  Branch (800:7): [True: 24, False: 0]
801
24
    started_background_thread_ = true;
802
24
    std::thread background_thread(PosixEnv::BackgroundThreadEntryPoint, this);
803
24
    background_thread.detach();
804
24
  }
805
806
  // If the queue is empty, the background thread may be waiting for work.
807
24
  if (background_work_queue_.empty()) {
  Branch (807:7): [True: 24, False: 0]
808
24
    background_work_cv_.Signal();
809
24
  }
810
811
24
  background_work_queue_.emplace(background_work_function, background_work_arg);
812
24
  background_work_mutex_.Unlock();
813
24
}
814
815
24
void PosixEnv::BackgroundThreadMain() {
816
48
  while (true) {
  Branch (816:10): [Folded - Ignored]
817
48
    background_work_mutex_.Lock();
818
819
    // Wait until there is work to be done.
820
72
    while (background_work_queue_.empty()) {
  Branch (820:12): [True: 24, False: 48]
821
24
      background_work_cv_.Wait();
822
24
    }
823
824
48
    assert(!background_work_queue_.empty());
  Branch (824:5): [True: 24, False: 24]
825
24
    auto background_work_function = background_work_queue_.front().function;
826
24
    void* background_work_arg = background_work_queue_.front().arg;
827
24
    background_work_queue_.pop();
828
829
24
    background_work_mutex_.Unlock();
830
24
    background_work_function(background_work_arg);
831
24
  }
832
24
}
833
834
namespace {
835
836
// Wraps an Env instance whose destructor is never created.
837
//
838
// Intended usage:
839
//   using PlatformSingletonEnv = SingletonEnv<PlatformEnv>;
840
//   void ConfigurePosixEnv(int param) {
841
//     PlatformSingletonEnv::AssertEnvNotInitialized();
842
//     // set global configuration flags.
843
//   }
844
//   Env* Env::Default() {
845
//     static PlatformSingletonEnv default_env;
846
//     return default_env.env();
847
//   }
848
template <typename EnvType>
849
class SingletonEnv {
850
 public:
851
11.0k
  SingletonEnv() {
852
11.0k
#if !defined(NDEBUG)
853
11.0k
    env_initialized_.store(true, std::memory_order_relaxed);
854
11.0k
#endif  // !defined(NDEBUG)
855
11.0k
    static_assert(sizeof(env_storage_) >= sizeof(EnvType),
856
11.0k
                  "env_storage_ will not fit the Env");
857
11.0k
    static_assert(std::is_standard_layout_v<SingletonEnv<EnvType>>);
858
11.0k
    static_assert(
859
11.0k
        offsetof(SingletonEnv<EnvType>, env_storage_) % alignof(EnvType) == 0,
860
11.0k
        "env_storage_ does not meet the Env's alignment needs");
861
11.0k
    static_assert(alignof(SingletonEnv<EnvType>) % alignof(EnvType) == 0,
862
11.0k
                  "env_storage_ does not meet the Env's alignment needs");
863
11.0k
    new (env_storage_) EnvType();
864
11.0k
  }
865
  ~SingletonEnv() = default;
866
867
  SingletonEnv(const SingletonEnv&) = delete;
868
  SingletonEnv& operator=(const SingletonEnv&) = delete;
869
870
66.5k
  Env* env() { return reinterpret_cast<Env*>(&env_storage_); }
871
872
0
  static void AssertEnvNotInitialized() {
873
0
#if !defined(NDEBUG)
874
0
    assert(!env_initialized_.load(std::memory_order_relaxed));
  Branch (874:5): [True: 0, False: 0]
875
0
#endif  // !defined(NDEBUG)
876
0
  }
877
878
 private:
879
  alignas(EnvType) char env_storage_[sizeof(EnvType)];
880
#if !defined(NDEBUG)
881
  static std::atomic<bool> env_initialized_;
882
#endif  // !defined(NDEBUG)
883
};
884
885
#if !defined(NDEBUG)
886
template <typename EnvType>
887
std::atomic<bool> SingletonEnv<EnvType>::env_initialized_;
888
#endif  // !defined(NDEBUG)
889
890
using PosixDefaultEnv = SingletonEnv<PosixEnv>;
891
892
}  // namespace
893
894
0
void EnvPosixTestHelper::SetReadOnlyFDLimit(int limit) {
895
0
  PosixDefaultEnv::AssertEnvNotInitialized();
896
0
  g_open_read_only_file_limit = limit;
897
0
}
898
899
0
void EnvPosixTestHelper::SetReadOnlyMMapLimit(int limit) {
900
0
  PosixDefaultEnv::AssertEnvNotInitialized();
901
0
  g_mmap_limit = limit;
902
0
}
903
904
66.5k
Env* Env::Default() {
905
66.5k
  static PosixDefaultEnv env_container;
906
66.5k
  return env_container.env();
907
66.5k
}
908
909
}  // namespace leveldb