typename Map::InsertOrReplaceResult Map::insertImpl()

in cachelib/datatype/Map-inl.h [318:388]


typename Map<K, V, C>::InsertOrReplaceResult Map<K, V, C>::insertImpl(
    const EntryKey& key, const EntryValue& value) {
  bool chainCloned = false;
  auto accessible = hashtable_.viewItemHandle()->isAccessible();
  // We try to expand hash table if it's full, if we can't do it
  // we have to abort this insert because we may not be albe to insert
  if (hashtable_->overLimit()) {
    const auto res = expandHashTable();
    if (!res) {
      throw std::bad_alloc();
    }
    chainCloned = true;
  }

  // If wasted space is more than threshold, trigger compaction
  if (bufferManager_.wastedBytesPct() > kWastedBytesPctThreshold) {
    compact();
  }

  const uint32_t valueSize = util::getValueSize(value);
  const uint32_t keySize = sizeof(EntryKey);
  auto addr = bufferManager_.allocate(keySize + valueSize);
  if (!addr) {
    // Clone the buffers (chained items), if we have not already done that in
    // this insert, so that if a user holds an old handle to the Map, that
    // handle will still allow the user to access the old Map.
    if (!chainCloned) {
      auto newHashTable = detail::copyHashTable<K, C>(*cache_, hashtable_,
                                                      hashtable_->capacity());
      if (!newHashTable) {
        throw std::bad_alloc();
      }

      auto newBufferManager =
          bufferManager_.clone(newHashTable.viewItemHandle());
      if (newBufferManager.empty()) {
        throw std::bad_alloc();
      }

      hashtable_ = std::move(newHashTable);
      bufferManager_ = BufferManager(*cache_, hashtable_.viewItemHandle());
      chainCloned = true;
    }
    if (bufferManager_.expand(keySize + valueSize)) {
      addr = bufferManager_.allocate(keySize + valueSize);
    }
  }
  if (chainCloned && accessible) {
    cache_->insertOrReplace(hashtable_.viewItemHandle());
  }
  if (!addr) {
    throw std::bad_alloc();
  }

  auto* kv = bufferManager_.template get<EntryKeyValue>(addr);
  std::memcpy(&kv->key, &key, keySize);
  std::memcpy(&kv->value, &value, valueSize);

  detail::BufferAddr oldAddr;
  try {
    oldAddr = hashtable_->insertOrReplace(key, addr);
  } catch (const std::bad_alloc& e) {
    bufferManager_.remove(addr);
    throw;
  }
  if (oldAddr) {
    bufferManager_.remove(oldAddr);
    return kReplaced;
  }
  return kInserted;
}