Rate limiting with lua - lua

We have implemented redis based rate limiting for our web service which has been taken from here. I am duplicating the relevant code here.
local limits = cjson.decode(ARGV[1])
local now = tonumber(ARGV[2])
local weight = tonumber(ARGV[3] or '1')
local longest_duration = limits[1][1] or 0
local saved_keys = {}
-- handle cleanup and limit checks
for i, limit in ipairs(limits) do
local duration = limit[1]
longest_duration = math.max(longest_duration, duration)
local precision = limit[3] or duration
precision = math.min(precision, duration)
local blocks = math.ceil(duration / precision)
local saved = {}
table.insert(saved_keys, saved)
saved.block_id = math.floor(now / precision)
saved.trim_before = saved.block_id - blocks + 1
saved.count_key = duration .. ':' .. precision .. ':'
saved.ts_key = saved.count_key .. 'o'
for j, key in ipairs(KEYS) do
local old_ts = redis.call('HGET', key, saved.ts_key)
old_ts = old_ts and tonumber(old_ts) or saved.trim_before
if old_ts > now then
-- don't write in the past
return 1
end
-- discover what needs to be cleaned up
local decr = 0
local dele = {}
local trim = math.min(saved.trim_before, old_ts + blocks)
for old_block = old_ts, trim - 1 do
local bkey = saved.count_key .. old_block
local bcount = redis.call('HGET', key, bkey)
if bcount then
decr = decr + tonumber(bcount)
table.insert(dele, bkey)
end
end
-- handle cleanup
local cur
if #dele > 0 then
redis.call('HDEL', key, unpack(dele))
cur = redis.call('HINCRBY', key, saved.count_key, -decr)
else
cur = redis.call('HGET', key, saved.count_key)
end
-- check our limits
if tonumber(cur or '0') + weight > limit[2] then
return 1
end
end
end
I am trying to figure out the meaning of the comment -- don't write in the past
I don't see how a case would be possible where old_ts is greater than now
I have put logs all over the lua code but without any success.
At maximum old_ts can be equal to saved.trim_before which in turn can be equal to now if precision is 1 and blocks is 1. But not greater .
It would be helpful if someone has insights on it.

If you look at the gist provided in the article
https://gist.github.com/josiahcarlson/80584b49da41549a7d5c
There is comment which asks
In over_limit_sliding_window_lua_, should
if old_ts > now then
at here be
if old_ts > saved.block_id then
And I agree to this, the old_ts is supposed to have the bucket and when the bucket jumps to the next slot, that is when old_ts will be greater then than the block_id

Related

In Lua error (800000000 + 3000000000 = -2147483648)

Here is my code. two num plus > 0 but add a variable < 0 !!!
function addExp(actorExp, val)
local actorExp = actorExp -- actorExp = 800000000
local val = val -- val = 3000000000
if actorExp + val -- Here actorExp > 0 then
-- actorExp + val > 0 but
actorExp = actorExp + val -- Here actorExp = -2147483648 ???
else return end
updateInfo(actor)
end
how can i fix it
This is called an overflow error.
The way computers store data is using binary (1s and 0s), and depending on the size (number of digits) of the binary used to store each number (often 32 'bits') will determine the maximum value. When the maximum value is reached, it will "overflow" back to the start, which in this case is -2147483648 as it is a "signed" (can be negative) number.

Lua - Analysing values in a text file

