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

Code before:
        dismissMemory(o->ptr, intsetBlobLen((intset *)o->ptr));
    } else if (o->encoding == OBJ_ENCODING_LISTPACK) {
        dismissMemory(o->ptr, lpBytes((unsigned char *)o->ptr));
    } else {
        serverPanic("Unknown set encoding type");
    }
}

/* See dismissObject() */
void dismissZsetObject(robj *o) {
    if (o->encoding == OBJ_ENCODING_SKIPLIST) {
        zset *zs = o->ptr;
        /* The skiplist nodes are usually smaller than the page size (typically 4KB),
         * so we skip releasing the skiplist and only release the hashtable. */
        dismissHashtable(zs->ht);
    } else if (o->encoding == OBJ_ENCODING_LISTPACK) {
        dismissMemory(o->ptr, lpBytes((unsigned char *)o->ptr));
    } else {
        serverPanic("Unknown zset encoding type");
    }
}

/* See dismissObject() */
void dismissHashObject(robj *o, size_t size_hint) {
    if (o->encoding == OBJ_ENCODING_HASHTABLE) {
        hashtable *ht = o->ptr;
        serverAssert(hashtableSize(ht) != 0);
        /* We iterate all fields only when average field/value size is bigger than
         * a page size, and there's a high chance we'll actually dismiss something. */
        if (size_hint / hashtableSize(ht) >= server.page_size) {
            hashtableIterator iter;
            hashtableInitIterator(&iter, ht, 0);
            void *next;
            while (hashtableNext(&iter, &next)) {
                entryDismissMemory(next);
            }
            hashtableResetIterator(&iter);
        }

        dismissHashtable(ht);
    } else if (o->encoding == OBJ_ENCODING_LISTPACK) {
        dismissMemory(o->ptr, lpBytes((unsigned char *)o->ptr));
    } else {
        serverPanic("Unknown hash encoding type");
    }
}

/* See dismissObject() */
void dismissStreamObject(robj *o, size_t size_hint) {
    stream *s = o->ptr;
    rax *rax = s->rax;

Review comment (suggestion):
There is an O(1) check here to estimate if it makes sense to dismiss the individual nodes. I agree in 99% of the times this is false, but for the few users that might actually store 4KB+ strings in a sorted sets, removing this logic can cause a regression.

I prefer that we avoid dropping this dismiss logic and instead adjust it to embedded strings, which means dismiss the skiplist node allocations. We can pass 0 as the size hint instead of trying to calculate it.

```C
                dismissMemory(zn, 0);
```

Code after:
        dismissMemory(o->ptr, intsetBlobLen((intset *)o->ptr));
    } else if (o->encoding == OBJ_ENCODING_LISTPACK) {
        dismissMemory(o->ptr, lpBytes((unsigned char *)o->ptr));
    } else {
        serverPanic("Unknown set encoding type");
    }
}

/* See dismissObject() */
void dismissZsetObject(robj *o, size_t size_hint) {
    if (o->encoding == OBJ_ENCODING_SKIPLIST) {
        zset *zs = o->ptr;
        zskiplist *zsl = zs->zsl;
        serverAssert(zsl->length != 0);
        /* We iterate all nodes only when average member size is bigger than a
         * page size, and there's a high chance we'll actually dismiss something. */
        if (size_hint / zsl->length >= server.page_size) {
            zskiplistNode *zn = zsl->tail;
            while (zn != NULL) {
                zskiplistNode *next = zn->backward;
                dismissMemory(zn, 0);
                zn = next;
            }
        }

        dismissHashtable(zs->ht);
    } else if (o->encoding == OBJ_ENCODING_LISTPACK) {
        dismissMemory(o->ptr, lpBytes((unsigned char *)o->ptr));
    } else {
        serverPanic("Unknown zset encoding type");
    }
}

/* See dismissObject() */
void dismissHashObject(robj *o, size_t size_hint) {
    if (o->encoding == OBJ_ENCODING_HASHTABLE) {
        hashtable *ht = o->ptr;
        serverAssert(hashtableSize(ht) != 0);
        /* We iterate all fields only when average field/value size is bigger than
         * a page size, and there's a high chance we'll actually dismiss something. */
        if (size_hint / hashtableSize(ht) >= server.page_size) {
            hashtableIterator iter;
            hashtableInitIterator(&iter, ht, 0);
            void *next;
            while (hashtableNext(&iter, &next)) {
                entryDismissMemory(next);
            }
            hashtableResetIterator(&iter);
        }

        dismissHashtable(ht);