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

Code before:
            /* Convert to entry with embedded value. */
            hashTypeEntry *new_entry = hashTypeCreateEntry(field, value);
            freeHashTypeEntry(entry);
            return new_entry;
        } else {
            /* Not embedded value. */
            hashTypeEntryPtrValue *entry_struct = getEntryStruct(entry);
            sdsfree(entry_struct->value);
            entry_struct->value = value;
            return entry;
        }
    }
    default:
        serverPanic("Unknown type");
    }
}

/* Returns memory usage of a hashTypeEntry, including all allocations owned by
 * the hashTypeEntry. */
size_t hashTypeEntryMemUsage(hashTypeEntry *entry) {
    switch (entryGetEncoding(entry)) {
    case ENTRY_ENC_EMB_VALUE:
        return zmalloc_usable_size(sdsAllocPtr(entry));
    case ENTRY_ENC_PTR_VALUE: {
        hashTypeEntryPtrValue *entry_struct = getEntryStruct(entry);
        return zmalloc_usable_size(entry_struct) + sdsAllocSize(entry_struct->value);
    }
    default:
        serverPanic("Unknown type");
    }
}

/* Defragments a hashtable entry (field-value pair) if needed, using the
 * provided defrag functions. The defrag functions return NULL if the allocation
 * was not moved, otherwise they return a pointer to the new memory location.
 * A separate sds defrag function is needed because of the unique memory layout
 * of sds strings.
 * If the location of the hashTypeEntry changed we return the new location,
 * otherwise we return NULL. */
hashTypeEntry *hashTypeEntryDefrag(hashTypeEntry *entry, void *(*defragfn)(void *), sds (*sdsdefragfn)(sds)) {
    void *alloc_ptr = hashTypeEntryAllocPtr(entry);
    switch (entryGetEncoding(entry)) {
    case ENTRY_ENC_EMB_VALUE:
        break;
    case ENTRY_ENC_PTR_VALUE: {
        hashTypeEntryPtrValue *entry_struct = alloc_ptr;
        sds new_value = sdsdefragfn(entry_struct->value);
        if (new_value) entry_struct->value = new_value;
        break;
    }
    default:

Review comment (suggestion):
```suggestion
        return zmalloc_usable_size(entry_struct) + sdsAllocSize(hashTypeEntryGetValue(entry));
```

Code after:
 * the hashTypeEntry. */
size_t hashTypeEntryMemUsage(hashTypeEntry *entry) {
    size_t mem = 0;
    if (entryHasValuePtr(entry)) {
        /* Alloc size is not stored in the embedded field. */
        mem = zmalloc_usable_size(hashTypeEntryAllocPtr(entry));
        mem += sdsAllocSize(*hashTypeEntryGetValueRef(entry));
    } else {
        /* Remaining alloc size is encoded in the embedded value SDS header. */
        sds field = entry;
        sds value = (char *)entry + sdslen(field) + 1 + sdsHdrSize(SDS_TYPE_8);
        size_t field_size = sdsHdrSize(sdsType(field)) + sdslen(field) + 1;
        size_t value_size = sdsHdrSize(SDS_TYPE_8) + sdsalloc(value) + 1;
        mem = field_size + value_size;
    }
    return mem;
}

/* Defragments a hashtable entry (field-value pair) if needed, using the
 * provided defrag functions. The defrag functions return NULL if the allocation
 * was not moved, otherwise they return a pointer to the new memory location.
 * A separate sds defrag function is needed because of the unique memory layout
 * of sds strings.
 * If the location of the hashTypeEntry changed we return the new location,
 * otherwise we return NULL. */
hashTypeEntry *hashTypeEntryDefrag(hashTypeEntry *entry, void *(*defragfn)(void *), sds (*sdsdefragfn)(sds)) {
    if (entryHasValuePtr(entry)) {
        sds *value_ref = hashTypeEntryGetValueRef(entry);
        sds new_value = sdsdefragfn(*value_ref);
        if (new_value) *value_ref = new_value;
    }
    return defragfn(hashTypeEntryAllocPtr(entry));
}

/* Used for releasing memory to OS to avoid unnecessary CoW. Called when we've
 * forked and memory won't be used again. See zmadvise_dontneed() */
void dismissHashTypeEntry(hashTypeEntry *entry) {
    /* Only dismiss values memory since the field size usually is small. */
    if (entryHasValuePtr(entry)) {
        dismissSds(*hashTypeEntryGetValueRef(entry));
    }
}

void freeHashTypeEntry(hashTypeEntry *entry) {
    if (entryHasValuePtr(entry)) {
        sdsfree(*hashTypeEntryGetValueRef(entry));
    }
    zfree(hashTypeEntryAllocPtr(entry));
}

/*-----------------------------------------------------------------------------