Skip to content

Update to upstream (1.22+) #25

@laanwj

Description

@laanwj

There have been quite a lot of updates upstream since the last pull from there.

But I'm sure there's other changes that make sense for us in the mean time

Specifically: google/leveldb@a53934a...master

Unfortunately this is far from a clean merge:

 .gitignore             | Unmerged
 build_detect_platform  | Unmerged
 db/c.cc                | Unmerged
 db/db_impl.cc          | Unmerged
 db/leveldbutil.cc      | Unmerged
 db/repair.cc           | Unmerged
 include/leveldb/env.h  | Unmerged
 port/atomic_pointer.h  | Unmerged
 port/port.h            | Unmerged
 port/port_posix.cc     | Unmerged
 port/port_posix.h      | Unmerged
 port/port_posix_sse.cc | Unmerged
 util/env_posix.cc      | Unmerged
 util/logging.cc        | Unmerged
Full list of conflicts
diff --cc .gitignore
index 71d87a4eeb60b9599e6a7a23d61a659c7befa553,c4b242534fb45faa8e608f4d5234469439dd1460..0000000000000000000000000000000000000000
--- a/.gitignore
+++ b/.gitignore
@@@ -1,13 -1,8 +1,34 @@@
++<<<<<<< HEAD
 +build_config.mk
 +*.a
 +*.o
 +*.dylib*
 +*.so
 +*.so.*
 +*_test
 +db_bench
 +leveldbutil
 +Release
 +Debug
 +Benchmark
 +vs2010.*
++||||||| merged common ancestors
++build_config.mk
++*.a
++*.o
++*.dylib*
++*.so
++*.so.*
++*_test
++db_bench
++leveldbutil
++=======
+ # Editors.
+ *.sw*
+ .vscode
+ .DS_Store
+ 
+ # Build directory.
+ build/
+ out/
++>>>>>>> master
diff --cc db/c.cc
index b23e3dcc9d06a1d854152b245de6918297026072,3a492f9ac558381d676ceb1249c20346c91eda7d..0000000000000000000000000000000000000000
--- a/db/c.cc
+++ b/db/c.cc
@@@ -4,10 -4,9 +4,19 @@@
  
  #include "leveldb/c.h"
  
++<<<<<<< HEAD
 +#include <stdlib.h>
 +#ifndef WIN32
 +#include <unistd.h>
 +#endif
++||||||| merged common ancestors
++#include <stdlib.h>
++#include <unistd.h>
++=======
+ #include <cstdint>
+ #include <cstdlib>
+ 
++>>>>>>> master
  #include "leveldb/cache.h"
  #include "leveldb/comparator.h"
  #include "leveldb/db.h"
