/**
* 空间索引申请方法(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;
}
Lua脚本操作Redis字节数组例子
最新推荐文章于 2024-05-30 16:30:41 发布