in cachelib/compact_cache/CCacheVariableLruBucket.h [291:373]
static int insert(Bucket* bucket,
const Key& key,
const Value* val,
size_t size,
EvictionCb evictionCb) {
/* The caller should ensure that the value is small enough to fit in
* the bucket. */
XDCHECK_LE(size, kMaxValueSize);
if (size > kMaxValueSize) {
XLOG(ERR) << "Cannot insert an value of size " << size
<< ", the size must be smaller than " << kMaxValueSize;
return -1;
}
/* Make sure that EntryDataSize is wide enough to hold the given
* size. */
checkOverflow<EntryDataOffset>(size);
if (size > std::numeric_limits<EntryDataSize>::max()) {
XLOG(ERR)
<< "Cannot insert an value of size " << size
<< ", the size must be smaller than the max value of EntryDataSize";
return -1;
}
#ifndef NDEBUG
checkBucketConsistency(bucket);
#endif
/* 1) Compute the required space for our entry. */
size_t requiredSpace = size + sizeof(EntryHdr) + sizeof(EntryData);
/* 2) Call evictEntries, which takes care of evicting as many entries as
* required in order to have the necessary space. */
bool evicted = evictEntries(bucket, requiredSpace, evictionCb);
#ifndef NDEBUG
/* EvictEntries should leave the bucket in a consistent state. */
checkBucketConsistency(bucket);
#endif
/* 3) Allocate a new spot in the "Empty" section by increasing
* bucket->totalDataSize. */
checkOverflow<EntryDataOffset>(bucket->totalDataSize + size +
sizeof(EntryData));
bucket->totalDataSize += size + sizeof(EntryData);
/* 4) Write the entry's data (EntryData) in the new spot. */
EntryData* newEntryData = getFirstEntryData(bucket);
memcpy(newEntryData->data, val, size);
/* 5) Update the headerIndex of all the existing EntryData objects
* since their header is about to get shifted one position to the
* right. */
for (unsigned int i = 0; i < bucket->numEntries; i++) {
getEntryData(bucket, i)->headerIndex++;
}
/* 6) Shift all the EntryHdr headers to the right so that we can
* write our new entry header in the first position. */
memmove(getEntryHeader(bucket, 1),
getEntryHeader(bucket, 0),
bucket->numEntries * sizeof(EntryHdr));
/* 7) Write the entry's header (EntryHdr) */
EntryHdr* newEntry = getEntryHeader(bucket, 0);
memcpy(&newEntry->key, &key, sizeof(Key));
newEntry->dataSize = size;
/* 8) Set the offsets in both the EntryHdr header and the
* EntryData so that they have a reference to each other. */
newEntry->dataOffset = kBucketDataSize - bucket->totalDataSize;
newEntryData->headerIndex = 0;
/* 9) Update the number of entries in the bucket. */
checkOverflow<EntryNum>(bucket->numEntries + 1);
bucket->numEntries++;
#ifndef NDEBUG
checkBucketConsistency(bucket);
#endif
return evicted ? 1 : 0;
}