diff --cc db/db_impl.cc
index 3bb58e560aa7c099c7937d226315d1ed46273d43,95e2bb4107d03a77c58c72af3659aafabeb3b4db..0000000000000000000000000000000000000000
--- a/db/db_impl.cc
+++ b/db/db_impl.cc
@@@ -409,12 -424,11 +424,19 @@@ Status DBImpl::RecoverLogFile(uint64_t 
    Slice record;
    WriteBatch batch;
    int compactions = 0;
-   MemTable* mem = NULL;
-   while (reader.ReadRecord(&record, &scratch) &&
-          status.ok()) {
+   MemTable* mem = nullptr;
+   while (reader.ReadRecord(&record, &scratch) && status.ok()) {
      if (record.size() < 12) {
++<<<<<<< HEAD
 +      reporter.Corruption(
 +          record.size(), Status::Corruption("log record too small", fname));
++||||||| merged common ancestors
++      reporter.Corruption(
++          record.size(), Status::Corruption("log record too small"));
++=======
+       reporter.Corruption(record.size(),
+                           Status::Corruption("log record too small"));
++>>>>>>> master
        continue;
      }
      WriteBatchInternal::SetContents(&batch, record);
diff --cc db/leveldbutil.cc
index d06d64d640b19f60a37571dcb887be5f36ce1514,55cdcc5772236a042a63a25fd260fcc1e412ec69..0000000000000000000000000000000000000000
--- a/db/leveldbutil.cc
+++ b/db/leveldbutil.cc
@@@ -16,10 -17,9 +17,20 @@@ class StdoutPrinter : public WritableFi
      fwrite(data.data(), 1, data.size(), stdout);
      return Status::OK();
    }
++<<<<<<< HEAD
 +  virtual Status Close() { return Status::OK(); }
 +  virtual Status Flush() { return Status::OK(); }
 +  virtual Status Sync() { return Status::OK(); }
 +  virtual std::string GetName() const { return "[stdout]"; }
++||||||| merged common ancestors
++  virtual Status Close() { return Status::OK(); }
++  virtual Status Flush() { return Status::OK(); }
++  virtual Status Sync() { return Status::OK(); }
++=======
+   Status Close() override { return Status::OK(); }
+   Status Flush() override { return Status::OK(); }
+   Status Sync() override { return Status::OK(); }
++>>>>>>> master
  };
  
  bool HandleDumpCommand(Env* env, char** files, int num) {
diff --cc db/repair.cc
index 7281e3d3457fe3a088a18472c25b699b986b42d5,d9d12ba556f0e78bd50218c4f9b06c9283fdd0a8..0000000000000000000000000000000000000000
--- a/db/repair.cc
+++ b/db/repair.cc
@@@ -202,8 -182,8 +182,16 @@@ class Repairer 
      int counter = 0;
      while (reader.ReadRecord(&record, &scratch)) {
        if (record.size() < 12) {
++<<<<<<< HEAD
 +        reporter.Corruption(
 +            record.size(), Status::Corruption("log record too small", logname));
++||||||| merged common ancestors
++        reporter.Corruption(
++            record.size(), Status::Corruption("log record too small"));
++=======
+         reporter.Corruption(record.size(),
+                             Status::Corruption("log record too small"));
++>>>>>>> master
          continue;
        }
        WriteBatchInternal::SetContents(&batch, record);
diff --cc include/leveldb/env.h
index 275d441eaeee49aa3418b0f672d03bd61d8bab6c,112fe964fb1cb2ce3e208ba64b92a82147279266..0000000000000000000000000000000000000000
--- a/include/leveldb/env.h
+++ b/include/leveldb/env.h
@@@ -190,14 -217,6 +217,23 @@@ class LEVELDB_EXPORT SequentialFile 
    //
    // REQUIRES: External synchronization
    virtual Status Skip(uint64_t n) = 0;
++<<<<<<< HEAD
 +
 +  // Get a name for the file, only for error reporting
 +  virtual std::string GetName() const = 0;
 +
 + private:
 +  // No copying allowed
 +  SequentialFile(const SequentialFile&);
 +  void operator=(const SequentialFile&);
++||||||| merged common ancestors
++
++ private:
++  // No copying allowed
++  SequentialFile(const SequentialFile&);
++  void operator=(const SequentialFile&);
++=======
++>>>>>>> master
  };
  
  // A file abstraction for randomly reading the contents of a file.
@@@ -217,14 -240,6 +257,23 @@@ class LEVELDB_EXPORT RandomAccessFile 
    // Safe for concurrent use by multiple threads.
    virtual Status Read(uint64_t offset, size_t n, Slice* result,
                        char* scratch) const = 0;
++<<<<<<< HEAD
 +
 +  // Get a name for the file, only for error reporting
 +  virtual std::string GetName() const = 0;
 +
 + private:
 +  // No copying allowed
 +  RandomAccessFile(const RandomAccessFile&);
 +  void operator=(const RandomAccessFile&);
++||||||| merged common ancestors
++
++ private:
++  // No copying allowed
++  RandomAccessFile(const RandomAccessFile&);
++  void operator=(const RandomAccessFile&);
++=======
++>>>>>>> master
  };
  
  // A file abstraction for sequential writing.  The implementation
@@@ -239,14 -258,6 +292,23 @@@ class LEVELDB_EXPORT WritableFile 
    virtual Status Close() = 0;
    virtual Status Flush() = 0;
    virtual Status Sync() = 0;
++<<<<<<< HEAD
 +
 +  // Get a name for the file, only for error reporting
 +  virtual std::string GetName() const = 0;
 +
 + private:
 +  // No copying allowed
 +  WritableFile(const WritableFile&);
 +  void operator=(const WritableFile&);
++||||||| merged common ancestors
++
++ private:
++  // No copying allowed
++  WritableFile(const WritableFile&);
++  void operator=(const WritableFile&);
++=======
++>>>>>>> master
  };
  
  // An interface for writing log messages.
