hirlite 0.0.2 → 0.0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/ext/hirlite_ext/extconf.rb +2 -2
  3. data/lib/hirlite/version.rb +1 -1
  4. data/vendor/rlite/deps/lua/Makefile +128 -0
  5. data/vendor/rlite/deps/lua/src/fpconv.c +205 -0
  6. data/vendor/rlite/deps/lua/src/fpconv.h +22 -0
  7. data/vendor/rlite/deps/lua/src/lapi.c +1087 -0
  8. data/vendor/rlite/deps/lua/src/lapi.h +16 -0
  9. data/vendor/rlite/deps/lua/src/lauxlib.c +652 -0
  10. data/vendor/rlite/deps/lua/src/lauxlib.h +174 -0
  11. data/vendor/rlite/deps/lua/src/lbaselib.c +653 -0
  12. data/vendor/rlite/deps/lua/src/lcode.c +831 -0
  13. data/vendor/rlite/deps/lua/src/lcode.h +76 -0
  14. data/vendor/rlite/deps/lua/src/ldblib.c +398 -0
  15. data/vendor/rlite/deps/lua/src/ldebug.c +638 -0
  16. data/vendor/rlite/deps/lua/src/ldebug.h +33 -0
  17. data/vendor/rlite/deps/lua/src/ldo.c +519 -0
  18. data/vendor/rlite/deps/lua/src/ldo.h +57 -0
  19. data/vendor/rlite/deps/lua/src/ldump.c +164 -0
  20. data/vendor/rlite/deps/lua/src/lfunc.c +174 -0
  21. data/vendor/rlite/deps/lua/src/lfunc.h +34 -0
  22. data/vendor/rlite/deps/lua/src/lgc.c +710 -0
  23. data/vendor/rlite/deps/lua/src/lgc.h +110 -0
  24. data/vendor/rlite/deps/lua/src/linit.c +38 -0
  25. data/vendor/rlite/deps/lua/src/liolib.c +556 -0
  26. data/vendor/rlite/deps/lua/src/llex.c +463 -0
  27. data/vendor/rlite/deps/lua/src/llex.h +81 -0
  28. data/vendor/rlite/deps/lua/src/llimits.h +128 -0
  29. data/vendor/rlite/deps/lua/src/lmathlib.c +263 -0
  30. data/vendor/rlite/deps/lua/src/lmem.c +86 -0
  31. data/vendor/rlite/deps/lua/src/lmem.h +49 -0
  32. data/vendor/rlite/deps/lua/src/loadlib.c +666 -0
  33. data/vendor/rlite/deps/lua/src/lobject.c +214 -0
  34. data/vendor/rlite/deps/lua/src/lobject.h +381 -0
  35. data/vendor/rlite/deps/lua/src/lopcodes.c +102 -0
  36. data/vendor/rlite/deps/lua/src/lopcodes.h +268 -0
  37. data/vendor/rlite/deps/lua/src/loslib.c +243 -0
  38. data/vendor/rlite/deps/lua/src/lparser.c +1339 -0
  39. data/vendor/rlite/deps/lua/src/lparser.h +82 -0
  40. data/vendor/rlite/deps/lua/src/lstate.c +214 -0
  41. data/vendor/rlite/deps/lua/src/lstate.h +169 -0
  42. data/vendor/rlite/deps/lua/src/lstring.c +111 -0
  43. data/vendor/rlite/deps/lua/src/lstring.h +31 -0
  44. data/vendor/rlite/deps/lua/src/lstrlib.c +871 -0
  45. data/vendor/rlite/deps/lua/src/ltable.c +588 -0
  46. data/vendor/rlite/deps/lua/src/ltable.h +40 -0
  47. data/vendor/rlite/deps/lua/src/ltablib.c +287 -0
  48. data/vendor/rlite/deps/lua/src/ltm.c +75 -0
  49. data/vendor/rlite/deps/lua/src/ltm.h +54 -0
  50. data/vendor/rlite/deps/lua/src/lua.c +392 -0
  51. data/vendor/rlite/deps/lua/src/lua.h +388 -0
  52. data/vendor/rlite/deps/lua/src/lua_bit.c +189 -0
  53. data/vendor/rlite/deps/lua/src/lua_cjson.c +1427 -0
  54. data/vendor/rlite/deps/lua/src/lua_cmsgpack.c +957 -0
  55. data/vendor/rlite/deps/lua/src/lua_struct.c +421 -0
  56. data/vendor/rlite/deps/lua/src/luac.c +200 -0
  57. data/vendor/rlite/deps/lua/src/luaconf.h +763 -0
  58. data/vendor/rlite/deps/lua/src/lualib.h +53 -0
  59. data/vendor/rlite/deps/lua/src/lundump.c +227 -0
  60. data/vendor/rlite/deps/lua/src/lundump.h +36 -0
  61. data/vendor/rlite/deps/lua/src/lvm.c +767 -0
  62. data/vendor/rlite/deps/lua/src/lvm.h +36 -0
  63. data/vendor/rlite/deps/lua/src/lzio.c +82 -0
  64. data/vendor/rlite/deps/lua/src/lzio.h +67 -0
  65. data/vendor/rlite/deps/lua/src/print.c +227 -0
  66. data/vendor/rlite/deps/lua/src/strbuf.c +251 -0
  67. data/vendor/rlite/deps/lua/src/strbuf.h +154 -0
  68. data/vendor/rlite/src/Makefile +97 -25
  69. data/vendor/rlite/{deps → src}/crc64.c +0 -0
  70. data/vendor/rlite/{deps → src}/crc64.h +0 -0
  71. data/vendor/rlite/src/dump.c +2 -2
  72. data/vendor/rlite/{deps → src}/endianconv.h +0 -0
  73. data/vendor/rlite/src/hirlite.c +134 -90
  74. data/vendor/rlite/src/hirlite.h +34 -1
  75. data/vendor/rlite/{deps → src}/hyperloglog.c +0 -0
  76. data/vendor/rlite/{deps → src}/hyperloglog.h +0 -0
  77. data/vendor/rlite/{deps → src}/lzf.h +0 -0
  78. data/vendor/rlite/{deps → src}/lzfP.h +0 -0
  79. data/vendor/rlite/{deps → src}/lzf_c.c +0 -0
  80. data/vendor/rlite/{deps → src}/lzf_d.c +0 -0
  81. data/vendor/rlite/src/page_btree.c +10 -10
  82. data/vendor/rlite/src/page_btree.h +2 -2
  83. data/vendor/rlite/src/page_list.c +3 -3
  84. data/vendor/rlite/src/page_list.h +1 -1
  85. data/vendor/rlite/src/page_multi_string.c +1 -1
  86. data/vendor/rlite/src/page_skiplist.c +1 -1
  87. data/vendor/rlite/src/page_skiplist.h +1 -1
  88. data/vendor/rlite/src/rand.c +93 -0
  89. data/vendor/rlite/src/rand.h +38 -0
  90. data/vendor/rlite/src/restore.c +286 -155
  91. data/vendor/rlite/src/restore.h +6 -0
  92. data/vendor/rlite/src/rlite.c +30 -30
  93. data/vendor/rlite/src/rlite.h +1 -1
  94. data/vendor/rlite/src/scripting.c +1138 -0
  95. data/vendor/rlite/src/scripting.h +10 -0
  96. data/vendor/rlite/{deps → src}/sha1.c +0 -0
  97. data/vendor/rlite/{deps → src}/sha1.h +0 -0
  98. data/vendor/rlite/src/solarisfixes.h +54 -0
  99. data/vendor/rlite/src/sort.c +4 -2
  100. data/vendor/rlite/src/sort.h +1 -1
  101. data/vendor/rlite/src/type_string.c +1 -1
  102. data/vendor/rlite/src/util.c +4 -4
  103. data/vendor/rlite/src/util.h +3 -3
  104. data/vendor/rlite/{deps → src}/utilfromredis.c +0 -0
  105. data/vendor/rlite/{deps → src}/utilfromredis.h +0 -0
  106. metadata +84 -15
