@@ -65,6 +65,7 @@ struct ParsingElementInfo peInfo[PE_MAX] = {
65
65
[PE_HASH_META ] = {elementHash , "elementHashMeta" , "Parsing Hash with expiry on fields" },
66
66
[PE_HASH_ZL ] = {elementHashZL , "elementHashZL" , "Parsing hash Ziplist" },
67
67
[PE_HASH_LP ] = {elementHashLP , "elementHashLP" , "Parsing hash Listpack" },
68
+ [PE_HASH_LP_EX ] = {elementHashLPEx , "elementHashLPEx" , "Parsing hash ListpackEx (with expiry)" },
68
69
[PE_HASH_ZM ] = {elementHashZM , "elementHashZM" , "Parsing hash Zipmap" },
69
70
/* set */
70
71
[PE_SET ] = {elementSet , "elementSet" , "Parsing set" },
@@ -99,6 +100,7 @@ struct ParsingElementInfo peInfo[PE_MAX] = {
99
100
[PE_RAW_HASH_META ] = {elementRawHash , "elementRawHashMeta" , "Parsing raw Hash with expiry" },
100
101
[PE_RAW_HASH_ZL ] = {elementRawHashZL , "elementRawHashZL" , "Parsing raw hash Ziplist" },
101
102
[PE_RAW_HASH_LP ] = {elementRawHashLP , "elementRawHashLP" , "Parsing raw hash Listpack" },
103
+ [PE_RAW_HASH_LP_EX ] = {elementRawHashLPEx , "elementRawHashLPEx" , "Parsing raw hash ListpackEx" },
102
104
[PE_RAW_HASH_ZM ] = {elementRawHashZM , "elementRawHashZM" , "Parsing raw hash Zipmap" },
103
105
/* set */
104
106
[PE_RAW_SET ] = {elementRawSet , "elementRawSet" , "Parsing raw set" },
@@ -563,6 +565,7 @@ _LIBRDB_API int RDB_handleByLevel(RdbParser *p, RdbDataType type, RdbHandlersLev
563
565
p -> handleTypeObjByLevel [RDB_TYPE_HASH_ZIPMAP ] = lvl ;
564
566
p -> handleTypeObjByLevel [RDB_TYPE_HASH_ZIPLIST ] = lvl ;
565
567
p -> handleTypeObjByLevel [RDB_TYPE_HASH_LISTPACK ] = lvl ;
568
+ p -> handleTypeObjByLevel [RDB_TYPE_HASH_LISTPACK_EX ] = lvl ;
566
569
break ;
567
570
case RDB_DATA_TYPE_MODULE :
568
571
p -> handleTypeObjByLevel [RDB_TYPE_MODULE_2 ] = lvl ;
@@ -1050,7 +1053,7 @@ static RdbStatus hashZiplist(RdbParser *p, BulkInfo *ziplistBulk) {
1050
1053
return RDB_STATUS_OK ;
1051
1054
}
1052
1055
1053
- static RdbStatus hashListPack (RdbParser * p , BulkInfo * lpBulk ) {
1056
+ static RdbStatus hashListPack (RdbParser * p , BulkInfo * lpBulk , int withExpiry ) {
1054
1057
size_t items = 0 ;
1055
1058
1056
1059
if (unlikely (0 == lpValidateIntegrity (lpBulk -> ref , lpBulk -> len , p -> deepIntegCheck , counterCallback , & items ))) {
@@ -1059,21 +1062,27 @@ static RdbStatus hashListPack(RdbParser *p, BulkInfo *lpBulk) {
1059
1062
return RDB_STATUS_ERROR ;
1060
1063
}
1061
1064
1062
- if (unlikely ((items & 1 ))) {
1065
+ /* [field][value][expiry] vs [field][value] */
1066
+ int tupleSize = (withExpiry ) ? 3 : 2 ;
1067
+ if (unlikely ((items % tupleSize ) != 0 )) {
1063
1068
RDB_reportError (p , RDB_ERR_HASH_LP_INTEG_CHECK ,
1064
- "hashListPack(): Listpack integrity check failed. Uneven number of items." );
1069
+ "hashListPack(): listpack has unexpected number of items." );
1065
1070
return RDB_STATUS_ERROR ;
1066
1071
}
1067
1072
1068
1073
if (p -> elmCtx .key .handleByLevel == RDB_LEVEL_STRUCT ) {
1069
1074
registerAppBulkForNextCb (p , lpBulk );
1070
- CALL_HANDLERS_CB (p , NOP , RDB_LEVEL_STRUCT , rdbStruct .handleHashLP , lpBulk -> ref );
1075
+ if (withExpiry )
1076
+ CALL_HANDLERS_CB (p , NOP , RDB_LEVEL_STRUCT , rdbStruct .handleHashLPEx , lpBulk -> ref );
1077
+ else
1078
+ CALL_HANDLERS_CB (p , NOP , RDB_LEVEL_STRUCT , rdbStruct .handleHashLP , lpBulk -> ref );
1071
1079
return RDB_STATUS_OK ;
1072
1080
}
1073
1081
1074
1082
p -> elmCtx .key .numItemsHint = items ;
1075
1083
unsigned char * iterLP = lpFirst (lpBulk -> ref );
1076
1084
while (iterLP ) {
1085
+ int64_t expiryVal = -1 ;
1077
1086
unsigned char * field , * value ;
1078
1087
unsigned int fieldLen , valueLen ;
1079
1088
long long fieldVal , valueVal ;
@@ -1083,6 +1092,16 @@ static RdbStatus hashListPack(RdbParser *p, BulkInfo *lpBulk) {
1083
1092
iterLP = lpNext (lpBulk -> ref , iterLP );
1084
1093
value = lpGetValue (iterLP , & valueLen , & valueVal );
1085
1094
iterLP = lpNext (lpBulk -> ref , iterLP );
1095
+ if (withExpiry ) {
1096
+ if (lpGet (iterLP , & expiryVal , NULL ) != NULL ) {
1097
+ RDB_reportError (p , RDB_ERR_HASH_LP_INTEG_CHECK ,
1098
+ "hashListPack(): integrity check failed. Expiry is a string instead of value." );
1099
+ return RDB_STATUS_ERROR ;
1100
+ }
1101
+
1102
+ if (expiryVal == 0 ) expiryVal = -1 ; /* If expiry not set */
1103
+ iterLP = lpNext (lpBulk -> ref , iterLP );
1104
+ }
1086
1105
1087
1106
if (!allocEmbeddedBulk (p , field , fieldLen , fieldVal , & embBulk1 ))
1088
1107
return RDB_STATUS_ERROR ;
@@ -1101,7 +1120,7 @@ static RdbStatus hashListPack(RdbParser *p, BulkInfo *lpBulk) {
1101
1120
rdbData .handleHashField ,
1102
1121
embBulk1 .binfo .ref ,
1103
1122
embBulk2 .binfo .ref ,
1104
- -1 /*no expiry*/ );
1123
+ expiryVal );
1105
1124
}
1106
1125
return RDB_STATUS_OK ;
1107
1126
}
@@ -1451,6 +1470,7 @@ RdbStatus elementNextRdbType(RdbParser *p) {
1451
1470
case RDB_TYPE_HASH_METADATA : return nextParsingElementKeyValue (p , PE_RAW_HASH_META , PE_HASH_META );
1452
1471
case RDB_TYPE_HASH_ZIPLIST : return nextParsingElementKeyValue (p , PE_RAW_HASH_ZL , PE_HASH_ZL );
1453
1472
case RDB_TYPE_HASH_LISTPACK : return nextParsingElementKeyValue (p , PE_RAW_HASH_LP , PE_HASH_LP );
1473
+ case RDB_TYPE_HASH_LISTPACK_EX : return nextParsingElementKeyValue (p , PE_RAW_HASH_LP_EX , PE_HASH_LP_EX );
1454
1474
case RDB_TYPE_HASH_ZIPMAP : return nextParsingElementKeyValue (p , PE_RAW_HASH_ZM , PE_HASH_ZM );
1455
1475
/* set */
1456
1476
case RDB_TYPE_SET : return nextParsingElementKeyValue (p , PE_RAW_SET , PE_SET );
@@ -1734,14 +1754,27 @@ RdbStatus elementHashZL(RdbParser *p) {
1734
1754
return nextParsingElement (p , PE_END_KEY );
1735
1755
}
1736
1756
1757
+ RdbStatus elementHashLPEx (RdbParser * p ) {
1758
+ BulkInfo * listpackBulk ;
1759
+
1760
+ IF_NOT_OK_RETURN (rdbLoadString (p , RQ_ALLOC_APP_BULK , NULL , & listpackBulk ));
1761
+
1762
+ /*** ENTER SAFE STATE ***/
1763
+
1764
+ if (RDB_STATUS_ERROR == hashListPack (p , listpackBulk , 1 /*withExpiry*/ ))
1765
+ return RDB_STATUS_ERROR ;
1766
+
1767
+ return nextParsingElement (p , PE_END_KEY );
1768
+ }
1769
+
1737
1770
RdbStatus elementHashLP (RdbParser * p ) {
1738
1771
BulkInfo * listpackBulk ;
1739
1772
1740
1773
IF_NOT_OK_RETURN (rdbLoadString (p , RQ_ALLOC_APP_BULK , NULL , & listpackBulk ));
1741
1774
1742
1775
/*** ENTER SAFE STATE ***/
1743
1776
1744
- if (RDB_STATUS_ERROR == hashListPack (p , listpackBulk ))
1777
+ if (RDB_STATUS_ERROR == hashListPack (p , listpackBulk , 0 /*withExpiry*/ ))
1745
1778
return RDB_STATUS_ERROR ;
1746
1779
1747
1780
return nextParsingElement (p , PE_END_KEY );
0 commit comments