fix(hset_family): Fix val being overwritten by TTL (#5094)

When hset is loaded from rdb, if a ttl is specified by the user, the
code recreates a string_view on top of the same memory location,
tset_blob_, that was used for val earlier. This causes the val string
view to point to the same value now as TTL has. For example if the val
string view was 'x' earlier (points to tset_blob_, size 1), and ttl is
7777777, val now becomes '7'.

To fix this val is now given it's own string. TTL is kept as string
view as the pointer is not reused anywhere in the following loop.

Signed-off-by: Abhijat Malviya <abhijat@dragonflydb.io>
This commit is contained in:
Abhijat Malviya 2025-05-10 20:11:42 +05:30 committed by GitHub
parent 8ce8ee68df
commit e341819256
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 31 additions and 15 deletions

View file

@ -482,11 +482,12 @@ void RdbLoaderBase::OpaqueObjLoader::CreateHMap(const LoadTrace* ltrace) {
}
});
std::string key;
std::string val;
for (size_t i = 0; i < ltrace->arr.size(); i += increment) {
// ToSV may reference an internal buffer, therefore we can use only before the
// next call to ToSV. To workaround, copy the key locally.
key = ToSV(ltrace->arr[i].rdb_var);
string_view val = ToSV(ltrace->arr[i + 1].rdb_var);
val = ToSV(ltrace->arr[i + 1].rdb_var);
if (ec_)
return;

View file

@ -1,23 +1,18 @@
import random
from itertools import chain, repeat
import re
import pytest
import asyncio
import async_timeout
import platform
import pymemcache
import logging
import shutil
import tarfile
import urllib.request
import shutil
from redis import asyncio as aioredis
from .utility import *
from .instance import DflyInstanceFactory, DflyInstance
from .seeder import Seeder as SeederV2
from itertools import chain, repeat
import async_timeout
import pymemcache
from . import dfly_args
from .instance import DflyInstanceFactory, DflyInstance
from .proxy import Proxy
from .seeder import DebugPopulateSeeder
from .seeder import Seeder as SeederV2
from .utility import *
ADMIN_PORT = 1211
@ -3115,3 +3110,23 @@ async def test_partial_replication_on_same_source_master(df_factory, use_takeove
lines = replica2.find_in_logs(f"Started full with localhost:{replica1.port}")
assert len(lines) == 0
assert len(replica1.find_in_logs("No partial sync due to diff")) > 0
async def test_replicate_hset_with_expiry(df_factory: DflyInstanceFactory):
master = df_factory.create(proactor_threads=2)
replica = df_factory.create(proactor_threads=2)
master.start()
replica.start()
cm = master.client()
await cm.execute_command("HSETEX key 86400 name 1234")
cr = replica.client()
await cr.execute_command(f"REPLICAOF localhost {master.port}")
await wait_available_async(cr)
result = await cr.hgetall("key")
assert "name" in result
assert result["name"] == "1234"