Simplify Limiter in env_posix.cc.

Now that we require C++11, we can use std::atomic<int>, which has
primitives for most of the logic we need. As a bonus, the happy path for
Limiter::Acquire() and Limiter::Release() only performs one atomic
operation.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=211469518
This commit is contained in:
costan 2018-09-04 09:31:27 -07:00 committed by Victor Costan
parent 9b44da73d9
commit 03064cbbb2

View File

@ -16,9 +16,12 @@
#include <sys/types.h> #include <sys/types.h>
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#include <atomic>
#include <deque> #include <deque>
#include <limits> #include <limits>
#include <set> #include <set>
#include "leveldb/env.h" #include "leveldb/env.h"
#include "leveldb/slice.h" #include "leveldb/slice.h"
#include "port/port.h" #include "port/port.h"
@ -53,52 +56,41 @@ static Status PosixError(const std::string& context, int err_number) {
// Helper class to limit resource usage to avoid exhaustion. // Helper class to limit resource usage to avoid exhaustion.
// Currently used to limit read-only file descriptors and mmap file usage // Currently used to limit read-only file descriptors and mmap file usage
// so that we do not end up running out of file descriptors, virtual memory, // so that we do not run out of file descriptors or virtual memory, or run into
// or running into kernel performance problems for very large databases. // kernel performance problems for very large databases.
class Limiter { class Limiter {
public: public:
// Limit maximum number of resources to |n|. // Limit maximum number of resources to |max_acquires|.
Limiter(intptr_t n) { Limiter(int max_acquires) : acquires_allowed_(max_acquires) {}
SetAllowed(n);
} Limiter(const Limiter&) = delete;
Limiter operator=(const Limiter&) = delete;
// If another resource is available, acquire it and return true. // If another resource is available, acquire it and return true.
// Else return false. // Else return false.
bool Acquire() LOCKS_EXCLUDED(mu_) { bool Acquire() {
if (GetAllowed() <= 0) { int old_acquires_allowed =
return false; acquires_allowed_.fetch_sub(1, std::memory_order_relaxed);
}
MutexLock l(&mu_); if (old_acquires_allowed > 0)
intptr_t x = GetAllowed();
if (x <= 0) {
return false;
} else {
SetAllowed(x - 1);
return true; return true;
}
acquires_allowed_.fetch_add(1, std::memory_order_relaxed);
return false;
} }
// Release a resource acquired by a previous call to Acquire() that returned // Release a resource acquired by a previous call to Acquire() that returned
// true. // true.
void Release() LOCKS_EXCLUDED(mu_) { void Release() {
MutexLock l(&mu_); acquires_allowed_.fetch_add(1, std::memory_order_relaxed);
SetAllowed(GetAllowed() + 1);
} }
private: private:
port::Mutex mu_; // The number of available resources.
port::AtomicPointer allowed_; //
// This is a counter and is not tied to the invariants of any other class, so
intptr_t GetAllowed() const { // it can be operated on safely using std::memory_order_relaxed.
return reinterpret_cast<intptr_t>(allowed_.Acquire_Load()); std::atomic<int> acquires_allowed_;
}
void SetAllowed(intptr_t v) EXCLUSIVE_LOCKS_REQUIRED(mu_) {
allowed_.Release_Store(reinterpret_cast<void*>(v));
}
Limiter(const Limiter&);
void operator=(const Limiter&);
}; };
class PosixSequentialFile: public SequentialFile { class PosixSequentialFile: public SequentialFile {