feat: support RDB_TYPE_HASH_* and related cmds from Redis 7.4 (#970)

This commit is contained in:
OMG-By 2025-06-25 10:43:35 +08:00 committed by GitHub
parent efcd939d44
commit 307a284aeb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 232 additions and 1 deletions

View File

@ -4740,4 +4740,166 @@ var redisCommands = map[string]redisCommand{
},
},
},
"HPEXPIREAT": {
"HASH",
[]keySpec{
{
"index",
1,
"",
0,
"range",
0,
1,
0,
0,
0,
0,
},
},
},
"HEXPIREAT": {
"HASH",
[]keySpec{
{
"index",
1,
"",
0,
"range",
0,
1,
0,
0,
0,
0,
},
},
},
"HEXPIRE": {
"HASH",
[]keySpec{
{
"index",
1,
"",
0,
"range",
0,
1,
0,
0,
0,
0,
},
},
},
"HPEXPIRE": {
"HASH",
[]keySpec{
{
"index",
1,
"",
0,
"range",
0,
1,
0,
0,
0,
0,
},
},
},
"HPERSIST": {
"HASH",
[]keySpec{
{
"index",
1,
"",
0,
"range",
0,
1,
0,
0,
0,
0,
},
},
},
"HEXPIRETIME": {
"HASH",
[]keySpec{
{
"index",
1,
"",
0,
"range",
0,
1,
0,
0,
0,
0,
},
},
},
"HPEXPIRETIME": {
"HASH",
[]keySpec{
{
"index",
1,
"",
0,
"range",
0,
1,
0,
0,
0,
0,
},
},
},
"HTTL": {
"HASH",
[]keySpec{
{
"index",
1,
"",
0,
"range",
0,
1,
0,
0,
0,
0,
},
},
},
"HPTTL": {
"HASH",
[]keySpec{
{
"index",
1,
"",
0,
"range",
0,
1,
0,
0,
0,
0,
},
},
},
}

View File

@ -2,6 +2,7 @@ package types
import (
"io"
"strconv"
"RedisShake/internal/log"
"RedisShake/internal/rdb/structure"
@ -34,6 +35,14 @@ func (o *HashObject) Rewrite() <-chan RedisCmd {
o.readHashZiplist()
case rdbTypeHashListpack:
o.readHashListpack()
case rdbTypeHashMetadataPreGa:
o.readHashTtl(true)
case rdbTypeHashListpackExPre:
o.readHashListpackTtl(true)
case rdbTypeHashMetadata:
o.readHashTtl(false)
case rdbTypeHashListpackEx:
o.readHashListpackTtl(false)
default:
log.Panicf("unknown hash type. typeByte=[%d]", o.typeByte)
}
@ -76,3 +85,56 @@ func (o *HashObject) readHashListpack() {
o.cmdC <- RedisCmd{"hset", o.key, key, value}
}
}
func (o *HashObject) readHashListpackTtl(isPre bool) {
rd := o.rd
if !isPre {
// read minExpire
_ = int64(structure.ReadUint64(rd))
}
list := structure.ReadListpack(rd)
size := len(list)
for i := 0; i < size; i += 3 {
key := list[i]
value := list[i+1]
expireAt,err := strconv.ParseInt(list[i+2], 10, 64)
if err != nil{
log.Panicf("readHashListpackTtl parsing expireAt %s error", list[i])
return
}
o.cmdC <- RedisCmd{"hset", o.key, key, value}
if expireAt != 0{
o.cmdC <- RedisCmd{"hpexpireat", o.key, strconv.FormatInt(expireAt, 10), "fields", "1", key}
}
}
}
func (o *HashObject) readHashTtl(isPre bool){
rd := o.rd
var minExpire int64
if !isPre {
minExpire = int64(structure.ReadUint64(rd))
log.Debugf("%s minExpire is %d", o.key, minExpire)
}
size := int(structure.ReadLength(rd))
for i := 0; i < size; i++ {
expireAt := int64(structure.ReadLength(rd))
if !isPre{
if expireAt != 0{
expireAt = expireAt + minExpire - 1
}
}
key := structure.ReadString(rd)
value := structure.ReadString(rd)
//HPEXPIREAT key unix-time-seconds [NX | XX | GT | LT] FIELDS numfields
o.cmdC <- RedisCmd{"hset", o.key, key, value}
if expireAt != 0{
o.cmdC <- RedisCmd{"hpexpireat", o.key, strconv.FormatInt(expireAt, 10), "fields", "1", key}
}
}
}

View File

@ -49,6 +49,12 @@ const (
rdbTypeSetListpack = 20 // RDB_TYPE_SET_LISTPACK
rdbTypeStreamListpacks3 = 21 // RDB_TYPE_STREAM_LISTPACKS_3
// https://github.com/redis/redis/pull/13391
rdbTypeHashMetadataPreGa = 22 // RDB_TYPE_HASH_METADATA_PRE_GA
rdbTypeHashListpackExPre = 23 // RDB_TYPE_HASH_LISTPACK_EX_PRE_GA
rdbTypeHashMetadata = 24 // RDB_TYPE_HASH_METADATA
rdbTypeHashListpackEx = 25 // RDB_TYPE_HASH_LISTPACK_EX
moduleTypeNameCharSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
rdbModuleOpcodeEOF = 0 // End of module value.
@ -85,7 +91,8 @@ func ParseObject(rd io.Reader, typeByte byte, key string) RedisObject {
o := new(ZsetObject)
o.LoadFromBuffer(rd, key, typeByte)
return o
case rdbTypeHash, rdbTypeHashZipmap, rdbTypeHashZiplist, rdbTypeHashListpack: // hash
case rdbTypeHash, rdbTypeHashZipmap, rdbTypeHashZiplist, rdbTypeHashListpack,
rdbTypeHashMetadataPreGa, rdbTypeHashListpackExPre, rdbTypeHashMetadata, rdbTypeHashListpackEx: // hash
o := new(HashObject)
o.LoadFromBuffer(rd, key, typeByte)
return o