Unverified Commit 82f00f51 authored by Moti Cohen's avatar Moti Cohen Committed by GitHub
Browse files

Optimize RDB_TYPE_HASH_METADATA to keep relative expiration time (#13438)

Modify RDB_TYPE_HASH_METADATA layout to store expiration times relative
to the minimum expiration time, which is written at the start as absolute time.
parent 447ce11a
...@@ -699,7 +699,7 @@ int rdbSaveObjectType(rio *rdb, robj *o) { ...@@ -699,7 +699,7 @@ int rdbSaveObjectType(rio *rdb, robj *o) {
else if (o->encoding == OBJ_ENCODING_LISTPACK_EX) else if (o->encoding == OBJ_ENCODING_LISTPACK_EX)
return rdbSaveType(rdb,RDB_TYPE_HASH_LISTPACK_EX); return rdbSaveType(rdb,RDB_TYPE_HASH_LISTPACK_EX);
else if (o->encoding == OBJ_ENCODING_HT) { else if (o->encoding == OBJ_ENCODING_HT) {
if (hashTypeGetMinExpire(o, 0) == EB_EXPIRE_TIME_INVALID) if (hashTypeGetMinExpire(o, /*accurate*/ 1) == EB_EXPIRE_TIME_INVALID)
return rdbSaveType(rdb,RDB_TYPE_HASH); return rdbSaveType(rdb,RDB_TYPE_HASH);
else else
return rdbSaveType(rdb,RDB_TYPE_HASH_METADATA); return rdbSaveType(rdb,RDB_TYPE_HASH_METADATA);
...@@ -970,7 +970,7 @@ ssize_t rdbSaveObject(rio *rdb, robj *o, robj *key, int dbid) { ...@@ -970,7 +970,7 @@ ssize_t rdbSaveObject(rio *rdb, robj *o, robj *key, int dbid) {
* RDB_TYPE_HASH_METADATA layout, including tuples of [ttl][field][value]. * RDB_TYPE_HASH_METADATA layout, including tuples of [ttl][field][value].
* Otherwise, use the standard RDB_TYPE_HASH layout containing only * Otherwise, use the standard RDB_TYPE_HASH layout containing only
* the tuples [field][value]. */ * the tuples [field][value]. */
uint64_t minExpire = hashTypeGetMinExpire(o, 0); uint64_t minExpire = hashTypeGetMinExpire(o, 1);
/* if RDB_TYPE_HASH_METADATA (Can have TTLs on fields) */ /* if RDB_TYPE_HASH_METADATA (Can have TTLs on fields) */
if (minExpire != EB_EXPIRE_TIME_INVALID) { if (minExpire != EB_EXPIRE_TIME_INVALID) {
...@@ -996,9 +996,13 @@ ssize_t rdbSaveObject(rio *rdb, robj *o, robj *key, int dbid) { ...@@ -996,9 +996,13 @@ ssize_t rdbSaveObject(rio *rdb, robj *o, robj *key, int dbid) {
/* save the TTL */ /* save the TTL */
if (hashWithMeta) { if (hashWithMeta) {
uint64_t ttl = hfieldGetExpireTime(field); uint64_t ttl, expiryTime= hfieldGetExpireTime(field);
/* 0 is used to indicate no TTL is set for this field */
if (ttl == EB_EXPIRE_TIME_INVALID) ttl = 0; /* Saved TTL value:
* - 0: Indicates no TTL. This is common case so we keep it small.
* - Otherwise: TTL is relative to minExpire (with +1 to avoid 0 that already taken)
*/
ttl = (expiryTime == EB_EXPIRE_TIME_INVALID) ? 0 : expiryTime - minExpire + 1;
if ((n = rdbSaveLen(rdb, ttl)) == -1) { if ((n = rdbSaveLen(rdb, ttl)) == -1) {
dictReleaseIterator(di); dictReleaseIterator(di);
return -1; return -1;
...@@ -2261,19 +2265,24 @@ robj *rdbLoadObject(int rdbtype, rio *rdb, sds key, int dbid, int *error) ...@@ -2261,19 +2265,24 @@ robj *rdbLoadObject(int rdbtype, rio *rdb, sds key, int dbid, int *error)
} else if (rdbtype == RDB_TYPE_HASH_METADATA || rdbtype == RDB_TYPE_HASH_METADATA_PRE_GA) { } else if (rdbtype == RDB_TYPE_HASH_METADATA || rdbtype == RDB_TYPE_HASH_METADATA_PRE_GA) {
sds value; sds value;
hfield field; hfield field;
uint64_t expireAt; uint64_t ttl, expireAt, minExpire = EB_EXPIRE_TIME_INVALID;
dict *dupSearchDict = NULL; dict *dupSearchDict = NULL;
/* If hash with TTLs, load next/min expiration time */ /* If hash with TTLs, load next/min expiration time
*
* - This value is serialized for future use-case of streaming the object
* directly to FLASH (while keeping in mem its next expiration time).
* - It is also being used to keep only relative TTL for fields in RDB file.
*/
if (rdbtype == RDB_TYPE_HASH_METADATA) { if (rdbtype == RDB_TYPE_HASH_METADATA) {
uint64_t minExpire = rdbLoadMillisecondTime(rdb, RDB_VERSION); minExpire = rdbLoadMillisecondTime(rdb, RDB_VERSION);
/* This value was serialized for future use-case of streaming the object
* directly to FLASH (while keeping in mem its next expiration time) */
UNUSED(minExpire);
if (rioGetReadError(rdb)) { if (rioGetReadError(rdb)) {
rdbReportCorruptRDB("Hash failed loading minExpire"); rdbReportCorruptRDB("Hash failed loading minExpire");
return NULL; return NULL;
} }
if (minExpire > EB_EXPIRE_TIME_INVALID) {
rdbReportCorruptRDB("Hash read invalid minExpire value");
}
} }
len = rdbLoadLen(rdb, NULL); len = rdbLoadLen(rdb, NULL);
...@@ -2301,14 +2310,27 @@ robj *rdbLoadObject(int rdbtype, rio *rdb, sds key, int dbid, int *error) ...@@ -2301,14 +2310,27 @@ robj *rdbLoadObject(int rdbtype, rio *rdb, sds key, int dbid, int *error)
len--; len--;
/* read the TTL */ /* read the TTL */
if (rdbLoadLenByRef(rdb, NULL, &expireAt) == -1) { if (rdbLoadLenByRef(rdb, NULL, &ttl) == -1) {
serverLog(LL_WARNING, "failed reading hash TTL"); serverLog(LL_WARNING, "failed reading hash TTL");
decrRefCount(o); decrRefCount(o);
if (dupSearchDict != NULL) dictRelease(dupSearchDict); if (dupSearchDict != NULL) dictRelease(dupSearchDict);
return NULL; return NULL;
} }
if (rdbtype == RDB_TYPE_HASH_METADATA) {
/* Loaded TTL value:
* - 0: Indicates no TTL. This is common case so we keep it small.
* - Otherwise: TTL is relative to minExpire (with +1 to avoid 0 that already taken)
*/
expireAt = (ttl != 0) ? (ttl + minExpire - 1) : 0;
} else { /* RDB_TYPE_HASH_METADATA_PRE_GA */
expireAt = ttl; /* Value is absolute */
}
if (expireAt > EB_EXPIRE_TIME_MAX) { if (expireAt > EB_EXPIRE_TIME_MAX) {
rdbReportCorruptRDB("invalid expireAt time: %llu", (unsigned long long)expireAt); rdbReportCorruptRDB("invalid expireAt time: %llu",
(unsigned long long) expireAt);
decrRefCount(o); decrRefCount(o);
return NULL; return NULL;
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment