27 #include <type_traits> 30 #include <boost/noncopyable.hpp> 31 #include <boost/random.hpp> 32 #include <boost/type_traits.hpp> 33 #include <glog/logging.h> 42 template <
typename ValT,
typename NodeT>
63 DCHECK(height >= 1 && height < 64) <<
height;
66 sizeof(
SkipListNode) + height *
sizeof(std::atomic<SkipListNode*>);
67 auto storage = std::allocator_traits<NodeAlloc>::allocate(alloc, size);
73 template <
typename NodeAlloc>
76 node->
height_ *
sizeof(std::atomic<SkipListNode*>);
78 std::allocator_traits<NodeAlloc>::deallocate(alloc, node, size);
81 template <
typename NodeAlloc>
83 AllocatorHasTrivialDeallocate<NodeAlloc>,
84 boost::has_trivial_destructor<SkipListNode>> {};
98 return skip_[layer].load(std::memory_order_consume);
105 node = node->
skip(0)) {
112 skip_[
h].store(next, std::memory_order_release);
118 const value_type&
data()
const {
129 return std::unique_lock<MicroSpinLock>(
spinLock_);
154 template <
typename U>
164 new (&
skip_[
i]) std::atomic<SkipListNode*>(
nullptr);
175 return flags_.load(std::memory_order_consume);
178 flags_.store(flags, std::memory_order_release);
191 std::atomic<SkipListNode*>
skip_[0];
195 enum { kMaxHeight = 64 };
205 DCHECK_LE(maxHeight, kMaxHeight) <<
"max height too big!";
206 double p = randomProb();
207 for (
int i = 0;
i < maxHeight; ++
i) {
208 if (p < lookupTable_[
i]) {
216 DCHECK_LT(height, kMaxHeight);
217 return sizeLimitTable_[
height];
227 static const double kProbInv = exp(1);
228 static const double kProb = 1.0 / kProbInv;
231 double sizeLimit = 1;
232 double p = lookupTable_[0] = (1 - kProb);
233 sizeLimitTable_[0] = 1;
234 for (
int i = 1;
i < kMaxHeight - 1; ++
i) {
236 sizeLimit *= kProbInv;
237 lookupTable_[
i] = lookupTable_[
i - 1] + p;
238 sizeLimitTable_[
i] = sizeLimit > kMaxSizeLimit
240 :
static_cast<size_t>(sizeLimit);
242 lookupTable_[kMaxHeight - 1] = 1;
243 sizeLimitTable_[kMaxHeight - 1] = kMaxSizeLimit;
251 double lookupTable_[kMaxHeight];
252 size_t sizeLimitTable_[kMaxHeight];
255 template <
typename NodeType,
typename NodeAlloc,
typename =
void>
258 template <
typename NodeType,
typename NodeAlloc>
262 typename
std::enable_if<
263 !NodeType::template DestroyIsNoOp<NodeAlloc>::value>
::type> {
266 : refs_(0), dirty_(false), alloc_(alloc) {
277 for (
auto& node : *nodes_) {
283 void add(NodeType* node) {
284 std::lock_guard<MicroSpinLock>
g(lock_);
285 if (nodes_.get() ==
nullptr) {
286 nodes_ = std::make_unique<std::vector<NodeType*>>(1, node);
288 nodes_->push_back(node);
290 DCHECK_GT(
refs(), 0);
291 dirty_.store(
true, std::memory_order_relaxed);
295 return refs_.fetch_add(1, std::memory_order_relaxed);
305 if (
LIKELY(!dirty_.load(std::memory_order_relaxed) ||
refs() > 1)) {
306 return refs_.fetch_add(-1, std::memory_order_relaxed);
309 std::unique_ptr<std::vector<NodeType*>> newNodes;
311 std::lock_guard<MicroSpinLock>
g(lock_);
312 if (nodes_.get() ==
nullptr ||
refs() > 1) {
313 return refs_.fetch_add(-1, std::memory_order_relaxed);
319 newNodes.swap(nodes_);
320 dirty_.store(
false, std::memory_order_relaxed);
325 for (
auto& node : *newNodes) {
332 return refs_.fetch_add(-1, std::memory_order_relaxed);
341 return refs_.load(std::memory_order_relaxed);
344 std::unique_ptr<std::vector<NodeType*>>
nodes_;
353 template <
typename NodeType,
typename NodeAlloc>
357 typename
std::enable_if<
358 NodeType::template DestroyIsNoOp<NodeAlloc>::value>
::type> {
void setMarkedForRemoval()
static SkipListRandomHeight * instance()
static double randomProb()
const value_type & data() const
size_t getSizeLimit(int height) const
void setSkip(uint8_t h, SkipListNode *next)
uint16_t getFlags() const
int getHeight(int maxHeight) const
std::unordered_map< std::string, IValidator * > refs
std::atomic< int32_t > refs_
—— Concurrent Priority Queue Implementation ——
std::atomic< bool > dirty_
NodeRecycler(const NodeAlloc &alloc)
std::atomic< uint16_t > flags_
SkipListNode(uint8_t height, U &&data, bool isHead)
constexpr auto size(C const &c) -> decltype(c.size())
void setFlags(uint16_t flags)
std::atomic< SkipListNode * > skip_[0]
bool markedForRemoval() const
static void destroy(NodeAlloc &alloc, SkipListNode *node)
static const char *const value
SkipListNode * copyHead(SkipListNode *node)
std::unique_lock< MicroSpinLock > acquireGuard()
NodeRecycler(const NodeAlloc &alloc)
static SkipListNode * create(NodeAlloc &alloc, int height, U &&data, bool isHead=false)
std::unique_ptr< std::vector< NodeType * > > nodes_
SkipListNode * skip(int layer) const