I’m writing power (watts) values to a text file in order to extract information I can use.
4.7
4.7
4.8
5.2
5.1
4.6
4.6
4.6
Currently I have the following code to give me the average, but I’d like to add to it so it tells me more such as, what was the highest value, the lowest value, the most frequent value, and if at all possible if there are any ‘0’ values recorded (* - if possible with that last one it would be good to ignore them..)
local ctr = 0
local sum = 0
for _ in io.lines"/www/EnergyPlug-b.txt" do
ctr = ctr + 1
end
print(ctr)
for line in io.lines"/www/EnergyPlug-b.txt" do
sum = sum + line
end
print(sum)
average = sum / ctr
print(average)
I did explore creating a Lua table via table.insert() off of the first io.lines section, like the following, but I’m not sure how good it is?
local rows = {}
-- go over the file line by line
for line in io.lines("/www/EnergyPlug-b.txt") do
-- if line matches ?.? then insert into table
local value = line:match("%d%p%d") -- 1.5
--print(value)
table.insert(rows, value)
end
local arraymax = math.max(unpack(rows))
local arraymin = math.min(unpack(rows))
print (arraymax) -- ?.?
print (arraymin) -- ?.?
If the above is suitable, how best should I go about identifying the items/values i mentioned at the very start ?
In the first snippet there is no reason to have a separate loop for ctr and sum. You can do it in one loop.
Your second snipped is ok. unpack is limited so this won't work for many thousand values.
You have to traverse the table anyway to get the other values so you can determin min and max in that loop too without that size limit.
local value = line:match("%d%p%d") if there are only those numbers in that file you can skip the pattern matching here.
The calculations are pretty straigt forward. I'm not sure what you're struggling with here.
local min = math.huge -- use a value that is definitely bigger than any value
local max = -math.huge -- use a value that is definitely smaller than any value
local counts = {} -- an emtpy table we'll use to count how often each value occurs
local numIngored = 0 -- how many 0 values have we ignored?
for line in io.lines(yourFileName) do
-- convert string to a number
local value = tonumber(line)
-- if we take the value into account
if value ~= 0.0 then
-- update min and max values
min = value < min and value or min
max = value > max and value or max
-- update counts
counts[value] = counts[value] and counts[value] + 1 or 1
else
-- count ignored values
numIgnored = numIgnored + 1
end
end
I'll leave it up to you to get the most frequent values from counts
Thanks to #piglet and using other SO posts, here is what I ended up with..
local min = math.huge -- use a value that is definitely bigger than any value
local max = -math.huge -- use a value that is definitely smaller than any value
local ctr = 0
local valtotal = 0
local counts = {} -- an emtpy table we'll use to count how often each value occurs
local numIngored = 0 -- how many 0 values have we ignored?
for line in io.lines("/www/EnergyPlug-b.txt") do
-- convert string to a number
local value = tonumber(line)
-- if we take the value into account
if value ~= 0.0 then
ctr = ctr + 1
valtotal = valtotal + value
-- update min and max values
min = value < min and value or min
max = value > max and value or max
-- update counts
counts[value] = counts[value] and counts[value] + 1 or 1
else
-- count ignored values
numIgnored = numIgnored + 1
end
end
print("----Table print out -----")
for k, v in pairs(counts) do
print(k,v)
end
print("---------------------------")
print("Lowest value recorded = " ..min)
print("Highest value recorded = " ..max)
print("Average value recorded = " ..round2(valtotal / ctr, 1))
print("Number of values recorded = " ..ctr)
print("---------------------------")
local max_val, key1 = -math.huge
for k, v in pairs(counts) do
if v > max_val then
max_val, key1 = v, k
end
end
local min_val, key2 = math.huge
for k1, v1 in pairs(counts) do
if v1 < min_val or v1 == min_val then
min_val, key2 = v1, k1
end
end
local min_qty, max_qty = 0, 0
local min_str, max_str = "", ""
for k2, v2 in pairs(counts) do
if v2 == min_val then
min_qty = min_qty + 1
min_str = min_str .. " " .. k2
elseif v2 == max_val then
max_qty = max_qty + 1
max_str = max_str .. " " .. k2
end
end
if min_qty == 1 then
print("Least recorded value was = " ..key2.. " recorded "..min_val.." times")
else
print("Least recorded values were = " ..min_str.. " each recorded "..min_val.." time")
end
if max_qty == 1 then
print("Most recorded value was = " ..key1.. " recorded "..max_val.." times")
else
print("Least recorded values were = " ..max_str.. " each recorded "..max_val.." time")
end
print("---------------------------")

Can anybody please tell me how to set or reset a bit in lua..?

I want to perform set and reset of particular bit in a number. As I'm using lua 5.1 I can't able to use APIs and shifting operators so it is becoming more and more complex so please help me finding this
bit library is shipped with the firmware.
Read the documentation: https://nodemcu.readthedocs.io/en/release/modules/bit/
You can do it without external libraries, if you know the position of the bit you wish to flip.
#! /usr/bin/env lua
local hex = 0xFF
local maxPos = 7
local function toggle( num, pos )
if pos < 0 or pos > maxPos then print( 'pick a valid pos, 0-' ..maxPos )
else
local bits = {} -- populate emtpy table
for i=1, maxPos do bits[i] = false end
for i = maxPos, pos +1, -1 do -- temporarily throw out the high bits
if num >= 2 ^i then
num = num -2 ^i
bits [i +1] = true
end
end
if num >= 2 ^pos then num = num -2 ^pos -- flip desired bit
else num = num +2 ^pos
end
for i = 1, #bits do -- add those high bits back in
if bits[i] then num = num +2 ^(i -1) end
end
end ; print( 'current value:', num )
return num
end
original value: 255
current value: 127
pick a valid pos, 0-7
current value: 127
current value: 255

How to time interval between event in lua