diff --cc port/port.h
index 4baafa8e22fd290cfd73ad4daf0b5245e0d109c1,4b247f74f9f5b848a5cc3225c23be0dd7726b53e..0000000000000000000000000000000000000000
--- a/port/port.h
+++ b/port/port.h
@@@ -10,12 -10,10 +10,18 @@@
  // Include the appropriate platform specific file below.  If you are
  // porting to a new platform, see "port_example.h" for documentation
  // of what the new port_<platform>.h file must provide.
- #if defined(LEVELDB_PLATFORM_POSIX)
- #  include "port/port_posix.h"
+ #if defined(LEVELDB_PLATFORM_POSIX) || defined(LEVELDB_PLATFORM_WINDOWS)
+ #include "port/port_stdcxx.h"
  #elif defined(LEVELDB_PLATFORM_CHROMIUM)
++<<<<<<< HEAD
 +#  include "port/port_chromium.h"
 +#elif defined(LEVELDB_PLATFORM_WINDOWS)
 +#  include "port/port_win.h"
++||||||| merged common ancestors
++#  include "port/port_chromium.h"
++=======
+ #include "port/port_chromium.h"
++>>>>>>> master
  #endif
  
  #endif  // STORAGE_LEVELDB_PORT_PORT_H_
diff --cc util/env_posix.cc
index f77918313eda73b3b31e58d4ea153db038508bf1,00ca9aedef58b2bd6e2439cc52dee37fffb67c97..0000000000000000000000000000000000000000
--- a/util/env_posix.cc
+++ b/util/env_posix.cc
@@@ -1,15 -1,10 +1,11 @@@
  // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file. See the AUTHORS file for names of contributors.
 +#if !defined(LEVELDB_PLATFORM_WINDOWS)
  
  #include <dirent.h>
- #include <errno.h>
  #include <fcntl.h>
  #include <pthread.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
  #include <sys/mman.h>
  #include <sys/resource.h>
  #include <sys/stat.h>
@@@ -121,26 -134,29 +135,37 @@@ class PosixSequentialFile final : publi
      }
      return Status::OK();
    }
++<<<<<<< HEAD
 +
 +  virtual std::string GetName() const { return filename_; }
 +};
++||||||| merged common ancestors
++};
++=======
++>>>>>>> master
  
- // pread() based random-access
- class PosixRandomAccessFile: public RandomAccessFile {
   private:
-   std::string filename_;
-   bool temporary_fd_;  // If true, fd_ is -1 and we open on every read.
-   int fd_;
-   Limiter* limiter_;
+   const int fd_;
+   const std::string filename_;
+ };
  
+ // Implements random read access in a file using pread().
+ //
+ // Instances of this class are thread-safe, as required by the RandomAccessFile
+ // API. Instances are immutable and Read() only calls thread-safe library
+ // functions.
+ class PosixRandomAccessFile final : public RandomAccessFile {
   public:
-   PosixRandomAccessFile(const std::string& fname, int fd, Limiter* limiter)
-       : filename_(fname), fd_(fd), limiter_(limiter) {
-     temporary_fd_ = !limiter->Acquire();
-     if (temporary_fd_) {
-       // Open file on every access.
-       close(fd_);
-       fd_ = -1;
+   // The new instance takes ownership of |fd|. |fd_limiter| must outlive this
+   // instance, and will be used to determine if .
+   PosixRandomAccessFile(std::string filename, int fd, Limiter* fd_limiter)
+       : has_permanent_fd_(fd_limiter->Acquire()),
+         fd_(has_permanent_fd_ ? fd : -1),
+         fd_limiter_(fd_limiter),
+         filename_(std::move(filename)) {
+     if (!has_permanent_fd_) {
+       assert(fd_ == -1);
+       ::close(fd);  // The file will be opened on every read.
      }
    }
  
@@@ -161,72 -178,87 +187,103 @@@
        }
      }
  
-     Status s;
-     ssize_t r = pread(fd, scratch, n, static_cast<off_t>(offset));
-     *result = Slice(scratch, (r < 0) ? 0 : r);
-     if (r < 0) {
-       // An error: return a non-ok status
-       s = IOError(filename_, errno);
+     assert(fd != -1);
+ 
+     Status status;
+     ssize_t read_size = ::pread(fd, scratch, n, static_cast<off_t>(offset));
+     *result = Slice(scratch, (read_size < 0) ? 0 : read_size);
+     if (read_size < 0) {
+       // An error: return a non-ok status.
+       status = PosixError(filename_, errno);
      }
-     if (temporary_fd_) {
+     if (!has_permanent_fd_) {
        // Close the temporary file descriptor opened earlier.
-       close(fd);
+       assert(fd != fd_);
+       ::close(fd);
      }
-     return s;
+     return status;
    }
++<<<<<<< HEAD
 +
 +  virtual std::string GetName() const { return filename_; }
 +};
++||||||| merged common ancestors
++};
++=======
++>>>>>>> master
  
- // mmap() based random-access
- class PosixMmapReadableFile: public RandomAccessFile {
   private:
-   std::string filename_;
-   void* mmapped_region_;
-   size_t length_;
-   Limiter* limiter_;
+   const bool has_permanent_fd_;  // If false, the file is opened on every read.
+   const int fd_;                 // -1 if has_permanent_fd_ is false.
+   Limiter* const fd_limiter_;
+   const std::string filename_;
+ };
  
+ // Implements random read access in a file using mmap().
+ //
+ // Instances of this class are thread-safe, as required by the RandomAccessFile
+ // API. Instances are immutable and Read() only calls thread-safe library
+ // functions.
+ class PosixMmapReadableFile final : public RandomAccessFile {
   public:
-   // base[0,length-1] contains the mmapped contents of the file.
-   PosixMmapReadableFile(const std::string& fname, void* base, size_t length,
-                         Limiter* limiter)
-       : filename_(fname), mmapped_region_(base), length_(length),
-         limiter_(limiter) {
-   }
- 
-   virtual ~PosixMmapReadableFile() {
-     munmap(mmapped_region_, length_);
-     limiter_->Release();
-   }
- 
-   virtual Status Read(uint64_t offset, size_t n, Slice* result,
-                       char* scratch) const {
-     Status s;
+   // mmap_base[0, length-1] points to the memory-mapped contents of the file. It
+   // must be the result of a successful call to mmap(). This instances takes
+   // over the ownership of the region.
+   //
+   // |mmap_limiter| must outlive this instance. The caller must have already
+   // aquired the right to use one mmap region, which will be released when this
+   // instance is destroyed.
+   PosixMmapReadableFile(std::string filename, char* mmap_base, size_t length,
+                         Limiter* mmap_limiter)
+       : mmap_base_(mmap_base),
+         length_(length),
+         mmap_limiter_(mmap_limiter),
+         filename_(std::move(filename)) {}
+ 
+   ~PosixMmapReadableFile() override {
+     ::munmap(static_cast<void*>(mmap_base_), length_);
+     mmap_limiter_->Release();
+   }
+ 
+   Status Read(uint64_t offset, size_t n, Slice* result,
+               char* scratch) const override {
      if (offset + n > length_) {
        *result = Slice();
-       s = IOError(filename_, EINVAL);
-     } else {
-       *result = Slice(reinterpret_cast<char*>(mmapped_region_) + offset, n);
+       return PosixError(filename_, EINVAL);
      }
-     return s;
+ 
+     *result = Slice(mmap_base_ + offset, n);
+     return Status::OK();
    }
++<<<<<<< HEAD
 +
 +  virtual std::string GetName() const { return filename_; }
 +};
++||||||| merged common ancestors
++};
++=======
++>>>>>>> master
  
- class PosixWritableFile : public WritableFile {
   private:
-   std::string filename_;
-   FILE* file_;
+   char* const mmap_base_;
+   const size_t length_;
+   Limiter* const mmap_limiter_;
+   const std::string filename_;
+ };
  
