polardbxengine/storage/xengine/core/util/ebr.h

137 lines
4.5 KiB
C++

/*
* Copyright (c) 2020, Alibaba Group Holding Limited
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "xengine/slice.h"
#include "util/spin_lock.h"
#include <atomic>
#include <pthread.h>
using namespace xengine;
using namespace xengine::common;
namespace xengine {
namespace util {
typedef void (*EBRDeleteFunc)(void*);
class EBRNode {
private:
void *ptr_;
EBRDeleteFunc func_;
std::atomic<EBRNode *> next_;
public:
EBRNode() : ptr_(nullptr), func_(nullptr), next_(nullptr) {}
EBRNode(void *p, EBRDeleteFunc f) : ptr_(p), func_(f), next_(nullptr) {}
EBRNode *next() { return next_.load(); }
void set_next(EBRNode *n) { next_.store(n); }
bool next_cas(EBRNode *&old, EBRNode *n) { return next_.compare_exchange_strong(old, n); }
EBRNode *next_exchange(EBRNode *n) { return next_.exchange(n); }
void do_reclaim() { func_(ptr_); }
};
class EBRManager;
class LocalEBR {
private:
LocalEBR *next_;
LocalEBR *prev_;
std::atomic<uint32_t> local_epoch_;
EBRNode *local_limbo_list_head_;
EBRNode *local_limbo_list_tail_;
uint64_t local_removed_count_;
EBRManager *ebr_;
public:
LocalEBR(EBRManager *ebr=nullptr)
: next_(nullptr),
prev_(nullptr),
local_epoch_(0),
local_limbo_list_head_(nullptr),
local_limbo_list_tail_(nullptr),
local_removed_count_(0),
ebr_(ebr) {}
LocalEBR *next() { return next_; }
LocalEBR *prev() { return prev_; }
void set_next(LocalEBR *n) { next_ = n; }
void set_prev(LocalEBR *p) { prev_ = p; }
uint32_t get_local_epoch() { return local_epoch_.load(); }
void enter_critical_area(uint32_t global_epoch);
void leave_critical_area();
int remove(void *p, EBRDeleteFunc f);
};
class EBRManager {
public:
static const uint32_t MAX_EPOCH = 3;
static const uint32_t ACTIVE_MASK = (1U << 31);
static const int64_t RECLAIM_LIMIT = 128;
private:
std::atomic<uint32_t> global_epoch_;
EBRNode curr_limbo_list_;
EBRNode limbo_list_[MAX_EPOCH];
pthread_key_t local_epoch_;
pthread_t pid;
SpinLock lock_; // Protect local epoch list
LocalEBR local_epoch_list_; // Dummy node
std::atomic<int64_t> removed_count_;
uint32_t get_gc_epoch() { return (global_epoch_.load() + 1) % MAX_EPOCH; }
uint32_t get_staging_epoch() { return global_epoch_.load(); }
LocalEBR *get_local_ebr() { return reinterpret_cast<LocalEBR *>(pthread_getspecific(local_epoch_)); }
SpinLock &get_lock() { return lock_; }
void forward_epoch() { global_epoch_.store((global_epoch_.load() + 1) % MAX_EPOCH); }
bool maybe_forward_epoch(uint32_t &gc_epoch);
void reclaim(EBRNode *retired_list);
bool need_reclaim() { return removed_count_.load() > RECLAIM_LIMIT; }
int thread_register(LocalEBR *&local_epoch);
public:
EBRManager()
: global_epoch_(0),
removed_count_(0) {
pthread_key_create(&local_epoch_, thread_exit);
local_epoch_list_.set_next(&local_epoch_list_);
local_epoch_list_.set_prev(&local_epoch_list_);
}
static EBRManager &get_instance() { static EBRManager ebr; return ebr; }
void enter_critical_area();
void leave_critical_area();
int remove(void *p, EBRDeleteFunc f);
void add_to_limbo_list(EBRNode *head, EBRNode *tail, uint64_t removed_count);
void maybe_do_reclaim();
static bool is_epoch_active(uint32_t local_epoch) { return (local_epoch & ACTIVE_MASK) > 0; }
static uint32_t epoch2active(uint32_t local_epoch) { return local_epoch | ACTIVE_MASK; }
static void thread_exit(void* ptr);
pthread_key_t &local_epoch_thread_key() { return local_epoch_; }
};
class EBRGaurd {
public:
EBRGaurd() { xengine::util::EBRManager::get_instance().enter_critical_area(); }
~EBRGaurd() { xengine::util::EBRManager::get_instance().leave_critical_area(); }
};
} // namespace util
} // namespace xengine
#define EBRMANAGER (xengine::util::EBRManager::get_instance())
#define ENTER_CRITICAL (EBRMANAGER.enter_critical_area())
#define LEAVE_CRITICAL (EBRMANAGER.leave_critical_area())
#define EBR_REMOVE(p, f) (EBRMANAGER.remove((p), (f)))
#define EBR_MAYBE_RECLAIM (EBRMANAGER.maybe_do_reclaim())