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

Code before:
        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:
        serverPanic("Unknown type");
    }
    return defragfn(alloc_ptr);
}

/* 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 (entryGetEncoding(entry) == ENTRY_ENC_PTR_VALUE) {
        dismissSds(getEntryStruct(entry)->value);
    }
}

void freeHashTypeEntry(hashTypeEntry *entry) {
    void *alloc_ptr = hashTypeEntryAllocPtr(entry);
    if (entryGetEncoding(entry) == ENTRY_ENC_PTR_VALUE) {
        sdsfree(((hashTypeEntryPtrValue *)alloc_ptr)->value);
    }
    zfree(alloc_ptr);
}


Review comment (suggestion):
```suggestion
        sds *value_ref = encodedPtrValueEntryGetValueref(entry);
        sds new_value = sdsdefragfn(*value_ref);
        if (new_value) *value_ref = new_value;
```

Code after:
 * 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));
}

/*-----------------------------------------------------------------------------
 * Hash type API
 *----------------------------------------------------------------------------*/

/* Check the length of a number of objects to see if we need to convert a
 * listpack to a real hash. Note that we only check string encoded objects
 * as their string length can be queried in constant time. */
void hashTypeTryConversion(robj *o, robj **argv, int start, int end) {
    int i;
    size_t sum = 0;

    if (o->encoding != OBJ_ENCODING_LISTPACK) return;

    /* We guess that most of the values in the input are unique, so
     * if there are enough arguments we create a pre-sized hash, which
     * might over allocate memory if there are duplicates. */
    size_t new_fields = (end - start + 1) / 2;
    if (new_fields > server.hash_max_listpack_entries) {
        hashTypeConvert(o, OBJ_ENCODING_HASHTABLE);
        hashtableExpand(o->ptr, new_fields);
        return;
    }