Redis Lua script problems only when many calls with different params - redis

I have script that works fine when I simply call it by hands, or when I call it using my API.
The same script works fine when I create 5 threads and each of them calls this script 10000 times with the same parameters.
But when I run performance testing of my API with tester-written script, I see wrong information in Redis and this information simply can't appear in Redis if script works correcty, so I'm assuming there is some problem in it.
Script:
-- ARGV[1] createdAt
-- ARGV[2] storyId
-- ARGV[3] storyType (image or video)
-- ARGV[4] storyFilename (original filename)
-- ARGV[5] storyThumbnail (thumbnail filename)
-- ARGV[6] storyTags
-- ARGV[7] authorId
-- ARGV[8] authorUsername
-- ARGV[9] authorName
-- ARGV[10] authorAvatarThumb
-- ARGV[11] PHP_INT_MAX
-- ARGV[12] timestamp = followers will see stories younger then this
-- ARGV[13..N] followerId
-- Init variables
local createdAt = ARGV[1]
local storyId = ARGV[2]
local storyType = ARGV[3]
local storyFilename = ARGV[4]
local storyThumbnail = ARGV[5]
local storyTags = cjson.decode(ARGV[6])
local authorId = tonumber(ARGV[7])
local authorUsername = ARGV[8]
local authorName = ARGV[9]
local authorAvatarThumb = ARGV[10]
local maxScore = ARGV[11]
local storyAuthorData = {
id = authorId,
username = authorUsername,
name = authorName,
avatarThumb = authorAvatarThumb,
storyCount = redis.call('ZCARD', 'user:' .. authorId .. ':storyIds') + 1,
lastStory = {
id = storyId,
thumbnail = storyThumbnail,
isViewed = false
}
}
local storyData = {
id = storyId,
thumbnail = storyThumbnail,
tags = storyTags,
viewerCount = 0,
isViewed = false
}
if storyType == 'image' then
storyAuthorData.lastStory.image = storyFilename
storyData.image = storyFilename
else
storyAuthorData.lastStory.video = storyFilename
storyData.video = storyFilename
end
local packedStoryData = cmsgpack.pack(storyData);
local packedAuthorData = cmsgpack.pack(storyAuthorData);
local authorStoryCountForFollower = redis.call('ZCOUNT', 'user:' .. authorId .. ':storyIds', '(' .. ARGV[12], '+inf')
storyAuthorData.storyCount = authorStoryCountForFollower
local packedAuthorDataForFollower = cmsgpack.pack(storyAuthorData);
redis.call('ZADD', 'storyIds', createdAt, storyId)
-- Iterate through followerIds
local followerId, followerAuthorsKey, followerAuthors, followerAuthor
for i = 13, #ARGV do
followerId = ARGV[i]
redis.call('SADD', 'story:' .. storyId .. ':projections', followerId)
redis.call('ZADD', 'forUser:' .. followerId .. ':storiesByUser:' .. authorId, createdAt, packedStoryData)
-- Iterate through follower' story authors and update current author
followerAuthorsKey = 'forUser:' .. followerId .. ':storyAuthors'
followerAuthors = redis.call('ZRANGE', followerAuthorsKey, 0, -1)
for j = 1, #followerAuthors do
followerAuthor = followerAuthors[j]
if cmsgpack.unpack(followerAuthor).id == authorId then
redis.call('ZREM', followerAuthorsKey, followerAuthor)
break
end
end
redis.call('ZADD', followerAuthorsKey, createdAt, packedAuthorDataForFollower)
end
-- Process author as follower of himself
redis.call('ZADD', 'user:' .. authorId .. ':storyIds', createdAt, storyId)
redis.call('ZADD', 'forUser:' .. authorId .. ':storiesByUser:' .. authorId, createdAt, packedStoryData)
followerAuthorsKey = 'forUser:' .. authorId .. ':storyAuthors'
followerAuthor = redis.call('ZREVRANGE', followerAuthorsKey, 0, 0, 'WITHSCORES')
if followerAuthor[2] == maxScore then
redis.call('ZREM', followerAuthorsKey, followerAuthor[1])
end
redis.call('ZADD', followerAuthorsKey, maxScore, packedAuthorData)
As you can see in this part:
-- Iterate through follower' story authors and update current author
followerAuthorsKey = 'forUser:' .. followerId .. ':storyAuthors'
followerAuthors = redis.call('ZRANGE', followerAuthorsKey, 0, -1)
for j = 1, #followerAuthors do
followerAuthor = followerAuthors[j]
if cmsgpack.unpack(followerAuthor).id == authorId then
redis.call('ZREM', followerAuthorsKey, followerAuthor)
break
end
end
redis.call('ZADD', followerAuthorsKey, createdAt, packedAuthorDataForFollower)
there is no possibility that for any key forUser:*:storyAuthors the same author would appear twice.
But in Redis I can see:
zrange forUser:5870:storyAuthors 0 -1 WITHSCORES
1) "\x86\xa8username\xaee8dccb3501913e\xa4name\xactaylor evans\xabavatarThumb\xd9+d083e43ff8dbec76904f09abb8be7dab_thumb.jpeg\xa2id\xcd\x14S\xaastoryCount\x0f\xa9lastStory\x84\xa2id\xd9 00001453abe86ec44260d64111619a76\xa9thumbnail\xd9%59810b11537769.89801964_thumbnail.jpg\xa8isViewed\xc3\xa5video\xbb59810b11537769.89801964.mp4"
2) "1501629201.733"
3) "\x86\xa8username\xaee8dccb3501913e\xa4name\xactaylor evans\xabavatarThumb\xd9+d083e43ff8dbec76904f09abb8be7dab_thumb.jpeg\xa2id\xcd\x14S\xa9lastStory\x84\xa2id\xd9 00001453a77458044360d641bc47c73c\xa5image\xbb59810c1122b659.53121588.jpg\xa9thumbnail\xd9%59810c1122b659.53121588_thumbnail.jpg\xa8isViewed\xc2\xaastoryCount\x1c"
4) "1501629457.3821001"
5) "\x86\xa8username\xaee8dccb3501913e\xa4name\xactaylor evans\xabavatarThumb\xd9+d083e43ff8dbec76904f09abb8be7dab_thumb.jpeg\xa2id\xcd\x14S\xa9lastStory\x84\xa2id\xd9 000014539c8c70044360d6417e07a91d\xa8isViewed\xc2\xa9thumbnail\xd9%59810c11637f43.19889868_thumbnail.jpg\xa5video\xbb59810c11637f43.19889868.mp4\xaastoryCount\x1d"
6) "1501629457.7586"
7) "\x86\xa8username\xaea2d4fb6a25ec2a\xa4name\xabjean brewer\xabavatarThumb\xd9+0cd3514371aa7f5ca53b1859b950f92e_thumb.jpeg\xa2id\xcd\x16\xee\xa9lastStory\x83\xa2id\xd9 000016ee38daa80f4360d641f61949da\xa8isViewed\xc3\xa5video\xbb59810c3e432b80.55025328.mp4\xaastoryCount\x04"
8) "1501629502.6382999"
9) "\x86\xa8username\xaea2d4fb6a25ec2a\xa4name\xabjean brewer\xabavatarThumb\xd9+0cd3514371aa7f5ca53b1859b950f92e_thumb.jpeg\xa2id\xcd\x16\xee\xa9lastStory\x83\xa2id\xd9 000016ee5e109c1f4360d6412826f135\xa8isViewed\xc3\xa5video\xbb59810c7e0b7e92.12898014.mp4\xaastoryCount\x1c"
10) "1501629566.4384999"
11) "\x86\xa8username\xae87163046b74033\xa4name\xaadianne kim\xabavatarThumb\xd9+5d59c5cfefd028e9042bff975f92a94e_thumb.jpeg\xa2id\xcd\x04\xf4\xa9lastStory\x83\xa2id\xd9 000004f4c590065f4360d641f56be683\xa8isViewed\xc3\xa5video\xbb59810d7ba433b2.90198935.mp4\xaastoryCount\x1a"
12) "1501629820.1026001"
13) "\x86\xa8username\xae87163046b74033\xa4name\xaadianne kim\xabavatarThumb\xd9+5d59c5cfefd028e9042bff975f92a94e_thumb.jpeg\xa2id\xcd\x04\xf4\xa9lastStory\x83\xa2id\xd9 000004f488d6bc714360d6418e77ad61\xa8isViewed\xc3\xa5video\xbb59810dc68ad4c6.78917372.mp4\xaastoryCount:"
14) "1501629894.9505999"
15) "\x86\xa8username\xae87163046b74033\xa4name\xaadianne kim\xabavatarThumb\xd9+5d59c5cfefd028e9042bff975f92a94e_thumb.jpeg\xa2id\xcd\x04\xf4\xa9lastStory\x83\xa2id\xd9 000004f402baf07e4360d641f1430d08\xa8isViewed\xc3\xa5video\xbb59810dfb69d323.13796483.mp4\xaastoryCountB"
16) "1501629947.7614"
17) "\x86\xa8username\xaea2d4fb6a25ec2a\xa4name\xabjean brewer\xabavatarThumb\xd9+0cd3514371aa7f5ca53b1859b950f92e_thumb.jpeg\xa2id\xcd\x16\xee\xaastoryCount\x1d\xa9lastStory\x84\xa2id\xd9 000016ee4815e74c4360d641c7cb3dfc\xa9thumbnail\xd9%59810d333d9445.06755396_thumbnail.jpg\xa8isViewed\xc3\xa5video\xbb59810d333d9445.06755396.mp4"
18) "4503599627370496"
There are also another problems showing that the data is not consistent.
I've increased RAM size from 2.8Gb to 16Gb and it did not help.
For KEYS params of lua script - number of params depends on how many followers does a user have. Users we use for testing have thousands of followers, so KEYS array can contain up to several thousands of elements.

