Lua脚本操作Redis字节数组例子

这段Lua脚本主要用于处理Redis中的字节数组,涉及到空间索引的申请方法。通过读取和处理传入的参数,如数据长度、块生成时间和更新时间等,计算并更新字节数组的索引。脚本中包含了计算新索引、更新文件长度、处理多块数据等多种情况,最终将处理后的索引存储回Redis。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    /**
     * 空间索引申请方法(value存储为Byte类型)
     * 索引结构:
     * 块开始索引,4字节,最大1.9G :2147483647/1024/1024/1024=1.9G (没有用块编号乘2048作开始索引,然后用两个字节存块编号,是因为两字节太小)
     * 索引偏移量4字节,最大1.9G :2147483647/1024/1024/1024=1.9G
     * 块生成时间与更新时间每个占4字节共8字节
     * 
     * 
     * @return
     */
    public static String getSpaceIndexByteLuaScript() {
        String luaStr = "local bigkey = KEYS[1];" 
                //数据长度
                + "local dataLen = tonumber(ARGV[1]);"
                //vid
                + "local smallKey = ARGV[2];"
                //临时编号
                + "local serNum = tonumber(ARGV[3]);" 
                //数据块长度
                + "local blockLen = tonumber(ARGV[4]);" 
                //终端时间
                + "local devTime = tonumber(ARGV[5]);" 
                //写入或更新标识,0写入,1更新
                + "local inUp =  tonumber(ARGV[6]);" 
                //该条数据该天打点状态
                + "local dayDotState =  tonumber(ARGV[7]);" 
                //日期行数据打点状态数据打点状态小Key
                + "local dayDotKey = ARGV[8];"
                //报警行数据打点状态
                + "local alarmTypeState =  tonumber(ARGV[9]);"
                //报警行数据打点状态数据打点状态小Key
                + "local alarmDotKey = ARGV[10];"
                //索引集合,字节:开始索引(4)+偏移索引(4)+块开始时间(4)+块开始更新(4);如果有多块,则重复前述
                + "local asciiIndex = redis.call('HGET',bigkey,smallKey);"
                //文件长度
                + "local oldfileLen = redis.call('HGET',bigkey,\"fileLen\");"
                //旧日期打点状态
                + "local oldDayDotState = redis.call('HGET',bigkey,dayDotKey);"
                //旧报警打点状态
                + "local oldAlarmTypeState = redis.call('HGET',bigkey,alarmDotKey);"
                
                + "local fileLen = 0;" 
                + "if(oldfileLen ~= false) then "
                + "    fileLen = tonumber(oldfileLen);" 
                + "end "
                  
                //上次索引日查询打点状态
                + "local oldDotState = 0;" 
                + "if(oldDayDotState ~= false) then "
                + "    oldDotState = tonumber(oldDayDotState);" 
                + "end "
                
                //上次索引报警查询打点状态
//                + "local oldAlarmDotState = 0;" 
//                + "if(oldAlarmTypeState ~= false) then "
//                + "    oldAlarmDotState = tonumber(oldAlarmTypeState);" 
//                + "end "
                
                //如果块大小为0,设定一个固定值
                + "if(blockLen == 0) then "
                + "    blockLen = 2048;" 
                + "end "
                
                //索引内容
                + "local beginIndex = 0;"
                + "local offSet = 0;"
                + "local blockSer = 0;"
                + "local insertTime = 0;"
                + "local updateTime = 0;"
                + "local indexTab  = {};"
                //开辟标识:0不开辟,1首次文件开辟,2重新开辟
                + "local blockFlag = 0;"
                
                //如果没有文件内容,则是文件首次申请空间
                + "if(fileLen == 0) then "
                + "       beginIndex = 0;"
                //头1个字节,每块开始包含8字节对应车辆ID
                + "       offSet = dataLen+1+8;"
                + "       blockSer = 1;"
                + "       insertTime = devTime;"
                + "       updateTime = devTime;"
                + "       fileLen = fileLen+blockLen;"
                //设置索引
                + "       indexTab[1] = beginIndex;"
                + "       indexTab[2] = offSet;"
                + "       indexTab[3] = insertTime;"
                + "       indexTab[4] = updateTime;"
                + "       blockFlag = 1;"
                + "else "
                        //如果是该车辆ID首次申请空间, 文件中新开辟一块区间进行写入,注意每块开始包含8字节对应车辆ID
                        + "if(asciiIndex == false or asciiIndex == nil) then "
                        + "       beginIndex = fileLen;"
                        //头1个字节,每块开始包含8字节对应车辆ID
                        + "       offSet = fileLen+dataLen+1+8;"
                        + "       blockSer = 1;"
                        + "       insertTime = devTime;"
                        + "       updateTime = devTime;"
                        + "       fileLen = fileLen+blockLen;"
                        //设置索引
                        + "       indexTab[1] = beginIndex;"
                        + "       indexTab[2] = offSet;"
                        + "       indexTab[3] = insertTime;"
                        + "       indexTab[4] = updateTime;"
                        + "       blockFlag = 2;"
                        + "else "
                        
                        //******解析ascii类型的索引:切割字符,获取最后4个索引int数值对应的个字符,再利用 字符转ASCII方法string.byte()转换出数字
                        //ascii字符串长度
                        + "local asciiStrlen = #asciiIndex; "
                        //上次存储的索引
                        + "    local oldbeginIndex = 0;"
                        + "    local oldoffSet = 0;"
                        + "    local oldinsertTime = 0;"
                        + "    local oldupdateTime = 0;"
                        //获取后面16个,因为每4个num对应一块索引值
                        +"for   i=1,4 do "
                                +"local num1,num2,num3,num4 = string.byte(asciiIndex,asciiStrlen-4*i+1,asciiStrlen-4*i+4); "
                                //二进制转int,这里的二进制=ascii
                                + "local num = 0; "
                                 //左移动3
                                + "num = num + math.floor(num1 * (2 ^ 24)); "
                                //左移动2
                                + "num = num + math.floor(num2 * (2 ^ 16)); "
                                //左移动1
                                + "num = num + math.floor(num3 * (2 ^ 8)); "
                                //左移动0
                                + "num = num + num4; "
                                
                                //块更新时间
                                + "if(i == 1) then "
                                + "    oldupdateTime = num;"
                                + "end "
                                //块写入时间
                                + "if(i == 2) then "
                                + "    oldinsertTime = num;"
                                + "end "
                                //偏移索引
                                + "if(i == 3) then "
                                + "    oldoffSet = num;"
                                + "end "
                                //块开始索引
                                + "if(i == 4) then "
                                + "    oldbeginIndex = num;"
                                + "end "
                                
                        + "end "
                        //上次块结束索引
                        + "    local oldendIndex = oldbeginIndex+blockLen-1;"
                       //分块数目
                        + "    local blocknum = math.modf(asciiStrlen/16);"
                        
                               //原来的块中(尽可能保证同一车同一个业务写入和更新在同一个块中)
                                + "if(((inUp == 1) and (oldoffSet + dataLen)<= oldendIndex) or ((inUp == 0) and (oldoffSet + dataLen*2)<= oldendIndex)) then "
                                + "       beginIndex = oldbeginIndex;"
                                + "       offSet = oldoffSet+dataLen;"
                                + "       blockSer = blocknum;"
                                //保证块中的“写入时间”是该块数据最小时间,而非该块创建写入的第一条时间
                                + "       if(devTime < oldinsertTime and devTime ~= 0) then "
                                + "            insertTime = devTime;"
                                + "       else "
                                + "            insertTime = oldinsertTime;"
                                + "       end "
                                
                                //只有这次时间大于块更新时间才替换,要不然会有数据查不了
                                + "       if(devTime > oldupdateTime) then "
                                + "            updateTime = devTime;"
                                + "       else "
                                + "            updateTime = oldupdateTime;"
                                + "       end "
                                //设置索引
                                + "       indexTab[1] = beginIndex;"
                                + "       indexTab[2] = offSet;"
                                + "       indexTab[3] = insertTime;"
                                + "       indexTab[4] = updateTime;"
                                + "else "
                                //重新开辟空间
                                + "       beginIndex = fileLen;"
                                //头1个字节,每块开始包含8字节对应车辆ID
                                + "       offSet = fileLen+dataLen+1+8;"
                                + "       blockSer =blocknum+1;"
                                + "       insertTime = devTime;"
                                + "       updateTime = devTime;"
                                + "       fileLen = fileLen+blockLen;"
                                //设置索引
                                + "       indexTab[1] = beginIndex;"
                                + "       indexTab[2] = offSet;"
                                + "       indexTab[3] = insertTime;"
                                + "       indexTab[4] = updateTime;"
                                + "       blockFlag = 2;"
                                + "end " 
                        + "end "
                + "end "
                
                 //*******缓存新索引,indexTab转成Ascii:注意indexTab每个元素都是4个字节:开始索引(4)+偏移索引(4)+块开始时间(4)+块开始更新(4);如果有多块,则重复前述
                 //本条数据所在块的索引Ascii字符
                 +"local str = \"\";"
                 +"local indexLen = table.getn(indexTab); "
                 +"for   i=1,indexLen do "
                 +"      local num = indexTab[i];"
                 //右移动3
                 +"      local rightShift = math.floor(num / (2 ^ 24));"
                 //转成Ascii
                 +"      rightShift = rightShift % 256;"
                 //ASCII转字符用string.char()
                 +"      str = str .. string.char(rightShift);"
                 //右移动2
                 +"      rightShift = math.floor(num / (2 ^ 16));"
                 //转成Ascii
                 +"      rightShift = rightShift % 256;"
                 +"      str = str .. string.char(rightShift);"
                 //右移动1
                 +"      rightShift = math.floor(num / (2 ^ 8));"
                 //转成Ascii
                 +"      rightShift = rightShift % 256;"
                 +"      str = str .. string.char(rightShift);"
                 //右移0
                 //转成Ascii
                 + "      num = num % 256;"
                 + "      str = str .. string.char(num);"
                 + " end "
                 
                 //***检查是否开辟新块:如果开辟新块,则块索引在原来索引上追加;如只有一块,直接采用;如不只一块而且不开辟,则替换原来的最后一块索引的asciiStr
                 //总索引asciiStr
                 +"local allStr = \"\";"
                 //只有一块数据,大多数情况下进入这个分支
                 + "if(blockSer == 1) then "
                 + "       allStr = str; "
                 + "else "
                        //开辟标识:0不开辟,1首次文件开辟,2重新开辟
                         + "if(blockFlag == 2) then "
                         //开辟新块,则直接追加
                         + "         allStr = asciiIndex .. str;"
                         + "else "
                         //原来的字符总长度
                         + "         local asciiStrlen = #asciiIndex; "
                         //截取第一个到去掉后面的16个,再追加:即替换掉最后(1块索引)16个
                         + "         local res = string.sub(asciiIndex,1,asciiStrlen-16);"
                         + "         allStr = res .. str;"
                         + "end "
                 + "end "
                 
                 //存储索引总集合
                 + " redis.call('HSET',bigkey,smallKey,allStr);" 
                //缓存文件新长度
                 + " redis.call('HSET',bigkey,\"fileLen\",fileLen);" 
            
                 //清空,减少传输数据量
                 + "indexTab = {};"
                 //返回写文件对应索引以及文件对应临时编号,在 Lua 索引值是以 1 为起始,但你也可以指定 0 开始。把块编号赋值给0编号
                 + "indexTab[0] = serNum;"
                 + "indexTab[-1] = blockFlag;"//块开辟标识
                 //这一步类似于JAVA中:HexStr.toStr(data)
                 //+ "local s=string.gsub(str,\"(.)\",function (x) return string.format(\"%02X \",string.byte(x)) end);"
                 //当条写入数据索引集合序列化结果,其实这里可以在外围转换为字节效率更高,但要方法待验证
                 //+ "indexTab[1] = str;"
                 + "local hexStr=string.gsub(str,\"(.)\",function (x) return string.format(\"%02X \",string.byte(x)) end);"
                 + "indexTab[1] = hexStr;"
                 //返回块编号:当条数据所在块编号
                 + "indexTab[2] = blockSer;"
                 //返回该条数据的块索引天打点大Key
                 + "indexTab[3] = bigkey;"
                 //返回该条数据的块索引天打点小Key
                 + "indexTab[4] = dayDotKey;"
                 //返回该条数据的块索引天打点上次状态
                 + "indexTab[5] = oldDotState;"
                 //返回该条数据的块索引天打点本次状态
                 + "indexTab[6] = dayDotState;"
                 //返回该条数据的写入更新标识
                 + "indexTab[7] = inUp;"
                 //返回该条数据的块索引报警打点小Key
                 + "indexTab[8] = alarmDotKey;"
                 //返回该条数据的块索引报警打点上次状态,是一个JSON的Map
                 + "indexTab[9] = oldAlarmTypeState;"
                 //返回该条数据的块索引报警打点本次状态
                 + "indexTab[10] = alarmTypeState;"
                 //测试用返回上次打点状态
//                 + "indexTab[11] = oldDayDotState;"
             
//                //****调试检查开始*****
//                 + "indexTab[3] = offSet;"    
//                 + "local as=string.gsub(allStr,\"(.)\",function (x) return string.format(\"%02X \",string.byte(x)) end);"
//                 + "indexTab[4] = as;"    
//                 + "local as2=string.gsub(str,\"(.)\",function (x) return string.format(\"%02X \",string.byte(x)) end);"
//                 + "indexTab[5] = as2;"    
//                 + "local as3=string.gsub(str,\"(.)\",function (x) return string.format(\"%02X \",string.byte(x)) end);"
//                 + "indexTab[6] = as3;"    
//                //ascii字符的总长度
//                + "local asciiStrlen = #str; "
//                + "indexTab[-2] = asciiStrlen;"//索引集合序列化结果 
//                + "local as=string.gsub(str,\"(.)\",function (x) return string.format(\"%02X \",string.byte(x)) end);"
//                + "indexTab[-3] = as;"//索引集合序列化结果 
//                //获取后面16个,因为每4个num对应一块索引值
//                +"for   i=1,4 do "
//                        +"local num1,num2,num3,num4 = string.byte(str,asciiStrlen-4*i+1,asciiStrlen-4*i+4); "
//                        //二进制转int,这里的二进制=ascii
//                        + "local num = 0; "
//                         //左移动3
//                        + "num = num + math.floor(num1 * (2 ^ 24)); "
//                        //左移动2
//                        + "num = num + math.floor(num2 * (2 ^ 16)); "
//                        //左移动1
//                        + "num = num + math.floor(num3 * (2 ^ 8)); "
//                        //左移动0
//                        + "num = num + num4; "
//                        
//                                //块更新时间
//                                + "if(i == 1) then "
//                                + "indexTab[-4] = num;"
//                                + "end "
//                                //块写入时间
//                                + "if(i == 2) then "
//                                + "indexTab[-5] = num;"
//                                + "end "
//                                //偏移索引
//                                + "if(i == 3) then "
//                                + "indexTab[-6] = num;"
//                                + "end "
//                                //块开始索引
//                                + "if(i == 4) then "
//                                + "indexTab[-7] = num;"
//                                + "end "
//                + "end "
//                //****测试检查结束*****
                
                + "return cjson.encode(indexTab);";
        
        return luaStr;
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值