class alignas()

in cachelib/allocator/nvmcache/TombStones.h [33:125]


class alignas(folly::hardware_destructive_interference_size) TombStones {
 public:
  class Guard;

  // adds an instance of  key
  // @param key  key for the record
  // @return a valid Guard representing the tombstone
  Guard add(folly::StringPiece key) {
    std::lock_guard<std::mutex> l(mutex_);
    auto it = keys_.find(key);

    if (it == keys_.end()) {
      it = keys_.insert(std::make_pair(key.toString(), 0)).first;
    }

    ++it->second;
    return Guard(it->first, *this);
  }

  // checks if there is a key present and returns true if so.
  bool isPresent(folly::StringPiece key) {
    std::lock_guard<std::mutex> l(mutex_);
    return keys_.count(key) != 0;
  }

  // Guard that wraps around the tombstone record. Removes the key from the
  // tombstone records upon destruction. A valid guard can be only created by
  // adding to the tombstone record.
  class Guard {
   public:
    Guard() {}
    ~Guard() {
      if (tombstones_) {
        tombstones_->remove(key_);
        tombstones_ = nullptr;
      }
    }

    // disable copying
    Guard(const Guard&) = delete;
    Guard& operator=(const Guard&&) = delete;

    // allow moving
    Guard(Guard&& other) noexcept
        : key_{std::move(other.key_)}, tombstones_(other.tombstones_) {
      other.tombstones_ = nullptr;
    }
    Guard& operator=(Guard&& other) noexcept {
      if (this != &other) {
        this->~Guard();
        new (this) Guard(std::move(other));
      }
      return *this;
    }

    folly::StringPiece key() const noexcept { return key_; }

    explicit operator bool() const noexcept { return tombstones_ != nullptr; }

   private:
    // only tombstone can create a guard.
    friend TombStones;
    Guard(folly::StringPiece key, TombStones& t) noexcept
        : key_(key), tombstones_(&t) {}

    // key for the tombstone
    folly::StringPiece key_;

    // tombstone record
    TombStones* tombstones_{nullptr};
  };

 private:
  // removes an instance of key. if the count drops to 0, we remove the key
  void remove(folly::StringPiece key) {
    std::lock_guard<std::mutex> l(mutex_);
    auto it = keys_.find(key);
    if (it == keys_.end() || it->second == 0) {
      // this is not supposed to happen if guards are destroyed appropriately
      throw std::runtime_error(fmt::format(
          "Invalid state. Key: {}. State: {}", key,
          it == keys_.end() ? "does not exist" : "exists, but count is 0"));
    }

    if (--(it->second) == 0) {
      keys_.erase(it);
    }
  }

  // mutex protecting the map below
  std::mutex mutex_;
  folly::F14NodeMap<std::string, uint64_t> keys_;
};