virtual Status Push()

in src/common/garbage_list.h [208:259]


  virtual Status Push(void* removed_item, DestroyCallback callback,
      void* context) {
    Epoch removal_epoch = epoch_manager_->GetCurrentEpoch();
    const uint64_t invalid_epoch = ~0llu;

    for(;;) {
      int64_t slot = (tail_.fetch_add(1) - 1) & (item_count_ - 1);

      // Everytime we work through 25% of the capacity of the list roll
      // the epoch over.
      if(((slot << 2) & (item_count_ - 1)) == 0)
        epoch_manager_->BumpCurrentEpoch();

      Item& item = items_[slot];

      Epoch priorItemEpoch = item.removal_epoch;
      if(priorItemEpoch == invalid_epoch) {
        // Someone is modifying this slot. Try elsewhere.
        continue;
      }

      Epoch result = CompareExchange64<Epoch>(&item.removal_epoch,
          invalid_epoch, priorItemEpoch);
      if(result != priorItemEpoch) {
        // Someone else is now modifying the slot or it has been
        // replaced with a new item. If someone replaces the old item
        // with a new one of the same epoch number, that's ok.
        continue;
      }

      // Ensure it is safe to free the old entry.
      if(priorItemEpoch) {
        if(!epoch_manager_->IsSafeToReclaim(priorItemEpoch)) {
          // Uh-oh, we couldn't free the old entry. Things aren't looking
          // good, but maybe it was just the result of a race. Replace the
          // epoch number we mangled and try elsewhere.
          *((volatile Epoch*) &item.removal_epoch) = priorItemEpoch;
          continue;
        }
        item.destroy_callback(item.destroy_callback_context,
                              item.removed_item);
      }

      // Now populate the entry with the new item.
      item.destroy_callback = callback;
      item.destroy_callback_context = context;
      item.removed_item = removed_item;
      *((volatile Epoch*) &item.removal_epoch) = removal_epoch;

      return Status::OK();
    }
  }