Repository: valkey-io/valkey
File: src/t_hash.c (C)

Code before:
}

/* Returns the address of the entry allocation. */
static void *hashTypeEntryAllocPtr(hashTypeEntry *entry) {
    char *buf = sdsAllocPtr(entry);
    if (entryHasValuePtr(entry)) {
        buf -= sizeof(sds *);
    }
    return buf;
}

/* Frees previous value, takes ownership of new value, returns entry (may be
 * reallocated). */
static hashTypeEntry *hashTypeEntryReplaceValue(hashTypeEntry *entry, sds value) {
    sds field = (sds)entry;
    size_t field_size = sdsHdrSize(sdsType(field)) + sdsalloc(field) + 1;
    size_t value_len = sdslen(value);
    size_t value_size = sdsReqSize(value_len, SDS_TYPE_8);
    if (!entryHasValuePtr(entry)) {
        /* Reuse the allocation if the new value fits and leaves no more than
         * 25% unused space after replacing the value. */
        char *alloc_ptr = sdsAllocPtr(entry);
        size_t required_size = field_size + value_size;
        size_t alloc_size;
        if (required_size <= EMBED_VALUE_MAX_ALLOC_SIZE &&
            required_size <= (alloc_size = zmalloc_usable_size(alloc_ptr)) &&
            required_size >= alloc_size * 3 / 4) {
            /* It fits in the allocation and leaves max 25% unused space. */
            sdswrite(alloc_ptr + field_size, alloc_size - field_size, SDS_TYPE_8, value, value_len);
            sdsfree(value);
            return entry;
        }
        hashTypeEntry *new_entry = hashTypeCreateEntry(hashTypeEntryGetField(entry), value);
        freeHashTypeEntry(entry);
        return new_entry;
    } else {
        /* The value pointer is located before the embedded field. */
        if (field_size + value_size <= EMBED_VALUE_MAX_ALLOC_SIZE) {
            /* Convert to entry with embedded value. */
            hashTypeEntry *new_entry = hashTypeCreateEntry(field, value);
            freeHashTypeEntry(entry);
            return new_entry;
        } else {
            /* Not embedded value. */
            sds *value_ref = hashTypeEntryGetValueRef(entry);
            sdsfree(*value_ref);
            *value_ref = value;
            return entry;
        }
    }
}

Review comment (performance):
Just a small note. I prefer this implementation because of the simplicity.
I would say that we could only compare the value size diff (the current VS the new value) since the field is immutable and the size is only impacted by the values diff. Only stating this since IIRC zmalloc_usable_size has some notable performance impact

Code after:
}

/* Returns the address of the entry allocation. */
static void *hashTypeEntryAllocPtr(hashTypeEntry *entry) {
    char *buf = sdsAllocPtr(entry);
    if (entryHasValuePtr(entry)) {
        buf -= sizeof(sds *);
    }
    return buf;
}

/* Frees previous value, takes ownership of new value, returns entry (may be
 * reallocated). */
static hashTypeEntry *hashTypeEntryReplaceValue(hashTypeEntry *entry, sds value) {
    sds field = (sds)entry;
    size_t field_size = sdsHdrSize(sdsType(field)) + sdsalloc(field) + 1;
    size_t value_len = sdslen(value);
    size_t value_size = sdsReqSize(value_len, SDS_TYPE_8);
    if (!entryHasValuePtr(entry)) {
        /* Reuse the allocation if the new value fits and leaves no more than
         * 25% unused space after replacing the value. */
        char *alloc_ptr = sdsAllocPtr(entry);
        size_t required_size = field_size + value_size;
        size_t alloc_size;
        if (required_size <= EMBED_VALUE_MAX_ALLOC_SIZE &&
            required_size <= (alloc_size = hashTypeEntryMemUsage(entry)) &&
            required_size >= alloc_size * 3 / 4) {
            /* It fits in the allocation and leaves max 25% unused space. */
            sdswrite(alloc_ptr + field_size, alloc_size - field_size, SDS_TYPE_8, value, value_len);
            sdsfree(value);
            return entry;
        }
        hashTypeEntry *new_entry = hashTypeCreateEntry(hashTypeEntryGetField(entry), value);
        freeHashTypeEntry(entry);
        return new_entry;
    } else {
        /* The value pointer is located before the embedded field. */
        if (field_size + value_size <= EMBED_VALUE_MAX_ALLOC_SIZE) {
            /* Convert to entry with embedded value. */
            hashTypeEntry *new_entry = hashTypeCreateEntry(field, value);
            freeHashTypeEntry(entry);
            return new_entry;
        } else {
            /* Not embedded value. */
            sds *value_ref = hashTypeEntryGetValueRef(entry);
            sdsfree(*value_ref);
            *value_ref = value;
            return entry;
        }
    }
}