cyber atomic hash map

整体结构

cyber atomic hash map是用一个数组存储桶(bucket),桶是一个链表的形式存储值,每一个结点是个entry,哈希冲突的解决方法是链地址法。

整体结构 --- entry

entry为bucket链表的结点单位,代码:

struct Entry {
  Entry() {}
  explicit Entry(K key) : key(key) {
    value_ptr.store(new V(), std::memory_order_release);
  }
  Entry(K key, const V &value) : key(key) {
    value_ptr.store(new V(value), std::memory_order_release);
  }
  Entry(K key, V &&value) : key(key) {
    value_ptr.store(new V(std::forward<V>(value)), std::memory_order_release);
  }
  ~Entry() { delete value_ptr.load(std::memory_order_acquire); }

  K key = 0;
  std::atomic<V *> value_ptr = {nullptr};
  std::atomic<Entry *> next = {nullptr};
};

存入每一个键值对的key,value,和同哈希值的next,需要注意的是value_ptr也就是指向value的指针,以及next指针都是原子的(atomic),也就是针对该指针的操作不需要考虑同步互斥问题。

整体结构 --- bucket

bucket串接的是一系列具有相同哈希值的键值对,且按照key升序串接,且具有一个头节点head_:

class Bucket {
  public:
    ...
  Entry *head_;
};

bucket接口:

bool Has(K key)

bool Has(K key) {
  Entry *m_target = head_->next.load(std::memory_order_acquire);
  while (Entry *target = m_target) {
    if (target->key < key) {
      m_target = target->next.load(std::memory_order_acquire);
      continue;
    } else {
      return target->key == key;
    }
  }
  return false;
}

由于每个buffer是个升序链表,所以可以如上寻找

bool Find(K key, Entry **prev_ptr, Entry **target_ptr)

bool Find(K key, Entry **prev_ptr, Entry **target_ptr) {
  Entry *prev = head_;
  Entry *m_target = head_->next.load(std::memory_order_acquire);
  while (Entry *target = m_target) {
    if (target->key == key) {
      *prev_ptr = prev;
      *target_ptr = target;
      return true;
    } else if (target->key > key) {
      *prev_ptr = prev;
      *target_ptr = target;
      return false;
    } else {
      prev = target;
      m_target = target->next.load(std::memory_order_acquire);
    }
  }
  *prev_ptr = prev;
  *target_ptr = nullptr;
  return false;
}

void Insert(K key, const V &value)

void Insert(K key, const V &value) {
  Entry *prev = nullptr;
  Entry *target = nullptr;
  Entry *new_entry = nullptr;
  V *new_value = nullptr;
  while (true) {
    if (Find(key, &prev, &target)) {
      // key exists, update value
      if (!new_value) {
        new_value = new V(value);
      }
      auto old_val_ptr = target->value_ptr.load(std::memory_order_acquire);
      if (target->value_ptr.compare_exchange_strong(
              old_val_ptr, new_value, std::memory_order_acq_rel,
              std::memory_order_relaxed)) {
        delete old_val_ptr;
        if (new_entry) {
          delete new_entry;
          new_entry = nullptr;
        }
        return;
      }
      continue;
    } else {
      if (!new_entry) {
        new_entry = new Entry(key, value);
      }
      new_entry->next.store(target, std::memory_order_release);
      if (prev->next.compare_exchange_strong(target, new_entry,
                                              std::memory_order_acq_rel,
                                              std::memory_order_relaxed)) {
        // Insert success
        if (new_value) {
          delete new_value;
          new_value = nullptr;
        }
        return;
      }
      // another entry has been inserted, retry
    }
  }
}

void Insert(K key, V &&value)

void Insert(K key, V &&value) {
  Entry *prev = nullptr;
  Entry *target = nullptr;
  Entry *new_entry = nullptr;
  V *new_value = nullptr;
  while (true) {
    if (Find(key, &prev, &target)) {
      // key exists, update value
      if (!new_value) {
        new_value = new V(std::forward<V>(value));
      }
      auto old_val_ptr = target->value_ptr.load(std::memory_order_acquire);
      if (target->value_ptr.compare_exchange_strong(
              old_val_ptr, new_value, std::memory_order_acq_rel,
              std::memory_order_relaxed)) {
        delete old_val_ptr;
        if (new_entry) {
          delete new_entry;
          new_entry = nullptr;
        }
        return;
      }
      continue;
    } else {
      if (!new_entry) {
        new_entry = new Entry(key, value);
      }
      new_entry->next.store(target, std::memory_order_release);
      if (prev->next.compare_exchange_strong(target, new_entry,
                                              std::memory_order_acq_rel,
                                              std::memory_order_relaxed)) {
        // Insert success
        if (new_value) {
          delete new_value;
          new_value = nullptr;
        }
        return;
      }
      // another entry has been inserted, retry
    }
  }
}

void Insert(K key)

void Insert(K key) {
  Entry *prev = nullptr;
  Entry *target = nullptr;
  Entry *new_entry = nullptr;
  V *new_value = nullptr;
  while (true) {
    if (Find(key, &prev, &target)) {
      // key exists, update value
      if (!new_value) {
        new_value = new V();
      }
      auto old_val_ptr = target->value_ptr.load(std::memory_order_acquire);
      if (target->value_ptr.compare_exchange_strong(
              old_val_ptr, new_value, std::memory_order_acq_rel,
              std::memory_order_relaxed)) {
        delete old_val_ptr;
        if (new_entry) {
          delete new_entry;
          new_entry = nullptr;
        }
        return;
      }
      continue;
    } else {
      if (!new_entry) {
        new_entry = new Entry(key);
      }
      new_entry->next.store(target, std::memory_order_release);
      if (prev->next.compare_exchange_strong(target, new_entry,
                                              std::memory_order_acq_rel,
                                              std::memory_order_relaxed)) {
        // Insert success
        if (new_value) {
          delete new_value;
          new_value = nullptr;
        }
        return;
      }
      // another entry has been inserted, retry
    }
  }
}

bool Get(K key, V **value)

bool Get(K key, V **value) {
  Entry *prev = nullptr;
  Entry *target = nullptr;
  if (Find(key, &prev, &target)) {
    *value = target->value_ptr.load(std::memory_order_acquire);
    return true;
  }
  return false;
}

接口

  bool Has(K key) {
    uint64_t index = key & mode_num_;
    return table_[index].Has(key);
  }

  bool Get(K key, V **value) {
    uint64_t index = key & mode_num_;
    return table_[index].Get(key, value);
  }

  bool Get(K key, V *value) {
    uint64_t index = key & mode_num_;
    V *val = nullptr;
    bool res = table_[index].Get(key, &val);
    if (res) {
      *value = *val;
    }
    return res;
  }

  void Set(K key) {
    uint64_t index = key & mode_num_;
    table_[index].Insert(key);
  }

  void Set(K key, const V &value) {
    uint64_t index = key & mode_num_;
    table_[index].Insert(key, value);
  }

  void Set(K key, V &&value) {
    uint64_t index = key & mode_num_;
    table_[index].Insert(key, std::forward<V>(value));
  }
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值