@@ -0,0 +1,1138 @@
1
+ /*
2
+ * Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
3
+ * Copyright (c) 2015, Sebastian Waisbrot <seppo0010 at gmail dot com>
4
+ * All rights reserved.
5
+ *
6
+ * Redistribution and use in source and binary forms, with or without
7
+ * modification, are permitted provided that the following conditions are met:
8
+ *
9
+ * * Redistributions of source code must retain the above copyright notice,
10
+ * this list of conditions and the following disclaimer.
11
+ * * Redistributions in binary form must reproduce the above copyright
12
+ * notice, this list of conditions and the following disclaimer in the
13
+ * documentation and/or other materials provided with the distribution.
14
+ * * Neither the name of Redis nor the names of its contributors may be used
15
+ * to endorse or promote products derived from this software without
16
+ * specific prior written permission.
17
+ *
18
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
+ * POSSIBILITY OF SUCH DAMAGE.
29
+ */
30
+
31
+ #include "rlite.h"
32
+ #include "hirlite.h"
33
+ #include "sha1.h"
34
+ #include "rand.h"
35
+ #include "constants.h"
36
+
37
+ #include <lua.h>
38
+ #include <lauxlib.h>
39
+ #include <lualib.h>
40
+ #include <ctype.h>
41
+ #include <math.h>
42
+
43
+ #define RLITE_DEBUG 0
44
+ #define RLITE_VERBOSE 1
45
+ #define RLITE_NOTICE 2
46
+ #define RLITE_WARNING 3
47
+ #define RLITE_LOG_RAW (1<<10) /* Modifier to log without timestamp */
48
+ #define RLITE_DEFAULT_VERBOSITY RLITE_NOTICE
49
+
50
+ void sha1hex(char *digest, char *script, size_t len);
51
+ static int setScript(rliteClient *c, char *script, long scriptlen) {
52
+ int retval;
53
+ char hash[40];
54
+ sha1hex(hash, script, scriptlen);
55
+ int selected_database = c->context->db->selected_database;
56
+ c->context->db->selected_database = c->context->db->number_of_databases;
57
+
58
+ RL_CALL(rl_set, RL_OK, c->context->db, (unsigned char *)hash, 40, (unsigned char *)script, scriptlen, 0, 0);
59
+
60
+ cleanup:
61
+ c->context->db->selected_database = selected_database;
62
+ return retval;
63
+ }
64
+
65
+ static int getScript(rliteClient *c, char hash[40], char **script, long *scriptlen) {
66
+ int retval;
67
+ int selected_database = c->context->db->selected_database;
68
+ c->context->db->selected_database = c->context->db->number_of_databases;
69
+
70
+ RL_CALL(rl_get, RL_OK, c->context->db, (unsigned char *)hash, 40, (unsigned char **)script, scriptlen);
71
+
72
+ cleanup:
73
+ c->context->db->selected_database = selected_database;
74
+ return retval;
75
+ }
76
+
77
+ void rliteLogRaw(int UNUSED(level), const char *UNUSED(fmt), ...) {
78
+ // TODO
79
+ }
80
+ void rliteLog(int UNUSED(level), const char *UNUSED(fmt), ...) {
81
+ // TODO
82
+ }
83
+ void rliteToLuaType_Int(lua_State *lua, rliteReply *reply);
84
+ void rliteToLuaType_Bulk(lua_State *lua, rliteReply *reply);
85
+ void rliteToLuaType_Status(lua_State *lua, rliteReply *reply);
86
+ void rliteToLuaType_Error(lua_State *lua, rliteReply *reply);
87
+ void rliteToLuaType_MultiBulk(lua_State *lua, rliteReply *reply);
88
+ int rlite_math_random (lua_State *L);
89
+ int rlite_math_randomseed (lua_State *L);
90
+
91
+ /* Take a Redis reply in the Redis protocol format and convert it into a
92
+ * Lua type. Thanks to this function, and the introduction of not connected
93
+ * clients, it is trivial to implement the rlite() lua function.
94
+ *
95
+ * Basically we take the arguments, execute the Redis command in the context
96
+ * of a non connected client, then take the generated reply and convert it
97
+ * into a suitable Lua type. With this trick the scripting feature does not
98
+ * need the introduction of a full Redis internals API. Basically the script
99
+ * is like a normal client that bypasses all the slow I/O paths.
100
+ *
101
+ * Note: in this function we do not do any sanity check as the reply is
102
+ * generated by Redis directly. This allows us to go faster.
103
+ * The reply string can be altered during the parsing as it is discarded
104
+ * after the conversion is completed.
105
+ *
106
+ * Errors are returned as a table with a single 'err' field set to the
107
+ * error string.
108
+ */
109
+
110
+ void rliteToLuaType(lua_State *lua, rliteReply *reply) {
111
+ switch(reply->type) {
112
+ case RLITE_REPLY_INTEGER:
113
+ rliteToLuaType_Int(lua,reply);
114
+ break;
115
+ case RLITE_REPLY_STRING:
116
+ rliteToLuaType_Bulk(lua,reply);
117
+ break;
118
+ case RLITE_REPLY_STATUS:
119
+ rliteToLuaType_Status(lua,reply);
120
+ break;
121
+ case RLITE_REPLY_ERROR:
122
+ rliteToLuaType_Error(lua,reply);
123
+ break;
124
+ case RLITE_REPLY_ARRAY:
125
+ rliteToLuaType_MultiBulk(lua,reply);
126
+ break;
127
+ }
128
+ }
129
+
130
+ void rliteToLuaType_Int(lua_State *lua, rliteReply *reply) {
131
+ lua_pushnumber(lua,(lua_Number)reply->integer);
132
+ }
133
+
134
+ void rliteToLuaType_Bulk(lua_State *lua, rliteReply *reply) {
135
+ lua_pushlstring(lua, reply->str, reply->len);
136
+ }
137
+
138
+ void rliteToLuaType_Status(lua_State *lua, rliteReply *reply) {
139
+ lua_newtable(lua);
140
+ lua_pushstring(lua,"ok");
141
+ lua_pushlstring(lua, reply->str, reply->len);
142
+ lua_settable(lua,-3);
143
+ }
144
+
145
+ void rliteToLuaType_Error(lua_State *lua, rliteReply *reply) {
146
+ lua_newtable(lua);
147
+ lua_pushstring(lua,"err");
148
+ lua_pushlstring(lua, reply->str, reply->len);
149
+ lua_settable(lua,-3);
150
+ }
151
+
152
+ void rliteToLuaType_MultiBulk(lua_State *lua, rliteReply *reply) {
153
+ size_t j;
154
+ lua_newtable(lua);
155
+ for (j = 0; j < reply->elements; j++) {
156
+ lua_pushnumber(lua,j+1);
157
+ rliteToLuaType(lua,reply->element[j]);
158
+ lua_settable(lua,-3);
159
+ }
160
+ }
161
+
162
+ void luaPushError(lua_State *lua, char *error) {
163
+ lua_Debug dbg;
164
+
165
+ lua_newtable(lua);
166
+ lua_pushstring(lua,"err");
167
+
168
+ /* Attempt to figure out where this function was called, if possible */
169
+ if(lua_getstack(lua, 1, &dbg) && lua_getinfo(lua, "nSl", &dbg)) {
170
+ // 4 for formatting, 1 for null termination, 35 ought to be enough for an integer
171
+ size_t len = strlen(dbg.source) + strlen(error) + 40;
172
+ char *msg = malloc(sizeof(char) * len);
173
+ snprintf(msg, len, "%s: %d: %s",
174
+ dbg.source, dbg.currentline, error);
175
+ lua_pushstring(lua, msg);
176
+ free(msg);
177
+ } else {
178
+ lua_pushstring(lua, error);
179
+ }
180
+ lua_settable(lua,-3);
181
+ }
182
+
183
+ /* Sort the array currently in the stack. We do this to make the output
184
+ * of commands like KEYS or SMEMBERS something deterministic when called
185
+ * from Lua (to play well with AOf/replication).
186
+ *
187
+ * The array is sorted using table.sort itself, and assuming all the
188
+ * list elements are strings. */
189
+ void luaSortArray(lua_State *lua) {
190
+ /* Initial Stack: array */
191
+ lua_getglobal(lua,"table");
192
+ lua_pushstring(lua,"sort");
193
+ lua_gettable(lua,-2); /* Stack: array, table, table.sort */
194
+ lua_pushvalue(lua,-3); /* Stack: array, table, table.sort, array */
195
+ if (lua_pcall(lua,1,0,0)) {
196
+ /* Stack: array, table, error */
197
+
198
+ /* We are not interested in the error, we assume that the problem is
199
+ * that there are 'false' elements inside the array, so we try
200
+ * again with a slower function but able to handle this case, that
201
+ * is: table.sort(table, __rlite__compare_helper) */
202
+ lua_pop(lua,1); /* Stack: array, table */
203
+ lua_pushstring(lua,"sort"); /* Stack: array, table, sort */
204
+ lua_gettable(lua,-2); /* Stack: array, table, table.sort */
205
+ lua_pushvalue(lua,-3); /* Stack: array, table, table.sort, array */
206
+ lua_getglobal(lua,"__rlite__compare_helper");
207
+ /* Stack: array, table, table.sort, array, __rlite__compare_helper */
208
+ lua_call(lua,2,0);
209
+ }
210
+ /* Stack: array (sorted), table */
211
+ lua_pop(lua,1); /* Stack: array (sorted) */
212
+ }
213
+
214
+ static lua_State *lua = NULL;
215
+ static rliteClient *lua_caller = NULL;
216
+ static rliteClient *lua_client = NULL;
217
+ static int lua_random_dirty;
218
+ static int lua_write_dirty;
219
+ static unsigned long long lua_time_start;
220
+ static unsigned long long lua_time_limit;
221
+ static int lua_timedout;
222
+ static int lua_kill;
223
+
224
+ #define LUA_CMD_OBJCACHE_SIZE 32
225
+ #define LUA_CMD_OBJCACHE_MAX_LEN 64
226
+ int luaRedisGenericCommand(lua_State *lua, int raise_error) {
227
+ int j, argc = lua_gettop(lua);
228
+ struct rliteCommand *cmd;
229
+ rliteClient *c = lua_client;
230
+ rliteReply *reply;
231
+
232
+ /* Cached across calls. */
233
+ static char **argv = NULL;
234
+ static size_t *argvlen = NULL;
235
+ static int argv_size = 0;
236
+ static int inuse = 0; /* Recursive calls detection. */
237
+
238
+ /* By using Lua debug hooks it is possible to trigger a recursive call
239
+ * to luaRedisGenericCommand(), which normally should never happen.
240
+ * To make this function reentrant is futile and makes it slower, but
241
+ * we should at least detect such a misuse, and abort. */
242
+ if (inuse) {
243
+ char *recursion_warning =
244
+ "luaRedisGenericCommand() recursive call detected. "
245
+ "Are you doing funny stuff with Lua debug hooks?";
246
+ rliteLog(RLITE_WARNING,"%s",recursion_warning);
247
+ luaPushError(lua,recursion_warning);
248
+ return 1;
249
+ }
250
+ inuse++;
251
+
252
+ /* Require at least one argument */
253
+ if (argc == 0) {
254
+ luaPushError(lua,
255
+ "Please specify at least one argument for rlite.call()");
256
+ inuse--;
257
+ return 1;
258
+ }
259
+
260
+ /* Build the arguments vector */
261
+ if (argv_size < argc) {
262
+ argv = realloc(argv, sizeof(char *) * argc);
263
+ argvlen = realloc(argvlen, sizeof(size_t) * argc);
264
+ argv_size = argc;
265
+ }
266
+
267
+ for (j = 0; j < argc; j++) {
268
+ char *obj_s;
269
+ size_t obj_len;
270
+ char dbuf[64];
271
+
272
+ if (lua_type(lua,j+1) == LUA_TNUMBER) {
273
+ /* We can't use lua_tolstring() for number -> string conversion
274
+ * since Lua uses a format specifier that loses precision. */
275
+ lua_Number num = lua_tonumber(lua,j+1);
276
+
277
+ obj_len = snprintf(dbuf,sizeof(dbuf),"%.17g",(double)num);
278
+ obj_s = dbuf;
279
+ } else {
280
+ obj_s = (char*)lua_tolstring(lua,j+1,&obj_len);
281
+ if (obj_s == NULL) break; /* Not a string. */
282
+ }
283
+
284
+ argv[j] = obj_s;
285
+ argvlen[j] = obj_len;
286
+ }
287
+
288
+ /* Check if one of the arguments passed by the Lua script
289
+ * is not a string or an integer (lua_isstring() return true for
290
+ * integers as well). */
291
+ if (j != argc) {
292
+ j--;
293
+ while (j >= 0) {
294
+ free(argv[j]);
295
+ j--;
296
+ }
297
+ luaPushError(lua,
298
+ "Lua rlite() command arguments must be strings or integers");
299
+ inuse--;
300
+ return 1;
301
+ }
302
+
303
+ /* Setup our fake client for command execution */
304
+ c->argvlen = argvlen;
305
+ c->argv = argv;
306
+ c->argc = argc;
307
+
308
+ /* Command lookup */
309
+ cmd = rliteLookupCommand(argv[0], argvlen[0]);
310
+ if (!cmd || ((cmd->arity > 0 && cmd->arity != argc) ||
311
+ (argc < -cmd->arity)))
312
+ {
313
+ if (cmd)
314
+ luaPushError(lua,
315
+ "Wrong number of args calling Redis command From Lua script");
316
+ else
317
+ luaPushError(lua,"Unknown Redis command called from Lua script");
318
+ goto cleanup;
319
+ }
320
+
321
+ /* There are commands that are not allowed inside scripts. */
322
+ if (cmd->flags & RLITE_CMD_NOSCRIPT) {
323
+ luaPushError(lua, "This Redis command is not allowed from scripts");
324
+ goto cleanup;
325
+ }
326
+
327
+ /* Write commands are forbidden against read-only slaves, or if a
328
+ * command marked as non-deterministic was already called in the context
329
+ * of this script. */
330
+ if (cmd->flags & RLITE_CMD_WRITE) {
331
+ if (lua_random_dirty) {
332
+ luaPushError(lua,
333
+ "Write commands not allowed after non deterministic commands");
334
+ goto cleanup;
335
+ }
336
+ }
337
+
338
+ if (cmd->flags & RLITE_CMD_RANDOM) lua_random_dirty = 1;
339
+ if (cmd->flags & RLITE_CMD_WRITE) lua_write_dirty = 1;
340
+
341
+ /* Run the command */
342
+ rliteAppendCommandClient(c);
343
+ rliteGetReply(c->context, (void **)&reply);
344
+
345
+ if (raise_error && reply->type != RLITE_REPLY_ERROR) raise_error = 0;
346
+ rliteToLuaType(lua,reply);
347
+ /* Sort the output array if needed, assuming it is a non-null multi bulk
348
+ * reply as expected. */
349
+ if ((cmd->flags & RLITE_CMD_SORT_FOR_SCRIPT) &&
350
+ (reply->type == RLITE_REPLY_ARRAY && reply->elements > 0)) {
351
+ luaSortArray(lua);
352
+ }
353
+ rliteFreeReplyObject(reply);
354
+ cleanup:
355
+ if (c->argv != argv) {
356
+ free(c->argv);
357
+ argv = NULL;
358
+ argv_size = 0;
359
+ }
360
+
361
+ if (raise_error) {
362
+ /* If we are here we should have an error in the stack, in the
363
+ * form of a table with an "err" field. Extract the string to
364
+ * return the plain error. */
365
+ lua_pushstring(lua,"err");
366
+ lua_gettable(lua,-2);
367
+ inuse--;
368
+ return lua_error(lua);
369
+ }
370
+ inuse--;
371
+ return 1;
372
+ }
373
+
374
+ int luaRedisCallCommand(lua_State *lua) {
375
+ return luaRedisGenericCommand(lua,1);
376
+ }
377
+
378
+ int luaRedisPCallCommand(lua_State *lua) {
379
+ return luaRedisGenericCommand(lua,0);
380
+ }
381
+
382
+ /* This adds rlite.sha1hex(string) to Lua scripts using the same hashing
383
+ * function used for sha1ing lua scripts. */
384
+ int luaRedisSha1hexCommand(lua_State *lua) {
385
+ int argc = lua_gettop(lua);
386
+ char digest[41];
387
+ size_t len;
388
+ char *s;
389
+
390
+ if (argc != 1) {
391
+ luaPushError(lua, "wrong number of arguments");
392
+ return 1;
393
+ }
394
+
395
+ s = (char*)lua_tolstring(lua,1,&len);
396
+ sha1hex(digest,s,len);
397
+ lua_pushstring(lua,digest);
398
+ return 1;
399
+ }
400
+
401
+ /* Returns a table with a single field 'field' set to the string value
402
+ * passed as argument. This helper function is handy when returning
403
+ * a Redis Protocol error or status reply from Lua:
404
+ *
405
+ * return rlite.error_reply("ERR Some Error")
406
+ * return rlite.status_reply("ERR Some Error")
407
+ */
408
+ int luaRedisReturnSingleFieldTable(lua_State *lua, char *field) {
409
+ if (lua_gettop(lua) != 1 || lua_type(lua,-1) != LUA_TSTRING) {
410
+ luaPushError(lua, "wrong number or type of arguments");
411
+ return 1;
412
+ }
413
+
414
+ lua_newtable(lua);
415
+ lua_pushstring(lua, field);
416
+ lua_pushvalue(lua, -3);
417
+ lua_settable(lua, -3);
418
+ return 1;
419
+ }
420
+
421
+ int luaRedisErrorReplyCommand(lua_State *lua) {
422
+ return luaRedisReturnSingleFieldTable(lua,"err");
423
+ }
424
+
425
+ int luaRedisStatusReplyCommand(lua_State *lua) {
426
+ return luaRedisReturnSingleFieldTable(lua,"ok");
427
+ }
428
+
429
+ int luaLogCommand(lua_State *lua) {
430
+ int j, argc = lua_gettop(lua);
431
+ int level;
432
+ char *log;
433
+ char **strs;
434
+ size_t *strlens;
435
+
436
+ if (argc < 2) {
437
+ luaPushError(lua, "rlite.log() requires two arguments or more.");
438
+ return 1;
439
+ } else if (!lua_isnumber(lua,-argc)) {
440
+ luaPushError(lua, "First argument must be a number (log level).");
441
+ return 1;
442
+ }
443
+ level = lua_tonumber(lua,-argc);
444
+ if (level < RLITE_DEBUG || level > RLITE_WARNING) {
445
+ luaPushError(lua, "Invalid debug level.");
446
+ return 1;
447
+ }
448
+
449
+ size_t totalsize = 0;
450
+ strs = malloc(sizeof(char *) * (argc - 1));
451
+ if (!strs) {
452
+ return 1;
453
+ }
454
+ strlens = malloc(sizeof(size_t) * (argc - 1));
455
+ if (!strlens) {
456
+ free(strs);
457
+ return 1;
458
+ }
459
+ strlens = malloc(sizeof(size_t) * (argc - 1));
460
+ for (j = 1; j < argc; j++) {
461
+ strs[j - 1] = (char*)lua_tolstring(lua,(-argc)+j,&strlens[j - 1]);
462
+ totalsize += strlens[j - 1];
463
+ }
464
+ log = malloc(sizeof(char) * (totalsize + 1));
465
+ if (!log) {
466
+ free(strs);
467
+ free(strlens);
468
+ return 1;
469
+ }
470
+
471
+ totalsize = 0;
472
+ for (j = 0; j < argc - 1; j++) {
473
+ memcpy(&log[totalsize], strs[j], strlens[j]);
474
+ totalsize += strlens[j];
475
+ }
476
+ log[totalsize] = 0;
477
+ rliteLogRaw(level,log);
478
+ return 0;
479
+ }
480
+
481
+ void luaMaskCountHook(lua_State *lua, lua_Debug *UNUSED(ar)) {
482
+ unsigned long long elapsed;
483
+
484
+ elapsed = rl_mstime() - lua_time_start;
485
+ if (elapsed >= lua_time_limit && lua_timedout == 0) {
486
+ rliteLog(RLITE_WARNING,"Lua slow script detected: still in execution after %lld milliseconds. You can try killing the script using the SCRIPT KILL command.",elapsed);
487
+ lua_timedout = 1;
488
+ }
489
+ if (lua_kill) {
490
+ rliteLog(RLITE_WARNING, "Lua script killed by user with SCRIPT KILL.");
491
+ lua_pushstring(lua, "Script killed by user with SCRIPT KILL...");
492
+ lua_error(lua);
493
+ }
494
+ }
495
+
496
+ void luaLoadLib(lua_State *lua, const char *libname, lua_CFunction luafunc) {
497
+ lua_pushcfunction(lua, luafunc);
498
+ lua_pushstring(lua, libname);
499
+ lua_call(lua, 1, 0);
500
+ }
501
+
502
+ LUALIB_API int (luaopen_cjson) (lua_State *L);
503
+ LUALIB_API int (luaopen_struct) (lua_State *L);
504
+ LUALIB_API int (luaopen_cmsgpack) (lua_State *L);
505
+ LUALIB_API int (luaopen_bit) (lua_State *L);
506
+
507
+ void luaLoadLibraries(lua_State *lua) {
508
+ luaLoadLib(lua, "", luaopen_base);
509
+ luaLoadLib(lua, LUA_TABLIBNAME, luaopen_table);
510
+ luaLoadLib(lua, LUA_STRLIBNAME, luaopen_string);
511
+ luaLoadLib(lua, LUA_MATHLIBNAME, luaopen_math);
512
+ luaLoadLib(lua, LUA_DBLIBNAME, luaopen_debug);
513
+ luaLoadLib(lua, "cjson", luaopen_cjson);
514
+ luaLoadLib(lua, "struct", luaopen_struct);
515
+ luaLoadLib(lua, "cmsgpack", luaopen_cmsgpack);
516
+ luaLoadLib(lua, "bit", luaopen_bit);
517
+
518
+ #if 0 /* Stuff that we don't load currently, for sandboxing concerns. */
519
+ luaLoadLib(lua, LUA_LOADLIBNAME, luaopen_package);
520
+ luaLoadLib(lua, LUA_OSLIBNAME, luaopen_os);
521
+ #endif
522
+ }
523
+
524
+ /* Remove a functions that we don't want to expose to the Redis scripting
525
+ * environment. */
526
+ void luaRemoveUnsupportedFunctions(lua_State *lua) {
527
+ lua_pushnil(lua);
528
+ lua_setglobal(lua,"loadfile");
529
+ }
530
+
531
+ /* This function installs metamethods in the global table _G that prevent
532
+ * the creation of globals accidentally.
533
+ *
534
+ * It should be the last to be called in the scripting engine initialization
535
+ * sequence, because it may interact with creation of globals. */
536
+ void scriptingEnableGlobalsProtection(lua_State *lua) {
537
+ /* strict.lua from: http://metalua.luaforge.net/src/lib/strict.lua.html.
538
+ * Modified to be adapted to Redis. */
539
+ char *code =""
540
+ "local mt = {}\n"
541
+ "setmetatable(_G, mt)\n"
542
+ "mt.__newindex = function (t, n, v)\n"
543
+ " if debug.getinfo(2) then\n"
544
+ " local w = debug.getinfo(2, \"S\").what\n"
545
+ " if w ~= \"main\" and w ~= \"C\" then\n"
546
+ " error(\"Script attempted to create global variable '\"..tostring(n)..\"'\", 2)\n"
547
+ " end\n"
548
+ " end\n"
549
+ " rawset(t, n, v)\n"
550
+ "end\n"
551
+ "mt.__index = function (t, n)\n"
552
+ " if debug.getinfo(2) and debug.getinfo(2, \"S\").what ~= \"C\" then\n"
553
+ " error(\"Script attempted to access unexisting global variable '\"..tostring(n)..\"'\", 2)\n"
554
+ " end\n"
555
+ " return rawget(t, n)\n"
556
+ "end\n";
557
+
558
+ luaL_loadbuffer(lua,code,strlen(code),"@enable_strict_lua");
559
+ lua_pcall(lua,0,0,0);
560
+ }
561
+
562
+ /* Initialize the scripting environment.
563
+ * It is possible to call this function to reset the scripting environment
564
+ * assuming that we call scriptingRelease() before.
565
+ * See scriptingReset() for more information. */
566
+ void scriptingInit(void) {
567
+ if (lua) {
568
+ return;
569
+ }
570
+ lua = lua_open();
571
+
572
+ luaLoadLibraries(lua);
573
+ luaRemoveUnsupportedFunctions(lua);
574
+
575
+ /* Initialize a dictionary we use to map SHAs to scripts.
576
+ * This is useful for replication, as we need to replicate EVALSHA
577
+ * as EVAL, so we need to remember the associated script. */
578
+
579
+ /* Register the rlite commands table and fields */
580
+ lua_newtable(lua);
581
+
582
+ /* rlite.call */
583
+ lua_pushstring(lua,"call");
584
+ lua_pushcfunction(lua,luaRedisCallCommand);
585
+ lua_settable(lua,-3);
586
+
587
+ /* rlite.pcall */
588
+ lua_pushstring(lua,"pcall");
589
+ lua_pushcfunction(lua,luaRedisPCallCommand);
590
+ lua_settable(lua,-3);
591
+
592
+ /* rlite.log and log levels. */
593
+ lua_pushstring(lua,"log");
594
+ lua_pushcfunction(lua,luaLogCommand);
595
+ lua_settable(lua,-3);
596
+
597
+ lua_pushstring(lua,"LOG_DEBUG");
598
+ lua_pushnumber(lua,RLITE_DEBUG);
599
+ lua_settable(lua,-3);
600
+
601
+ lua_pushstring(lua,"LOG_VERBOSE");
602
+ lua_pushnumber(lua,RLITE_VERBOSE);
603
+ lua_settable(lua,-3);
604
+
605
+ lua_pushstring(lua,"LOG_NOTICE");
606
+ lua_pushnumber(lua,RLITE_NOTICE);
607
+ lua_settable(lua,-3);
608
+
609
+ lua_pushstring(lua,"LOG_WARNING");
610
+ lua_pushnumber(lua,RLITE_WARNING);
611
+ lua_settable(lua,-3);
612
+
613
+ /* rlite.sha1hex */
614
+ lua_pushstring(lua, "sha1hex");
615
+ lua_pushcfunction(lua, luaRedisSha1hexCommand);
616
+ lua_settable(lua, -3);
617
+
618
+ /* rlite.error_reply and rlite.status_reply */
619
+ lua_pushstring(lua, "error_reply");
620
+ lua_pushcfunction(lua, luaRedisErrorReplyCommand);
621
+ lua_settable(lua, -3);
622
+ lua_pushstring(lua, "status_reply");
623
+ lua_pushcfunction(lua, luaRedisStatusReplyCommand);
624
+ lua_settable(lua, -3);
625
+
626
+ /* Finally set the table as 'redis' global var. */
627
+ lua_setglobal(lua,"redis");
628
+
629
+ /* Replace math.random and math.randomseed with our implementations. */
630
+ lua_getglobal(lua,"math");
631
+
632
+ lua_pushstring(lua,"random");
633
+ lua_pushcfunction(lua,rlite_math_random);
634
+ lua_settable(lua,-3);
635
+
636
+ lua_pushstring(lua,"randomseed");
637
+ lua_pushcfunction(lua,rlite_math_randomseed);
638
+ lua_settable(lua,-3);
639
+
640
+ lua_setglobal(lua,"math");
641
+
642
+ /* Add a helper function that we use to sort the multi bulk output of non
643
+ * deterministic commands, when containing 'false' elements. */
644
+ {
645
+ char *compare_func = "function __rlite__compare_helper(a,b)\n"
646
+ " if a == false then a = '' end\n"
647
+ " if b == false then b = '' end\n"
648
+ " return a<b\n"
649
+ "end\n";
650
+ luaL_loadbuffer(lua,compare_func,strlen(compare_func),"@cmp_func_def");
651
+ lua_pcall(lua,0,0,0);
652
+ }
653
+
654
+ /* Add a helper function we use for pcall error reporting.
655
+ * Note that when the error is in the C function we want to report the
656
+ * information about the caller, that's what makes sense from the point
657
+ * of view of the user debugging a script. */
658
+ {
659
+ char *errh_func = "function __rlite__err__handler(err)\n"
660
+ " local i = debug.getinfo(2,'nSl')\n"
661
+ " if i and i.what == 'C' then\n"
662
+ " i = debug.getinfo(3,'nSl')\n"
663
+ " end\n"
664
+ " if i then\n"
665
+ " return i.source .. ':' .. i.currentline .. ': ' .. err\n"
666
+ " else\n"
667
+ " return err\n"
668
+ " end\n"
669
+ "end\n";
670
+ luaL_loadbuffer(lua,errh_func,strlen(errh_func),"@err_handler_def");
671
+ lua_pcall(lua,0,0,0);
672
+ }
673
+
674
+ /* Create the (non connected) client that we use to execute Redis commands
675
+ * inside the Lua interpreter.
676
+ * Note: there is no need to create it again when this function is called
677
+ * by scriptingReset(). */
678
+ if (lua_client == NULL) {
679
+ lua_client = malloc(sizeof(*lua_client));
680
+
681
+ lua_client->flags = RLITE_LUA_CLIENT;
682
+ }
683
+
684
+ /* Lua beginners often don't use "local", this is likely to introduce
685
+ * subtle bugs in their code. To prevent problems we protect accesses
686
+ * to global variables. */
687
+ scriptingEnableGlobalsProtection(lua);
688
+ }
689
+
690
+ /* Release resources related to Lua scripting.
691
+ * This function is used in order to reset the scripting environment. */
692
+ void scriptingRelease(void) {
693
+ lua_close(lua);
694
+ }
695
+
696
+ void scriptingReset(void) {
697
+ scriptingRelease();
698
+ scriptingInit();
699
+ }
700
+
701
+ /* Perform the SHA1 of the input string. We use this both for hashing script
702
+ * bodies in order to obtain the Lua function name, and in the implementation
703
+ * of rlite.sha1().
704
+ *
705
+ * 'digest' should point to a 41 bytes buffer: 40 for SHA1 converted into an
706
+ * hexadecimal number, plus 1 byte for null term. */
707
+ void sha1hex(char *digest, char *script, size_t len) {
708
+ SHA1_CTX ctx;
709
+ unsigned char hash[20];
710
+ char *cset = "0123456789abcdef";
711
+ int j;
712
+
713
+ SHA1Init(&ctx);
714
+ SHA1Update(&ctx,(unsigned char*)script,len);
715
+ SHA1Final(hash,&ctx);
716
+
717
+ for (j = 0; j < 20; j++) {
718
+ digest[j*2] = cset[((hash[j]&0xF0)>>4)];
719
+ digest[j*2+1] = cset[(hash[j]&0xF)];
720
+ }
721
+ digest[40] = '\0';
722
+ }
723
+
724
+ rliteReply *luaReplyToStringReply(int type) {
725
+ rliteReply* reply;
726
+ const char *_err = lua_tostring(lua,-1);
727
+ size_t i, len = strlen(_err);
728
+ char *err = malloc(sizeof(char) * (len + 1));
729
+ if (!err) {
730
+ return NULL;
731
+ }
732
+ for (i = 0; i < len; i++) {
733
+ if (_err[i] == '\r' || _err[i] == '\n') err[i] = ' ';
734
+ else err[i] = _err[i];
735
+ }
736
+ err[len] = '\0';
737
+ reply = createStringTypeObject(type, err, len);
738
+ free(err);
739
+ return reply;
740
+ }
741
+ void luaReplyToRedisReply(rliteClient *c, lua_State *lua) {
742
+ int t = lua_type(lua,-1);
743
+
744
+ switch(t) {
745
+ case LUA_TSTRING:
746
+ c->reply = createStringObject((char*)lua_tostring(lua,-1),lua_strlen(lua,-1));
747
+ break;
748
+ case LUA_TBOOLEAN:
749
+ if (lua_toboolean(lua,-1)) {
750
+ c->reply = createLongLongObject(1);
751
+ } else {
752
+ c->reply = createNullReplyObject();
753
+ }
754
+ break;
755
+ case LUA_TNUMBER:
756
+ c->reply = createLongLongObject((long long)lua_tonumber(lua,-1));
757
+ break;
758
+ case LUA_TTABLE:
759
+ /* We need to check if it is an array, an error, or a status reply.
760
+ * Error are returned as a single element table with 'err' field.
761
+ * Status replies are returned as single element table with 'ok' field */
762
+ lua_pushstring(lua,"err");
763
+ lua_gettable(lua,-2);
764
+ t = lua_type(lua,-1);
765
+ if (t == LUA_TSTRING) {
766
+ c->reply = luaReplyToStringReply(RLITE_REPLY_ERROR);
767
+ lua_pop(lua,2);
768
+ return;
769
+ }
770
+
771
+ lua_pop(lua,1);
772
+ lua_pushstring(lua,"ok");
773
+ lua_gettable(lua,-2);
774
+ t = lua_type(lua,-1);
775
+ if (t == LUA_TSTRING) {
776
+ c->reply = luaReplyToStringReply(RLITE_REPLY_STATUS);
777
+ lua_pop(lua,1);
778
+ } else {
779
+ rliteReply *reply = createArrayObject(2);
780
+ void *tmp;
781
+ size_t j = 1;
782
+
783
+ lua_pop(lua,1); /* Discard the 'ok' field value we popped */
784
+ while(1) {
785
+ lua_pushnumber(lua,j++);
786
+ lua_gettable(lua,-2);
787
+ t = lua_type(lua,-1);
788
+ if (t == LUA_TNIL) {
789
+ lua_pop(lua,1);
790
+ break;
791
+ }
792
+ luaReplyToRedisReply(c, lua);
793
+ if (j - 2 == reply->elements) {
794
+ tmp = realloc(reply->element, sizeof(rliteReply *) * reply->elements * 2);
795
+ if (!tmp) {
796
+ // TODO: free stuff, panic
797
+ c->reply = NULL;
798
+ return;
799
+ }
800
+ reply->element = tmp;
801
+ }
802
+ reply->element[j - 2] = c->reply;
803
+ }
804
+ // TODO: shrink reply->element
805
+ reply->elements = j - 2;
806
+ c->reply = reply;
807
+ }
808
+ break;
809
+ default:
810
+ c->reply = createNullReplyObject();
811
+ }
812
+ lua_pop(lua,1);
813
+ }
814
+
815
+ /* Set an array of Redis String Objects as a Lua array (table) stored into a
816
+ * global variable. */
817
+ void luaSetGlobalArray(lua_State *lua, char *var, char **elev, size_t *elevlen, int elec) {
818
+ int j;
819
+
820
+ lua_newtable(lua);
821
+ for (j = 0; j < elec; j++) {
822
+ lua_pushlstring(lua,elev[j],elevlen[j]);
823
+ lua_rawseti(lua,-2,j+1);
824
+ }
825
+ lua_setglobal(lua,var);
826
+ }
827
+
828
+ /* Define a lua function with the specified function name and body.
829
+ * The function name musts be a 2 characters long string, since all the
830
+ * functions we defined in the Lua context are in the form:
831
+ *
832
+ * f_<hex sha1 sum>
833
+ *
834
+ * On success RLITE_OK is returned, and nothing is left on the Lua stack.
835
+ * On error RLITE_ERR is returned and an appropriate error is set in the
836
+ * client context. */
837
+ int luaCreateFunction(rliteClient *c, lua_State *lua, char *funcname, char *body, size_t bodylen) {
838
+ const char *f = "function ";
839
+ const char *params = "() ";
840
+ const char *end = " end";
841
+ size_t funcnamelen = 42;
842
+ size_t funcdeflen = bodylen + funcnamelen + strlen(f) + strlen(params) + strlen(end) + 1;
843
+ char *funcdef = malloc(sizeof(char) * funcdeflen);
844
+
845
+
846
+ strcpy(funcdef, f);
847
+ funcdeflen = strlen(f);
848
+
849
+ memcpy(&funcdef[funcdeflen], funcname, funcnamelen);
850
+ funcdeflen += funcnamelen;
851
+
852
+ strcpy(&funcdef[funcdeflen], params);
853
+ funcdeflen += strlen(params);
854
+
855
+ memcpy(&funcdef[funcdeflen], body, bodylen);
856
+ funcdeflen += bodylen;
857
+
858
+ strcpy(&funcdef[funcdeflen], end);
859
+ funcdeflen += strlen(end);
860
+
861
+ funcdef[funcdeflen] = 0;
862
+
863
+ if (luaL_loadbuffer(lua,funcdef,funcdeflen,"@user_script")) {
864
+ char err[1024];
865
+ snprintf(err, 1024, "ERR Error compiling script (new function): %s",
866
+ lua_tostring(lua,-1));
867
+ c->reply = createErrorObject(err);
868
+ lua_pop(lua,1);
869
+ free(funcdef);
870
+ return RLITE_ERR;
871
+ }
872
+ free(funcdef);
873
+ if (lua_pcall(lua,0,0,0)) {
874
+ char err[1024];
875
+ snprintf(err, 1024, "ERR Error running script (new function): %s",
876
+ lua_tostring(lua,-1));
877
+ c->reply = createErrorObject(err);
878
+ lua_tostring(lua,-1);
879
+ lua_pop(lua,1);
880
+ return RLITE_ERR;
881
+ }
882
+
883
+ /* We also save a SHA1 -> Original script map in a dictionary
884
+ * so that we can replicate / write in the AOF all the
885
+ * EVALSHA commands as EVAL using the original script. */
886
+ {
887
+ int retval = setScript(c, body, bodylen);
888
+ if (retval != RL_OK) {
889
+ return retval;
890
+ }
891
+ }
892
+ return RLITE_OK;
893
+ }
894
+
895
+ void evalGenericCommand(rliteClient *c, int evalsha) {
896
+ scriptingInit();
897
+ lua_client->context = c->context;
898
+ char funcname[43];
899
+ long long numkeys;
900
+ int delhook = 0, err;
901
+
902
+ /* We want the same PRNG sequence at every call so that our PRNG is
903
+ * not affected by external state. */
904
+ rliteSrand48(0);
905
+
906
+ /* We set this flag to zero to remember that so far no random command
907
+ * was called. This way we can allow the user to call commands like
908
+ * SRANDMEMBER or RANDOMKEY from Lua scripts as far as no write command
909
+ * is called (otherwise the replication and AOF would end with non
910
+ * deterministic sequences).
911
+ *
912
+ * Thanks to this flag we'll raise an error every time a write command
913
+ * is called after a random command was used. */
914
+ lua_random_dirty = 0;
915
+ lua_write_dirty = 0;
916
+
917
+ /* Get the number of arguments that are keys */
918
+ if (getLongLongFromObjectOrReply(c,c->argv[2],c->argvlen[2],&numkeys,NULL) != RLITE_OK)
919
+ return;
920
+ if (numkeys > (c->argc - 3)) {
921
+ c->reply = createErrorObject("Number of keys can't be greater than number of args");
922
+ return;
923
+ } else if (numkeys < 0) {
924
+ c->reply = createErrorObject("Number of keys can't be negative");
925
+ return;
926
+ }
927
+
928
+ /* We obtain the script SHA1, then check if this function is already
929
+ * defined into the Lua state */
930
+ funcname[0] = 'f';
931
+ funcname[1] = '_';
932
+ if (!evalsha) {
933
+ /* Hash the code if this is an EVAL call */
934
+ sha1hex(funcname+2,c->argv[1],c->argvlen[1]);
935
+ } else {
936
+ /* We already have the SHA if it is a EVALSHA */
937
+ int j;
938
+ char *sha = c->argv[1];
939
+
940
+ /* Convert to lowercase. We don't use tolower since the function
941
+ * managed to always show up in the profiler output consuming
942
+ * a non trivial amount of time. */
943
+ for (j = 0; j < 40; j++)
944
+ funcname[j+2] = (sha[j] >= 'A' && sha[j] <= 'Z') ?
945
+ sha[j]+('a'-'A') : sha[j];
946
+ funcname[42] = '\0';
947
+
948
+ char *body;
949
+ long bodylen;
950
+ int retval = getScript(c, funcname + 2, &body, &bodylen);
951
+ if (retval != RL_OK) {
952
+ c->reply = createErrorObject(RLITE_NOSCRIPTERR);
953
+ return;
954
+ }
955
+ luaCreateFunction(c, lua, funcname, body, bodylen);
956
+ rl_free(body);
957
+ }
958
+
959
+ /* Push the pcall error handler function on the stack. */
960
+ lua_getglobal(lua, "__rlite__err__handler");
961
+
962
+ /* Try to lookup the Lua function */
963
+ lua_getglobal(lua, funcname);
964
+ if (lua_isnil(lua,-1)) {
965
+ lua_pop(lua,1); /* remove the nil from the stack */
966
+ /* Function not defined... let's define it if we have the
967
+ * body of the function. If this is an EVALSHA call we can just
968
+ * return an error. */
969
+ if (evalsha) {
970
+ lua_pop(lua,1); /* remove the error handler from the stack. */
971
+ c->reply = createErrorObject(RLITE_NOSCRIPTERR);
972
+ return;
973
+ }
974
+ if (luaCreateFunction(c,lua,funcname,c->argv[1], c->argvlen[1]) == RLITE_ERR) {
975
+ lua_pop(lua,1); /* remove the error handler from the stack. */
976
+ /* The error is sent to the client by luaCreateFunction()
977
+ * itself when it returns RLITE_ERR. */
978
+ return;
979
+ }
980
+ /* Now the following is guaranteed to return non nil */
981
+ lua_getglobal(lua, funcname);
982
+ if (lua_isnil(lua,-1)) {
983
+ // TODO: panic
984
+ return;
985
+ }
986
+ }
987
+
988
+ /* Populate the argv and keys table accordingly to the arguments that
989
+ * EVAL received. */
990
+ luaSetGlobalArray(lua,"KEYS",c->argv+3,c->argvlen+3,numkeys);
991
+ luaSetGlobalArray(lua,"ARGV",c->argv+3+numkeys,c->argvlen+3+numkeys,c->argc-3-numkeys);
992
+
993
+ /* Set a hook in order to be able to stop the script execution if it
994
+ * is running for too much time.
995
+ * We set the hook only if the time limit is enabled as the hook will
996
+ * make the Lua script execution slower. */
997
+ lua_caller = c;
998
+ lua_time_start = rl_mstime();
999
+ lua_kill = 0;
1000
+ if (lua_time_limit > 0) {
1001
+ lua_sethook(lua,luaMaskCountHook,LUA_MASKCOUNT,100000);
1002
+ delhook = 1;
1003
+ }
1004
+
1005
+ /* At this point whether this script was never seen before or if it was
1006
+ * already defined, we can call it. We have zero arguments and expect
1007
+ * a single return value. */
1008
+ err = lua_pcall(lua,0,1,-2);
1009
+
1010
+ /* Perform some cleanup that we need to do both on error and success. */
1011
+ if (delhook) lua_sethook(lua,luaMaskCountHook,0,0); /* Disable hook */
1012
+ if (lua_timedout) {
1013
+ lua_timedout = 0;
1014
+ /* Restore the readable handler that was unregistered when the
1015
+ * script timeout was detected. */
1016
+ }
1017
+ lua_caller = NULL;
1018
+
1019
+ /* Call the Lua garbage collector from time to time to avoid a
1020
+ * full cycle performed by Lua, which adds too latency.
1021
+ *
1022
+ * The call is performed every LUA_GC_CYCLE_PERIOD executed commands
1023
+ * (and for LUA_GC_CYCLE_PERIOD collection steps) because calling it
1024
+ * for every command uses too much CPU. */
1025
+ #define LUA_GC_CYCLE_PERIOD 50
1026
+ {
1027
+ static long gc_count = 0;
1028
+
1029
+ gc_count++;
1030
+ if (gc_count == LUA_GC_CYCLE_PERIOD) {
1031
+ lua_gc(lua,LUA_GCSTEP,LUA_GC_CYCLE_PERIOD);
1032
+ gc_count = 0;
1033
+ }
1034
+ }
1035
+
1036
+ if (err) {
1037
+ char err[1024];
1038
+ snprintf(err, 1024, "Error running script (call to %s): %s\n",
1039
+ funcname, lua_tostring(lua,-1));
1040
+ c->reply = createErrorObject(err);
1041
+ lua_pop(lua,2); /* Consume the Lua reply and remove error handler. */
1042
+ } else {
1043
+ /* On success convert the Lua return value into Redis protocol, and
1044
+ * send it to * the client. */
1045
+ luaReplyToRedisReply(c,lua); /* Convert and consume the reply. */
1046
+ lua_pop(lua,1); /* Remove the error handler. */
1047
+ }
1048
+ }
1049
+
1050
+ void evalCommand(rliteClient *c) {
1051
+ evalGenericCommand(c,0);
1052
+ }
1053
+
1054
+ void evalShaCommand(rliteClient *c) {
1055
+ if (c->argvlen[1] != 40) {
1056
+ /* We know that a match is not possible if the provided SHA is
1057
+ * not the right length. So we return an error ASAP, this way
1058
+ * evalGenericCommand() can be implemented without string length
1059
+ * sanity check */
1060
+ c->reply = createErrorObject(RLITE_NOSCRIPTERR);
1061
+ return;
1062
+ }
1063
+ evalGenericCommand(c,1);
1064
+ }
1065
+
1066
+ /* We replace math.random() with our implementation that is not affected
1067
+ * by specific libc random() implementations and will output the same sequence
1068
+ * (for the same seed) in every arch. */
1069
+
1070
+ /* The following implementation is the one shipped with Lua itself but with
1071
+ * rand() replaced by rliteLrand48(). */
1072
+ int rlite_math_random (lua_State *L) {
1073
+ /* the `%' avoids the (rare) case of r==1, and is needed also because on
1074
+ some systems (SunOS!) `rand()' may return a value larger than RAND_MAX */
1075
+ lua_Number r = (lua_Number)(rliteLrand48()%RLITE_LRAND48_MAX) /
1076
+ (lua_Number)RLITE_LRAND48_MAX;
1077
+ switch (lua_gettop(L)) { /* check number of arguments */
1078
+ case 0: { /* no arguments */
1079
+ lua_pushnumber(L, r); /* Number between 0 and 1 */
1080
+ break;
1081
+ }
1082
+ case 1: { /* only upper limit */
1083
+ int u = luaL_checkint(L, 1);
1084
+ luaL_argcheck(L, 1<=u, 1, "interval is empty");
1085
+ lua_pushnumber(L, floor(r*u)+1); /* int between 1 and `u' */
1086
+ break;
1087
+ }
1088
+ case 2: { /* lower and upper limits */
1089
+ int l = luaL_checkint(L, 1);
1090
+ int u = luaL_checkint(L, 2);
1091
+ luaL_argcheck(L, l<=u, 2, "interval is empty");
1092
+ lua_pushnumber(L, floor(r*(u-l+1))+l); /* int between `l' and `u' */
1093
+ break;
1094
+ }
1095
+ default: return luaL_error(L, "wrong number of arguments");
1096
+ }
1097
+ return 1;
1098
+ }
1099
+
1100
+ int rlite_math_randomseed (lua_State *L) {
1101
+ rliteSrand48(luaL_checkint(L, 1));
1102
+ return 0;
1103
+ }
1104
+
1105
+ /* ---------------------------------------------------------------------------
1106
+ * SCRIPT command for script environment introspection and control
1107
+ * ------------------------------------------------------------------------- */
1108
+
1109
+ void scriptCommand(rliteClient *c) {
1110
+ if (c->argc == 2 && !strcasecmp(c->argv[1],"flush")) {
1111
+ scriptingReset();
1112
+ c->reply = createStatusObject(RLITE_STR_OK);
1113
+ } else if (c->argc >= 2 && !strcasecmp(c->argv[1],"exists")) {
1114
+ int j;
1115
+
1116
+ c->reply = createArrayObject(c->argc - 2);
1117
+ for (j = 2; j < c->argc; j++) {
1118
+ c->reply->element[j - 2] = createLongLongObject(getScript(c, c->argv[j], NULL, NULL) == RL_OK ? 1 : 0);
1119
+ }
1120
+ } else if (c->argc == 3 && !strcasecmp(c->argv[1],"load")) {
1121
+ char sha[41];
1122
+
1123
+ sha1hex(sha,c->argv[2],c->argvlen[2]);
1124
+ setScript(c, c->argv[2], c->argvlen[2]);
1125
+ c->reply = createStringObject(sha,40);
1126
+ } else if (c->argc == 2 && !strcasecmp(c->argv[1],"kill")) {
1127
+ if (lua_caller == NULL) {
1128
+ c->reply = createCStringObject("NOTBUSY No scripts in execution right now.\r\n");
1129
+ } else if (lua_write_dirty) {
1130
+ c->reply = createCStringObject("UNKILLABLE Sorry the script already executed write commands against the dataset. You can either wait the script termination or kill the server in a hard way using the SHUTDOWN NOSAVE command.\r\n");
1131
+ } else {
1132
+ lua_kill = 1;
1133
+ c->reply = createStatusObject(RLITE_STR_OK);
1134
+ }
1135
+ } else {
1136
+ c->reply = createErrorObject("ERR Unknown SCRIPT subcommand or wrong # of args.");
1137
+ }
1138
+ }