static void checkBucketConsistency()

in cachelib/compact_cache/CCacheVariableLruBucket.h [624:694]


  static void checkBucketConsistency(Bucket* bucket) {
    EntryHandle handle = first(bucket);
    size_t totalSize = 0;
    size_t nEntries = 0;
    bool headerOffsetError = false;

    /* Check that the data part does not overlap the entry headers. */
    XDCHECK_GE(reinterpret_cast<uintptr_t>(getFirstEntryData(bucket)),
               reinterpret_cast<uintptr_t>(
                   getEntryHeader(bucket, bucket->numEntries)));

    /* Keep track of the EntryData's offsets and sizes as we see then
     * when iterating on the EntryHdr headers. We will later use this to
     * check that the EntryData objects are contiguous. */
    using EntryInfo = std::pair<EntryDataOffset, EntryDataSize>;
    std::vector<EntryInfo> entryDataSeen;

    /* Iterate on the EntryHdr headers. */
    while (handle) {
      EntryData* entryData = getEntryData(handle.bucket_, handle.pos_);
      totalSize += handle.size() + sizeof(EntryData);
      /* The offset headers of the entries we are seeing should match
       * their order. */
      if (entryData->headerIndex != nEntries) {
        headerOffsetError = true;
      }

      EntryHdr* entryHeader = getEntryHeader(bucket, handle.pos_);
      EntryDataOffset dataOffset = entryHeader->dataOffset;
      EntryDataSize dataSize = entryHeader->dataSize;
      entryDataSeen.push_back(std::make_pair(dataOffset, dataSize));

      handle.next();
      nEntries++;
    }

    /* Sort entryDataSeen by offset, in increasing order. */
    auto compareFn = [](const EntryInfo& a, const EntryInfo& b) -> bool {
      return a.first < b.first;
    };
    std::sort(entryDataSeen.begin(), entryDataSeen.end(), compareFn);

    /* Check that the EntryData objects are contiguous. */
    bool dataOffsetError = false;
    EntryDataOffset expectedNextOffset = getFirstEntryDataOffset(bucket);
    for (unsigned int i = 0; i < entryDataSeen.size(); i++) {
      if (entryDataSeen[i].first != expectedNextOffset) {
        /* The current entry does not start where expected. */
        dataOffsetError = true;
        break;
      }
      /* The next entry should start right after the current entry. */
      expectedNextOffset += entryDataSeen[i].second + sizeof(EntryData);
    }

    /* the last EntryData should have ended at the very end of the
     * bucket. */
    if (expectedNextOffset != kBucketDataSize) {
      dataOffsetError = true;
    }

    /* Throw an assert if something is wrong. */
    if (headerOffsetError || dataOffsetError ||
        totalSize != bucket->totalDataSize || nEntries != bucket->numEntries) {
      /* Copy the bucket locally for easier debugging in case the slab is
       * not in the core dump file. */
      Bucket bucketCopy;
      memcpy(&bucketCopy, bucket, sizeof(Bucket));
      XDCHECK(false);
    }
  }