I am writing a simple script in lua. If the LED is on, it will increment the counter by 1. If the led is off for more than 1 seconds, it reset the counter.
So how exactly do we time event like that in lua ?
This is what i have and been testing multiple ways so far.
function ReadADC1()
local adc_voltage_value = 0
adc_voltage_value = tonumber(adc.readadc()) * 2 -- 0.10 --get dec number out of this -- need to know where package adc come from
--convert to voltage
adc_voltage_value = adc_voltage_value *0.000537109375 --get V
adc_voltage_value = math.floor(adc_voltage_value *1000 +0.5) --since number is base off resolution
--print (adc_voltage_value)
return adc_voltage_value
end
-- end of readADC1() TESTED
function interval()
local counter1 =0
ledValue = ReadADC1()
if (ledValue >= OnThreshHold) then
ledStatus = 1
t1=os.time()
else
ledStatus = 0
t2 = os.time()
end
--counter1 =0
for i=1,20 do
if (ledStatus == 1) then -- if led is off for more than 1 second, reset counter = 0
counter1 = counter1 + 1
elseif ((ledStatus ==0 and ((os.difftime(os.time(),t2)/100000) > 1000))) then -- increment counter when led is on
counter1 = 0
end
end
print (counter1)
end
I know for sure the logic for interval is wrong since os.time return a huge number (i assume it in psecond instead of second).
Any suggest or solution is welcome. I tried vmstarttimer and vmstoptimmer before this but not sure how it work.
EDIT:
function counter()
local ledValue = ReadADC1()
local t1 = os.clock()
while true do
local t2 = os.clock()
local dt = t2 - t1
t1 = t2
if ((ledValue < OnThreshHold) and (dt < 1)) then -- if led is off for less than 1 second
ledCounter = ledCounter + 1
elseif ((ledValue < OnThreshHold) and (dt > 1)) then-- if led is off for more than 1 second
ledCounter = 0;
else
ledCounter = ledCounter
end
print (ledCounter)
end
end
Ultimately, it will be return ledCounter instead of print counter since I will plug the value of counter to another function that will print a message correspond to the number of counter
You could use os.clock which returns your programs runtime since start in seconds.
Returns an approximation of the amount in seconds of CPU time used by the program.
Source
This function could be used in this way.
local t1 = os.clock() -- begin
local t2 = os.clock() -- end
local dt = t2 - t1 -- calulate delta time
-- or looped
local t1 = os.clock() -- begin
while true do
local t2 = os.clock() -- end
local dt = t2 - t1 -- calulate delta time
t1 = t2 -- reset t1
-- use dt ...
end
-- or wait for time elapsed
-- runs until 1 second passed
local t1 = os.clock()
while (os.clock() - t1) < 1 do
-- do stuff while dt is smaller than 1
-- could even reset timer (t1) to current to
-- repeat waiting
-- t1 = os.clock() | ...
end
-- logic for your example
function counter()
local time = os.clock()
local lastLedOn = false
local counter = 0
while true do
if os.clock() - time > 1.0 then
break
end
if getLedValue() == on then -- replace
time = os.clock()
if not lastLedOn then
lastLedOn = true
counter = counter + 1
-- print(counter) | or here if you want to print repeatedly
end
end
end
print(counter)
end -- was unable to test it

Error in function rembuff:floor() in lua code file: attempt to call method 'floor' (a nil value)

In Machine Translation Dataset I have successfully pre-trained my model in Lua. Now I move to train my model.
But I get the error in a Lua file in the function rembuff:floor()
Error: Attempt to call method 'floor' (a nil value)
This is that specific function :
function MarginBatchBeamSearcher:nextSearchStep(t, batch_pred_inp, batch_ctx, beam_dec, beam_scorer,gold_scores, target, target_w, gold_rnn_state_dec, delts, losses, global_noise)
local K = self.K
local resval, resind, rembuff = self.resval, self.resind, self.rembuff
local finalval, finalind = self.finalval, self.finalind
self:synchDropout(t, global_noise)
-- pred_inp should be what was predicted at the last step
local outs = beam_dec:forward({batch_pred_inp, batch_ctx, unpack(self.prev_state)})
local all_scores = beam_scorer:forward(outs[#outs]) -- should be (batch_l*K) x V matrix
local V = all_scores:size(2)
local mistaken_preds = {}
for n = 1, self.batch_size do
delts[n] = 0
losses[n] = 0
if t <= target_w[n]-1 then -- only do things if t <= length (incl end token) - 2
local beam_size = #self.pred_pfxs[n]
local nstart = (n-1)*K+1
local nend = n*K
local scores = all_scores:sub(nstart, nstart+beam_size-1):view(-1) -- scores for this example
-- take top K
torch.topk(resval, resind, scores, K, 1, true)
-- see if we violated margin
torch.min(finalval, finalind, resval, 1) -- resind[finalind[1]] is idx of K'th highest predicted word
-- checking that true score at least 1 higher than K'th
losses[n] = math.max(0, 1 - gold_scores[n][target[t+1][n]] + finalval[1])
-- losses[n] = math.max(0, - gold_scores[n][target[t+1][n]] + finalval[1])
if losses[n] > 0 then
local parent_idx = math.ceil(resind[finalind[1]]/V)
local pred_word = ((resind[finalind[1]]-1)%V) + 1
mistaken_preds[n] = {prev = self.pred_pfxs[n][parent_idx], val = pred_word}
delts[n] = 1 -- can change.....
else
-- put predicted next words in pred_inp
rembuff:add(resind, -1) -- set rembuff = resind - 1
rembuff:div(V)
--if rembuff.floor then
rembuff:floor()
I am unable to rectify this error :
Please help !

Resources