1 /*************************************************************************************************
2  * The scripting extension
3  *                                                               Copyright (C) 2009-2012 FAL Labs
4  * This file is part of Kyoto Tycoon.
5  * This program is free software: you can redistribute it and/or modify it under the terms of
6  * the GNU General Public License as published by the Free Software Foundation, either version
7  * 3 of the License, or any later version.
8  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10  * See the GNU General Public License for more details.
11  * You should have received a copy of the GNU General Public License along with this program.
12  * If not, see <http://www.gnu.org/licenses/>.
13  *************************************************************************************************/
14 
15 
16 #include "myscript.h"
17 #include "myconf.h"
18 
19 
20 #if _KT_LUA
21 
22 
23 extern "C" {
24 #include <lua.h>
25 #include <lualib.h>
26 #include <lauxlib.h>
27 }
28 
29 
30 /* precedent type declaration */
31 struct ScriptProcessorCore;
32 class StringBuilder;
33 struct SoftCursor;
34 struct SoftDB;
35 class SoftVisitor;
36 class SoftFileProcessor;
37 class SoftMapReduce;
38 typedef std::map<std::string, std::string> StringMap;
39 typedef std::vector<std::string> StringVector;
40 
41 
42 /* function prototypes */
43 static void reporterror(ScriptProcessorCore* core, const char* name);
44 static void throwinvarg(lua_State* lua, const char* func);
45 static void setfielduint(lua_State* lua, const char* name, uint32_t num);
46 static void setfieldstr(lua_State* lua, const char* name, const char* str);
47 static void setfieldfunc(lua_State* lua, const char* name, lua_CFunction func);
48 static void setfieldvalue(lua_State* lua, const char* name, int32_t index);
49 static void define_module(lua_State* lua);
50 static int kt_atoi(lua_State* lua);
51 static int kt_atoix(lua_State* lua);
52 static int kt_atof(lua_State* lua);
53 static int kt_hash_murmur(lua_State* lua);
54 static int kt_hash_fnv(lua_State* lua);
55 static int kt_levdist(lua_State* lua);
56 static int kt_time(lua_State* lua);
57 static int kt_sleep(lua_State* lua);
58 static int kt_pack(lua_State* lua);
59 static int kt_unpack(lua_State *lua);
60 static int kt_split(lua_State *lua);
61 static int kt_codec(lua_State *lua);
62 static int kt_bit(lua_State *lua);
63 static int kt_strstr(lua_State *lua);
64 static int kt_strfwm(lua_State *lua);
65 static int kt_strbwm(lua_State *lua);
66 static int kt_regex(lua_State *lua);
67 static int kt_arraydump(lua_State *lua);
68 static int kt_arrayload(lua_State *lua);
69 static int kt_mapdump(lua_State *lua);
70 static int kt_mapload(lua_State *lua);
71 static void define_err(lua_State* lua);
72 static int err_new(lua_State* lua);
73 static int err_tostring(lua_State* lua);
74 static int err_set(lua_State* lua);
75 static int err_code(lua_State* lua);
76 static int err_name(lua_State* lua);
77 static int err_message(lua_State* lua);
78 static void define_vis(lua_State* lua);
79 static int vis_new(lua_State* lua);
80 static int vis_visit_full(lua_State* lua);
81 static int vis_visit_empty(lua_State* lua);
82 static void define_fproc(lua_State* lua);
83 static int fproc_new(lua_State* lua);
84 static int fproc_process(lua_State* lua);
85 static void define_cur(lua_State* lua);
86 static int cur_new(lua_State* lua);
87 static int cur_gc(lua_State* lua);
88 static int cur_tostring(lua_State* lua);
89 static int cur_call(lua_State* lua);
90 static int cur_disable(lua_State* lua);
91 static int cur_accept(lua_State* lua);
92 static int cur_set_value(lua_State* lua);
93 static int cur_remove(lua_State* lua);
94 static int cur_get_key(lua_State* lua);
95 static int cur_get_value(lua_State* lua);
96 static int cur_get(lua_State* lua);
97 static int cur_seize(lua_State* lua);
98 static int cur_jump(lua_State* lua);
99 static int cur_jump_back(lua_State* lua);
100 static int cur_step(lua_State* lua);
101 static int cur_step_back(lua_State* lua);
102 static int cur_db(lua_State* lua);
103 static int cur_error(lua_State* lua);
104 static void define_db(lua_State* lua);
105 static int db_new(lua_State* lua);
106 static int db_gc(lua_State* lua);
107 static int db_tostring(lua_State* lua);
108 static int db_index(lua_State* lua);
109 static int db_newindex(lua_State* lua);
110 static int db_new_ptr(lua_State* lua);
111 static int db_delete_ptr(lua_State* lua);
112 static int db_process(lua_State* lua);
113 static int db_error(lua_State* lua);
114 static int db_open(lua_State* lua);
115 static int db_close(lua_State* lua);
116 static int db_accept(lua_State* lua);
117 static int db_accept_bulk(lua_State* lua);
118 static int db_iterate(lua_State* lua);
119 static int db_set(lua_State* lua);
120 static int db_add(lua_State* lua);
121 static int db_replace(lua_State* lua);
122 static int db_append(lua_State* lua);
123 static int db_increment(lua_State* lua);
124 static int db_increment_double(lua_State* lua);
125 static int db_cas(lua_State* lua);
126 static int db_remove(lua_State* lua);
127 static int db_get(lua_State* lua);
128 static int db_check(lua_State* lua);
129 static int db_seize(lua_State* lua);
130 static int db_set_bulk(lua_State* lua);
131 static int db_remove_bulk(lua_State* lua);
132 static int db_get_bulk(lua_State* lua);
133 static int db_clear(lua_State* lua);
134 static int db_synchronize(lua_State* lua);
135 static int db_occupy(lua_State* lua);
136 static int db_copy(lua_State* lua);
137 static int db_begin_transaction(lua_State* lua);
138 static int db_end_transaction(lua_State* lua);
139 static int db_transaction(lua_State* lua);
140 static int db_dump_snapshot(lua_State* lua);
141 static int db_load_snapshot(lua_State* lua);
142 static int db_count(lua_State* lua);
143 static int db_size(lua_State* lua);
144 static int db_path(lua_State* lua);
145 static int db_status(lua_State* lua);
146 static int db_match_prefix(lua_State* lua);
147 static int db_match_regex(lua_State* lua);
148 static int db_match_similar(lua_State* lua);
149 static int db_merge(lua_State* lua);
150 static int db_mapreduce(lua_State* lua);
151 static int db_mapreduce_emit(lua_State* lua);
152 static int db_mapreduce_iter(lua_State* lua);
153 static int db_cursor(lua_State* lua);
154 static int db_cursor_process(lua_State* lua);
155 static int db_pairs(lua_State* lua);
156 static int serv_log(lua_State* lua);
157 
158 
159 /**
160  * ScriptProcessor internal.
161  */
162 struct ScriptProcessorCore {
163   std::string path;
164   int32_t thid;
165   kt::RPCServer* serv;
166   kt::TimedDB* dbs;
167   int32_t dbnum;
168   const std::map<std::string, int32_t>* dbmap;
169   lua_State *lua;
170 };
171 
172 
173 /**
174  * Wrapper of a string.
175  */
176 class StringBuilder {
177  public:
StringBuilder(lua_State * lua,int32_t index)178   StringBuilder(lua_State* lua, int32_t index) : str_(), ok_(false) {
179     char nbuf[kc::NUMBUFSIZ];
180     const char* ptr = NULL;
181     size_t size = 0;
182     switch (lua_type(lua, index)) {
183       case LUA_TNUMBER: {
184         double num = lua_tonumber(lua, index);
185         if (num == std::floor(num)) {
186           std::snprintf(nbuf, sizeof(nbuf) - 1, "%lld", (long long)num);
187         } else {
188           std::snprintf(nbuf, sizeof(nbuf) - 1, "%f", num);
189         }
190         nbuf[sizeof(nbuf)-1] = '\0';
191         ptr = nbuf;
192         size = std::strlen(ptr);
193         break;
194       }
195       case LUA_TBOOLEAN: {
196         ptr = lua_toboolean(lua, index) ? "true" : "false";
197         size = std::strlen(ptr);
198         break;
199       }
200       case LUA_TSTRING: {
201         ptr = lua_tolstring(lua, index, &size);
202         break;
203       }
204     }
205     if (ptr) {
206       str_.append(ptr, size);
207       ok_ = true;
208     }
209   }
str()210   const std::string& str() {
211     return str_;
212   }
ok()213   bool ok() {
214     return ok_;
215   }
216  private:
217   std::string str_;
218   bool ok_;
219 };
220 
221 
222 /**
223  * Default constructor.
224  */
ScriptProcessor()225 ScriptProcessor::ScriptProcessor() {
226   _assert_(true);
227   ScriptProcessorCore* core = new ScriptProcessorCore;
228   core->thid = 0;
229   core->serv = NULL;
230   core->dbs = NULL;
231   core->dbnum = 0;
232   core->dbmap = NULL;
233   core->lua = NULL;
234   opq_ = core;
235 }
236 
237 
238 /**
239  * Destructor.
240  */
~ScriptProcessor()241 ScriptProcessor::~ScriptProcessor() {
242   _assert_(true);
243   ScriptProcessorCore* core = (ScriptProcessorCore*)opq_;
244   lua_State* lua = core->lua;
245   if (lua) lua_close(lua);
246   delete core;
247 }
248 
249 
250 /**
251  * Set domain-specific resources.
252  */
set_resources(int32_t thid,kt::RPCServer * serv,kt::TimedDB * dbs,int32_t dbnum,const std::map<std::string,int32_t> * dbmap)253 bool ScriptProcessor::set_resources(int32_t thid, kt::RPCServer* serv,
254                                     kt::TimedDB* dbs, int32_t dbnum,
255                                     const std::map<std::string, int32_t>* dbmap) {
256   _assert_(serv && dbs && dbnum >= 0 && dbmap);
257   ScriptProcessorCore* core = (ScriptProcessorCore*)opq_;
258   lua_State *lua = luaL_newstate();
259   if (!lua) return false;
260   luaL_openlibs(lua);
261   lua_settop(lua, 0);
262   lua_newtable(lua);
263   define_module(lua);
264   define_err(lua);
265   define_vis(lua);
266   define_fproc(lua);
267   define_cur(lua);
268   define_db(lua);
269   lua_setglobal(lua, "__kyototycoon__");
270   lua_getglobal(lua, "__kyototycoon__");
271   lua_pushlightuserdata(lua, serv);
272   lua_setfield(lua, -2, "__serv__");
273   setfieldstr(lua, "VERSION", kt::VERSION);
274   setfielduint(lua, "RVSUCCESS", kt::RPCClient::RVSUCCESS);
275   setfielduint(lua, "RVENOIMPL", kt::RPCClient::RVENOIMPL);
276   setfielduint(lua, "RVEINVALID", kt::RPCClient::RVEINVALID);
277   setfielduint(lua, "RVELOGIC", kt::RPCClient::RVELOGIC);
278   setfielduint(lua, "RVEINTERNAL", kt::RPCClient::RVEINTERNAL);
279   setfielduint(lua, "thid", thid);
280   lua_getfield(lua, -1, "DB");
281   lua_newtable(lua);
282   for (int32_t i = 0; i < dbnum; i++) {
283     lua_getfield(lua, -2, "new");
284     lua_pushvalue(lua, -3);
285     lua_pushlightuserdata(lua, dbs + i);
286     if (lua_pcall(lua, 2, 1, 0) != 0) {
287       lua_close(lua);
288       return false;
289     }
290     lua_rawseti(lua, -2, i + 1);
291   }
292   lua_rawgeti(lua, -1, 1);
293   lua_setfield(lua, -4, "db");
294   std::map<std::string, int32_t>::const_iterator it = dbmap->begin();
295   std::map<std::string, int32_t>::const_iterator itend = dbmap->end();
296   while (it != itend) {
297     lua_rawgeti(lua, -1, it->second + 1);
298     lua_setfield(lua, -2, it->first.c_str());
299     ++it;
300   }
301   lua_setfield(lua, -3, "dbs");
302   lua_pop(lua, 1);
303   setfieldfunc(lua, "log", serv_log);
304   lua_settop(lua, 0);
305   core->thid = thid;
306   core->serv = serv;
307   core->dbs = dbs;
308   core->dbnum = dbnum;
309   core->dbmap = dbmap;
310   core->lua = lua;
311   return true;
312 }
313 
314 
315 /**
316  * Load a script file.
317  */
load(const std::string & path)318 bool ScriptProcessor::load(const std::string& path) {
319   _assert_(true);
320   ScriptProcessorCore* core = (ScriptProcessorCore*)opq_;
321   core->path = path;
322   lua_State* lua = core->lua;
323   int64_t size;
324   char* script = kc::File::read_file(path, &size);
325   if (!script) return false;
326   bool err = false;
327   lua_settop(lua, 0);
328   if (luaL_loadstring(lua, script) != 0 || lua_pcall(lua, 0, 0, 0) != 0) {
329     reporterror(core, "(init)");
330     err = true;
331   }
332   delete[] script;
333   return !err;
334 }
335 
336 
337 /**
338  * Clear the internal state.
339  */
clear()340 void ScriptProcessor::clear() {
341   _assert_(true);
342   ScriptProcessorCore* core = (ScriptProcessorCore*)opq_;
343   lua_State* lua = core->lua;
344   if (lua) lua_close(lua);
345   core->thid = 0;
346   core->serv = NULL;
347   core->dbs = NULL;
348   core->dbnum = 0;
349   core->dbmap = NULL;
350   core->lua = NULL;
351 }
352 
353 
354 /**
355  * Call a procedure.
356  */
call(const std::string & name,const std::map<std::string,std::string> & inmap,std::map<std::string,std::string> & outmap)357 kt::RPCClient::ReturnValue ScriptProcessor::call(const std::string& name,
358                                                  const std::map<std::string, std::string>& inmap,
359                                                  std::map<std::string, std::string>& outmap) {
360   _assert_(true);
361   ScriptProcessorCore* core = (ScriptProcessorCore*)opq_;
362   lua_State* lua = core->lua;
363   lua_settop(lua, 0);
364   lua_newtable(lua);
365   lua_getglobal(lua, name.c_str());
366   if (!lua_isfunction(lua, -1)) {
367     lua_settop(lua, 0);
368     return kt::RPCClient::RVENOIMPL;
369   }
370   lua_newtable(lua);
371   std::map<std::string, std::string>::const_iterator it = inmap.begin();
372   std::map<std::string, std::string>::const_iterator itend = inmap.end();
373   while (it != itend) {
374     lua_pushlstring(lua, it->first.data(), it->first.size());
375     lua_pushlstring(lua, it->second.data(), it->second.size());
376     lua_settable(lua, -3);
377     ++it;
378   }
379   lua_pushvalue(lua, 1);
380   kt::RPCClient::ReturnValue rv;
381   if (lua_pcall(lua, 2, 1, 0) == 0) {
382     lua_pushnil(lua);
383     while (lua_next(lua, 1) != 0) {
384       StringBuilder key(lua, -2);
385       StringBuilder value(lua, -1);
386       if (key.ok() && value.ok()) outmap[key.str()] = value.str();
387       lua_pop(lua, 1);
388     }
389     rv = (kt::RPCClient::ReturnValue)lua_tointeger(lua, -1);
390   } else {
391     reporterror(core, name.c_str());
392     rv = kt::RPCClient::RVEINTERNAL;
393   }
394   lua_settop(lua, 0);
395   return rv;
396 }
397 
398 
399 /**
400  * Burrow of cursors no longer in use.
401  */
402 class CursorBurrow {
403  private:
404   typedef std::vector<kt::TimedDB::Cursor*> CursorList;
405  public:
CursorBurrow()406   explicit CursorBurrow() : lock_(), dcurs_() {}
~CursorBurrow()407   ~CursorBurrow() {
408     sweap();
409   }
sweap()410   void sweap() {
411     kc::ScopedSpinLock lock(&lock_);
412     if (dcurs_.size() > 0) {
413       CursorList::iterator dit = dcurs_.begin();
414       CursorList::iterator ditend = dcurs_.end();
415       while (dit != ditend) {
416         kt::TimedDB::Cursor* cur = *dit;
417         delete cur;
418         ++dit;
419       }
420       dcurs_.clear();
421     }
422   }
deposit(kt::TimedDB::Cursor * cur)423   void deposit(kt::TimedDB::Cursor* cur) {
424     kc::ScopedSpinLock lock(&lock_);
425     dcurs_.push_back(cur);
426   }
427  private:
428   kc::SpinLock lock_;
429   CursorList dcurs_;
430 } g_curbur;
431 
432 
433 /**
434  * Wrapper of a database.
435  */
436 struct SoftCursor {
437   kt::TimedDB::Cursor* cur;
438 };
439 
440 
441 /**
442  * Wrapper of a database.
443  */
444 struct SoftDB {
445   kt::TimedDB* db;
446   bool light;
447 };
448 
449 
450 /**
451  * Wrapper of a visitor.
452  */
453 class SoftVisitor : public kt::TimedDB::Visitor {
454  public:
SoftVisitor(lua_State * lua,bool writable)455   explicit SoftVisitor(lua_State* lua, bool writable) :
456       lua_(lua), writable_(writable), top_(0) {
457     top_ = lua_gettop(lua_);
458   }
459  private:
visit_full(const char * kbuf,size_t ksiz,const char * vbuf,size_t vsiz,size_t * sp,int64_t * xtp)460   const char* visit_full(const char* kbuf, size_t ksiz,
461                          const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) {
462     lua_settop(lua_, top_);
463     int32_t argc;
464     if (lua_istable(lua_, -1)) {
465       lua_getfield(lua_, -1, "visit_full");
466       if (!lua_isfunction(lua_, -1)) return NOP;
467       lua_pushvalue(lua_, -2);
468       lua_pushlstring(lua_, kbuf, ksiz);
469       lua_pushlstring(lua_, vbuf, vsiz);
470       lua_pushnumber(lua_, *xtp < kt::TimedDB::XTMAX ? *xtp : kt::TimedDB::XTMAX);
471       argc = 4;
472     } else {
473       if (!lua_isfunction(lua_, -1)) return NOP;
474       lua_pushvalue(lua_, -1);
475       lua_pushlstring(lua_, kbuf, ksiz);
476       lua_pushlstring(lua_, vbuf, vsiz);
477       lua_pushnumber(lua_, *xtp < kt::TimedDB::XTMAX ? *xtp : kt::TimedDB::XTMAX);
478       argc = 3;
479     }
480     const char* rv = NOP;
481     if (lua_pcall(lua_, argc, 2, 0) == 0) {
482       if (lua_islightuserdata(lua_, -2)) {
483         const char* trv = (const char*)lua_touserdata(lua_, -2);
484         if (trv == kt::TimedDB::Visitor::REMOVE) rv = kt::TimedDB::Visitor::REMOVE;
485       } else {
486         size_t rsiz;
487         const char* rbuf = lua_tolstring(lua_, -2, &rsiz);
488         if (rbuf) {
489           rv = rbuf;
490           *sp = rsiz;
491         }
492         *xtp = lua_isnumber(lua_, -1) ? lua_tonumber(lua_, -1) : -*xtp;
493       }
494     }
495     if (!writable_) rv = NULL;
496     return rv;
497   }
visit_empty(const char * kbuf,size_t ksiz,size_t * sp,int64_t * xtp)498   const char* visit_empty(const char* kbuf, size_t ksiz, size_t* sp, int64_t* xtp) {
499     lua_settop(lua_, top_);
500     int32_t argc;
501     if (lua_istable(lua_, -1)) {
502       lua_getfield(lua_, -1, "visit_empty");
503       if (!lua_isfunction(lua_, -1)) return NOP;
504       lua_pushvalue(lua_, -2);
505       lua_pushlstring(lua_, kbuf, ksiz);
506       argc = 2;
507     } else {
508       if (!lua_isfunction(lua_, -1)) return NOP;
509       lua_pushvalue(lua_, -1);
510       lua_pushlstring(lua_, kbuf, ksiz);
511       lua_pushnil(lua_);
512       argc = 2;
513     }
514     const char* rv = NOP;
515     if (lua_pcall(lua_, argc, 2, 0) == 0) {
516       if (lua_islightuserdata(lua_, -1)) {
517         const char* trv = (const char*)lua_touserdata(lua_, -1);
518         if (trv == kt::TimedDB::Visitor::REMOVE) rv = kt::TimedDB::Visitor::REMOVE;
519       } else {
520         size_t rsiz;
521         const char* rbuf = lua_tolstring(lua_, -2, &rsiz);
522         if (rbuf) {
523           rv = rbuf;
524           *sp = rsiz;
525         }
526         *xtp = lua_isnumber(lua_, -1) ? lua_tonumber(lua_, -1) : kc::INT64MAX;
527       }
528     }
529     if (!writable_) rv = NULL;
530     return rv;
531   }
visit_before()532   void visit_before() {
533     lua_settop(lua_, top_);
534     if (!lua_istable(lua_, -1)) return;
535     lua_getfield(lua_, -1, "visit_before");
536     if (!lua_isfunction(lua_, -1)) return;
537     lua_pushvalue(lua_, -2);
538     lua_pcall(lua_, 1, 0, 0);
539   }
visit_after()540   void visit_after() {
541     lua_settop(lua_, top_);
542     if (!lua_istable(lua_, -1)) return;
543     lua_getfield(lua_, -1, "visit_after");
544     if (!lua_isfunction(lua_, -1)) return;
545     lua_pushvalue(lua_, -2);
546     lua_pcall(lua_, 1, 0, 0);
547   }
548   lua_State* lua_;
549   bool writable_;
550   int32_t top_;
551 };
552 
553 
554 /**
555  * Wrapper of a file processor.
556  */
557 class SoftFileProcessor : public kc::BasicDB::FileProcessor {
558  public:
SoftFileProcessor(lua_State * lua)559   explicit SoftFileProcessor(lua_State* lua) : lua_(lua) {}
560  private:
process(const std::string & path,int64_t count,int64_t size)561   bool process(const std::string& path, int64_t count, int64_t size) {
562     int32_t argc;
563     if (lua_istable(lua_, -1)) {
564       lua_getfield(lua_, -1, "process");
565       lua_pushvalue(lua_, -2);
566       lua_pushstring(lua_, path.c_str());
567       lua_pushnumber(lua_, count);
568       lua_pushnumber(lua_, size);
569       argc = 4;
570     } else {
571       lua_pushvalue(lua_, -1);
572       lua_pushstring(lua_, path.c_str());
573       lua_pushnumber(lua_, count);
574       lua_pushnumber(lua_, size);
575       argc = 3;
576     }
577     bool rv = false;
578     if (lua_pcall(lua_, argc, 1, 0) == 0) rv = lua_toboolean(lua_, -1);
579     return rv;
580   }
581   lua_State* lua_;
582 };
583 
584 
585 class SoftMapReduce : public kt::MapReduce {
586  public:
SoftMapReduce(lua_State * lua,int32_t logidx,int32_t procidx)587   SoftMapReduce(lua_State* lua, int32_t logidx, int32_t procidx) :
588       lua_(lua), logidx_(logidx), procidx_(procidx) {}
map(const char * kbuf,size_t ksiz,const char * vbuf,size_t vsiz)589   bool map(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz) {
590     int32_t top = lua_gettop(lua_);
591     lua_pushlightuserdata(lua_, (void*)this);
592     lua_setglobal(lua_, "__mr_self");
593     lua_pushvalue(lua_, 2);
594     lua_pushlstring(lua_, kbuf, ksiz);
595     lua_pushlstring(lua_, vbuf, vsiz);
596     lua_pushcfunction(lua_, db_mapreduce_emit);
597     bool rv;
598     if (lua_pcall(lua_, 3, 1, 0) == 0) {
599       rv = lua_toboolean(lua_, -1);
600     } else {
601       rv = false;
602     }
603     lua_settop(lua_, top);
604     return rv;
605   }
reduce(const char * kbuf,size_t ksiz,ValueIterator * iter)606   bool reduce(const char* kbuf, size_t ksiz, ValueIterator* iter) {
607     int32_t top = lua_gettop(lua_);
608     lua_pushlightuserdata(lua_, (void*)iter);
609     lua_setglobal(lua_, "__mr_iter");
610     lua_pushvalue(lua_, 3);
611     lua_pushlstring(lua_, kbuf, ksiz);
612     lua_pushcfunction(lua_, db_mapreduce_iter);
613     bool rv;
614     if (lua_pcall(lua_, 2, 1, 0) == 0) {
615       rv = lua_toboolean(lua_, -1);
616     } else {
617       rv = false;
618     }
619     lua_settop(lua_, top);
620     return rv;
621   }
log(const char * name,const char * message)622   bool log(const char* name, const char* message) {
623     if (logidx_ < 1) return true;
624     int32_t top = lua_gettop(lua_);
625     lua_pushvalue(lua_, logidx_);
626     lua_pushstring(lua_, name);
627     lua_pushstring(lua_, message);
628     bool rv;
629     if (lua_pcall(lua_, 2, 1, 0) == 0) {
630       rv = lua_toboolean(lua_, -1);
631     } else {
632       rv = false;
633     }
634     lua_settop(lua_, top);
635     return rv;
636   }
preprocess()637   bool preprocess() {
638     if (procidx_ < 1) return true;
639     int32_t top = lua_gettop(lua_);
640     lua_pushlightuserdata(lua_, (void*)this);
641     lua_setglobal(lua_, "__mr_self");
642     lua_pushvalue(lua_, procidx_);
643     lua_pushcfunction(lua_, db_mapreduce_emit);
644     bool rv;
645     if (lua_pcall(lua_, 1, 1, 0) == 0) {
646       rv = lua_toboolean(lua_, -1);
647     } else {
648       rv = false;
649     }
650     lua_settop(lua_, top);
651     return rv;
652   }
midprocess()653   bool midprocess() {
654     return preprocess();
655   }
postprocess()656   bool postprocess() {
657     if (procidx_ < 1) return true;
658     int32_t top = lua_gettop(lua_);
659     lua_pushlightuserdata(lua_, (void*)this);
660     lua_setglobal(lua_, "__mr_self");
661     lua_pushvalue(lua_, procidx_);
662     bool rv;
663     if (lua_pcall(lua_, 0, 1, 0) == 0) {
664       rv = lua_toboolean(lua_, -1);
665     } else {
666       rv = false;
667     }
668     lua_settop(lua_, top);
669     return rv;
670   }
emit_public(const char * kbuf,size_t ksiz,const char * vbuf,size_t vsiz)671   bool emit_public(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz) {
672     return emit(kbuf, ksiz, vbuf, vsiz);
673   }
674  private:
675   lua_State* lua_;
676   int32_t logidx_;
677   int32_t procidx_;
678 };
679 
680 
681 /**
682  * Report error information.
683  */
reporterror(ScriptProcessorCore * core,const char * name)684 static void reporterror(ScriptProcessorCore* core, const char* name) {
685   lua_State* lua = core->lua;
686   int argc = lua_gettop(lua);
687   core->serv->log(kt::RPCServer::Logger::ERROR, "[SCRIPT]: %s: %s",
688                   name, argc > 0 ? lua_tostring(lua, argc) : "unknown");
689 }
690 
691 
692 /**
693  * Throw the invalid argument error.
694  */
throwinvarg(lua_State * lua,const char * func)695 static void throwinvarg(lua_State* lua, const char* func) {
696   char msg[256];
697   size_t len = std::sprintf(msg, "%s: invalid arguments", func);
698   lua_pushlstring(lua, msg, len);
699   lua_error(lua);
700 }
701 
702 
703 /**
704  * Set a field of unsigned integer.
705  */
setfielduint(lua_State * lua,const char * name,uint32_t num)706 static void setfielduint(lua_State* lua, const char* name, uint32_t num) {
707   lua_pushinteger(lua, num);
708   lua_setfield(lua, -2, name);
709 }
710 
711 
712 /**
713  * Set a field of string.
714  */
setfieldstr(lua_State * lua,const char * name,const char * str)715 static void setfieldstr(lua_State* lua, const char* name, const char* str) {
716   lua_pushstring(lua, str);
717   lua_setfield(lua, -2, name);
718 }
719 
720 
721 /**
722  * Set a field of function.
723  */
setfieldfunc(lua_State * lua,const char * name,lua_CFunction func)724 static void setfieldfunc(lua_State* lua, const char* name, lua_CFunction func) {
725   lua_pushcfunction(lua, func);
726   lua_setfield(lua, -2, name);
727 }
728 
729 
730 /**
731  * Set a field of stacked value.
732  */
setfieldvalue(lua_State * lua,const char * name,int32_t index)733 static void setfieldvalue(lua_State* lua, const char* name, int32_t index) {
734   lua_pushvalue(lua, index);
735   lua_setfield(lua, -2, name);
736 }
737 
738 
739 /**
740  * Define objects of the module.
741  */
define_module(lua_State * lua)742 static void define_module(lua_State* lua) {
743   setfieldfunc(lua, "atoi", kt_atoi);
744   setfieldfunc(lua, "atoix", kt_atoix);
745   setfieldfunc(lua, "atof", kt_atof);
746   setfieldfunc(lua, "hash_murmur", kt_hash_murmur);
747   setfieldfunc(lua, "hash_fnv", kt_hash_fnv);
748   setfieldfunc(lua, "levdist", kt_levdist);
749   setfieldfunc(lua, "time", kt_time);
750   setfieldfunc(lua, "sleep", kt_sleep);
751   setfieldfunc(lua, "pack", kt_pack);
752   setfieldfunc(lua, "unpack", kt_unpack);
753   setfieldfunc(lua, "split", kt_split);
754   setfieldfunc(lua, "codec", kt_codec);
755   setfieldfunc(lua, "bit", kt_bit);
756   setfieldfunc(lua, "strstr", kt_strstr);
757   setfieldfunc(lua, "strfwm", kt_strfwm);
758   setfieldfunc(lua, "strbwm", kt_strbwm);
759   setfieldfunc(lua, "regex", kt_regex);
760   setfieldfunc(lua, "arraydump", kt_arraydump);
761   setfieldfunc(lua, "arrayload", kt_arrayload);
762   setfieldfunc(lua, "mapdump", kt_mapdump);
763   setfieldfunc(lua, "mapload", kt_mapload);
764 }
765 
766 
767 /**
768  * Implementation of atoi.
769  */
kt_atoi(lua_State * lua)770 static int kt_atoi(lua_State* lua) {
771   int32_t argc = lua_gettop(lua);
772   if (argc != 1) throwinvarg(lua, __KCFUNC__);
773   const char* str = lua_tostring(lua, 1);
774   if (!str) return 0;
775   lua_pushnumber(lua, kc::atoi(str));
776   return 1;
777 }
778 
779 
780 /**
781  * Implementation of atoix.
782  */
kt_atoix(lua_State * lua)783 static int kt_atoix(lua_State* lua) {
784   int32_t argc = lua_gettop(lua);
785   if (argc != 1) throwinvarg(lua, __KCFUNC__);
786   const char* str = lua_tostring(lua, 1);
787   if (!str) return 0;
788   lua_pushnumber(lua, kc::atoix(str));
789   return 1;
790 }
791 
792 
793 /**
794  * Implementation of atof.
795  */
kt_atof(lua_State * lua)796 static int kt_atof(lua_State* lua) {
797   int32_t argc = lua_gettop(lua);
798   if (argc != 1) throwinvarg(lua, __KCFUNC__);
799   const char* str = lua_tostring(lua, 1);
800   if (!str) return 0;
801   lua_pushnumber(lua, kc::atof(str));
802   return 1;
803 }
804 
805 
806 /**
807  * Implementation of hash_murmur.
808  */
kt_hash_murmur(lua_State * lua)809 static int kt_hash_murmur(lua_State* lua) {
810   int32_t argc = lua_gettop(lua);
811   if (argc != 1) throwinvarg(lua, __KCFUNC__);
812   size_t len;
813   const char* str = lua_tolstring(lua, 1, &len);
814   if (!str) return 0;
815   lua_pushinteger(lua, kc::hashmurmur(str, len) & ((1ULL << 48) - 1));
816   return 1;
817 }
818 
819 
820 /**
821  * Implementation of hash_fnv.
822  */
kt_hash_fnv(lua_State * lua)823 static int kt_hash_fnv(lua_State* lua) {
824   int32_t argc = lua_gettop(lua);
825   if (argc != 1) throwinvarg(lua, __KCFUNC__);
826   size_t len;
827   const char* str = lua_tolstring(lua, 1, &len);
828   if (!str) return 0;
829   lua_pushinteger(lua, kc::hashfnv(str, len) & ((1ULL << 48) - 1));
830   return 1;
831 }
832 
833 
834 /**
835  * Implementation of levdist.
836  */
kt_levdist(lua_State * lua)837 static int kt_levdist(lua_State* lua) {
838   int32_t argc = lua_gettop(lua);
839   if (argc < 2) throwinvarg(lua, __KCFUNC__);
840   size_t asiz;
841   const char* abuf = lua_tolstring(lua, 1, &asiz);
842   size_t bsiz;
843   const char* bbuf = lua_tolstring(lua, 2, &bsiz);
844   if (!abuf || !bbuf) throwinvarg(lua, __KCFUNC__);
845   bool utf = argc > 2 ? lua_toboolean(lua, 3) : false;
846   size_t dist;
847   if (utf) {
848     uint32_t astack[128];
849     uint32_t* aary = asiz > sizeof(astack) / sizeof(*astack) ? new uint32_t[asiz] : astack;
850     size_t anum;
851     kc::strutftoucs(abuf, asiz, aary, &anum);
852     uint32_t bstack[128];
853     uint32_t* bary = bsiz > sizeof(bstack) / sizeof(*bstack) ? new uint32_t[bsiz] : bstack;
854     size_t bnum;
855     kc::strutftoucs(bbuf, bsiz, bary, &bnum);
856     dist = kc::strucsdist(aary, anum, bary, bnum);
857     if (bary != bstack) delete[] bary;
858     if (aary != astack) delete[] aary;
859   } else {
860     dist = kc::memdist(abuf, asiz, bbuf, bsiz);
861   }
862   lua_pushinteger(lua, dist);
863   return 1;
864 }
865 
866 
867 /**
868  * Implementation of hash_fnv.
869  */
kt_time(lua_State * lua)870 static int kt_time(lua_State* lua) {
871   int32_t argc = lua_gettop(lua);
872   if (argc != 0) throwinvarg(lua, __KCFUNC__);
873   lua_pushnumber(lua, kc::time());
874   return 1;
875 }
876 
877 
878 /**
879  * Implementation of sleep.
880  */
kt_sleep(lua_State * lua)881 static int kt_sleep(lua_State* lua) {
882   int32_t argc = lua_gettop(lua);
883   if (argc > 1) throwinvarg(lua, __KCFUNC__);
884   double sec = argc > 0 ? lua_tonumber(lua, 1) : 0;
885   if (sec > 0) {
886     kc::Thread::sleep(sec);
887   } else {
888     kc::Thread::yield();
889   }
890   return 0;
891 }
892 
893 
894 /**
895  * Implementation of pack.
896  */
kt_pack(lua_State * lua)897 static int kt_pack(lua_State* lua) {
898   int32_t argc = lua_gettop(lua);
899   if (argc < 1) throwinvarg(lua, __KCFUNC__);
900   const char* format = lua_tostring(lua, 1);
901   if (!format) throwinvarg(lua, __KCFUNC__);
902   lua_newtable(lua);
903   int32_t aidx = argc + 1;
904   int32_t eidx = 1;
905   for (int32_t i = 2; i <= argc; i++) {
906     size_t len;
907     switch (lua_type(lua, i)) {
908       case LUA_TNUMBER: case LUA_TSTRING: {
909         lua_pushvalue(lua, i);
910         lua_rawseti(lua, aidx, eidx++);
911         break;
912       }
913       case LUA_TTABLE: {
914         len = lua_objlen(lua, i);
915         for (size_t j = 1; j <= len; j++) {
916           lua_rawgeti(lua, i, j);
917           lua_rawseti(lua, aidx, eidx++);
918         }
919         break;
920       }
921       default: {
922         lua_pushnumber(lua, 0);
923         lua_rawseti(lua, aidx, eidx++);
924         break;
925       }
926     }
927   }
928   lua_replace(lua, 2);
929   lua_settop(lua, 2);
930   std::string xstr;
931   int32_t emax = eidx - 1;
932   eidx = 1;
933   while (*format != '\0') {
934     int32_t c = *format;
935     int32_t loop = 1;
936     if (format[1] == '*') {
937       loop = kc::INT32MAX;
938       format++;
939     } else if (format[1] >= '0' && format[1] <= '9') {
940       char* suffix;
941       loop = std::strtol(format + 1, &suffix, 10);
942       format = suffix - 1;
943     }
944     loop = loop < emax ? loop : emax;
945     int32_t end = eidx + loop - 1;
946     if (end > emax) end = emax;
947     while (eidx <= end) {
948       lua_rawgeti(lua, 2, eidx);
949       double num = lua_tonumber(lua, 3);
950       lua_pop(lua, 1);
951       uint8_t cnum;
952       uint16_t snum;
953       uint32_t inum;
954       uint64_t lnum;
955       double dnum;
956       float fnum;
957       uint64_t wnum;
958       char wbuf[kc::NUMBUFSIZ], *wp;
959       switch (c) {
960         case 'c': case 'C': {
961           cnum = num;
962           xstr.append((char*)&cnum, sizeof(cnum));
963           break;
964         }
965         case 's': case 'S': {
966           snum = num;
967           xstr.append((char*)&snum, sizeof(snum));
968           break;
969         }
970         case 'i': case 'I': {
971           inum = num;
972           xstr.append((char*)&inum, sizeof(inum));
973           break;
974         }
975         case 'l': case 'L': {
976           lnum = num;
977           xstr.append((char*)&lnum, sizeof(lnum));
978           break;
979         }
980         case 'f': case 'F': {
981           fnum = num;
982           xstr.append((char*)&fnum, sizeof(fnum));
983           break;
984         }
985         case 'd': case 'D': {
986           dnum = num;
987           xstr.append((char*)&dnum, sizeof(dnum));
988           break;
989         }
990         case 'n': {
991           snum = num;
992           snum = kc::hton16(snum);
993           xstr.append((char*)&snum, sizeof(snum));
994           break;
995         }
996         case 'N': {
997           inum = num;
998           inum = kc::hton32(inum);
999           xstr.append((char*)&inum, sizeof(inum));
1000           break;
1001         }
1002         case 'M': {
1003           lnum = num;
1004           lnum = kc::hton64(lnum);
1005           xstr.append((char*)&lnum, sizeof(lnum));
1006           break;
1007         }
1008         case 'w': case 'W': {
1009           wnum = num;
1010           wp = wbuf;
1011           if (wnum < (1ULL << 7)) {
1012             *(wp++) = wnum;
1013           } else if (wnum < (1ULL << 14)) {
1014             *(wp++) = (wnum >> 7) | 0x80;
1015             *(wp++) = wnum & 0x7f;
1016           } else if (wnum < (1ULL << 21)) {
1017             *(wp++) = (wnum >> 14) | 0x80;
1018             *(wp++) = ((wnum >> 7) & 0x7f) | 0x80;
1019             *(wp++) = wnum & 0x7f;
1020           } else if (wnum < (1ULL << 28)) {
1021             *(wp++) = (wnum >> 21) | 0x80;
1022             *(wp++) = ((wnum >> 14) & 0x7f) | 0x80;
1023             *(wp++) = ((wnum >> 7) & 0x7f) | 0x80;
1024             *(wp++) = wnum & 0x7f;
1025           } else if (wnum < (1ULL << 35)) {
1026             *(wp++) = (wnum >> 28) | 0x80;
1027             *(wp++) = ((wnum >> 21) & 0x7f) | 0x80;
1028             *(wp++) = ((wnum >> 14) & 0x7f) | 0x80;
1029             *(wp++) = ((wnum >> 7) & 0x7f) | 0x80;
1030             *(wp++) = wnum & 0x7f;
1031           } else if (wnum < (1ULL << 42)) {
1032             *(wp++) = (wnum >> 35) | 0x80;
1033             *(wp++) = ((wnum >> 28) & 0x7f) | 0x80;
1034             *(wp++) = ((wnum >> 21) & 0x7f) | 0x80;
1035             *(wp++) = ((wnum >> 14) & 0x7f) | 0x80;
1036             *(wp++) = ((wnum >> 7) & 0x7f) | 0x80;
1037             *(wp++) = wnum & 0x7f;
1038           } else if (wnum < (1ULL << 49)) {
1039             *(wp++) = (wnum >> 42) | 0x80;
1040             *(wp++) = ((wnum >> 35) & 0x7f) | 0x80;
1041             *(wp++) = ((wnum >> 28) & 0x7f) | 0x80;
1042             *(wp++) = ((wnum >> 21) & 0x7f) | 0x80;
1043             *(wp++) = ((wnum >> 14) & 0x7f) | 0x80;
1044             *(wp++) = ((wnum >> 7) & 0x7f) | 0x80;
1045             *(wp++) = wnum & 0x7f;
1046           } else if (wnum < (1ULL << 56)) {
1047             *(wp++) = (wnum >> 49) | 0x80;
1048             *(wp++) = ((wnum >> 42) & 0x7f) | 0x80;
1049             *(wp++) = ((wnum >> 35) & 0x7f) | 0x80;
1050             *(wp++) = ((wnum >> 28) & 0x7f) | 0x80;
1051             *(wp++) = ((wnum >> 21) & 0x7f) | 0x80;
1052             *(wp++) = ((wnum >> 14) & 0x7f) | 0x80;
1053             *(wp++) = ((wnum >> 7) & 0x7f) | 0x80;
1054             *(wp++) = wnum & 0x7f;
1055           } else {
1056             *(wp++) = (wnum >> 63) | 0x80;
1057             *(wp++) = ((wnum >> 49) & 0x7f) | 0x80;
1058             *(wp++) = ((wnum >> 42) & 0x7f) | 0x80;
1059             *(wp++) = ((wnum >> 35) & 0x7f) | 0x80;
1060             *(wp++) = ((wnum >> 28) & 0x7f) | 0x80;
1061             *(wp++) = ((wnum >> 21) & 0x7f) | 0x80;
1062             *(wp++) = ((wnum >> 14) & 0x7f) | 0x80;
1063             *(wp++) = ((wnum >> 7) & 0x7f) | 0x80;
1064             *(wp++) = wnum & 0x7f;
1065           }
1066           xstr.append(wbuf, wp - wbuf);
1067           break;
1068         }
1069       }
1070       eidx++;
1071     }
1072     format++;
1073     if (eidx > emax) break;
1074   }
1075   lua_pushlstring(lua, xstr.data(), xstr.size());
1076   return 1;
1077 }
1078 
1079 
1080 /**
1081  * Implementation of unpack.
1082  */
kt_unpack(lua_State * lua)1083 static int kt_unpack(lua_State *lua) {
1084   int32_t argc = lua_gettop(lua);
1085   if (argc != 2) throwinvarg(lua, __KCFUNC__);
1086   const char* format = lua_tostring(lua, 1);
1087   size_t size;
1088   const char* buf = lua_tolstring(lua, 2, &size);
1089   if (!format) throwinvarg(lua, __KCFUNC__);
1090   if (!buf) {
1091     buf = "";
1092     size = 0;
1093   }
1094   lua_newtable(lua);
1095   const char* rp = buf;
1096   int32_t eidx = 1;
1097   while (*format != '\0') {
1098     int32_t c = *format;
1099     int32_t loop = 1;
1100     if (format[1] == '*') {
1101       loop = kc::INT32MAX;
1102       format++;
1103     } else if (format[1] >= '0' && format[1] <= '9') {
1104       char* suffix;
1105       loop = strtol(format + 1, &suffix, 10);
1106       format = suffix - 1;
1107     }
1108     loop = loop < (int32_t)size ? loop : size;
1109     for (int32_t i = 0; i < loop && size > 0; i++) {
1110       uint8_t cnum;
1111       uint16_t snum;
1112       uint32_t inum;
1113       uint64_t lnum;
1114       float fnum;
1115       double dnum;
1116       uint64_t wnum;
1117       switch (c) {
1118         case 'c': {
1119           if (size >= sizeof(cnum)) {
1120             std::memcpy(&cnum, rp, sizeof(cnum));
1121             lua_pushnumber(lua, (int8_t)cnum);
1122             lua_rawseti(lua, 3, eidx++);
1123             rp += sizeof(cnum);
1124             size -= sizeof(cnum);
1125           } else {
1126             size = 0;
1127           }
1128           break;
1129         }
1130         case 'C': {
1131           if (size >= sizeof(cnum)) {
1132             std::memcpy(&cnum, rp, sizeof(cnum));
1133             lua_pushnumber(lua, (uint8_t)cnum);
1134             lua_rawseti(lua, 3, eidx++);
1135             rp += sizeof(cnum);
1136             size -= sizeof(cnum);
1137           } else {
1138             size = 0;
1139           }
1140           break;
1141         }
1142         case 's': {
1143           if (size >= sizeof(snum)) {
1144             std::memcpy(&snum, rp, sizeof(snum));
1145             lua_pushnumber(lua, (int16_t)snum);
1146             lua_rawseti(lua, 3, eidx++);
1147             rp += sizeof(snum);
1148             size -= sizeof(snum);
1149           } else {
1150             size = 0;
1151           }
1152           break;
1153         }
1154         case 'S': {
1155           if (size >= sizeof(snum)) {
1156             std::memcpy(&snum, rp, sizeof(snum));
1157             lua_pushnumber(lua, (uint16_t)snum);
1158             lua_rawseti(lua, 3, eidx++);
1159             rp += sizeof(snum);
1160             size -= sizeof(snum);
1161           } else {
1162             size = 0;
1163           }
1164           break;
1165         }
1166         case 'i': {
1167           if (size >= sizeof(inum)) {
1168             std::memcpy(&inum, rp, sizeof(inum));
1169             lua_pushnumber(lua, (int32_t)inum);
1170             lua_rawseti(lua, 3, eidx++);
1171             rp += sizeof(inum);
1172             size -= sizeof(inum);
1173           } else {
1174             size = 0;
1175           }
1176           break;
1177         }
1178         case 'I': {
1179           if (size >= sizeof(inum)) {
1180             std::memcpy(&inum, rp, sizeof(inum));
1181             lua_pushnumber(lua, (uint32_t)inum);
1182             lua_rawseti(lua, 3, eidx++);
1183             rp += sizeof(inum);
1184             size -= sizeof(inum);
1185           } else {
1186             size = 0;
1187           }
1188           break;
1189         }
1190         case 'l': {
1191           if (size >= sizeof(lnum)) {
1192             std::memcpy(&lnum, rp, sizeof(lnum));
1193             lua_pushnumber(lua, (int64_t)lnum);
1194             lua_rawseti(lua, 3, eidx++);
1195             rp += sizeof(lnum);
1196             size -= sizeof(lnum);
1197           } else {
1198             size = 0;
1199           }
1200           break;
1201         }
1202         case 'L': {
1203           if (size >= sizeof(lnum)) {
1204             std::memcpy(&lnum, rp, sizeof(lnum));
1205             lua_pushnumber(lua, (uint64_t)lnum);
1206             lua_rawseti(lua, 3, eidx++);
1207             rp += sizeof(lnum);
1208             size -= sizeof(lnum);
1209           } else {
1210             size = 0;
1211           }
1212           break;
1213         }
1214         case 'f': case 'F': {
1215           if (size >= sizeof(fnum)) {
1216             std::memcpy(&fnum, rp, sizeof(fnum));
1217             lua_pushnumber(lua, (float)fnum);
1218             lua_rawseti(lua, 3, eidx++);
1219             rp += sizeof(fnum);
1220             size -= sizeof(fnum);
1221           } else {
1222             size = 0;
1223           }
1224           break;
1225         }
1226         case 'd': case 'D': {
1227           if (size >= sizeof(dnum)) {
1228             std::memcpy(&dnum, rp, sizeof(dnum));
1229             lua_pushnumber(lua, (double)dnum);
1230             lua_rawseti(lua, 3, eidx++);
1231             rp += sizeof(dnum);
1232             size -= sizeof(dnum);
1233           } else {
1234             size = 0;
1235           }
1236           break;
1237         }
1238         case 'n': {
1239           if (size >= sizeof(snum)) {
1240             std::memcpy(&snum, rp, sizeof(snum));
1241             snum = kc::ntoh16(snum);
1242             lua_pushnumber(lua, (uint16_t)snum);
1243             lua_rawseti(lua, 3, eidx++);
1244             rp += sizeof(snum);
1245             size -= sizeof(snum);
1246           } else {
1247             size = 0;
1248           }
1249           break;
1250         }
1251         case 'N': {
1252           if (size >= sizeof(inum)) {
1253             std::memcpy(&inum, rp, sizeof(inum));
1254             inum = kc::ntoh32(inum);
1255             lua_pushnumber(lua, (uint32_t)inum);
1256             lua_rawseti(lua, 3, eidx++);
1257             rp += sizeof(inum);
1258             size -= sizeof(inum);
1259           } else {
1260             size = 0;
1261           }
1262           break;
1263         }
1264         case 'M': {
1265           if (size >= sizeof(lnum)) {
1266             std::memcpy(&lnum, rp, sizeof(lnum));
1267             lnum = kc::ntoh64(lnum);
1268             lua_pushnumber(lua, (uint64_t)lnum);
1269             lua_rawseti(lua, 3, eidx++);
1270             rp += sizeof(lnum);
1271             size -= sizeof(lnum);
1272           } else {
1273             size = 0;
1274           }
1275           break;
1276         }
1277         case 'w': case 'W': {
1278           wnum = 0;
1279           do {
1280             inum = *(unsigned char*)rp;
1281             wnum = wnum * 0x80 + (inum & 0x7f);
1282             rp++;
1283             size--;
1284           } while (inum >= 0x80 && size > 0);
1285           lua_pushnumber(lua, (uint64_t)wnum);
1286           lua_rawseti(lua, 3, eidx++);
1287           break;
1288         }
1289       }
1290     }
1291     format++;
1292     if (size < 1) break;
1293   }
1294   return 1;
1295 }
1296 
1297 
1298 /**
1299  * Implementation of split.
1300  */
kt_split(lua_State * lua)1301 static int kt_split(lua_State *lua) {
1302   int32_t argc = lua_gettop(lua);
1303   if (argc < 1) throwinvarg(lua, __KCFUNC__);
1304   size_t isiz;
1305   const char* ibuf = lua_tolstring(lua, 1, &isiz);
1306   if (!ibuf) throwinvarg(lua, __KCFUNC__);
1307   const char* delims = argc > 1 ? lua_tostring(lua, 2) : NULL;
1308   lua_newtable(lua);
1309   int32_t lnum = 1;
1310   if (delims) {
1311     const char* str = ibuf;
1312     while (true) {
1313       const char* sp = str;
1314       while (*str != '\0' && !std::strchr(delims, *str)) {
1315         str++;
1316       }
1317       lua_pushlstring(lua, sp, str - sp);
1318       lua_rawseti(lua, -2, lnum++);
1319       if (*str == '\0') break;
1320       str++;
1321     }
1322   } else {
1323     const char* ptr = ibuf;
1324     int32_t size = isiz;
1325     while (size >= 0) {
1326       const char* rp = ptr;
1327       const char* ep = ptr + size;
1328       while (rp < ep) {
1329         if (*rp == '\0') break;
1330         rp++;
1331       }
1332       lua_pushlstring(lua, ptr, rp - ptr);
1333       lua_rawseti(lua, -2, lnum++);
1334       rp++;
1335       size -= rp - ptr;
1336       ptr = rp;
1337     }
1338   }
1339   return 1;
1340 }
1341 
1342 
1343 /**
1344  * Implementation of codec.
1345  */
kt_codec(lua_State * lua)1346 static int kt_codec(lua_State *lua) {
1347   int32_t argc = lua_gettop(lua);
1348   if (argc != 2) throwinvarg(lua, __KCFUNC__);
1349   const char* mode = lua_tostring(lua, 1);
1350   size_t isiz;
1351   const char* ibuf = lua_tolstring(lua, 2, &isiz);
1352   if (!mode || !ibuf) throwinvarg(lua, __KCFUNC__);
1353   char* obuf = NULL;
1354   size_t osiz = 0;
1355   if (*mode == '~') {
1356     mode++;
1357     if (!kc::stricmp(mode, "url")) {
1358       obuf = kc::urldecode(ibuf, &osiz);
1359     } else if (!kc::stricmp(mode, "base")) {
1360       obuf = kc::basedecode(ibuf, &osiz);
1361     } else if (!kc::stricmp(mode, "quote")) {
1362       obuf = kc::quotedecode(ibuf, &osiz);
1363     } else if (!kc::stricmp(mode, "hex")) {
1364       obuf = kc::hexdecode(ibuf, &osiz);
1365     } else if (!kc::stricmp(mode, "zlib")) {
1366       obuf = kc::ZLIB::decompress(ibuf, isiz, &osiz, kc::ZLIB::RAW);
1367     } else if (!kc::stricmp(mode, "deflate")) {
1368       obuf = kc::ZLIB::decompress(ibuf, isiz, &osiz, kc::ZLIB::DEFLATE);
1369     } else if (!kc::stricmp(mode, "gzip")) {
1370       obuf = kc::ZLIB::decompress(ibuf, isiz, &osiz, kc::ZLIB::GZIP);
1371     }
1372   } else {
1373     if (!kc::stricmp(mode, "url")) {
1374       obuf = kc::urlencode(ibuf, isiz);
1375       osiz = obuf ? std::strlen(obuf) : 0;
1376     } else if (!kc::stricmp(mode, "base")) {
1377       obuf = kc::baseencode(ibuf, isiz);
1378       osiz = obuf ? std::strlen(obuf) : 0;
1379     } else if (!kc::stricmp(mode, "quote")) {
1380       obuf = kc::quoteencode(ibuf, isiz);
1381       osiz = obuf ? std::strlen(obuf) : 0;
1382     } else if (!kc::stricmp(mode, "hex")) {
1383       obuf = kc::hexencode(ibuf, isiz);
1384       osiz = obuf ? std::strlen(obuf) : 0;
1385     } else if (!kc::stricmp(mode, "zlib")) {
1386       obuf = kc::ZLIB::compress(ibuf, isiz, &osiz, kc::ZLIB::RAW);
1387     } else if (!kc::stricmp(mode, "deflate")) {
1388       obuf = kc::ZLIB::compress(ibuf, isiz, &osiz, kc::ZLIB::DEFLATE);
1389     } else if (!kc::stricmp(mode, "gzip")) {
1390       obuf = kc::ZLIB::compress(ibuf, isiz, &osiz, kc::ZLIB::GZIP);
1391     }
1392   }
1393   if (obuf) {
1394     lua_pushlstring(lua, obuf, osiz);
1395     delete[] obuf;
1396   } else {
1397     lua_pushnil(lua);
1398   }
1399   return 1;
1400 }
1401 
1402 
1403 /**
1404  * Implementation of bit.
1405  */
kt_bit(lua_State * lua)1406 static int kt_bit(lua_State *lua) {
1407   int32_t argc = lua_gettop(lua);
1408   if (argc < 2) throwinvarg(lua, __KCFUNC__);
1409   const char* mode = lua_tostring(lua, 1);
1410   uint32_t num = lua_tonumber(lua, 2);
1411   uint32_t aux = argc > 2 ? lua_tonumber(lua, 3) : 0;
1412   if (!mode) throwinvarg(lua, __KCFUNC__);
1413   if (!kc::stricmp(mode, "and")) {
1414     num &= aux;
1415   } else if (!kc::stricmp(mode, "or")) {
1416     num |= aux;
1417   } else if (!kc::stricmp(mode, "xor")) {
1418     num ^= aux;
1419   } else if (!kc::stricmp(mode, "not")) {
1420     num = ~num;
1421   } else if (!kc::stricmp(mode, "left")) {
1422     num <<= aux;
1423   } else if (!kc::stricmp(mode, "right")) {
1424     num >>= aux;
1425   }
1426   lua_pushnumber(lua, num);
1427   return 1;
1428 }
1429 
1430 
1431 /**
1432  * Implementation of strstr.
1433  */
kt_strstr(lua_State * lua)1434 static int kt_strstr(lua_State *lua) {
1435   int32_t argc = lua_gettop(lua);
1436   if (argc < 2) throwinvarg(lua, __KCFUNC__);
1437   const char* str = lua_tostring(lua, 1);
1438   const char* pat = lua_tostring(lua, 2);
1439   if (!str || !pat) throwinvarg(lua, __KCFUNC__);
1440   const char* alt = argc > 2 ? lua_tostring(lua, 3) : NULL;
1441   if (alt) {
1442     std::string xstr;
1443     size_t plen = std::strlen(pat);
1444     size_t alen = std::strlen(alt);
1445     if (plen > 0) {
1446       const char* pv;
1447       while ((pv = std::strstr(str, pat)) != NULL) {
1448         xstr.append(str, pv - str);
1449         xstr.append(alt, alen);
1450         str = pv + plen;
1451       }
1452     }
1453     xstr.append(str);
1454     lua_pushlstring(lua, xstr.data(), xstr.size());
1455   } else {
1456     const char* pv = std::strstr(str, pat);
1457     if (pv) {
1458       int32_t idx = pv - str + 1;
1459       lua_pushinteger(lua, idx);
1460     } else {
1461       lua_pushinteger(lua, 0);
1462     }
1463   }
1464   return 1;
1465 }
1466 
1467 
1468 /**
1469  * Implementation of strfwm.
1470  */
kt_strfwm(lua_State * lua)1471 static int kt_strfwm(lua_State *lua) {
1472   int32_t argc = lua_gettop(lua);
1473   if (argc < 2) throwinvarg(lua, __KCFUNC__);
1474   const char* str = lua_tostring(lua, 1);
1475   const char* pat = lua_tostring(lua, 2);
1476   if (!str || !pat) throwinvarg(lua, __KCFUNC__);
1477   lua_pushboolean(lua, kc::strfwm(str, pat));
1478   return 1;
1479 }
1480 
1481 
1482 /**
1483  * Implementation of strbwm.
1484  */
kt_strbwm(lua_State * lua)1485 static int kt_strbwm(lua_State *lua) {
1486   int32_t argc = lua_gettop(lua);
1487   if (argc < 2) throwinvarg(lua, __KCFUNC__);
1488   const char* str = lua_tostring(lua, 1);
1489   const char* pat = lua_tostring(lua, 2);
1490   if (!str || !pat) throwinvarg(lua, __KCFUNC__);
1491   lua_pushboolean(lua, kc::strbwm(str, pat));
1492   return 1;
1493 }
1494 
1495 
1496 /**
1497  * Implementation of regex.
1498  */
kt_regex(lua_State * lua)1499 static int kt_regex(lua_State *lua) {
1500   int32_t argc = lua_gettop(lua);
1501   if (argc < 2) throwinvarg(lua, __KCFUNC__);
1502   const char* str = lua_tostring(lua, 1);
1503   const char* pat = lua_tostring(lua, 2);
1504   if (!str || !pat) throwinvarg(lua, __KCFUNC__);
1505   const char* alt = argc > 2 ? lua_tostring(lua, 3) : NULL;
1506   if (alt) {
1507     std::string xstr = kc::Regex::replace(str, pat, alt);
1508     lua_pushlstring(lua, xstr.data(), xstr.size());
1509   } else {
1510     bool rv = kc::Regex::match(str, pat);
1511     lua_pushboolean(lua, rv);
1512   }
1513   return 1;
1514 }
1515 
1516 
1517 /**
1518  * Implementation of arraydump.
1519  */
kt_arraydump(lua_State * lua)1520 static int kt_arraydump(lua_State *lua) {
1521   int32_t argc = lua_gettop(lua);
1522   if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
1523   size_t rnum = lua_objlen(lua, 1);
1524   std::string rstr;
1525   rstr.reserve(rnum * 16 + 256);
1526   for (size_t i = 1; i <= rnum; i++) {
1527     lua_rawgeti(lua, 1, i);
1528     char vnbuf[kc::NUMBUFSIZ];
1529     const char* vbuf = NULL;
1530     size_t vsiz = 0;
1531     switch (lua_type(lua, -1)) {
1532       case LUA_TNUMBER: {
1533         double num = lua_tonumber(lua, -1);
1534         if (num == std::floor(num)) {
1535           vsiz = std::sprintf(vnbuf, "%lld", (long long)num);
1536         } else {
1537           vsiz = std::snprintf(vnbuf, sizeof(vnbuf), "%.6f", num);
1538           vnbuf[sizeof(vnbuf)-1] = '\0';
1539         }
1540         vbuf = vnbuf;
1541         break;
1542       }
1543       case LUA_TSTRING: {
1544         vbuf = lua_tolstring(lua, -1, &vsiz);
1545         break;
1546       }
1547     }
1548     if (vbuf) {
1549       char nbuf[kc::NUMBUFSIZ];
1550       size_t nsiz = kc::writevarnum(nbuf, vsiz);
1551       rstr.append(nbuf, nsiz);
1552       rstr.append(vbuf, vsiz);
1553     }
1554     lua_pop(lua, 1);
1555   }
1556   lua_pushlstring(lua, rstr.data(), rstr.size());
1557   return 1;
1558 }
1559 
1560 
1561 /**
1562  * Implementation of arrayload.
1563  */
kt_arrayload(lua_State * lua)1564 static int kt_arrayload(lua_State *lua) {
1565   int32_t argc = lua_gettop(lua);
1566   if (argc != 1) throwinvarg(lua, __KCFUNC__);
1567   size_t size;
1568   const char* rp = lua_tolstring(lua, 1, &size);
1569   if (!rp) throwinvarg(lua, __KCFUNC__);
1570   lua_newtable(lua);
1571   int32_t idx = 1;
1572   while (size > 0) {
1573     uint64_t vsiz;
1574     size_t step = kc::readvarnum(rp, size, &vsiz);
1575     rp += step;
1576     size -= step;
1577     if (vsiz > size) break;
1578     lua_pushlstring(lua, rp, vsiz);
1579     lua_rawseti(lua, -2, idx++);
1580     rp += vsiz;
1581     size -= vsiz;
1582   }
1583   return 1;
1584 }
1585 
1586 
1587 /**
1588  * Implementation of mapdump.
1589  */
kt_mapdump(lua_State * lua)1590 static int kt_mapdump(lua_State *lua) {
1591   int32_t argc = lua_gettop(lua);
1592   if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
1593   std::string rstr;
1594   rstr.reserve(512);
1595   lua_pushnil(lua);
1596   while (lua_next(lua, 1) != 0) {
1597     char knbuf[kc::NUMBUFSIZ];
1598     const char* kbuf = NULL;
1599     size_t ksiz = 0;
1600     switch (lua_type(lua, -2)) {
1601       case LUA_TNUMBER: {
1602         double num = lua_tonumber(lua, -2);
1603         if (num == std::floor(num)) {
1604           ksiz = std::sprintf(knbuf, "%lld", (long long)num);
1605         } else {
1606           ksiz = std::snprintf(knbuf, sizeof(knbuf), "%.6f", num);
1607           knbuf[sizeof(knbuf)-1] = '\0';
1608         }
1609         kbuf = knbuf;
1610         break;
1611       }
1612       case LUA_TSTRING: {
1613         kbuf = lua_tolstring(lua, -2, &ksiz);
1614         break;
1615       }
1616     }
1617     char vnbuf[kc::NUMBUFSIZ];
1618     const char* vbuf = NULL;
1619     size_t vsiz = 0;
1620     switch (lua_type(lua, -1)) {
1621       case LUA_TNUMBER: {
1622         double num = lua_tonumber(lua, -1);
1623         if (num == std::floor(num)) {
1624           vsiz = std::sprintf(vnbuf, "%lld", (long long)num);
1625         } else {
1626           vsiz = std::snprintf(vnbuf, sizeof(vnbuf), "%.6f", num);
1627           vnbuf[sizeof(vnbuf)-1] = '\0';
1628         }
1629         vbuf = vnbuf;
1630         break;
1631       }
1632       case LUA_TSTRING: {
1633         vbuf = lua_tolstring(lua, -1, &vsiz);
1634         break;
1635       }
1636     }
1637     if (kbuf && vbuf) {
1638       char nbuf[kc::NUMBUFSIZ*2];
1639       size_t nsiz = kc::writevarnum(nbuf, ksiz);
1640       nsiz += kc::writevarnum(nbuf + nsiz, vsiz);
1641       rstr.append(nbuf, nsiz);
1642       rstr.append(kbuf, ksiz);
1643       rstr.append(vbuf, vsiz);
1644     }
1645     lua_pop(lua, 1);
1646   }
1647   lua_pushlstring(lua, rstr.data(), rstr.size());
1648   return 1;
1649 }
1650 
1651 
1652 /**
1653  * Implementation of mapload.
1654  */
kt_mapload(lua_State * lua)1655 static int kt_mapload(lua_State *lua) {
1656   int32_t argc = lua_gettop(lua);
1657   if (argc != 1) throwinvarg(lua, __KCFUNC__);
1658   size_t size;
1659   const char* rp = lua_tolstring(lua, 1, &size);
1660   if (!rp) throwinvarg(lua, __KCFUNC__);
1661   lua_newtable(lua);
1662   while (size > 1) {
1663     uint64_t ksiz;
1664     size_t step = kc::readvarnum(rp, size, &ksiz);
1665     rp += step;
1666     size -= step;
1667     if (size < 1) break;
1668     uint64_t vsiz;
1669     step = kc::readvarnum(rp, size, &vsiz);
1670     rp += step;
1671     size -= step;
1672     size_t rsiz = ksiz + vsiz;
1673     if (rsiz > size) break;
1674     lua_pushlstring(lua, rp, ksiz);
1675     lua_pushlstring(lua, rp + ksiz, vsiz);
1676     lua_settable(lua, -3);
1677     rp += rsiz;
1678     size -= rsiz;
1679   }
1680   return 1;
1681 }
1682 
1683 
1684 /**
1685  * Define objects of the Error class.
1686  */
define_err(lua_State * lua)1687 static void define_err(lua_State* lua) {
1688   lua_newtable(lua);
1689   setfielduint(lua, "SUCCESS", kc::BasicDB::Error::SUCCESS);
1690   setfielduint(lua, "NOIMPL", kc::BasicDB::Error::NOIMPL);
1691   setfielduint(lua, "INVALID", kc::BasicDB::Error::INVALID);
1692   setfielduint(lua, "NOREPOS", kc::BasicDB::Error::NOREPOS);
1693   setfielduint(lua, "NOPERM", kc::BasicDB::Error::NOPERM);
1694   setfielduint(lua, "BROKEN", kc::BasicDB::Error::BROKEN);
1695   setfielduint(lua, "DUPREC", kc::BasicDB::Error::DUPREC);
1696   setfielduint(lua, "NOREC", kc::BasicDB::Error::NOREC);
1697   setfielduint(lua, "LOGIC", kc::BasicDB::Error::LOGIC);
1698   setfielduint(lua, "SYSTEM", kc::BasicDB::Error::SYSTEM);
1699   setfielduint(lua, "MISC", kc::BasicDB::Error::MISC);
1700   setfieldfunc(lua, "new", err_new);
1701   lua_newtable(lua);
1702   setfieldfunc(lua, "__tostring", err_tostring);
1703   lua_setfield(lua, -2, "meta_");
1704   lua_setfield(lua, 1, "Error");
1705 }
1706 
1707 
1708 /**
1709  * Implementation of new.
1710  */
err_new(lua_State * lua)1711 static int err_new(lua_State* lua) {
1712   int32_t argc = lua_gettop(lua);
1713   if (argc < 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
1714   if (argc > 3) throwinvarg(lua, __KCFUNC__);
1715   lua_newtable(lua);
1716   if (argc > 2 && lua_isnumber(lua, 2) && lua_isstring(lua, 3)) {
1717     setfieldvalue(lua, "code_", 2);
1718     setfieldvalue(lua, "message_", 3);
1719   } else {
1720     setfielduint(lua, "code_", 0);
1721     setfieldstr(lua, "message_", "error");
1722   }
1723   setfieldfunc(lua, "set", err_set);
1724   setfieldfunc(lua, "code", err_code);
1725   setfieldfunc(lua, "name", err_name);
1726   setfieldfunc(lua, "message", err_message);
1727   lua_getfield(lua, 1, "meta_");
1728   lua_setmetatable(lua, -2);
1729   return 1;
1730 }
1731 
1732 
1733 /**
1734  * Implementation of __tostring.
1735  */
err_tostring(lua_State * lua)1736 static int err_tostring(lua_State* lua) {
1737   int32_t argc = lua_gettop(lua);
1738   if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
1739   lua_getfield(lua, 1, "code_");
1740   uint32_t code = lua_tonumber(lua, -1);
1741   lua_getfield(lua, 1, "message_");
1742   const char* message = lua_tostring(lua, -1);
1743   const char* name = kc::BasicDB::Error::codename((kc::BasicDB::Error::Code)code);
1744   lua_pushfstring(lua, "%s: %s", name, message);
1745   return 1;
1746 }
1747 
1748 
1749 /**
1750  * Implementation of set.
1751  */
err_set(lua_State * lua)1752 static int err_set(lua_State* lua) {
1753   int32_t argc = lua_gettop(lua);
1754   if (argc != 3 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
1755   if (argc > 2 && lua_isnumber(lua, 2) && lua_isstring(lua, 3)) {
1756     lua_pushvalue(lua, 2);
1757     lua_setfield(lua, 1, "code_");
1758     lua_pushvalue(lua, 3);
1759     lua_setfield(lua, 1, "message_");
1760   }
1761   lua_pushnil(lua);
1762   return 1;
1763 }
1764 
1765 
1766 /**
1767  * Implementation of code.
1768  */
err_code(lua_State * lua)1769 static int err_code(lua_State* lua) {
1770   int32_t argc = lua_gettop(lua);
1771   if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
1772   lua_getfield(lua, 1, "code_");
1773   return 1;
1774 }
1775 
1776 
1777 /**
1778  * Implementation of name.
1779  */
err_name(lua_State * lua)1780 static int err_name(lua_State* lua) {
1781   int32_t argc = lua_gettop(lua);
1782   if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
1783   lua_getfield(lua, 1, "code_");
1784   uint32_t code = lua_tonumber(lua, -1);
1785   const char* name = kc::BasicDB::Error::codename((kc::BasicDB::Error::Code)code);
1786   lua_pushstring(lua, name);
1787   return 1;
1788 }
1789 
1790 
1791 /**
1792  * Implementation of message.
1793  */
err_message(lua_State * lua)1794 static int err_message(lua_State* lua) {
1795   int32_t argc = lua_gettop(lua);
1796   if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
1797   lua_getfield(lua, 1, "message_");
1798   return 1;
1799 }
1800 
1801 
1802 /**
1803  * Define objects of the Visitor class.
1804  */
define_vis(lua_State * lua)1805 static void define_vis(lua_State* lua) {
1806   lua_newtable(lua);
1807   lua_pushlightuserdata(lua, (void*)kt::TimedDB::Visitor::NOP);
1808   lua_setfield(lua, -2, "NOP");
1809   lua_pushlightuserdata(lua, (void*)kt::TimedDB::Visitor::REMOVE);
1810   lua_setfield(lua, -2, "REMOVE");
1811   setfieldfunc(lua, "new", vis_new);
1812   lua_newtable(lua);
1813   lua_setfield(lua, -2, "meta_");
1814   lua_setfield(lua, 1, "Visitor");
1815 }
1816 
1817 
1818 /**
1819  * Implementation of new.
1820  */
vis_new(lua_State * lua)1821 static int vis_new(lua_State* lua) {
1822   int32_t argc = lua_gettop(lua);
1823   if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
1824   lua_newtable(lua);
1825   setfieldfunc(lua, "visit_full", vis_visit_full);
1826   setfieldfunc(lua, "visit_empty", vis_visit_empty);
1827   lua_getfield(lua, 1, "meta_");
1828   lua_setmetatable(lua, -2);
1829   return 1;
1830 }
1831 
1832 
1833 /**
1834  * Implementation of visit_full.
1835  */
vis_visit_full(lua_State * lua)1836 static int vis_visit_full(lua_State* lua) {
1837   int32_t argc = lua_gettop(lua);
1838   if (argc != 3 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
1839   lua_pushnil(lua);
1840   return 1;
1841 }
1842 
1843 
1844 /**
1845  * Implementation of visit_empty.
1846  */
vis_visit_empty(lua_State * lua)1847 static int vis_visit_empty(lua_State* lua) {
1848   int32_t argc = lua_gettop(lua);
1849   if (argc != 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
1850   lua_pushnil(lua);
1851   return 1;
1852 }
1853 
1854 
1855 /**
1856  * Define objects of the FileProcessor class.
1857  */
define_fproc(lua_State * lua)1858 static void define_fproc(lua_State* lua) {
1859   lua_newtable(lua);
1860   setfieldfunc(lua, "new", fproc_new);
1861   lua_newtable(lua);
1862   lua_setfield(lua, -2, "meta_");
1863   lua_setfield(lua, 1, "FileProcessor");
1864 }
1865 
1866 
1867 /**
1868  * Implementation of new.
1869  */
fproc_new(lua_State * lua)1870 static int fproc_new(lua_State* lua) {
1871   int32_t argc = lua_gettop(lua);
1872   if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
1873   lua_newtable(lua);
1874   setfieldfunc(lua, "process", fproc_process);
1875   lua_getfield(lua, 1, "meta_");
1876   lua_setmetatable(lua, -2);
1877   return 1;
1878 }
1879 
1880 
1881 /**
1882  * Implementation of process.
1883  */
fproc_process(lua_State * lua)1884 static int fproc_process(lua_State* lua) {
1885   int32_t argc = lua_gettop(lua);
1886   if (argc != 4 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
1887   lua_pushboolean(lua, true);
1888   return 1;
1889 }
1890 
1891 
1892 /**
1893  * Define objects of the Cursor class.
1894  */
define_cur(lua_State * lua)1895 static void define_cur(lua_State* lua) {
1896   lua_newtable(lua);
1897   setfieldfunc(lua, "new", cur_new);
1898   lua_newtable(lua);
1899   setfieldfunc(lua, "__tostring", cur_tostring);
1900   setfieldfunc(lua, "__call", cur_call);
1901   lua_setfield(lua, -2, "meta_");
1902   lua_setfield(lua, 1, "Cursor");
1903 }
1904 
1905 
1906 /**
1907  * Implementation of new.
1908  */
cur_new(lua_State * lua)1909 static int cur_new(lua_State* lua) {
1910   int32_t argc = lua_gettop(lua);
1911   if (argc != 2 || !lua_istable(lua, 1) || !lua_istable(lua, 2)) throwinvarg(lua, __KCFUNC__);
1912   lua_getfield(lua, 2, "db_ptr_");
1913   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
1914   if (!db) throwinvarg(lua, __KCFUNC__);
1915   lua_newtable(lua);
1916   g_curbur.sweap();
1917   SoftCursor* cur = (SoftCursor*)lua_newuserdata(lua, sizeof(*cur));
1918   cur->cur = db->db->cursor();
1919   lua_newtable(lua);
1920   setfieldfunc(lua, "__gc", cur_gc);
1921   lua_setmetatable(lua, -2);
1922   lua_setfield(lua, -2, "cur_ptr_");
1923   lua_pushvalue(lua, 2);
1924   lua_setfield(lua, -2, "db_");
1925   setfieldfunc(lua, "disable", cur_disable);
1926   setfieldfunc(lua, "accept", cur_accept);
1927   setfieldfunc(lua, "set_value", cur_set_value);
1928   setfieldfunc(lua, "remove", cur_remove);
1929   setfieldfunc(lua, "get_key", cur_get_key);
1930   setfieldfunc(lua, "get_value", cur_get_value);
1931   setfieldfunc(lua, "get", cur_get);
1932   setfieldfunc(lua, "seize", cur_seize);
1933   setfieldfunc(lua, "jump", cur_jump);
1934   setfieldfunc(lua, "jump_back", cur_jump_back);
1935   setfieldfunc(lua, "step", cur_step);
1936   setfieldfunc(lua, "step_back", cur_step_back);
1937   setfieldfunc(lua, "db", cur_db);
1938   setfieldfunc(lua, "error", cur_error);
1939   lua_getfield(lua, 1, "meta_");
1940   lua_setmetatable(lua, -2);
1941   return 1;
1942 }
1943 
1944 
1945 /**
1946  * Implementation of __gc.
1947  */
cur_gc(lua_State * lua)1948 static int cur_gc(lua_State* lua) {
1949   int32_t argc = lua_gettop(lua);
1950   if (argc < 1 || !lua_isuserdata(lua, 1)) return 0;
1951   SoftCursor* cur = (SoftCursor*)lua_touserdata(lua, 1);
1952   if (!cur) return 0;
1953   if (cur->cur) g_curbur.deposit(cur->cur);
1954   return 0;
1955 }
1956 
1957 
1958 /**
1959  * Implementation of __tostring.
1960  */
cur_tostring(lua_State * lua)1961 static int cur_tostring(lua_State* lua) {
1962   int32_t argc = lua_gettop(lua);
1963   if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
1964   lua_getfield(lua, 1, "cur_ptr_");
1965   SoftCursor* cur = (SoftCursor*)lua_touserdata(lua, -1);
1966   if (!cur) {
1967     lua_pushstring(lua, "(disabled)");
1968     return 1;
1969   }
1970   kt::TimedDB* db = cur->cur->db();
1971   std::string path = db->path();
1972   if (path.size() < 1) path = "(nil)";
1973   std::string str = kc::strprintf("%s: ", path.c_str());
1974   size_t ksiz;
1975   char* kbuf = cur->cur->get_key(&ksiz);
1976   if (kbuf) {
1977     str.append(kbuf, ksiz);
1978     delete[] kbuf;
1979   } else {
1980     str.append("(nil)");
1981   }
1982   lua_pushstring(lua, str.c_str());
1983   return 1;
1984 }
1985 
1986 
1987 /**
1988  * Implementation of __call.
1989  */
cur_call(lua_State * lua)1990 static int cur_call(lua_State* lua) {
1991   int32_t argc = lua_gettop(lua);
1992   if (argc < 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
1993   lua_getfield(lua, 1, "cur_ptr_");
1994   SoftCursor* cur = (SoftCursor*)lua_touserdata(lua, -1);
1995   if (!cur) throwinvarg(lua, __KCFUNC__);
1996   const char* vbuf;
1997   size_t ksiz, vsiz;
1998   int64_t xt;
1999   char* kbuf = cur->cur->get(&ksiz, &vbuf, &vsiz, &xt, true);
2000   if (kbuf) {
2001     lua_pushlstring(lua, kbuf, ksiz);
2002     lua_pushlstring(lua, vbuf, vsiz);
2003     delete[] kbuf;
2004     return 2;
2005   }
2006   lua_pushnil(lua);
2007   return 1;
2008 }
2009 
2010 
2011 /**
2012  * Implementation of disable.
2013  */
cur_disable(lua_State * lua)2014 static int cur_disable(lua_State* lua) {
2015   int32_t argc = lua_gettop(lua);
2016   if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2017   lua_getfield(lua, 1, "cur_ptr_");
2018   SoftCursor* cur = (SoftCursor*)lua_touserdata(lua, -1);
2019   if (!cur) throwinvarg(lua, __KCFUNC__);
2020   delete cur->cur;
2021   cur->cur = NULL;
2022   lua_pushnil(lua);
2023   lua_setfield(lua, 1, "cur_ptr_");
2024   lua_pushnil(lua);
2025   return 1;
2026 }
2027 
2028 
2029 /**
2030  * Implementation of accept.
2031  */
cur_accept(lua_State * lua)2032 static int cur_accept(lua_State* lua) {
2033   int32_t argc = lua_gettop(lua);
2034   if (argc < 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2035   if (argc > 4) throwinvarg(lua, __KCFUNC__);
2036   lua_getfield(lua, 1, "cur_ptr_");
2037   SoftCursor* cur = (SoftCursor*)lua_touserdata(lua, -1);
2038   if (!cur) throwinvarg(lua, __KCFUNC__);
2039   bool writable = argc > 2 ? lua_toboolean(lua, 3) : true;
2040   bool step = argc > 3 ? lua_toboolean(lua, 4) : false;
2041   bool rv;
2042   if (lua_istable(lua, 2) || lua_isfunction(lua, 2)) {
2043     lua_pushvalue(lua, 2);
2044     SoftVisitor visitor(lua, writable);
2045     rv = cur->cur->accept(&visitor, writable, step);
2046   } else {
2047     throwinvarg(lua, __KCFUNC__);
2048     rv = false;
2049   }
2050   lua_pushboolean(lua, rv);
2051   return 1;
2052 }
2053 
2054 
2055 /**
2056  * Implementation of set_value.
2057  */
cur_set_value(lua_State * lua)2058 static int cur_set_value(lua_State* lua) {
2059   int32_t argc = lua_gettop(lua);
2060   if (argc < 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2061   if (argc > 4) throwinvarg(lua, __KCFUNC__);
2062   lua_getfield(lua, 1, "cur_ptr_");
2063   SoftCursor* cur = (SoftCursor*)lua_touserdata(lua, -1);
2064   size_t vsiz;
2065   const char* vbuf = lua_tolstring(lua, 2, &vsiz);
2066   if (!cur || !vsiz) throwinvarg(lua, __KCFUNC__);
2067   int64_t xt = argc > 2 && !lua_isnil(lua, 3) ? lua_tonumber(lua, 3) : kc::INT64MAX;
2068   bool step = argc > 3 ? lua_toboolean(lua, 4) : false;
2069   bool rv = cur->cur->set_value(vbuf, vsiz, step, xt);
2070   lua_pushboolean(lua, rv);
2071   return 1;
2072 }
2073 
2074 
2075 /**
2076  * Implementation of remove.
2077  */
cur_remove(lua_State * lua)2078 static int cur_remove(lua_State* lua) {
2079   int32_t argc = lua_gettop(lua);
2080   if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2081   lua_getfield(lua, 1, "cur_ptr_");
2082   SoftCursor* cur = (SoftCursor*)lua_touserdata(lua, -1);
2083   if (!cur) throwinvarg(lua, __KCFUNC__);
2084   bool rv = cur->cur->remove();
2085   lua_pushboolean(lua, rv);
2086   return 1;
2087 }
2088 
2089 
2090 /**
2091  * Implementation of get_key.
2092  */
cur_get_key(lua_State * lua)2093 static int cur_get_key(lua_State* lua) {
2094   int32_t argc = lua_gettop(lua);
2095   if (argc < 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2096   if (argc > 2) throwinvarg(lua, __KCFUNC__);
2097   lua_getfield(lua, 1, "cur_ptr_");
2098   SoftCursor* cur = (SoftCursor*)lua_touserdata(lua, -1);
2099   if (!cur) throwinvarg(lua, __KCFUNC__);
2100   bool step = argc > 1 ? lua_toboolean(lua, 2) : false;
2101   size_t ksiz;
2102   char* kbuf = cur->cur->get_key(&ksiz, step);
2103   if (kbuf) {
2104     lua_pushlstring(lua, kbuf, ksiz);
2105     delete[] kbuf;
2106   } else {
2107     lua_pushnil(lua);
2108   }
2109   return 1;
2110 }
2111 
2112 
2113 /**
2114  * Implementation of get_value.
2115  */
cur_get_value(lua_State * lua)2116 static int cur_get_value(lua_State* lua) {
2117   int32_t argc = lua_gettop(lua);
2118   if (argc < 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2119   if (argc > 2) throwinvarg(lua, __KCFUNC__);
2120   lua_getfield(lua, 1, "cur_ptr_");
2121   SoftCursor* cur = (SoftCursor*)lua_touserdata(lua, -1);
2122   if (!cur) throwinvarg(lua, __KCFUNC__);
2123   bool step = argc > 1 ? lua_toboolean(lua, 2) : false;
2124   size_t vsiz;
2125   char* vbuf = cur->cur->get_value(&vsiz, step);
2126   if (vbuf) {
2127     lua_pushlstring(lua, vbuf, vsiz);
2128     delete[] vbuf;
2129   } else {
2130     lua_pushnil(lua);
2131   }
2132   return 1;
2133 }
2134 
2135 
2136 /**
2137  * Implementation of get.
2138  */
cur_get(lua_State * lua)2139 static int cur_get(lua_State* lua) {
2140   int32_t argc = lua_gettop(lua);
2141   if (argc < 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2142   if (argc > 2) throwinvarg(lua, __KCFUNC__);
2143   lua_getfield(lua, 1, "cur_ptr_");
2144   SoftCursor* cur = (SoftCursor*)lua_touserdata(lua, -1);
2145   if (!cur) throwinvarg(lua, __KCFUNC__);
2146   bool step = argc > 1 ? lua_toboolean(lua, 2) : false;
2147   const char* vbuf;
2148   size_t ksiz, vsiz;
2149   int64_t xt;
2150   char* kbuf = cur->cur->get(&ksiz, &vbuf, &vsiz, &xt, step);
2151   if (kbuf) {
2152     lua_pushlstring(lua, kbuf, ksiz);
2153     lua_pushlstring(lua, vbuf, vsiz);
2154     lua_pushnumber(lua, xt < kt::TimedDB::XTMAX ? xt : kt::TimedDB::XTMAX);
2155     delete[] kbuf;
2156     return 3;
2157   }
2158   lua_pushnil(lua);
2159   return 1;
2160 }
2161 
2162 
2163 /**
2164  * Implementation of seize.
2165  */
cur_seize(lua_State * lua)2166 static int cur_seize(lua_State* lua) {
2167   int32_t argc = lua_gettop(lua);
2168   if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2169   lua_getfield(lua, 1, "cur_ptr_");
2170   SoftCursor* cur = (SoftCursor*)lua_touserdata(lua, -1);
2171   if (!cur) throwinvarg(lua, __KCFUNC__);
2172   const char* vbuf;
2173   size_t ksiz, vsiz;
2174   int64_t xt;
2175   char* kbuf = cur->cur->seize(&ksiz, &vbuf, &vsiz, &xt);
2176   if (kbuf) {
2177     lua_pushlstring(lua, kbuf, ksiz);
2178     lua_pushlstring(lua, vbuf, vsiz);
2179     lua_pushnumber(lua, xt < kt::TimedDB::XTMAX ? xt : kt::TimedDB::XTMAX);
2180     delete[] kbuf;
2181     return 3;
2182   }
2183   lua_pushnil(lua);
2184   return 1;
2185 }
2186 
2187 
2188 /**
2189  * Implementation of jump.
2190  */
cur_jump(lua_State * lua)2191 static int cur_jump(lua_State* lua) {
2192   int32_t argc = lua_gettop(lua);
2193   if (argc < 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2194   if (argc > 2) throwinvarg(lua, __KCFUNC__);
2195   lua_getfield(lua, 1, "cur_ptr_");
2196   SoftCursor* cur = (SoftCursor*)lua_touserdata(lua, -1);
2197   if (!cur) throwinvarg(lua, __KCFUNC__);
2198   bool rv;
2199   if (argc > 1) {
2200     size_t ksiz;
2201     const char* kbuf = lua_tolstring(lua, 2, &ksiz);
2202     if (!kbuf) throwinvarg(lua, __KCFUNC__);
2203     rv = cur->cur->jump(kbuf, ksiz);
2204   } else {
2205     rv = cur->cur->jump();
2206   }
2207   lua_pushboolean(lua, rv);
2208   return 1;
2209 }
2210 
2211 
2212 /**
2213  * Implementation of jump_back.
2214  */
cur_jump_back(lua_State * lua)2215 static int cur_jump_back(lua_State* lua) {
2216   int32_t argc = lua_gettop(lua);
2217   if (argc < 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2218   if (argc > 2) throwinvarg(lua, __KCFUNC__);
2219   lua_getfield(lua, 1, "cur_ptr_");
2220   SoftCursor* cur = (SoftCursor*)lua_touserdata(lua, -1);
2221   if (!cur) throwinvarg(lua, __KCFUNC__);
2222   bool rv;
2223   if (argc > 1) {
2224     size_t ksiz;
2225     const char* kbuf = lua_tolstring(lua, 2, &ksiz);
2226     if (!kbuf) throwinvarg(lua, __KCFUNC__);
2227     rv = cur->cur->jump_back(kbuf, ksiz);
2228   } else {
2229     rv = cur->cur->jump_back();
2230   }
2231   lua_pushboolean(lua, rv);
2232   return 1;
2233 }
2234 
2235 
2236 /**
2237  * Implementation of step.
2238  */
cur_step(lua_State * lua)2239 static int cur_step(lua_State* lua) {
2240   int32_t argc = lua_gettop(lua);
2241   if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2242   lua_getfield(lua, 1, "cur_ptr_");
2243   SoftCursor* cur = (SoftCursor*)lua_touserdata(lua, -1);
2244   if (!cur) throwinvarg(lua, __KCFUNC__);
2245   bool rv = cur->cur->step();
2246   lua_pushboolean(lua, rv);
2247   return 1;
2248 }
2249 
2250 
2251 /**
2252  * Implementation of step_back.
2253  */
cur_step_back(lua_State * lua)2254 static int cur_step_back(lua_State* lua) {
2255   int32_t argc = lua_gettop(lua);
2256   if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2257   lua_getfield(lua, 1, "cur_ptr_");
2258   SoftCursor* cur = (SoftCursor*)lua_touserdata(lua, -1);
2259   if (!cur) throwinvarg(lua, __KCFUNC__);
2260   bool rv = cur->cur->step_back();
2261   lua_pushboolean(lua, rv);
2262   return 1;
2263 }
2264 
2265 
2266 /**
2267  * Implementation of db.
2268  */
cur_db(lua_State * lua)2269 static int cur_db(lua_State* lua) {
2270   int32_t argc = lua_gettop(lua);
2271   if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2272   lua_getfield(lua, 1, "cur_ptr_");
2273   SoftCursor* cur = (SoftCursor*)lua_touserdata(lua, -1);
2274   if (!cur) throwinvarg(lua, __KCFUNC__);
2275   lua_getfield(lua, 1, "db_");
2276   return 1;
2277 }
2278 
2279 
2280 /**
2281  * Implementation of error.
2282  */
cur_error(lua_State * lua)2283 static int cur_error(lua_State* lua) {
2284   int32_t argc = lua_gettop(lua);
2285   if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2286   lua_getfield(lua, 1, "cur_ptr_");
2287   SoftCursor* cur = (SoftCursor*)lua_touserdata(lua, -1);
2288   if (!cur) throwinvarg(lua, __KCFUNC__);
2289   lua_getfield(lua, 1, "db_");
2290   lua_getfield(lua, -1, "error");
2291   lua_pushvalue(lua, -2);
2292   lua_call(lua, 1, 1);
2293   return 1;
2294 }
2295 
2296 
2297 /**
2298  * Define objects of the DB class.
2299  */
define_db(lua_State * lua)2300 static void define_db(lua_State* lua) {
2301   lua_newtable(lua);
2302   setfielduint(lua, "OREADER", kc::BasicDB::OREADER);
2303   setfielduint(lua, "OWRITER", kc::BasicDB::OWRITER);
2304   setfielduint(lua, "OCREATE", kc::BasicDB::OCREATE);
2305   setfielduint(lua, "OTRUNCATE", kc::BasicDB::OTRUNCATE);
2306   setfielduint(lua, "OAUTOTRAN", kc::BasicDB::OAUTOTRAN);
2307   setfielduint(lua, "OAUTOSYNC", kc::BasicDB::OAUTOSYNC);
2308   setfielduint(lua, "ONOLOCK", kc::BasicDB::ONOLOCK);
2309   setfielduint(lua, "OTRYLOCK", kc::BasicDB::OTRYLOCK);
2310   setfielduint(lua, "ONOREPAIR", kc::BasicDB::ONOREPAIR);
2311   setfielduint(lua, "MSET", kc::PolyDB::MSET);
2312   setfielduint(lua, "MADD", kc::PolyDB::MADD);
2313   setfielduint(lua, "MREPLACE", kc::PolyDB::MREPLACE);
2314   setfielduint(lua, "MAPPEND", kc::PolyDB::MAPPEND);
2315   setfielduint(lua, "XNOLOCK", kc::MapReduce::XNOLOCK);
2316   setfielduint(lua, "XNOCOMP", kc::MapReduce::XNOCOMP);
2317   setfieldfunc(lua, "new", db_new);
2318   setfieldfunc(lua, "new_ptr", db_new_ptr);
2319   setfieldfunc(lua, "delete_ptr", db_delete_ptr);
2320   setfieldfunc(lua, "process", db_process);
2321   lua_newtable(lua);
2322   setfieldfunc(lua, "__tostring", db_tostring);
2323   setfieldfunc(lua, "__index", db_index);
2324   setfieldfunc(lua, "__newindex", db_newindex);
2325   lua_setfield(lua, -2, "meta_");
2326   lua_setfield(lua, 1, "DB");
2327 }
2328 
2329 
2330 /**
2331  * Implementation of new.
2332  */
db_new(lua_State * lua)2333 static int db_new(lua_State* lua) {
2334   int32_t argc = lua_gettop(lua);
2335   if (argc < 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2336   if (argc > 2) throwinvarg(lua, __KCFUNC__);
2337   lua_newtable(lua);
2338   SoftDB* db = (SoftDB*)lua_newuserdata(lua, sizeof(*db));
2339   if (argc > 1 && lua_islightuserdata(lua, 2)) {
2340     db->db = (kt::TimedDB*)lua_touserdata(lua, 2);
2341     db->light = true;
2342   } else {
2343     db->db = new kt::TimedDB;
2344     db->light = false;
2345   }
2346   lua_newtable(lua);
2347   setfieldfunc(lua, "__gc", db_gc);
2348   lua_setmetatable(lua, -2);
2349   lua_setfield(lua, -2, "db_ptr_");
2350   lua_getglobal(lua, "__kyototycoon__");
2351   lua_getfield(lua, -1, "Error");
2352   lua_setfield(lua, -3, "err_");
2353   lua_getfield(lua, -1, "Cursor");
2354   lua_setfield(lua, -3, "cur_");
2355   lua_pop(lua, 1);
2356   setfieldfunc(lua, "error", db_error);
2357   setfieldfunc(lua, "open", db_open);
2358   setfieldfunc(lua, "close", db_close);
2359   setfieldfunc(lua, "accept", db_accept);
2360   setfieldfunc(lua, "accept_bulk", db_accept_bulk);
2361   setfieldfunc(lua, "iterate", db_iterate);
2362   setfieldfunc(lua, "set", db_set);
2363   setfieldfunc(lua, "add", db_add);
2364   setfieldfunc(lua, "replace", db_replace);
2365   setfieldfunc(lua, "append", db_append);
2366   setfieldfunc(lua, "increment", db_increment);
2367   setfieldfunc(lua, "increment_double", db_increment_double);
2368   setfieldfunc(lua, "cas", db_cas);
2369   setfieldfunc(lua, "remove", db_remove);
2370   setfieldfunc(lua, "get", db_get);
2371   setfieldfunc(lua, "check", db_check);
2372   setfieldfunc(lua, "seize", db_seize);
2373   setfieldfunc(lua, "set_bulk", db_set_bulk);
2374   setfieldfunc(lua, "remove_bulk", db_remove_bulk);
2375   setfieldfunc(lua, "get_bulk", db_get_bulk);
2376   setfieldfunc(lua, "clear", db_clear);
2377   setfieldfunc(lua, "synchronize", db_synchronize);
2378   setfieldfunc(lua, "occupy", db_occupy);
2379   setfieldfunc(lua, "copy", db_copy);
2380   setfieldfunc(lua, "begin_transaction", db_begin_transaction);
2381   setfieldfunc(lua, "end_transaction", db_end_transaction);
2382   setfieldfunc(lua, "transaction", db_transaction);
2383   setfieldfunc(lua, "dump_snapshot", db_dump_snapshot);
2384   setfieldfunc(lua, "load_snapshot", db_load_snapshot);
2385   setfieldfunc(lua, "count", db_count);
2386   setfieldfunc(lua, "size", db_size);
2387   setfieldfunc(lua, "path", db_path);
2388   setfieldfunc(lua, "status", db_status);
2389   setfieldfunc(lua, "match_prefix", db_match_prefix);
2390   setfieldfunc(lua, "match_regex", db_match_regex);
2391   setfieldfunc(lua, "match_similar", db_match_similar);
2392   setfieldfunc(lua, "merge", db_merge);
2393   setfieldfunc(lua, "mapreduce", db_mapreduce);
2394   setfieldfunc(lua, "cursor", db_cursor);
2395   setfieldfunc(lua, "cursor_process", db_cursor_process);
2396   setfieldfunc(lua, "pairs", db_pairs);
2397   lua_getfield(lua, 1, "meta_");
2398   lua_setmetatable(lua, -2);
2399   return 1;
2400 }
2401 
2402 
2403 /**
2404  * Implementation of __gc.
2405  */
db_gc(lua_State * lua)2406 static int db_gc(lua_State* lua) {
2407   int32_t argc = lua_gettop(lua);
2408   if (argc < 1 || !lua_isuserdata(lua, 1)) return 0;
2409   SoftDB* db = (SoftDB*)lua_touserdata(lua, 1);
2410   if (!db) return 0;
2411   if (!db->light) delete db->db;
2412   return 0;
2413 }
2414 
2415 
2416 /**
2417  * Implementation of __tostring.
2418  */
db_tostring(lua_State * lua)2419 static int db_tostring(lua_State* lua) {
2420   int32_t argc = lua_gettop(lua);
2421   if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2422   lua_getfield(lua, 1, "db_ptr_");
2423   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
2424   if (!db) throwinvarg(lua, __KCFUNC__);
2425   std::string path = db->db->path();
2426   if (path.size() < 1) path = "(nil)";
2427   std::string str = kc::strprintf("%s: %lld: %lld", path.c_str(),
2428                                   (long long)db->db->count(), (long long)db->db->size());
2429   lua_pushstring(lua, str.c_str());
2430   return 1;
2431 }
2432 
2433 
2434 /**
2435  * Implementation of __index.
2436  */
db_index(lua_State * lua)2437 static int db_index(lua_State* lua) {
2438   int32_t argc = lua_gettop(lua);
2439   if (argc != 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2440   lua_getfield(lua, 1, "db_ptr_");
2441   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
2442   size_t ksiz;
2443   const char* kbuf = lua_tolstring(lua, 2, &ksiz);
2444   if (!db || !kbuf) throwinvarg(lua, __KCFUNC__);
2445   size_t vsiz;
2446   char* vbuf = db->db->get(kbuf, ksiz, &vsiz);
2447   if (vbuf) {
2448     lua_pushlstring(lua, vbuf, vsiz);
2449     delete[] vbuf;
2450   } else {
2451     lua_pushnil(lua);
2452   }
2453   return 1;
2454 }
2455 
2456 
2457 /**
2458  * Implementation of __newindex.
2459  */
db_newindex(lua_State * lua)2460 static int db_newindex(lua_State* lua) {
2461   int32_t argc = lua_gettop(lua);
2462   if (argc != 3 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2463   lua_getfield(lua, 1, "db_ptr_");
2464   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
2465   size_t ksiz;
2466   const char* kbuf = lua_tolstring(lua, 2, &ksiz);
2467   size_t vsiz;
2468   const char* vbuf = lua_tolstring(lua, 3, &vsiz);
2469   if (!db || !kbuf) throwinvarg(lua, __KCFUNC__);
2470   bool rv;
2471   if (vbuf) {
2472     rv = db->db->set(kbuf, ksiz, vbuf, vsiz);
2473   } else {
2474     rv = db->db->remove(kbuf, ksiz);
2475   }
2476   lua_pushboolean(lua, rv);
2477   return 1;
2478 }
2479 
2480 
2481 /**
2482  * Implementation of new_ptr.
2483  */
db_new_ptr(lua_State * lua)2484 static int db_new_ptr(lua_State* lua) {
2485   int32_t argc = lua_gettop(lua);
2486   if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2487   kt::TimedDB* db = new kt::TimedDB;
2488   lua_pushlightuserdata(lua, (void*)db);
2489   return 1;
2490 }
2491 
2492 
2493 /**
2494  * Implementation of delete_ptr.
2495  */
db_delete_ptr(lua_State * lua)2496 static int db_delete_ptr(lua_State* lua) {
2497   int32_t argc = lua_gettop(lua);
2498   if (argc != 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2499   if (lua_islightuserdata(lua, 2)) {
2500     kt::TimedDB* db = (kt::TimedDB*)lua_touserdata(lua, 2);
2501     delete db;
2502   }
2503   lua_pushnil(lua);
2504   return 1;
2505 }
2506 
2507 
2508 /**
2509  * Implementation of process.
2510  */
db_process(lua_State * lua)2511 static int db_process(lua_State* lua) {
2512   int32_t argc = lua_gettop(lua);
2513   if (argc < 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2514   if (argc > 4) throwinvarg(lua, __KCFUNC__);
2515   if (!lua_isfunction(lua, 2)) throwinvarg(lua, __KCFUNC__);
2516   lua_getfield(lua, 1, "new");
2517   lua_pushvalue(lua, 1);
2518   lua_call(lua, 1, 1);
2519   int32_t objidx = lua_gettop(lua);
2520   lua_getfield(lua, objidx, "open");
2521   lua_pushvalue(lua, objidx);
2522   if (argc > 2) lua_pushvalue(lua, 3);
2523   if (argc > 3) lua_pushvalue(lua, 4);
2524   lua_call(lua, argc - 1, 1);
2525   if (!lua_toboolean(lua, -1)) {
2526     lua_getfield(lua, objidx, "error");
2527     lua_pushvalue(lua, objidx);
2528     lua_call(lua, 1, 1);
2529     return 1;
2530   }
2531   lua_pushvalue(lua, 2);
2532   lua_pushvalue(lua, objidx);
2533   int32_t erridx = 0;
2534   if (lua_pcall(lua, 1, 0, 0) != 0) erridx = lua_gettop(lua);
2535   lua_getfield(lua, objidx, "close");
2536   lua_pushvalue(lua, objidx);
2537   lua_call(lua, 1, 1);
2538   if (erridx > 0) {
2539     lua_pushvalue(lua, erridx);
2540     lua_error(lua);
2541   }
2542   if (!lua_toboolean(lua, -1)) {
2543     lua_getfield(lua, objidx, "error");
2544     lua_pushvalue(lua, objidx);
2545     lua_call(lua, 1, 1);
2546     return 1;
2547   }
2548   lua_pushnil(lua);
2549   return 1;
2550 }
2551 
2552 
2553 /**
2554  * Implementation of error.
2555  */
db_error(lua_State * lua)2556 static int db_error(lua_State* lua) {
2557   int32_t argc = lua_gettop(lua);
2558   if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2559   lua_getfield(lua, 1, "db_ptr_");
2560   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
2561   if (!db) throwinvarg(lua, __KCFUNC__);
2562   kc::BasicDB::Error err = db->db->error();
2563   lua_getfield(lua, 1, "err_");
2564   lua_getfield(lua, -1, "new");
2565   lua_pushvalue(lua, -2);
2566   lua_pushinteger(lua, err.code());
2567   lua_pushstring(lua, err.message());
2568   lua_call(lua, 3, 1);
2569   return 1;
2570 }
2571 
2572 
2573 /**
2574  * Implementation of open.
2575  */
db_open(lua_State * lua)2576 static int db_open(lua_State* lua) {
2577   int32_t argc = lua_gettop(lua);
2578   if (argc < 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2579   if (argc > 3) throwinvarg(lua, __KCFUNC__);
2580   lua_getfield(lua, 1, "db_ptr_");
2581   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
2582   if (!db) throwinvarg(lua, __KCFUNC__);
2583   const char* path = ":";
2584   if (argc > 1 && lua_isstring(lua, 2)) path = lua_tostring(lua, 2);
2585   uint32_t mode = kc::BasicDB::OWRITER | kc::BasicDB::OCREATE;
2586   if (argc > 2 && lua_isnumber(lua, 3)) mode = lua_tonumber(lua, 3);
2587   bool rv = db->db->open(path, mode);
2588   lua_pushboolean(lua, rv);
2589   return 1;
2590 }
2591 
2592 
2593 /**
2594  * Implementation of close.
2595  */
db_close(lua_State * lua)2596 static int db_close(lua_State* lua) {
2597   int32_t argc = lua_gettop(lua);
2598   if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2599   lua_getfield(lua, 1, "db_ptr_");
2600   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
2601   if (!db) throwinvarg(lua, __KCFUNC__);
2602   g_curbur.sweap();
2603   bool rv = db->db->close();
2604   lua_pushboolean(lua, rv);
2605   return 1;
2606 }
2607 
2608 
2609 /**
2610  * Implementation of accept.
2611  */
db_accept(lua_State * lua)2612 static int db_accept(lua_State* lua) {
2613   int32_t argc = lua_gettop(lua);
2614   if (argc < 3 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2615   if (argc > 4) throwinvarg(lua, __KCFUNC__);
2616   lua_getfield(lua, 1, "db_ptr_");
2617   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
2618   size_t ksiz;
2619   const char* kbuf = lua_tolstring(lua, 2, &ksiz);
2620   if (!db || !kbuf) throwinvarg(lua, __KCFUNC__);
2621   bool writable = argc > 3 ? lua_toboolean(lua, 4) : true;
2622   bool rv;
2623   if (lua_istable(lua, 3) || lua_isfunction(lua, 3)) {
2624     lua_pushvalue(lua, 3);
2625     SoftVisitor visitor(lua, writable);
2626     rv = db->db->accept(kbuf, ksiz, &visitor, writable);
2627   } else {
2628     throwinvarg(lua, __KCFUNC__);
2629     rv = false;
2630   }
2631   lua_pushboolean(lua, rv);
2632   return 1;
2633 }
2634 
2635 
2636 /**
2637  * Implementation of accept_bulk.
2638  */
db_accept_bulk(lua_State * lua)2639 static int db_accept_bulk(lua_State* lua) {
2640   int32_t argc = lua_gettop(lua);
2641   if (argc < 3 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2642   if (argc > 4) throwinvarg(lua, __KCFUNC__);
2643   lua_getfield(lua, 1, "db_ptr_");
2644   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
2645   if (!db || !lua_istable(lua, 2)) throwinvarg(lua, __KCFUNC__);
2646   size_t knum = lua_objlen(lua, 2);
2647   StringVector keys;
2648   keys.reserve(knum);
2649   for (size_t i = 1; i <= knum; i++) {
2650     lua_rawgeti(lua, 2, i);
2651     size_t ksiz;
2652     const char* kbuf = lua_tolstring(lua, -1, &ksiz);
2653     if (kbuf) keys.push_back(std::string(kbuf, ksiz));
2654     lua_pop(lua, 1);
2655   }
2656   bool writable = argc > 3 ? lua_toboolean(lua, 4) : true;
2657   bool rv;
2658   if (lua_istable(lua, 3) || lua_isfunction(lua, 3)) {
2659     lua_pushvalue(lua, 3);
2660     SoftVisitor visitor(lua, writable);
2661     rv = db->db->accept_bulk(keys, &visitor, writable);
2662   } else {
2663     throwinvarg(lua, __KCFUNC__);
2664     rv = false;
2665   }
2666   lua_pushboolean(lua, rv);
2667   return 1;
2668 }
2669 
2670 
2671 /**
2672  * Implementation of iterate.
2673  */
db_iterate(lua_State * lua)2674 static int db_iterate(lua_State* lua) {
2675   int32_t argc = lua_gettop(lua);
2676   if (argc < 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2677   if (argc > 3) throwinvarg(lua, __KCFUNC__);
2678   lua_getfield(lua, 1, "db_ptr_");
2679   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
2680   if (!db) throwinvarg(lua, __KCFUNC__);
2681   bool writable = argc > 2 ? lua_toboolean(lua, 3) : true;
2682   bool rv;
2683   if (lua_istable(lua, 2) || lua_isfunction(lua, 2)) {
2684     lua_pushvalue(lua, 2);
2685     SoftVisitor visitor(lua, writable);
2686     rv = db->db->iterate(&visitor, writable);
2687   } else {
2688     throwinvarg(lua, __KCFUNC__);
2689     rv = false;
2690   }
2691   lua_pushboolean(lua, rv);
2692   return 1;
2693 }
2694 
2695 
2696 /**
2697  * Implementation of set.
2698  */
db_set(lua_State * lua)2699 static int db_set(lua_State* lua) {
2700   int32_t argc = lua_gettop(lua);
2701   if (argc < 3 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2702   if (argc > 4) throwinvarg(lua, __KCFUNC__);
2703   lua_getfield(lua, 1, "db_ptr_");
2704   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
2705   size_t ksiz;
2706   const char* kbuf = lua_tolstring(lua, 2, &ksiz);
2707   size_t vsiz;
2708   const char* vbuf = lua_tolstring(lua, 3, &vsiz);
2709   if (!db || !kbuf || !vbuf) throwinvarg(lua, __KCFUNC__);
2710   int64_t xt = argc > 3 && !lua_isnil(lua, 4) ? lua_tonumber(lua, 4) : kc::INT64MAX;
2711   bool rv = db->db->set(kbuf, ksiz, vbuf, vsiz, xt);
2712   lua_pushboolean(lua, rv);
2713   return 1;
2714 }
2715 
2716 
2717 /**
2718  * Implementation of add.
2719  */
db_add(lua_State * lua)2720 static int db_add(lua_State* lua) {
2721   int32_t argc = lua_gettop(lua);
2722   if (argc < 3 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2723   if (argc > 4) throwinvarg(lua, __KCFUNC__);
2724   lua_getfield(lua, 1, "db_ptr_");
2725   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
2726   size_t ksiz;
2727   const char* kbuf = lua_tolstring(lua, 2, &ksiz);
2728   size_t vsiz;
2729   const char* vbuf = lua_tolstring(lua, 3, &vsiz);
2730   if (!db || !kbuf || !vbuf) throwinvarg(lua, __KCFUNC__);
2731   int64_t xt = argc > 3 && !lua_isnil(lua, 4) ? lua_tonumber(lua, 4) : kc::INT64MAX;
2732   bool rv = db->db->add(kbuf, ksiz, vbuf, vsiz, xt);
2733   lua_pushboolean(lua, rv);
2734   return 1;
2735 }
2736 
2737 
2738 /**
2739  * Implementation of replace.
2740  */
db_replace(lua_State * lua)2741 static int db_replace(lua_State* lua) {
2742   int32_t argc = lua_gettop(lua);
2743   if (argc < 3 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2744   if (argc > 4) throwinvarg(lua, __KCFUNC__);
2745   lua_getfield(lua, 1, "db_ptr_");
2746   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
2747   size_t ksiz;
2748   const char* kbuf = lua_tolstring(lua, 2, &ksiz);
2749   size_t vsiz;
2750   const char* vbuf = lua_tolstring(lua, 3, &vsiz);
2751   if (!db || !kbuf || !vbuf) throwinvarg(lua, __KCFUNC__);
2752   int64_t xt = argc > 3 && !lua_isnil(lua, 4) ? lua_tonumber(lua, 4) : kc::INT64MAX;
2753   bool rv = db->db->replace(kbuf, ksiz, vbuf, vsiz, xt);
2754   lua_pushboolean(lua, rv);
2755   return 1;
2756 }
2757 
2758 
2759 /**
2760  * Implementation of append.
2761  */
db_append(lua_State * lua)2762 static int db_append(lua_State* lua) {
2763   int32_t argc = lua_gettop(lua);
2764   if (argc < 3 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2765   if (argc > 4) throwinvarg(lua, __KCFUNC__);
2766   lua_getfield(lua, 1, "db_ptr_");
2767   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
2768   size_t ksiz;
2769   const char* kbuf = lua_tolstring(lua, 2, &ksiz);
2770   size_t vsiz;
2771   const char* vbuf = lua_tolstring(lua, 3, &vsiz);
2772   if (!db || !kbuf || !vbuf) throwinvarg(lua, __KCFUNC__);
2773   int64_t xt = argc > 3 && !lua_isnil(lua, 4) ? lua_tonumber(lua, 4) : kc::INT64MAX;
2774   bool rv = db->db->append(kbuf, ksiz, vbuf, vsiz, xt);
2775   lua_pushboolean(lua, rv);
2776   return 1;
2777 }
2778 
2779 
2780 /**
2781  * Implementation of increment.
2782  */
db_increment(lua_State * lua)2783 static int db_increment(lua_State* lua) {
2784   int32_t argc = lua_gettop(lua);
2785   if (argc < 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2786   if (argc > 5) throwinvarg(lua, __KCFUNC__);
2787   lua_getfield(lua, 1, "db_ptr_");
2788   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
2789   size_t ksiz;
2790   const char* kbuf = lua_tolstring(lua, 2, &ksiz);
2791   if (!db || !kbuf) throwinvarg(lua, __KCFUNC__);
2792   int64_t num = argc > 2 ? lua_tonumber(lua, 3) : 0;
2793   double orig = argc > 3 ? lua_tonumber(lua, 4) : 0;
2794   int64_t orint;
2795   if (kc::chkinf(orig)) {
2796     orint = orig >= 0 ? kc::INT64MAX : kc::INT64MIN;
2797   } else {
2798     orint = orig;
2799   }
2800   int64_t xt = argc > 4 && !lua_isnil(lua, 5) ? lua_tonumber(lua, 5) : kc::INT64MAX;
2801   num = db->db->increment(kbuf, ksiz, num, orint, xt);
2802   if (num == kc::INT64MIN) {
2803     lua_pushnil(lua);
2804   } else {
2805     lua_pushnumber(lua, num);
2806   }
2807   return 1;
2808 }
2809 
2810 
2811 /**
2812  * Implementation of increment_double.
2813  */
db_increment_double(lua_State * lua)2814 static int db_increment_double(lua_State* lua) {
2815   int32_t argc = lua_gettop(lua);
2816   if (argc < 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2817   if (argc > 5) throwinvarg(lua, __KCFUNC__);
2818   lua_getfield(lua, 1, "db_ptr_");
2819   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
2820   size_t ksiz;
2821   const char* kbuf = lua_tolstring(lua, 2, &ksiz);
2822   if (!db || !kbuf) throwinvarg(lua, __KCFUNC__);
2823   double num = argc > 2 ? lua_tonumber(lua, 3) : 0;
2824   double orig = argc > 3 ? lua_tonumber(lua, 4) : 0;
2825   int64_t xt = argc > 4 && !lua_isnil(lua, 5) ? lua_tonumber(lua, 5) : kc::INT64MAX;
2826   num = db->db->increment_double(kbuf, ksiz, num, orig, xt);
2827   if (kc::chknan(num)) {
2828     lua_pushnil(lua);
2829   } else {
2830     lua_pushnumber(lua, num);
2831   }
2832   return 1;
2833 }
2834 
2835 
2836 /**
2837  * Implementation of cas.
2838  */
db_cas(lua_State * lua)2839 static int db_cas(lua_State* lua) {
2840   int32_t argc = lua_gettop(lua);
2841   if (argc < 4 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2842   if (argc > 5) throwinvarg(lua, __KCFUNC__);
2843   lua_getfield(lua, 1, "db_ptr_");
2844   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
2845   size_t ksiz;
2846   const char* kbuf = lua_tolstring(lua, 2, &ksiz);
2847   size_t ovsiz;
2848   const char* ovbuf = lua_tolstring(lua, 3, &ovsiz);
2849   size_t nvsiz;
2850   const char* nvbuf = lua_tolstring(lua, 4, &nvsiz);
2851   if (!db || !kbuf) throwinvarg(lua, __KCFUNC__);
2852   int64_t xt = argc > 4 && !lua_isnil(lua, 5) ? lua_tonumber(lua, 5) : kc::INT64MAX;
2853   bool rv = db->db->cas(kbuf, ksiz, ovbuf, ovsiz, nvbuf, nvsiz, xt);
2854   lua_pushboolean(lua, rv);
2855   return 1;
2856 }
2857 
2858 
2859 /**
2860  * Implementation of remove.
2861  */
db_remove(lua_State * lua)2862 static int db_remove(lua_State* lua) {
2863   int32_t argc = lua_gettop(lua);
2864   if (argc != 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2865   lua_getfield(lua, 1, "db_ptr_");
2866   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
2867   size_t ksiz;
2868   const char* kbuf = lua_tolstring(lua, 2, &ksiz);
2869   if (!db || !kbuf) throwinvarg(lua, __KCFUNC__);
2870   bool rv = db->db->remove(kbuf, ksiz);
2871   lua_pushboolean(lua, rv);
2872   return 1;
2873 }
2874 
2875 
2876 /**
2877  * Implementation of get.
2878  */
db_get(lua_State * lua)2879 static int db_get(lua_State* lua) {
2880   int32_t argc = lua_gettop(lua);
2881   if (argc != 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2882   lua_getfield(lua, 1, "db_ptr_");
2883   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
2884   size_t ksiz;
2885   const char* kbuf = lua_tolstring(lua, 2, &ksiz);
2886   if (!db || !kbuf) throwinvarg(lua, __KCFUNC__);
2887   size_t vsiz;
2888   int64_t xt;
2889   char* vbuf = db->db->get(kbuf, ksiz, &vsiz, &xt);
2890   if (vbuf) {
2891     lua_pushlstring(lua, vbuf, vsiz);
2892     lua_pushnumber(lua, xt < kt::TimedDB::XTMAX ? xt : kt::TimedDB::XTMAX);
2893     delete[] vbuf;
2894     return 2;
2895   }
2896   lua_pushnil(lua);
2897   return 1;
2898 }
2899 
2900 
2901 /**
2902  * Implementation of check.
2903  */
db_check(lua_State * lua)2904 static int db_check(lua_State* lua) {
2905   int32_t argc = lua_gettop(lua);
2906   if (argc != 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2907   lua_getfield(lua, 1, "db_ptr_");
2908   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
2909   size_t ksiz;
2910   const char* kbuf = lua_tolstring(lua, 2, &ksiz);
2911   if (!db || !kbuf) throwinvarg(lua, __KCFUNC__);
2912   int32_t vsiz = db->db->check(kbuf, ksiz);
2913   lua_pushnumber(lua, vsiz);
2914   return 1;
2915 }
2916 
2917 
2918 /**
2919  * Implementation of seize.
2920  */
db_seize(lua_State * lua)2921 static int db_seize(lua_State* lua) {
2922   int32_t argc = lua_gettop(lua);
2923   if (argc != 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2924   lua_getfield(lua, 1, "db_ptr_");
2925   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
2926   size_t ksiz;
2927   const char* kbuf = lua_tolstring(lua, 2, &ksiz);
2928   if (!db || !kbuf) throwinvarg(lua, __KCFUNC__);
2929   size_t vsiz;
2930   int64_t xt;
2931   char* vbuf = db->db->seize(kbuf, ksiz, &vsiz, &xt);
2932   if (vbuf) {
2933     lua_pushlstring(lua, vbuf, vsiz);
2934     lua_pushnumber(lua, xt < kt::TimedDB::XTMAX ? xt : kt::TimedDB::XTMAX);
2935     delete[] vbuf;
2936     return 2;
2937   }
2938   lua_pushnil(lua);
2939   return 1;
2940 }
2941 
2942 
2943 /**
2944  * Implementation of set_bulk.
2945  */
db_set_bulk(lua_State * lua)2946 static int db_set_bulk(lua_State* lua) {
2947   int32_t argc = lua_gettop(lua);
2948   if (argc < 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
2949   if (argc > 4) throwinvarg(lua, __KCFUNC__);
2950   lua_getfield(lua, 1, "db_ptr_");
2951   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
2952   if (!db || !lua_istable(lua, 2)) throwinvarg(lua, __KCFUNC__);
2953   StringMap recs;
2954   lua_pushnil(lua);
2955   while (lua_next(lua, 2) != 0) {
2956     char knbuf[kc::NUMBUFSIZ];
2957     const char* kbuf = NULL;
2958     size_t ksiz = 0;
2959     switch (lua_type(lua, -2)) {
2960       case LUA_TNUMBER: {
2961         double num = lua_tonumber(lua, -2);
2962         if (num == std::floor(num)) {
2963           ksiz = std::sprintf(knbuf, "%lld", (long long)num);
2964         } else {
2965           ksiz = std::snprintf(knbuf, sizeof(knbuf), "%.6f", num);
2966           knbuf[sizeof(knbuf)-1] = '\0';
2967         }
2968         kbuf = knbuf;
2969         break;
2970       }
2971       case LUA_TSTRING: {
2972         kbuf = lua_tolstring(lua, -2, &ksiz);
2973         break;
2974       }
2975     }
2976     char vnbuf[kc::NUMBUFSIZ];
2977     const char* vbuf = NULL;
2978     size_t vsiz = 0;
2979     switch (lua_type(lua, -1)) {
2980       case LUA_TNUMBER: {
2981         double num = lua_tonumber(lua, -1);
2982         if (num == std::floor(num)) {
2983           vsiz = std::sprintf(vnbuf, "%lld", (long long)num);
2984         } else {
2985           vsiz = std::snprintf(vnbuf, sizeof(vnbuf), "%.6f", num);
2986           vnbuf[sizeof(vnbuf)-1] = '\0';
2987         }
2988         vbuf = vnbuf;
2989         break;
2990       }
2991       case LUA_TSTRING: {
2992         vbuf = lua_tolstring(lua, -1, &vsiz);
2993         break;
2994       }
2995     }
2996     if (kbuf && vbuf) recs[std::string(kbuf, ksiz)] = std::string(vbuf, vsiz);
2997     lua_pop(lua, 1);
2998   }
2999   int64_t xt = argc > 2 && !lua_isnil(lua, 3) ? lua_tonumber(lua, 3) : kc::INT64MAX;
3000   bool atomic = argc > 3 ? lua_toboolean(lua, 4) : true;
3001   int64_t rv = db->db->set_bulk(recs, xt, atomic);
3002   lua_pushnumber(lua, rv);
3003   return 1;
3004 }
3005 
3006 
3007 /**
3008  * Implementation of remove_bulk.
3009  */
db_remove_bulk(lua_State * lua)3010 static int db_remove_bulk(lua_State* lua) {
3011   int32_t argc = lua_gettop(lua);
3012   if (argc < 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
3013   if (argc > 3) throwinvarg(lua, __KCFUNC__);
3014   lua_getfield(lua, 1, "db_ptr_");
3015   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
3016   if (!db || !lua_istable(lua, 2)) throwinvarg(lua, __KCFUNC__);
3017   size_t knum = lua_objlen(lua, 2);
3018   StringVector keys;
3019   keys.reserve(knum);
3020   for (size_t i = 1; i <= knum; i++) {
3021     lua_rawgeti(lua, 2, i);
3022     size_t ksiz;
3023     const char* kbuf = lua_tolstring(lua, -1, &ksiz);
3024     if (kbuf) keys.push_back(std::string(kbuf, ksiz));
3025     lua_pop(lua, 1);
3026   }
3027   bool atomic = argc > 2 ? lua_toboolean(lua, 3) : true;
3028   int64_t rv = db->db->remove_bulk(keys, atomic);
3029   lua_pushnumber(lua, rv);
3030   return 1;
3031 }
3032 
3033 
3034 /**
3035  * Implementation of get_bulk.
3036  */
db_get_bulk(lua_State * lua)3037 static int db_get_bulk(lua_State* lua) {
3038   int32_t argc = lua_gettop(lua);
3039   if (argc < 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
3040   if (argc > 3) throwinvarg(lua, __KCFUNC__);
3041   lua_getfield(lua, 1, "db_ptr_");
3042   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
3043   if (!db || !lua_istable(lua, 2)) throwinvarg(lua, __KCFUNC__);
3044   size_t knum = lua_objlen(lua, 2);
3045   StringVector keys;
3046   keys.reserve(knum);
3047   for (size_t i = 1; i <= knum; i++) {
3048     lua_rawgeti(lua, 2, i);
3049     size_t ksiz;
3050     const char* kbuf = lua_tolstring(lua, -1, &ksiz);
3051     if (kbuf) keys.push_back(std::string(kbuf, ksiz));
3052     lua_pop(lua, 1);
3053   }
3054   bool atomic = argc > 2 ? lua_toboolean(lua, 3) : true;
3055   StringMap recs;
3056   int64_t rv = db->db->get_bulk(keys, &recs, atomic);
3057   if (rv < 0) {
3058     lua_pushnil(lua);
3059   } else {
3060     lua_newtable(lua);
3061     StringMap::const_iterator it = recs.begin();
3062     StringMap::const_iterator itend = recs.end();
3063     while (it != itend) {
3064       lua_pushlstring(lua, it->first.data(), it->first.size());
3065       lua_pushlstring(lua, it->second.data(), it->second.size());
3066       lua_settable(lua, -3);
3067       ++it;
3068     }
3069   }
3070   return 1;
3071 }
3072 
3073 
3074 /**
3075  * Implementation of clear.
3076  */
db_clear(lua_State * lua)3077 static int db_clear(lua_State* lua) {
3078   int32_t argc = lua_gettop(lua);
3079   if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
3080   lua_getfield(lua, 1, "db_ptr_");
3081   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
3082   if (!db) throwinvarg(lua, __KCFUNC__);
3083   bool rv = db->db->clear();
3084   lua_pushboolean(lua, rv);
3085   return 1;
3086 }
3087 
3088 
3089 /**
3090  * Implementation of synchronize.
3091  */
db_synchronize(lua_State * lua)3092 static int db_synchronize(lua_State* lua) {
3093   int32_t argc = lua_gettop(lua);
3094   if (argc < 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
3095   if (argc > 3) throwinvarg(lua, __KCFUNC__);
3096   lua_getfield(lua, 1, "db_ptr_");
3097   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
3098   if (!db) throwinvarg(lua, __KCFUNC__);
3099   bool hard = argc > 1 ? lua_toboolean(lua, 2) : false;
3100   bool rv;
3101   if (argc > 2 && (lua_istable(lua, 3) || lua_isfunction(lua, 3))) {
3102     lua_pushvalue(lua, 3);
3103     SoftFileProcessor proc(lua);
3104     rv = db->db->synchronize(hard, &proc);
3105   } else {
3106     rv = db->db->synchronize(hard, NULL);
3107   }
3108   lua_pushboolean(lua, rv);
3109   return 1;
3110 }
3111 
3112 
3113 /**
3114  * Implementation of occupy.
3115  */
db_occupy(lua_State * lua)3116 static int db_occupy(lua_State* lua) {
3117   int32_t argc = lua_gettop(lua);
3118   if (argc < 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
3119   if (argc > 3) throwinvarg(lua, __KCFUNC__);
3120   lua_getfield(lua, 1, "db_ptr_");
3121   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
3122   if (!db) throwinvarg(lua, __KCFUNC__);
3123   bool writable = argc > 1 ? lua_toboolean(lua, 2) : false;
3124   bool rv;
3125   if (argc > 2 && (lua_istable(lua, 3) || lua_isfunction(lua, 3))) {
3126     lua_pushvalue(lua, 3);
3127     SoftFileProcessor proc(lua);
3128     rv = db->db->occupy(writable, &proc);
3129   } else {
3130     rv = db->db->occupy(writable, NULL);
3131   }
3132   lua_pushboolean(lua, rv);
3133   return 1;
3134 }
3135 
3136 
3137 /**
3138  * Implementation of copy.
3139  */
db_copy(lua_State * lua)3140 static int db_copy(lua_State* lua) {
3141   int32_t argc = lua_gettop(lua);
3142   if (argc != 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
3143   lua_getfield(lua, 1, "db_ptr_");
3144   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
3145   const char* dest = lua_tostring(lua, 2);
3146   if (!db || !dest) throwinvarg(lua, __KCFUNC__);
3147   bool rv = db->db->copy(dest);
3148   lua_pushboolean(lua, rv);
3149   return 1;
3150 }
3151 
3152 
3153 /**
3154  * Implementation of begin_transaction.
3155  */
db_begin_transaction(lua_State * lua)3156 static int db_begin_transaction(lua_State* lua) {
3157   int32_t argc = lua_gettop(lua);
3158   if (argc < 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
3159   if (argc > 2) throwinvarg(lua, __KCFUNC__);
3160   lua_getfield(lua, 1, "db_ptr_");
3161   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
3162   if (!db) throwinvarg(lua, __KCFUNC__);
3163   bool hard = argc > 1 ? lua_toboolean(lua, 2) : false;
3164   bool rv = db->db->begin_transaction(hard);
3165   lua_pushboolean(lua, rv);
3166   return 1;
3167 }
3168 
3169 
3170 /**
3171  * Implementation of end_transaction.
3172  */
db_end_transaction(lua_State * lua)3173 static int db_end_transaction(lua_State* lua) {
3174   int32_t argc = lua_gettop(lua);
3175   if (argc < 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
3176   if (argc > 2) throwinvarg(lua, __KCFUNC__);
3177   lua_getfield(lua, 1, "db_ptr_");
3178   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
3179   if (!db) throwinvarg(lua, __KCFUNC__);
3180   bool commit = argc > 1 ? lua_toboolean(lua, 2) : true;
3181   bool rv = db->db->end_transaction(commit);
3182   lua_pushboolean(lua, rv);
3183   return 1;
3184 }
3185 
3186 
3187 /**
3188  * Implementation of transaction.
3189  */
db_transaction(lua_State * lua)3190 static int db_transaction(lua_State* lua) {
3191   int32_t argc = lua_gettop(lua);
3192   if (argc < 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
3193   if (argc > 3) throwinvarg(lua, __KCFUNC__);
3194   lua_getfield(lua, 1, "db_ptr_");
3195   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
3196   if (!db) throwinvarg(lua, __KCFUNC__);
3197   bool hard = argc > 2 ? lua_toboolean(lua, 3) : false;
3198   lua_getfield(lua, 1, "begin_transaction");
3199   lua_pushvalue(lua, 1);
3200   lua_pushboolean(lua, hard);
3201   lua_call(lua, 2, 1);
3202   if (!lua_toboolean(lua, -1)) return 1;
3203   lua_pushvalue(lua, 2);
3204   int32_t erridx = 0;
3205   if (lua_pcall(lua, 0, 1, 0) != 0) erridx = lua_gettop(lua);
3206   bool commit = erridx == 0 && lua_toboolean(lua, -1);
3207   lua_getfield(lua, 1, "end_transaction");
3208   lua_pushvalue(lua, 1);
3209   lua_pushboolean(lua, commit);
3210   lua_call(lua, 2, 1);
3211   if (erridx > 0) {
3212     lua_pushvalue(lua, erridx);
3213     lua_error(lua);
3214   }
3215   return 1;
3216 }
3217 
3218 
3219 /**
3220  * Implementation of dump_snapshot.
3221  */
db_dump_snapshot(lua_State * lua)3222 static int db_dump_snapshot(lua_State* lua) {
3223   int32_t argc = lua_gettop(lua);
3224   if (argc != 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
3225   lua_getfield(lua, 1, "db_ptr_");
3226   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
3227   const char* dest = lua_tostring(lua, 2);
3228   if (!db || !dest) throwinvarg(lua, __KCFUNC__);
3229   bool rv = db->db->dump_snapshot(dest);
3230   lua_pushboolean(lua, rv);
3231   return 1;
3232 }
3233 
3234 
3235 /**
3236  * Implementation of load_snapshot.
3237  */
db_load_snapshot(lua_State * lua)3238 static int db_load_snapshot(lua_State* lua) {
3239   int32_t argc = lua_gettop(lua);
3240   if (argc != 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
3241   lua_getfield(lua, 1, "db_ptr_");
3242   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
3243   const char* src = lua_tostring(lua, 2);
3244   if (!db || !src) throwinvarg(lua, __KCFUNC__);
3245   bool rv = db->db->load_snapshot(src);
3246   lua_pushboolean(lua, rv);
3247   return 1;
3248 }
3249 
3250 
3251 /**
3252  * Implementation of count.
3253  */
db_count(lua_State * lua)3254 static int db_count(lua_State* lua) {
3255   int32_t argc = lua_gettop(lua);
3256   if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
3257   lua_getfield(lua, 1, "db_ptr_");
3258   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
3259   if (!db) throwinvarg(lua, __KCFUNC__);
3260   int64_t count = db->db->count();
3261   lua_pushnumber(lua, count);
3262   return 1;
3263 }
3264 
3265 
3266 /**
3267  * Implementation of size.
3268  */
db_size(lua_State * lua)3269 static int db_size(lua_State* lua) {
3270   int32_t argc = lua_gettop(lua);
3271   if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
3272   lua_getfield(lua, 1, "db_ptr_");
3273   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
3274   if (!db) throwinvarg(lua, __KCFUNC__);
3275   int64_t size = db->db->size();
3276   lua_pushnumber(lua, size);
3277   return 1;
3278 }
3279 
3280 
3281 /**
3282  * Implementation of path.
3283  */
db_path(lua_State * lua)3284 static int db_path(lua_State* lua) {
3285   int32_t argc = lua_gettop(lua);
3286   if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
3287   lua_getfield(lua, 1, "db_ptr_");
3288   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
3289   if (!db) throwinvarg(lua, __KCFUNC__);
3290   const std::string& path = db->db->path();
3291   if (path.size() > 0) {
3292     lua_pushstring(lua, path.c_str());
3293   } else {
3294     lua_pushnil(lua);
3295   }
3296   return 1;
3297 }
3298 
3299 
3300 /**
3301  * Implementation of status.
3302  */
db_status(lua_State * lua)3303 static int db_status(lua_State* lua) {
3304   int32_t argc = lua_gettop(lua);
3305   if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
3306   lua_getfield(lua, 1, "db_ptr_");
3307   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
3308   if (!db) throwinvarg(lua, __KCFUNC__);
3309   StringMap status;
3310   bool rv = db->db->status(&status);
3311   if (rv) {
3312     lua_newtable(lua);
3313     StringMap::const_iterator it = status.begin();
3314     StringMap::const_iterator itend = status.end();
3315     while (it != itend) {
3316       lua_pushlstring(lua, it->first.data(), it->first.size());
3317       lua_pushlstring(lua, it->second.data(), it->second.size());
3318       lua_settable(lua, -3);
3319       ++it;
3320     }
3321   } else {
3322     lua_pushnil(lua);
3323   }
3324   return 1;
3325 }
3326 
3327 
3328 /**
3329  * Implementation of match_prefix.
3330  */
db_match_prefix(lua_State * lua)3331 static int db_match_prefix(lua_State* lua) {
3332   int32_t argc = lua_gettop(lua);
3333   if (argc < 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
3334   lua_getfield(lua, 1, "db_ptr_");
3335   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
3336   size_t psiz;
3337   const char* pbuf = lua_tolstring(lua, 2, &psiz);
3338   if (!db || !pbuf) throwinvarg(lua, __KCFUNC__);
3339   int64_t max = argc > 2 ? lua_tonumber(lua, 3) : -1;
3340   StringVector keys;
3341   int64_t num = db->db->match_prefix(std::string(pbuf, psiz), &keys, max);
3342   if (num >= 0) {
3343     lua_newtable(lua);
3344     StringVector::const_iterator it = keys.begin();
3345     StringVector::const_iterator itend = keys.end();
3346     int32_t idx = 1;
3347     while (it != itend) {
3348       lua_pushlstring(lua, it->data(), it->size());
3349       lua_rawseti(lua, -2, idx++);
3350       ++it;
3351     }
3352   } else {
3353     lua_pushnil(lua);
3354   }
3355   return 1;
3356 }
3357 
3358 
3359 /**
3360  * Implementation of match_regex.
3361  */
db_match_regex(lua_State * lua)3362 static int db_match_regex(lua_State* lua) {
3363   int32_t argc = lua_gettop(lua);
3364   if (argc < 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
3365   lua_getfield(lua, 1, "db_ptr_");
3366   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
3367   size_t rsiz;
3368   const char* rbuf = lua_tolstring(lua, 2, &rsiz);
3369   if (!db || !rbuf) throwinvarg(lua, __KCFUNC__);
3370   int64_t max = argc > 2 ? lua_tonumber(lua, 3) : -1;
3371   StringVector keys;
3372   int64_t num = db->db->match_regex(std::string(rbuf, rsiz), &keys, max);
3373   if (num >= 0) {
3374     lua_newtable(lua);
3375     StringVector::const_iterator it = keys.begin();
3376     StringVector::const_iterator itend = keys.end();
3377     int32_t idx = 1;
3378     while (it != itend) {
3379       lua_pushlstring(lua, it->data(), it->size());
3380       lua_rawseti(lua, -2, idx++);
3381       ++it;
3382     }
3383   } else {
3384     lua_pushnil(lua);
3385   }
3386   return 1;
3387 }
3388 
3389 
3390 /**
3391  * Implementation of match_similar.
3392  */
db_match_similar(lua_State * lua)3393 static int db_match_similar(lua_State* lua) {
3394   int32_t argc = lua_gettop(lua);
3395   if (argc < 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
3396   lua_getfield(lua, 1, "db_ptr_");
3397   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
3398   size_t osiz;
3399   const char* obuf = lua_tolstring(lua, 2, &osiz);
3400   if (!db || !obuf) throwinvarg(lua, __KCFUNC__);
3401   int64_t range = argc > 2 ? lua_tonumber(lua, 3) : -1;
3402   bool utf = argc > 3 ? lua_toboolean(lua, 4) : false;
3403   int64_t max = argc > 4 ? lua_tonumber(lua, 5) : -1;
3404   StringVector keys;
3405   int64_t num = db->db->match_similar(std::string(obuf, osiz), range, utf, &keys, max);
3406   if (num >= 0) {
3407     lua_newtable(lua);
3408     StringVector::const_iterator it = keys.begin();
3409     StringVector::const_iterator itend = keys.end();
3410     int32_t idx = 1;
3411     while (it != itend) {
3412       lua_pushlstring(lua, it->data(), it->size());
3413       lua_rawseti(lua, -2, idx++);
3414       ++it;
3415     }
3416   } else {
3417     lua_pushnil(lua);
3418   }
3419   return 1;
3420 }
3421 
3422 
3423 /**
3424  * Implementation of merge.
3425  */
db_merge(lua_State * lua)3426 static int db_merge(lua_State* lua) {
3427   int32_t argc = lua_gettop(lua);
3428   if (argc < 2 || !lua_istable(lua, 1) || !lua_istable(lua, 2)) throwinvarg(lua, __KCFUNC__);
3429   if (argc > 3) throwinvarg(lua, __KCFUNC__);
3430   lua_getfield(lua, 1, "db_ptr_");
3431   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
3432   if (!db) throwinvarg(lua, __KCFUNC__);
3433   uint32_t mode = kt::TimedDB::MSET;
3434   if (argc > 2 && lua_isnumber(lua, 3)) mode = lua_tonumber(lua, 3);
3435   size_t num = lua_objlen(lua, 2);
3436   if (num < 1) {
3437     lua_pushboolean(lua, true);
3438     return 1;
3439   }
3440   kt::TimedDB** srcary = new kt::TimedDB*[num];
3441   size_t srcnum = 0;
3442   for (size_t i = 1; i <= num; i++) {
3443     lua_rawgeti(lua, 2, i);
3444     if (lua_istable(lua, -1)) {
3445       lua_getfield(lua, -1, "db_ptr_");
3446       SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
3447       srcary[srcnum++] = db->db;
3448       lua_pop(lua, 1);
3449     }
3450     lua_pop(lua, 1);
3451   }
3452   bool rv = db->db->merge(srcary, srcnum, (kt::TimedDB::MergeMode)mode);
3453   delete[] srcary;
3454   lua_pushboolean(lua, rv);
3455   return 1;
3456 }
3457 
3458 
3459 /**
3460  * Implementation of mapreduce.
3461  */
db_mapreduce(lua_State * lua)3462 static int db_mapreduce(lua_State* lua) {
3463   int32_t argc = lua_gettop(lua);
3464   if (argc < 3 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
3465   if (argc > 10) throwinvarg(lua, __KCFUNC__);
3466   lua_getfield(lua, 1, "db_ptr_");
3467   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
3468   if (!db) throwinvarg(lua, __KCFUNC__);
3469   if (!db || !lua_isfunction(lua, 2) || !lua_isfunction(lua, 3)) throwinvarg(lua, __KCFUNC__);
3470   const char* tmppath = argc > 3 ? lua_tostring(lua, 4) : NULL;
3471   if (!tmppath) tmppath = "";
3472   uint32_t opts = argc > 4 ? lua_tonumber(lua, 5) : 0;
3473   int32_t dbnum = argc > 5 ? lua_tonumber(lua, 6) : -1;
3474   int64_t clim = argc > 6 ? lua_tonumber(lua, 7) : -1;
3475   int64_t cbnum = argc > 7 ? lua_tonumber(lua, 8) : -1;
3476   int32_t logidx = -1;
3477   if (argc > 8 && lua_isfunction(lua, 9)) logidx = 9;
3478   int32_t procidx = -1;
3479   if (argc > 9 && lua_isfunction(lua, 10)) procidx = 10;
3480   SoftMapReduce mr(lua, logidx, procidx);
3481   mr.tune_storage(dbnum, clim, cbnum);
3482   bool rv = mr.execute(db->db, tmppath, opts);
3483   lua_pushnil(lua);
3484   lua_setglobal(lua, "__mr_iter");
3485   lua_pushnil(lua);
3486   lua_setglobal(lua, "__mr_self");
3487   lua_pushboolean(lua, rv);
3488   return 1;
3489 }
3490 
3491 
3492 /**
3493  * Implementation of mapreduce_emit.
3494  */
db_mapreduce_emit(lua_State * lua)3495 static int db_mapreduce_emit(lua_State* lua) {
3496   int32_t argc = lua_gettop(lua);
3497   if (argc != 2) throwinvarg(lua, __KCFUNC__);
3498   size_t ksiz;
3499   const char* kbuf = lua_tolstring(lua, 1, &ksiz);
3500   size_t vsiz;
3501   const char* vbuf = lua_tolstring(lua, 2, &vsiz);
3502   if (!kbuf || !vbuf) throwinvarg(lua, __KCFUNC__);
3503   lua_getglobal(lua, "__mr_self");
3504   SoftMapReduce* mr = (SoftMapReduce*)lua_touserdata(lua, -1);
3505   bool rv;
3506   if (mr) {
3507     rv = mr->emit_public(kbuf, ksiz, vbuf, vsiz);
3508   } else {
3509     rv = false;
3510   }
3511   lua_pushboolean(lua, rv);
3512   return 1;
3513 }
3514 
3515 
3516 /**
3517  * Implementation of mapreduce_iter.
3518  */
db_mapreduce_iter(lua_State * lua)3519 static int db_mapreduce_iter(lua_State* lua) {
3520   int32_t argc = lua_gettop(lua);
3521   if (argc != 0) throwinvarg(lua, __KCFUNC__);
3522   lua_getglobal(lua, "__mr_iter");
3523   kc::MapReduce::ValueIterator* iter = (kc::MapReduce::ValueIterator*)lua_touserdata(lua, -1);
3524   if (iter) {
3525     size_t vsiz;
3526     const char* vbuf = iter->next(&vsiz);
3527     if (vbuf) {
3528       lua_pushlstring(lua, vbuf, vsiz);
3529     } else {
3530       lua_pushnil(lua);
3531     }
3532   } else {
3533     lua_pushnil(lua);
3534   }
3535   return 1;
3536 }
3537 
3538 
3539 /**
3540  * Implementation of cursor.
3541  */
db_cursor(lua_State * lua)3542 static int db_cursor(lua_State* lua) {
3543   int32_t argc = lua_gettop(lua);
3544   if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
3545   lua_getfield(lua, 1, "db_ptr_");
3546   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
3547   if (!db) throwinvarg(lua, __KCFUNC__);
3548   lua_getfield(lua, 1, "cur_");
3549   lua_getfield(lua, -1, "new");
3550   lua_getfield(lua, 1, "cur_");
3551   lua_pushvalue(lua, 1);
3552   lua_call(lua, 2, 1);
3553   return 1;
3554 }
3555 
3556 
3557 /**
3558  * Implementation of cursor_process.
3559  */
db_cursor_process(lua_State * lua)3560 static int db_cursor_process(lua_State* lua) {
3561   int32_t argc = lua_gettop(lua);
3562   if (argc != 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
3563   if (!lua_isfunction(lua, 2)) throwinvarg(lua, __KCFUNC__);
3564   lua_getfield(lua, 1, "db_ptr_");
3565   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
3566   if (!db) throwinvarg(lua, __KCFUNC__);
3567   lua_getfield(lua, 1, "cur_");
3568   lua_getfield(lua, -1, "new");
3569   lua_getfield(lua, 1, "cur_");
3570   lua_pushvalue(lua, 1);
3571   lua_call(lua, 2, 1);
3572   int32_t objidx = lua_gettop(lua);
3573   lua_pushvalue(lua, 2);
3574   lua_pushvalue(lua, objidx);
3575   int32_t erridx = 0;
3576   if (lua_pcall(lua, 1, 0, 0) != 0) erridx = lua_gettop(lua);
3577   lua_getfield(lua, objidx, "disable");
3578   lua_pushvalue(lua, objidx);
3579   lua_call(lua, 1, 0);
3580   if (erridx > 0) {
3581     lua_pushvalue(lua, erridx);
3582     lua_error(lua);
3583   }
3584   return 0;
3585 }
3586 
3587 
3588 /**
3589  * Implementation of pairs.
3590  */
db_pairs(lua_State * lua)3591 static int db_pairs(lua_State* lua) {
3592   int32_t argc = lua_gettop(lua);
3593   if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__);
3594   lua_getfield(lua, 1, "db_ptr_");
3595   SoftDB* db = (SoftDB*)lua_touserdata(lua, -1);
3596   if (!db) throwinvarg(lua, __KCFUNC__);
3597   lua_getfield(lua, 1, "cur_");
3598   lua_getfield(lua, -1, "new");
3599   lua_getfield(lua, 1, "cur_");
3600   lua_pushvalue(lua, 1);
3601   lua_call(lua, 2, 1);
3602   lua_getfield(lua, -1, "jump");
3603   lua_pushvalue(lua, -2);
3604   lua_call(lua, 1, 0);
3605   lua_pushvalue(lua, 1);
3606   lua_pushnil(lua);
3607   return 3;
3608 }
3609 
3610 
3611 /**
3612  * Implementation of log.
3613  */
serv_log(lua_State * lua)3614 static int serv_log(lua_State* lua) {
3615   int32_t argc = lua_gettop(lua);
3616   if (argc != 2 || !lua_isstring(lua, 1)) throwinvarg(lua, __KCFUNC__);
3617   lua_getglobal(lua, "__kyototycoon__");
3618   lua_getfield(lua, -1, "__serv__");
3619   kt::RPCServer* serv = (kt::RPCServer*)lua_touserdata(lua, -1);
3620   const char* kstr = lua_tostring(lua, 1);
3621   const char* message = lua_tostring(lua, 2);
3622   if (kstr && message) {
3623     kt::RPCServer::Logger::Kind kind = kt::RPCServer::Logger::DEBUG;
3624     if (!kc::stricmp(kstr, "info")) {
3625       kind = kt::RPCServer::Logger::INFO;
3626     } else if (!kc::stricmp(kstr, "system")) {
3627       kind = kt::RPCServer::Logger::SYSTEM;
3628     } else if (!kc::stricmp(kstr, "error")) {
3629       kind = kt::RPCServer::Logger::ERROR;
3630     }
3631     serv->log(kind, "[SCRIPT]: %s", message);
3632   }
3633   return 0;
3634 }
3635 
3636 
3637 #else
3638 
3639 
3640 /**
3641  * ScriptProcessor internal.
3642  */
3643 struct ScriptProcessorCore {
3644   std::string path;
3645   int32_t thid;
3646   kt::RPCServer* serv;
3647   kt::TimedDB* dbs;
3648   int32_t dbnum;
3649   const std::map<std::string, int32_t>* dbmap;
3650 };
3651 
3652 
3653 /**
3654  * Default constructor.
3655  */
ScriptProcessor()3656 ScriptProcessor::ScriptProcessor() {
3657   _assert_(true);
3658   ScriptProcessorCore* core = new ScriptProcessorCore;
3659   core->thid = 0;
3660   core->serv = NULL;
3661   core->dbs = NULL;
3662   core->dbnum = 0;
3663   core->dbmap = NULL;
3664   opq_ = core;
3665 }
3666 
3667 
3668 /**
3669  * Destructor.
3670  */
~ScriptProcessor()3671 ScriptProcessor::~ScriptProcessor() {
3672   _assert_(true);
3673   ScriptProcessorCore* core = (ScriptProcessorCore*)opq_;
3674   delete core;
3675 }
3676 
3677 
3678 /**
3679  * Set domain-specific resources.
3680  */
set_resources(int32_t thid,kt::RPCServer * serv,kt::TimedDB * dbs,int32_t dbnum,const std::map<std::string,int32_t> * dbmap)3681 bool ScriptProcessor::set_resources(int32_t thid, kt::RPCServer* serv,
3682                                     kt::TimedDB* dbs, int32_t dbnum,
3683                                     const std::map<std::string, int32_t>* dbmap) {
3684   _assert_(serv && dbs && dbnum >= 0 && dbmap);
3685   ScriptProcessorCore* core = (ScriptProcessorCore*)opq_;
3686   core->thid = thid;
3687   core->serv = serv;
3688   core->dbs = dbs;
3689   core->dbnum = dbnum;
3690   core->dbmap = dbmap;
3691   return true;
3692 }
3693 
3694 
3695 /**
3696  * Load a script file.
3697  */
load(const std::string & path)3698 bool ScriptProcessor::load(const std::string& path) {
3699   _assert_(true);
3700   ScriptProcessorCore* core = (ScriptProcessorCore*)opq_;
3701   core->path = path;
3702   return true;
3703 }
3704 
3705 
3706 /**
3707  * Clear the internal state.
3708  */
clear()3709 void ScriptProcessor::clear() {
3710   _assert_(true);
3711   ScriptProcessorCore* core = new ScriptProcessorCore;
3712   core->thid = 0;
3713   core->serv = NULL;
3714   core->dbs = NULL;
3715   core->dbnum = 0;
3716   core->dbmap = NULL;
3717 }
3718 
3719 
3720 /**
3721  * Call a procedure.
3722  */
call(const std::string & name,const std::map<std::string,std::string> & inmap,std::map<std::string,std::string> & outmap)3723 kt::RPCClient::ReturnValue ScriptProcessor::call(const std::string& name,
3724                                                  const std::map<std::string, std::string>& inmap,
3725                                                  std::map<std::string, std::string>& outmap) {
3726   _assert_(true);
3727   ScriptProcessorCore* core = (ScriptProcessorCore*)opq_;
3728   kt::RPCClient::ReturnValue rv;
3729   if (name == "echo") {
3730     std::string keys;
3731     std::map<std::string, std::string>::const_iterator it = inmap.begin();
3732     std::map<std::string, std::string>::const_iterator itend = inmap.end();
3733     while (it != itend) {
3734       if (!keys.empty()) keys.append(",");
3735       keys.append(it->first);
3736       ++it;
3737     }
3738     core->serv->log(kt::RPCServer::Logger::DEBUG, "[SCRIPT]: %s: thid=%d inmap=%s",
3739                     name.c_str(), core->thid, keys.c_str());
3740     outmap.insert(inmap.begin(), inmap.end());
3741     rv = kt::RPCClient::RVSUCCESS;
3742   } else {
3743     rv = kt::RPCClient::RVENOIMPL;
3744   }
3745   return rv;
3746 }
3747 
3748 
3749 #endif
3750 
3751 
3752 // END OF FILE
3753