blob: 3affedf3833307f91f303f41e92f00baad7cabec [file] [log] [blame]
#ifndef THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_RCU_SIMPLE_RCU_H_
#define THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_RCU_SIMPLE_RCU_H_
#include <atomic>
#include <cstddef>
#include <vector>
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "absl/synchronization/mutex.h"
// This is a very minimalistic implementation of RCU. It is intended to be used
// for simple cases where there will only be X updates to the data and this must
// be passed in when creating the object.
// We will not release objects even if there are no active readers.
// The MOST important thing to note about this data structure is that it allows
// for LOCKLESS GETS.
namespace milotic_tlbmc {
template <typename T>
class SimpleRcu {
public:
SimpleRcu() = default;
explicit SimpleRcu(T&& data, size_t max_updates) : max_updates_(max_updates) {
data_.reserve(max_updates + 1);
data_.push_back(std::move(data));
current_index_.store(0, std::memory_order_release);
}
absl::Status Update(T&& data) {
int next_index = current_index_.load(std::memory_order_acquire) + 1;
if (next_index > max_updates_) {
return absl::InternalError(absl::StrCat(
"We have reached the maximum number of updates: ", max_updates_));
}
data_.push_back(std::move(data));
absl::MutexLock lock(&mutex_);
current_index_.store(next_index, std::memory_order_release);
return absl::OkStatus();
}
const T* Get() const {
int current_index = current_index_.load(std::memory_order_acquire);
// Specifically in g3's vector implementation, operator[] obtains current
// vector size(). This can lead to a data race. We can use the iterator to
// directly access the value without checking the size since we can
// guarantee we are within the vectors size.
return &(*(data_.begin() + current_index));
}
private:
const size_t max_updates_ = 0;
absl::Mutex mutex_;
std::atomic<size_t> current_index_;
// We will ALWAYS reserve the maximum number of updates, so we can guarantee
// all pointers will always be valid
std::vector<T> data_;
};
} // namespace milotic_tlbmc
#endif // THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_RCU_SIMPLE_RCU_H_