+ class PosixWritableFile final : public WritableFile {
   public:
-   PosixWritableFile(const std::string& fname, FILE* f)
-       : filename_(fname), file_(f) { }
- 
-   ~PosixWritableFile() {
-     if (file_ != NULL) {
+   PosixWritableFile(std::string filename, int fd)
+       : pos_(0),
+         fd_(fd),
+         is_manifest_(IsManifest(filename)),
+         filename_(std::move(filename)),
+         dirname_(Dirname(filename_)) {}
+ 
+   ~PosixWritableFile() override {
+     if (fd_ >= 0) {
        // Ignoring any potential errors
-       fclose(file_);
+       Close();
      }
    }
  
@@@ -255,81 -345,146 +370,178 @@@
    }
  
    Status SyncDirIfManifest() {
-     const char* f = filename_.c_str();
-     const char* sep = strrchr(f, '/');
-     Slice basename;
-     std::string dir;
-     if (sep == NULL) {
-       dir = ".";
-       basename = f;
+     Status status;
+     if (!is_manifest_) {
+       return status;
+     }
+ 
+     int fd = ::open(dirname_.c_str(), O_RDONLY | kOpenBaseFlags);
+     if (fd < 0) {
+       status = PosixError(dirname_, errno);
      } else {
-       dir = std::string(f, sep - f);
-       basename = sep + 1;
+       status = SyncFd(fd, dirname_);
+       ::close(fd);
+     }
+     return status;
+   }
+ 
+   // Ensures that all the caches associated with the given file descriptor's
+   // data are flushed all the way to durable media, and can withstand power
+   // failures.
+   //
+   // The path argument is only used to populate the description string in the
+   // returned Status if an error occurs.
+   static Status SyncFd(int fd, const std::string& fd_path) {
+ #if HAVE_FULLFSYNC
+     // On macOS and iOS, fsync() doesn't guarantee durability past power
+     // failures. fcntl(F_FULLFSYNC) is required for that purpose. Some
+     // filesystems don't support fcntl(F_FULLFSYNC), and require a fallback to
+     // fsync().
+     if (::fcntl(fd, F_FULLFSYNC) == 0) {
+       return Status::OK();
      }
++<<<<<<< HEAD
 +    Status s;
 +    if (basename.starts_with("MANIFEST")) {
 +      int fd = open(dir.c_str(), O_RDONLY);
 +      if (fd < 0) {
 +        s = IOError(dir, errno);
 +      } else {
 +        if (fsync(fd) < 0 && errno != EINVAL) {
 +          s = IOError(dir, errno);
 +        }
 +        close(fd);
 +      }
++||||||| merged common ancestors
++    Status s;
++    if (basename.starts_with("MANIFEST")) {
++      int fd = open(dir.c_str(), O_RDONLY);
++      if (fd < 0) {
++        s = IOError(dir, errno);
++      } else {
++        if (fsync(fd) < 0) {
++          s = IOError(dir, errno);
++        }
++        close(fd);
++      }
++=======
+ #endif  // HAVE_FULLFSYNC
+ 
+ #if HAVE_FDATASYNC
+     bool sync_success = ::fdatasync(fd) == 0;
+ #else
+     bool sync_success = ::fsync(fd) == 0;
+ #endif  // HAVE_FDATASYNC
+ 
+     if (sync_success) {
+       return Status::OK();
++>>>>>>> master
      }
-     return s;
+     return PosixError(fd_path, errno);
    }
  
-   virtual Status Sync() {
-     // Ensure new files referred to by the manifest are in the filesystem.
-     Status s = SyncDirIfManifest();
-     if (!s.ok()) {
-       return s;
+   // Returns the directory name in a path pointing to a file.
+   //
+   // Returns "." if the path does not contain any directory separator.
+   static std::string Dirname(const std::string& filename) {
+     std::string::size_type separator_pos = filename.rfind('/');
+     if (separator_pos == std::string::npos) {
+       return std::string(".");
      }
-     if (fflush_unlocked(file_) != 0 ||
-         fdatasync(fileno(file_)) != 0) {
-       s = Status::IOError(filename_, strerror(errno));
+     // The filename component should not contain a path separator. If it does,
+     // the splitting was done incorrectly.
+     assert(filename.find('/', separator_pos + 1) == std::string::npos);
+ 
+     return filename.substr(0, separator_pos);
+   }
+ 
+   // Extracts the file name from a path pointing to a file.
+   //
+   // The returned Slice points to |filename|'s data buffer, so it is only valid
+   // while |filename| is alive and unchanged.
+   static Slice Basename(const std::string& filename) {
+     std::string::size_type separator_pos = filename.rfind('/');
+     if (separator_pos == std::string::npos) {
+       return Slice(filename);
      }
-     return s;
+     // The filename component should not contain a path separator. If it does,
+     // the splitting was done incorrectly.
+     assert(filename.find('/', separator_pos + 1) == std::string::npos);
+ 
+     return Slice(filename.data() + separator_pos + 1,
+                  filename.length() - separator_pos - 1);
    }
  
+   // True if the given file is a manifest file.
+   static bool IsManifest(const std::string& filename) {
+     return Basename(filename).starts_with("MANIFEST");
+   }
++<<<<<<< HEAD
++
 +  virtual std::string GetName() const { return filename_; }
++||||||| merged common ancestors
++=======
+ 
+   // buf_[0, pos_ - 1] contains data to be written to fd_.
+   char buf_[kWritableFileBufferSize];
+   size_t pos_;
+   int fd_;
+ 
+   const bool is_manifest_;  // True if the file's name starts with MANIFEST.
+   const std::string filename_;
+   const std::string dirname_;  // The directory of filename_.
++>>>>>>> master
  };
  
- static int LockOrUnlock(int fd, bool lock) {
+ int LockOrUnlock(int fd, bool lock) {
    errno = 0;
-   struct flock f;
-   memset(&f, 0, sizeof(f));
-   f.l_type = (lock ? F_WRLCK : F_UNLCK);
-   f.l_whence = SEEK_SET;
-   f.l_start = 0;
-   f.l_len = 0;        // Lock/unlock entire file
-   return fcntl(fd, F_SETLK, &f);
+   struct ::flock file_lock_info;
+   std::memset(&file_lock_info, 0, sizeof(file_lock_info));
+   file_lock_info.l_type = (lock ? F_WRLCK : F_UNLCK);
+   file_lock_info.l_whence = SEEK_SET;
+   file_lock_info.l_start = 0;
+   file_lock_info.l_len = 0;  // Lock/unlock entire file.
+   return ::fcntl(fd, F_SETLK, &file_lock_info);
  }
  
+ // Instances are thread-safe because they are immutable.
  class PosixFileLock : public FileLock {
   public:
-   int fd_;
-   std::string name_;
+   PosixFileLock(int fd, std::string filename)
+       : fd_(fd), filename_(std::move(filename)) {}
+ 
+   int fd() const { return fd_; }
+   const std::string& filename() const { return filename_; }
+ 
+  private:
+   const int fd_;
+   const std::string filename_;
  };
  
- // Set of locked files.  We keep a separate set instead of just
- // relying on fcntrl(F_SETLK) since fcntl(F_SETLK) does not provide
- // any protection against multiple uses from the same process.
+ // Tracks the files locked by PosixEnv::LockFile().
+ //
+ // We maintain a separate set instead of relying on fcntl(F_SETLK) because
+ // fcntl(F_SETLK) does not provide any protection against multiple uses from the
+ // same process.
+ //
+ // Instances are thread-safe because all member data is guarded by a mutex.
  class PosixLockTable {
-  private:
-   port::Mutex mu_;
-   std::set<std::string> locked_files_;
   public:
-   bool Insert(const std::string& fname) {
-     MutexLock l(&mu_);
-     return locked_files_.insert(fname).second;
-   }
-   void Remove(const std::string& fname) {
-     MutexLock l(&mu_);
+   bool Insert(const std::string& fname) LOCKS_EXCLUDED(mu_) {
+     mu_.Lock();
+     bool succeeded = locked_files_.insert(fname).second;
+     mu_.Unlock();
+     return succeeded;
+   }
+   void Remove(const std::string& fname) LOCKS_EXCLUDED(mu_) {
+     mu_.Lock();
      locked_files_.erase(fname);
+     mu_.Unlock();
    }
+ 
+  private:
+   port::Mutex mu_;
+   std::set<std::string> locked_files_ GUARDED_BY(mu_);
  };
  
  class PosixEnv : public Env {
@@@ -581,80 -750,71 +807,91 @@@
  };
  
  // Return the maximum number of concurrent mmaps.
++<<<<<<< HEAD
 +static int MaxMmaps() {
 +  if (mmap_limit >= 0) {
 +    return mmap_limit;
 +  }
 +  // Up to 4096 mmaps for 64-bit binaries; none for smaller pointer sizes.
 +  mmap_limit = sizeof(void*) >= 8 ? 4096 : 0;
 +  return mmap_limit;
 +}
++||||||| merged common ancestors
++static int MaxMmaps() {
++  if (mmap_limit >= 0) {
++    return mmap_limit;
++  }
++  // Up to 1000 mmaps for 64-bit binaries; none for smaller pointer sizes.
++  mmap_limit = sizeof(void*) >= 8 ? 1000 : 0;
++  return mmap_limit;
++}
++=======
+ int MaxMmaps() { return g_mmap_limit; }
++>>>>>>> master
  
  // Return the maximum number of read-only files to keep open.
- static intptr_t MaxOpenFiles() {
-   if (open_read_only_file_limit >= 0) {
-     return open_read_only_file_limit;
+ int MaxOpenFiles() {
+   if (g_open_read_only_file_limit >= 0) {
+     return g_open_read_only_file_limit;
    }
-   struct rlimit rlim;
-   if (getrlimit(RLIMIT_NOFILE, &rlim)) {
+   struct ::rlimit rlim;
+   if (::getrlimit(RLIMIT_NOFILE, &rlim)) {
      // getrlimit failed, fallback to hard-coded default.
-     open_read_only_file_limit = 50;
+     g_open_read_only_file_limit = 50;
    } else if (rlim.rlim_cur == RLIM_INFINITY) {
-     open_read_only_file_limit = std::numeric_limits<int>::max();
+     g_open_read_only_file_limit = std::numeric_limits<int>::max();
    } else {
      // Allow use of 20% of available file descriptors for read-only files.
-     open_read_only_file_limit = rlim.rlim_cur / 5;
+     g_open_read_only_file_limit = rlim.rlim_cur / 5;
    }
-   return open_read_only_file_limit;
+   return g_open_read_only_file_limit;
  }
  
+ }  // namespace
+ 
  PosixEnv::PosixEnv()
-     : started_bgthread_(false),
-       mmap_limit_(MaxMmaps()),
-       fd_limit_(MaxOpenFiles()) {
-   PthreadCall("mutex_init", pthread_mutex_init(&mu_, NULL));
-   PthreadCall("cvar_init", pthread_cond_init(&bgsignal_, NULL));
- }
+     : background_work_cv_(&background_work_mutex_),
+       started_background_thread_(false),
+       mmap_limiter_(MaxMmaps()),
+       fd_limiter_(MaxOpenFiles()) {}
  
- void PosixEnv::Schedule(void (*function)(void*), void* arg) {
-   PthreadCall("lock", pthread_mutex_lock(&mu_));
+ void PosixEnv::Schedule(
+     void (*background_work_function)(void* background_work_arg),
+     void* background_work_arg) {
+   background_work_mutex_.Lock();
  
-   // Start background thread if necessary
-   if (!started_bgthread_) {
-     started_bgthread_ = true;
-     PthreadCall(
-         "create thread",
-         pthread_create(&bgthread_, NULL,  &PosixEnv::BGThreadWrapper, this));
+   // Start the background thread, if we haven't done so already.
+   if (!started_background_thread_) {
+     started_background_thread_ = true;
+     std::thread background_thread(PosixEnv::BackgroundThreadEntryPoint, this);
+     background_thread.detach();
    }
  
-   // If the queue is currently empty, the background thread may currently be
-   // waiting.
-   if (queue_.empty()) {
-     PthreadCall("signal", pthread_cond_signal(&bgsignal_));
+   // If the queue is empty, the background thread may be waiting for work.
+   if (background_work_queue_.empty()) {
+     background_work_cv_.Signal();
    }
  
-   // Add to priority queue
-   queue_.push_back(BGItem());
-   queue_.back().function = function;
-   queue_.back().arg = arg;
- 
-   PthreadCall("unlock", pthread_mutex_unlock(&mu_));
+   background_work_queue_.emplace(background_work_function, background_work_arg);
+   background_work_mutex_.Unlock();
  }
  
- void PosixEnv::BGThread() {
+ void PosixEnv::BackgroundThreadMain() {
    while (true) {
-     // Wait until there is an item that is ready to run
-     PthreadCall("lock", pthread_mutex_lock(&mu_));
-     while (queue_.empty()) {
-       PthreadCall("wait", pthread_cond_wait(&bgsignal_, &mu_));
+     background_work_mutex_.Lock();
+ 
+     // Wait until there is work to be done.
+     while (background_work_queue_.empty()) {
+       background_work_cv_.Wait();
      }
  
-     void (*function)(void*) = queue_.front().function;
-     void* arg = queue_.front().arg;
-     queue_.pop_front();
+     assert(!background_work_queue_.empty());
+     auto background_work_function = background_work_queue_.front().function;
+     void* background_work_arg = background_work_queue_.front().arg;
+     background_work_queue_.pop();
  
-     PthreadCall("unlock", pthread_mutex_unlock(&mu_));
-     (*function)(arg);
+     background_work_mutex_.Unlock();
+     background_work_function(background_work_arg);
    }
  }
  
diff --cc util/logging.cc
index db6160c8f19929e9517e371ba2295e0d0e38e421,75e9d037d3f9ebeadc9bd78185aa9e100b0e42b8..0000000000000000000000000000000000000000
--- a/util/logging.cc
+++ b/util/logging.cc
@@@ -46,27 -49,36 +49,74 @@@ std::string EscapeString(const Slice& v
  }
  
  bool ConsumeDecimalNumber(Slice* in, uint64_t* val) {
++<<<<<<< HEAD
 +  uint64_t v = 0;
 +  int digits = 0;
 +  while (!in->empty()) {
 +    unsigned char c = (*in)[0];
 +    if (c >= '0' && c <= '9') {
 +      ++digits;
 +      const int delta = (c - '0');
 +      static const uint64_t kMaxUint64 = ~static_cast<uint64_t>(0);
 +      if (v > kMaxUint64/10 ||
 +          (v == kMaxUint64/10 && delta > kMaxUint64%10)) {
 +        // Overflow
 +        return false;
 +      }
 +      v = (v * 10) + delta;
 +      in->remove_prefix(1);
 +    } else {
 +      break;
++||||||| merged common ancestors
++  uint64_t v = 0;
++  int digits = 0;
++  while (!in->empty()) {
++    char c = (*in)[0];
++    if (c >= '0' && c <= '9') {
++      ++digits;
++      const int delta = (c - '0');
++      static const uint64_t kMaxUint64 = ~static_cast<uint64_t>(0);
++      if (v > kMaxUint64/10 ||
++          (v == kMaxUint64/10 && delta > kMaxUint64%10)) {
++        // Overflow
++        return false;
++      }
++      v = (v * 10) + delta;
++      in->remove_prefix(1);
++    } else {
++      break;
++=======
+   // Constants that will be optimized away.
+   constexpr const uint64_t kMaxUint64 = std::numeric_limits<uint64_t>::max();
+   constexpr const char kLastDigitOfMaxUint64 =
+       '0' + static_cast<char>(kMaxUint64 % 10);
+ 
+   uint64_t value = 0;
+ 
+   // reinterpret_cast-ing from char* to uint8_t* to avoid signedness.
+   const uint8_t* start = reinterpret_cast<const uint8_t*>(in->data());
+ 
+   const uint8_t* end = start + in->size();
+   const uint8_t* current = start;
+   for (; current != end; ++current) {
+     const uint8_t ch = *current;
+     if (ch < '0' || ch > '9') break;
+ 
+     // Overflow check.
+     // kMaxUint64 / 10 is also constant and will be optimized away.
+     if (value > kMaxUint64 / 10 ||
+         (value == kMaxUint64 / 10 && ch > kLastDigitOfMaxUint64)) {
+       return false;
++>>>>>>> master
      }
+ 
+     value = (value * 10) + (ch - '0');
    }
-   *val = v;
-   return (digits > 0);
+ 
+   *val = value;
+   const size_t digits_consumed = current - start;
+   in->remove_prefix(digits_consumed);
+   return digits_consumed != 0;
  }
  
  }  // namespace leveldb
* Unmerged path build_detect_platform
* Unmerged path port/atomic_pointer.h
* Unmerged path port/port_posix.cc
* Unmerged path port/port_posix.h
* Unmerged path port/port_posix_sse.cc

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions