summaryrefslogtreecommitdiff
path: root/src/scripting.c
Commit message (Collapse)AuthorAgeFilesLines
* Scripting: objects caching for Lua c->argv creation.antirez2014-05-071-3/+40
| | | | | | Reusing small objects when possible is a major speedup under certain conditions, since it is able to avoid the malloc/free pattern that otherwise is performed for every argument in the client command vector.
* Scripting: Use faster API for Lua client c->argv creation.antirez2014-05-071-3/+6
| | | | | | | Replace the three calls to Lua API lua_tostring, lua_lua_strlen, and lua_isstring, with a single call to lua_tolstring. ~ 5% consistent speed gain measured.
* Scripting: don't call lua_gc() after Lua script run.antirez2014-05-071-1/+17
| | | | | | | | Calling lua_gc() after every script execution is too expensive, and apparently does not make the execution smoother: the same peak latency was measured before and after the commit. This change accounts for scripts execution speedup in the order of 10%.
* Scripting: cache argv in luaRedisGenericCommand().antirez2014-05-071-4/+15
| | | | ~ 4% consistently measured speed improvement.
* Fixed missing c->bufpos reset in luaRedisGenericCommand().antirez2014-05-071-0/+1
| | | | | Bug introduced when adding a fast path to avoid copying the reply buffer for small replies that fit into the client static buffer.
* Scripting: replace tolower() with faster code in evalGenericCommand().antirez2014-05-071-1/+5
| | | | | | The function showed up consuming a non trivial amount of time in the profiler output. After this change benchmarking gives a 6% speed improvement that can be consistently measured.
* Scripting: luaRedisGenericCommand() fast path for buffer-only replies.antirez2014-05-071-7/+15
| | | | | | When the reply is only contained in the client static output buffer, use a fast path avoiding the dynamic allocation of an SDS string to concatenate the client reply objects.
* Scripting: simpler reply buffer creation in luaRedisGenericCommand().antirez2014-05-071-5/+2
| | | | | It if faster to just create the string with a single sdsnewlen() call. If c->bufpos is zero, the call will simply be like sdsemtpy().
* Process events with processEventsWhileBlocked() when blocked.antirez2014-04-241-2/+1
| | | | | | | | When we are blocked and a few events a processed from time to time, it is smarter to call the event handler a few times in order to handle the accept, read, write, close cycle of a client in a single pass, otherwise there is too much latency added for clients to receive a reply while the server is busy in some way (for example during the DB loading).
* Fix script cache bug in the scripting engine.antirez2014-02-131-0/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This commit fixes a serious Lua scripting replication issue, described by Github issue #1549. The root cause of the problem is that scripts were put inside the script cache, assuming that slaves and AOF already contained it, even if the scripts sometimes produced no changes in the data set, and were not actaully propagated to AOF/slaves. Example: eval "if tonumber(KEYS[1]) > 0 then redis.call('incr', 'x') end" 1 0 Then: evalsha <sha1 step 1 script> 1 0 At this step sha1 of the script is added to the replication script cache (the script is marked as known to the slaves) and EVALSHA command is transformed to EVAL. However it is not dirty (there is no changes to db), so it is not propagated to the slaves. Then the script is called again: evalsha <sha1 step 1 script> 1 1 At this step master checks that the script already exists in the replication script cache and doesn't transform it to EVAL command. It is dirty and propagated to the slaves, but they fail to evaluate the script as they don't have it in the script cache. The fix is trivial and just uses the new API to force the propagation of the executed command regardless of the dirty state of the data set. Thank you to @minus-infinity on Github for finding the issue, understanding the root cause, and fixing it.
* Scripting: use mstime() and mstime_t for lua_time_start.antirez2014-02-031-2/+2
| | | | | | | server.lua_time_start is expressed in milliseconds. Use mstime_t instead of long long, and populate it with mstime() instead of ustime()/1000. Functionally identical but more natural.
* Fixed grammar: before H the article is a, not an.antirez2013-12-051-2/+2
|
* Fixed critical memory leak from EVAL.antirez2013-08-291-4/+9
| | | | | | | | | | | | | | | | Multiple missing calls to lua_pop prevented the error handler function pushed on the stack for lua_pcall() to be popped before returning, causing a memory leak in almost all the code paths of EVAL (both successful calls and calls returning errors). This caused two issues: Lua leaking memory (and this was very visible from INFO memory output, as the 'used_memory_lua' field reported an always increasing amount of memory used), and as a result slower and slower GC cycles resulting in all the CPU being used. Thanks to Tanguy Le Barzic for noticing something was wrong with his 2.8 slave, and for creating a testing EC2 environment where I was able to investigate the issue.
* Flush the replication script cache after SCRIPT FLUSH.antirez2013-06-251-0/+1
|
* Force propagation of SCRIPT LOAD to AOF.antirez2013-06-251-1/+1
|
* SCRIPT FLUSH comment minor pedantic improvement.antirez2013-06-251-1/+1
|
* Move Replication Script Cache initialization in safer place.antirez2013-06-241-4/+0
| | | | | It should be called just one time at startup and not every time the Lua scripting engine is re-initialized, otherwise memory is leaked.
* Use the RSC to replicate EVALSHA unmodified.antirez2013-06-241-15/+25
| | | | | | This commit uses the Replication Script Cache in order to avoid translating EVALSHA into EVAL whenever possible for both the AOF and slaves.
* New API to force propagation.antirez2013-06-211-0/+1
| | | | | | | | | | | | | | | The old REDIS_CMD_FORCE_REPLICATION flag was removed from the implementation of Redis, now there is a new API to force specific executions of a command to be propagated to AOF / Replication link: void forceCommandPropagation(int flags); The new API is also compatible with Lua scripting, so a script that will execute commands that are forced to be propagated, will also be propagated itself accordingly even if no change to data is operated. As a side effect, this new design fixes the issue with scripts not able to propagate PUBLISH to slaves (issue #873).
* Allow writes from scripts called by AOF loading in read-only slaves.antirez2013-06-191-0/+1
| | | | This fixes issue #1163
* Lua script errors format more unified.antirez2013-06-181-1/+1
| | | | | lua_pcall error handler now formats errors in a way more similar to luaPushError() so that errors generated in different contexts look alike.
* Lua scripting: improve error reporting.antirez2013-06-181-3/+27
| | | | | When calling Lua scripts we try to report not just the error but information about the code line causing the error.
* Try to report source of bad Lua API callsioddly2013-05-221-2/+14
|
* Fixed many typos.guiquanz2013-01-191-6/+6
|
* Multiple fixes for EVAL (issue #872).antirez2013-01-101-20/+21
| | | | | | | | 1) The event handler was no restored after a timeout condition if the command was eventually executed with success. 2) The command was not converted to EVAL in case of errors in the middle of the execution. 3) Terrible duplication of code without any apparent reason.
* EVALSHA is now case insensitive.antirez2012-11-221-1/+1
| | | | | | EVALSHA used to crash if the SHA1 was not lowercase (Issue #783). Fixed using a case insensitive dictionary type for the sha -> script map used for replication of scripts.
* BSD license added to every C source and header file.antirez2012-11-081-0/+29
|
* Differentiate SCRIPT KILL error replies.antirez2012-10-221-2/+2
| | | | | | | | | | | | | | | | When calling SCRIPT KILL currently you can get two errors: * No script in timeout (busy) state. * The script already performed a write. It is useful to be able to distinguish the two errors, but right now both start with "ERR" prefix, so string matching (that is fragile) must be used. This commit introduces two different prefixes. -NOTBUSY and -UNKILLABLE respectively to reply with an error when no script is busy at the moment, and when the script already executed a write operation and can not be killed.
* Revert "Scripting: redis.NIL to return nil bulk replies."antirez2012-10-011-35/+4
| | | | | | | | This reverts commit e061d797d739f2beeb22b9e8ac519d1df070e3a8. Conflicts: src/scripting.c
* Scripting: add helper functions redis.error_reply() and redis.status_reply().antirez2012-09-281-0/+36
| | | | | | | | | | A previous commit introduced Redis.NIL. This commit adds similar helper functions to return tables with a single field set to the specified string so that instead of using 'return {err="My Error"}' it is possible to use a more idiomatic form: return redis.error_reply("My Error") return redis.status_reply("OK")
* Scripting: redis.NIL to return nil bulk replies.antirez2012-09-281-4/+35
| | | | | | | | | | | | | | | | | | | | | | | | | Lua arrays can't contain nil elements (see http://www.lua.org/pil/19.1.html for more information), so Lua scripts were not able to return a multi-bulk reply containing nil bulk elements inside. This commit introduces a special conversion: a table with just a "nilbulk" field set to a boolean value is converted by Redis as a nil bulk reply, but at the same time for Lua this type is not a "nil" so can be used inside Lua arrays. This type is also assigned to redis.NIL, so the following two forms are equivalent and will be able to return a nil bulk reply as second element of a three elements array: EVAL "return {1,redis.NIL,3}" 0 EVAL "return {1,{nilbulk=true},3}" 0 The result in redis-cli will be: 1) (integer) 1 2) (nil) 3) (integer) 3
* Scripting: Force SORT BY constant determinism inside SORT itself.antirez2012-09-051-2/+0
| | | | | | | | | | | | | | | | | | | | | | | | | | | | SORT is able to return (faster than when ordering) unordered output if the "BY" clause is used with a constant value. However we try to play well with scripting requirements of determinism providing always sorted outputs when SORT (and other similar commands) are called by Lua scripts. However we used the general mechanism in place in scripting in order to reorder SORT output, that is, if the command has the "S" flag set, the Lua scripting engine will take an additional step when converting a multi bulk reply to Lua value, calling a Lua sorting function. This is suboptimal as we can do it faster inside SORT itself. This is also broken as issue #545 shows us: basically when SORT is used with a constant BY, and additionally also GET is used, the Lua scripting engine was trying to order the output as a flat array, while it was actually a list of key-value pairs. What we do know is to recognized if the caller of SORT is the Lua client (since we can check this using the REDIS_LUA_CLIENT flag). If so, and if a "don't sort" condition is triggered by the BY option with a constant string, we force the lexicographical sorting. This commit fixes this bug and improves the performance, and at the same time simplifies the implementation. This does not mean I'm smart today, it means I was stupid when I committed the original implementation ;)
* Scripting: Reset Lua fake client reply_bytes after command execution.antirez2012-08-311-0/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | Lua scripting uses a fake client in order to run commands in the context of a client, accumulate the reply, and convert it into a Lua object to return to the caller. This client is reused again and again, and is referenced by the server.lua_client globally accessible pointer. However after every call to redis.call() or redis.pcall(), that is handled by the luaRedisGenericCommand() function, the reply_bytes field of the client was not set back to zero. This filed is used to estimate the amount of memory currently used in the reply. Because of the lack of reset, script after script executed, this value used to get bigger and bigger, and in the end on 32 bit systems it triggered the following assert: redisAssert(c->reply_bytes < ULONG_MAX-(1024*64)); On 64 bit systems this does not happen because it takes too much time to reach values near to 2^64 for users to see the practical effect of the bug. Now in the cleanup stage of luaRedisGenericCommand() we reset the reply_bytes counter to zero, avoiding the issue. It is not practical to add a test for this bug, but the fix was manually tested using a debugger. This commit fixes issue #656.
* Scripting: require at least one argument for redis.call().antirez2012-08-311-0/+7
| | | | | | | | | | Redis used to crash with a call like the following: EVAL "redis.call()" 0 Now the explicit check for at least one argument prevents the problem. This commit fixes issue #655.
* Set LUA_MASKCOUNT hook more selectively. Fixes issue #480.antirez2012-04-271-5/+7
| | | | | | | | | | | | | | | An user reported a crash with Redis scripting (see issue #480 on github), inspection of the kindly provided strack trace showed that server.lua_caller was probably set to NULL. The stack trace also slowed that the call to the hook was originating from a point where we just used to set/get a few global variables in the Lua state. What was happening is that we did not set the timeout hook selectively only when the user script was called. Now we set it more selectively, specifically only in the context of the lua_pcall() call, and make sure to remove the hook when the call returns. Otherwise the hook can get called in random contexts every time we do something with the Lua state.
* Remove loadfile() access from the scripting engine.antirez2012-04-231-0/+9
|
* EVAL errors are more clear now.antirez2012-04-131-3/+3
|
* Use Lua tostring() before concatenation.antirez2012-04-131-1/+1
|
* mt.declared is no longer needed.antirez2012-04-131-4/+2
| | | | | | | | Lua global protection can now be simpified becuase we no longer have the global() function. It's useless to occupy memory with this table, it is also not faster because the metamethods we use are only called when a global object does not exist or we are trying to create it from a script.
* Stop access to global vars. Not configurable.antirez2012-04-131-21/+4
| | | | | | | | | | After considering the interaction between ability to delcare globals in scripts using the 'global' function, and the complexities related to hanlding replication and AOF in a sane way with globals AND ability to turn protection On and Off, we reconsidered the design. The new design makes clear that there is only one good way to write Redis scripts, that is not using globals. In the rare cases state must be retained across calls a Redis key can be used.
* Globals protection global() function modified for speed and correctness.antirez2012-04-131-2/+6
|
* Scripting: globals protection can now be switched on/off.antirez2012-04-131-34/+47
|
* Protect globals access in Lua scripting.antirez2012-03-291-0/+44
|
* added redis.sha1hex(string) as lua scripting function.Nathan Fritz2012-03-281-5/+33
| | | | | (The original implementation was modified by @antirez to conform Redis coding standards.)
* Support for read-only slaves. Semantical fixes.antirez2012-03-201-4/+34
| | | | | | | | | | This commit introduces support for read only slaves via redis.conf and CONFIG GET/SET commands. Also various semantical fixes are implemented here: 1) MULTI/EXEC with only read commands now work where the server is into a state where writes (or commands increasing memory usage) are not allowed. Before this patch everything inside a transaction would fail in this conditions. 2) Scripts just calling read-only commands will work against read only slaves, when the server is out of memory, or when persistence is into an error condition. Before the patch EVAL always failed in this condition.
* Lua_cmsgpack added to Redis scripting.antirez2012-02-241-0/+2
|
* added lua struct c extensionlsbardel2012-02-131-1/+3
|
* Now Lua scripts dispatch Redis commands properly calling the call() ↵antirez2012-02-021-1/+2
| | | | function. In order to make this possible call() was improved with a new flags argument that controls how the Redis command is executed.
* SORT is now more deterministic: does not accept to compare by score items ↵antirez2012-02-011-2/+31
| | | | that have scores not representing a valid double. Also items with the same score are compared lexycographically. At the same time the scripting side introduced the ability to sort the output of SORT when sort uses the BY <constant> optimization, resulting in no specific ordering. Since in this case the user may use GET, and the result of GET can be null, converted into false as Lua data type, this commit also introduces the ability to sort Lua tables containining false, only if the first (faster) attempt at using just table.sort with a single argument fails.
* Order output of commands returning random arrays using table.sort when ↵antirez2012-01-311-1/+23
| | | | called from Lua, partially fixing issue #165. The issue is yet not completely fixed since we can't add the REDIS_CMD_SORT_FOR_SCRIPT flag in SORT currently, both because it may contain NULLs and because it is not cool to re-sort everything at every call when instead this should be sorted only if BY <constant> is used.