Related

Roblox Studio- attempt to index nil with 'leaderstats' error in output

so i want to make this so when i click it gives me a "Coin" but it does not work & says attempt to index nil with 'leaderstats'
`game.Players.PlayerAdded:Connect(function(player)
local leaderstats = Instance.new('Folder', player)
leaderstats.Name = 'leaderstats'
local coins = Instance.new('IntValue', leaderstats)
coins.Name = 'Coins'
coins.Value = 0
end)
game.ReplicatedStorage.Remotes.Add.OnServerEvent:Connect(function()
local currency = 'Coins'
local amount = 5
player.leaderstats[currency].Value = player.leaderstats[currency].Value + amount
end)``
You forgot the "player" parameter in OnServerEvent which is why it's nil
fix:
game.ReplicatedStorage.Remotes.Add.OnServerEvent:Connect(function(player) --added player parameter
local currency = 'Coins'
local amount = 5
player.leaderstats[currency].Value = player.leaderstats[currency].Value + amount
end)

LUA script for modification object in Redis

I Need a short advise please about LUA script for modification object in Redis.
I Have Redis List with entities like that:
{
"#class": "com.myproject.model.Book",
"bookId": "someId",
"author": "someAuthor"
}
now, I need to change my entity to allow multiple authors for certain book, and create migration script for this:
{
"#class": "com.myproject.model.Book",
"bookId": "someId",
"authors": [
"java.util.ArrayList",
[
"someAuthor"
]
]
}
What I Think I need to do with LUA:
local book
local cacheName --cache name in my case
local authorId;
local size = redis.call('LLEN', cacheName)
if size == 0
then
return -1
end
while size > 0
do
book = redis.call('LPOP', cacheName)
-- modify entity here
affectedEntitiesCount = affectedEntitiesCount + 1
redis.call('RPUSH', cacheName, book)
size = size - 1
end
return affectedEntitiesCount
But I have no idea how to modify book according requirements.
Can someone take a look and suggest?
solved:
local book
local cacheName
local authorPattern= '"author":"[^"]*"'
local authorId
local replacementAuthors = '"authors":["java.util.ArrayList",["%s"]]'
local size = redis.call('LLEN', cacheName)
if size == 0
then
return -1
end
while size > 0
do
book = redis.call('LPOP', cacheName)
authorId = string.match(string.match(book, authorPattern), [["authorId":"([^"]+)]])
replacedAuthors = string.format(replacedAuthors , authorId)
book = string.gsub(book, authorPattern, replacedAuthors)
affectedEntitiesCount = affectedEntitiesCount + 1
redis.call('RPUSH', cacheName, book)
size = size - 1
end
return affectedEntitiesCount
Since it appears that you're storing JSON-encoded values in your list, you can use the cjson library that's embedded in Redis' Lua engine.
For example:
...
book = cjson.decode(redis.call('LPOP', cacheName))
book['bookId'] = book['bookId']..'foo' -- concat 'foo' to bookId
...
redis.call('RPUSH', cacheName, cjson.encode(book))
Note: also make sure that you use the KEYS input array to parameterize the script's input key names (e.g. local cacheName = KEYS[1])

How to implement Automation for Drag and drop between two file explorers on Windows

I am trying to automate drag and drop between two File Explorers on windows OS. I could find online help to drag and drop implementation for Browsers.
But no help for drag and drop for file to another File Explorer.
Use for this the Shell.Application object. To get the selection from the explorer you can use the following function:
;===============================================================================
; Function Name....: _ActiveExplorer_GetSelected
; Description......: Creates an array with
; - Count of selected files/folder
; - Path of active Explorer window and
; - the path/es of selected file/s /folder
; Requirement(s)...: Opened Explorer window
; Return Value(s)..: Array with data, $a[0] = Count, $a[1] = Folderpath, $a[2..] = File/Foldername
; .................: ATTENTION! Last index $a[0]+1 !!
; Author(s)........: BugFix ( AutoIt#bug-fix.info )
;===============================================================================
Func _ActiveExplorer_GetSelected()
Local $oShell = ObjCreate("Shell.Application")
Local $oExplorer, $sPath, $oFolderView, $iCount = 0, $sSelectedFiles = '', $n = 2
Local $oShellWindows = $oShell.Windows
For $i = 0 To $oShellWindows.Count -1
$oExplorer = $oShellWindows($i)
$sPath = StringReplace(StringReplace(StringTrimLeft($oExplorer.LocationURL, 8), '%20', ' '), '/', '\')
If WinGetTitle('[ACTIVE]') = $sPath Then ExitLoop
Next
$oFolderView = $oExplorer.Document.SelectedItems()
$iCount = $oFolderView.Count
Local $aOut[$iCount +2]
$aOut[0] = $iCount
$aOut[1] = $sPath
If $iCount = 0 Then
Return ''
Else
For $oFolderItem In $oFolderView
$aOut[$n] = $oFolderItem.Name
$n += 1
Next
Return $aOut
EndIf
EndFunc ; ==>_ActiveExplorer_GetSelected

Lua - Uploading to Pastebin

Note that this is Roblox's version of lua.
I want to upload a table to Pastebin. Here is what I have for Pastebin.
h = game:GetService'HttpService'
JSON = h:JSONEncode(ImgScript) --ImgScript is a table formatted like {{x,y,z}, {x,y,z}, {x,y,z}, etc.}
h:PostAsync('http://pastebin.com/api/api_post.php','&api_dev_key=CensoredDevKey&api_option=paste&api_paste_code=' .. JSON)
This doesn't work, and I can't seem to figure out why.
EDIT:
I also tried this and it didn't work.
h = game:GetService'HttpService'
api_params = {
["api_dev_key"] = "CensoredDevKey",
["api_option"] = "paste",
["api_paste_code"] = ImgScript
}
api_params = h:JSONEncode(api_params)
h:PostAsync('http://www.pastebin.com/api/api_post.php', api_params)
EDIT:
I also tried this and it didn't work:
h = game:GetService'HttpService'
JSON = h:JSONEncode(ImgScript) --ImgScript is a table formatted like {{x,y,z}, {x,y,z}, {x,y,z}, etc.}
data = h:UrlEncode('&api_dev_key=CensoredDevKey&api_option=paste&api_paste_code=' .. JSON)
h:PostAsync('http://pastebin.com/api/api_post.php', data)
Try the following:
h = game:GetService'HttpService'
pasteData = h:UrlEncode( h:JSONEncode(ImgScript) )
h:PostAsync(
'http://pastebin.com/api/api_post.php',
'api_dev_key=CensoredDevKey&api_option=paste&api_paste_code=' .. pasteData,
2
)
The last parameter, 2 specifies that the data being sent is Application/Url-Encoded.
I think that this should do the trick. Do inform here if it doesn't.
PS: Where are you receiving the result from this POST request?
So I've finished the code, but sadly, Roblox limits the PostAsync size to 256 bytes so any upload larger than that will be GZIPed (up to 1024kb), which Pastebin doesn't know what to do with.
Anyhow, I've released the code here:
http://www.roblox.com/Pastebin-Upload-item?id=302297532
It is:
--Created by GShocked. PM me if you have questions!
h = game:GetService'HttpService'
api_dev_key = '' --Your Pastebin developer key goes here. Log in first, and then you can find it at pastebin.com/api
api_paste_code = '' --The content of your new paste
api_paste_private = '1' --0 public; 1 unlisted; 2 private
api_paste_name = '' --Name your new paste
api_paste_expire_date = 'N' --N for never expire, 10M for 10 minutes, etc.
api_paste_format = 'lua' --The syntax highlighting
api_user_key = '' --This is generated using the login info
api_paste_name = h:UrlEncode(api_paste_name)
api_paste_code = h:UrlEncode(api_paste_code)
username = '' --Your Pastebin username goes here
password = '' --Your Pastebin password goes here
api_user_key = h:PostAsync(
'http://pastebin.com/api/api_login.php',
'api_dev_key=' .. api_dev_key .. '&api_user_name=' .. username .. '&api_user_password=' .. password,
2
)
print(api_user_key) --DON'T DELETE THIS! IT IS ESSENTIAL FOR THE USER KEY TO BE GENERATED!
h:PostAsync(
'http://pastebin.com/api/api_post.php',
'api_option=paste&api_user_key=' .. api_user_key .. '&api_paste_private=' .. api_paste_private .. '&api_paste_name=' .. api_paste_name .. '&api_paste_expire_date=' .. api_paste_expire_date .. '&api_paste_format=' .. api_paste_format .. '&api_dev_key=' .. api_dev_key .. '&api_paste_code=' .. api_paste_code,
2
)

AutoIt - How to read pdf document properties

I'm trying to read PDF' page size eg.height X weight. Page size can be found in
File -> Properties -> Page Size
I used the code below to fetch the property value:
$path = FileOpenDialog("Select a file to read attributes",#ScriptDir,"All (*.*)")
$prop = _GetExtProperty($path,-1)
_ArrayDisplay($prop,"Property Array")
Func _GetExtProperty($sPath, $iProp)
Local $iExist, $sFile, $sDir, $oShellApp, $oDir, $oFile, $aProperty, $sProperty
$iExist = FileExists($sPath)
If $iExist = 0 Then
SetError(1)
Return 0
Else
$sFile = StringTrimLeft($sPath, StringInStr($sPath, "\", 0, -1))
$sDir = StringTrimRight($sPath, (StringLen($sPath) - StringInStr($sPath, "\", 0, -1)))
$oShellApp = ObjCreate ("shell.application")
$oDir = $oShellApp.NameSpace ($sDir)
$oFile = $oDir.Parsename ($sFile)
If $iProp = -1 Then
Local $aProperty[35]
For $i = 0 To 34
$aProperty[$i] = $oDir.GetDetailsOf ($oFile, $i)
Next
Return $aProperty
Else
$sProperty = $oDir.GetDetailsOf ($oFile, $iProp)
If $sProperty = "" Then
Return 0
Else
Return $sProperty
EndIf
EndIf
EndIf
EndFunc ;==>_GetExtProperty
By using above code i managed to get file size in MB, Created date , Modified date, Location and so on, but not Page Size. Appreciated, if anyone could advice how I can get page size. Any reference, advice or sample code is highly appreciated.
Nearly the same, but maybe it helps.
#include <Array.au3>
;===============================================================================
; Function Name.....: _FileGetProperty
; Description.......: Returns a property or all properties for a file.
; Version...........: 1.0.2
; Change Date.......: 2008-07-28
; AutoIt Version....: 3.2.12.1
;
; Parameter(s)......: $S_PATH - String containing the file path to return the property from.
; $S_PROPERTY - [optional] String containing the name of the property to return. (default = "")
; Requirements(s)...: None
; Return Value(s)...: Success: Returns a string containing the property value.
; If $S_PROPERTY is empty, an two-dimensional array is returned:
; $av_array[0][0] = Number of properties.
; $av_array[1][0] = 1st property name.
; $as_array[1][1] = 1st property value.
; $av_array[n][0] = nth property name.
; $as_array[n][1] = nth property value.
; Failure: Returns 0 and sets #error to:
; 1 = The folder $S_PATH does not exist.
; 2 = The property $S_PROPERTY does not exist or the array could not be created.
; 3 = Unable to create the "Shell.Application" object $objShell.
;
; Author(s).........: - Simucal <Simucal#gmail.com>
; - Modified by: Sean Hart <autoit#hartmail.ca>
; - Modified by: teh_hahn <sPiTsHiT#gmx.de>
; Company...........: None
; URL...............: None
; Note(s)...........: None
;===============================================================================
Global $re = _FileGetProperty(#ScriptDir & '\1Tutorial - AutoItWiki1.pdf')
If #error Then MsgBox(16, 'ERROR', 'Error: ' & #error & #CRLF & '1 = The folder $S_PATH does not exist.' & #CRLF & _
'2 = The property $S_PROPERTY does not exist or the array could not be created.' & #CRLF & _
'3 = Unable to create the "Shell.Application" object $objShell.')
_ArrayDisplay($re)
Func _FileGetProperty(Const $S_PATH, Const $S_PROPERTY = "")
If Not FileExists($S_PATH) Then Return SetError(1, 0, 0)
Local Const $S_FILE = StringTrimLeft($S_PATH, StringInStr($S_PATH, "\", 0, -1))
Local Const $S_DIR = StringTrimRight($S_PATH, StringLen($S_FILE) + 1)
Local Const $objShell = ObjCreate("Shell.Application")
If #error Then Return SetError(3, 0, 0)
Local Const $objFolder = $objShell.NameSpace($S_DIR)
Local Const $objFolderItem = $objFolder.Parsename($S_FILE)
If $S_PROPERTY Then
For $i = 0 To 99
If $objFolder.GetDetailsOf($objFolder.Items, $i) = $S_PROPERTY Then Return $objFolder.GetDetailsOf($objFolderItem, $i)
Next
Return SetError(2, 0, 0)
EndIf
Local $av_ret[1][2] = [[1]]
For $i = 0 To 99
If $objFolder.GetDetailsOf($objFolder.Items, $i) Then
ReDim $av_ret[$av_ret[0][0] + 1][2]
$av_ret[$av_ret[0][0]][0] = $objFolder.GetDetailsOf($objFolder.Items, $i)
$av_ret[$av_ret[0][0]][1] = $objFolder.GetDetailsOf($objFolderItem, $i)
$av_ret[0][0] += 1
EndIf
Next
If Not $av_ret[1][0] Then Return SetError(2, 0, 0)
$av_ret[0][0] -= 1
Return $av_ret
EndFunc ;==>_FileGetProperty