diff --git a/binding/lua_c/util_test.lua b/binding/lua_c/util_test.lua index 6cfb855..cb67a20 100644 --- a/binding/lua_c/util_test.lua +++ b/binding/lua_c/util_test.lua @@ -38,6 +38,8 @@ header, err = xdb.load_header("../../data/ip2region.xdb") if err ~= nil then print("failed to load header: ", err) else + print(string.format("xdb header buffer `%s` loaded", header)) + local tpl = [[ header: { version: %d @@ -47,9 +49,9 @@ header: { end_index_ptr: %d }]] + local t = header:to_table() print(string.format(tpl, - header["version"], header["index_policy"], - header["created_at"], header["start_index_ptr"], header["end_index_ptr"]) + t["version"], t["index_policy"], t["created_at"], t["start_index_ptr"], t["end_index_ptr"]) ) end @@ -59,7 +61,7 @@ v_index, err = xdb.load_vector_index("../../data/ip2region.xdb") if err ~= nil then print("failed to load vector index: ", err) else - print("xdb vector index loaded") + print(string.format("xdb vector index buffer `%s` loaded", v_index)) end @@ -68,9 +70,10 @@ c_buffer, err = xdb.load_content("../../data/ip2region.xdb") if err ~= nil then print("failed to load content: ", err) else - print("xdb content loaded") + print(string.format("xdb content buffer `%s` loaded", c_buffer)) end + print("\n--- testing search ... ") local ip_str = "1.2.3.4" searcher, err = xdb.new_with_file_only("../../data/ip2region.xdb") diff --git a/binding/lua_c/xdb_searcher.c b/binding/lua_c/xdb_searcher.c index df51fda..b5a8a02 100644 --- a/binding/lua_c/xdb_searcher.c +++ b/binding/lua_c/xdb_searcher.c @@ -12,19 +12,236 @@ #include "lauxlib.h" #include "../c/xdb_searcher.h" -#define XDB_METATABLE_NAME "xdb_searcher_mt" +#define XDB_SEARCHER_METATABLE_NAME "xdb_searcher_mt" +#define XDB_BUFFER_METATABLE_NAME "xdb_buffer_mt" + +#define xdb_header_buffer 1 +#define xdb_vector_index_buffer 2 +#define xdb_content_buffer 3 + + +// --- xdb buffer interface impl + +struct xdb_buffer_entry { + int type; // buffer type + char *name; // buffer name + void *ptr; // buffer ptr + void (*closer) (void *); +}; +typedef struct xdb_buffer_entry xdb_buffer_t; + +static int lua_xdb_buffer_name(lua_State *L) { + xdb_buffer_t *buffer; + + luaL_argcheck(L, lua_gettop(L) == 1, 1, "call via ':'"); + buffer = (xdb_buffer_t *) luaL_checkudata(L, 1, XDB_BUFFER_METATABLE_NAME); + + lua_pushstring(L, buffer->name); + return 1; +} + +static int lua_xdb_buffer_to_table(lua_State *L) { + xdb_buffer_t *buffer; + xdb_header_t *header; + + luaL_argcheck(L, lua_gettop(L) == 1, 1, "call via ':'"); + buffer = (xdb_buffer_t *) luaL_checkudata(L, 1, XDB_BUFFER_METATABLE_NAME); + + lua_newtable(L); + if (buffer->type == xdb_header_buffer) { + header = (xdb_header_t *) buffer->ptr; + lua_pushinteger(L, header->version); + lua_setfield(L, -2, "version"); + + lua_pushinteger(L, header->index_policy); + lua_setfield(L, -2, "index_policy"); + + lua_pushinteger(L, header->created_at); + lua_setfield(L, -2, "created_at"); + + lua_pushinteger(L, header->start_index_ptr); + lua_setfield(L, -2, "start_index_ptr"); + + lua_pushinteger(L, header->end_index_ptr); + lua_setfield(L, -2, "end_index_ptr"); + } else { + // do nothing for now + } + + return 1; +} + +static int lua_xdb_buffer_length(lua_State *L) { + xdb_buffer_t *buffer; + + luaL_argcheck(L, lua_gettop(L) == 1, 1, "call via ':'"); + buffer = (xdb_buffer_t *) luaL_checkudata(L, 1, XDB_BUFFER_METATABLE_NAME); + + if (buffer->type == xdb_header_buffer) { + lua_pushinteger(L, ((xdb_header_t *) buffer->ptr)->length); + } else if (buffer->type == xdb_vector_index_buffer) { + lua_pushinteger(L, ((xdb_vector_index_t *) buffer->ptr)->length); + } else if (buffer->type == xdb_content_buffer) { + lua_pushinteger(L, ((xdb_content_t *) buffer->ptr)->length); + } else { + lua_pushinteger(L, -1); + } + + return 1; +} + +static int lua_xdb_buffer_tostring(lua_State *L) { + xdb_buffer_t *buffer; + + luaL_argcheck(L, lua_gettop(L) == 1, 1, "call via ':'"); + buffer = (xdb_buffer_t *) luaL_checkudata(L, 1, XDB_BUFFER_METATABLE_NAME); + + lua_pushfstring(L, "xdb %s buffer object {name: %s, type: %d}", buffer->name, buffer->name, buffer->type); + return 1; +} + +static int lua_xdb_buffer_close(lua_State *L) { + xdb_buffer_t *buffer; + + luaL_argcheck(L, lua_gettop(L) == 1, 1, "call via ':'"); + buffer = (xdb_buffer_t *) luaL_checkudata(L, 1, XDB_BUFFER_METATABLE_NAME); + + // check and call the closer + if (buffer->closer != NULL) { + buffer->closer(buffer->ptr); + } + + return 0; +} + +// module method define, should be access via ':' +static const struct luaL_Reg xdb_buffer_methods[] = { + {"name", lua_xdb_buffer_name}, + {"to_table", lua_xdb_buffer_to_table}, + {"length", lua_xdb_buffer_length}, + {"close", lua_xdb_buffer_close}, + {"__gc", lua_xdb_buffer_close}, + {"__tostring", lua_xdb_buffer_tostring}, + {NULL, NULL}, +}; + +// --- End of xdb buffer + + +// --- buffer util function + +static int lua_xdb_load_header_from_file(lua_State *L) { + const char *db_path; + xdb_header_t *header; + xdb_buffer_t *buffer; + + luaL_argcheck(L, lua_gettop(L) == 1, 1, "call via '.' and the xdb file path expected"); + db_path = luaL_checkstring(L, 1); + header = xdb_load_header_from_file(db_path); + if (header == NULL) { + lua_pushnil(L); + return 1; + } + + // alloc the buffer. + buffer = (xdb_buffer_t *) lua_newuserdata(L, sizeof(xdb_buffer_t)); + if (buffer == NULL) { + return luaL_error(L, "failed to alloc xdb buffer entry"); + } + + // init the buffer + buffer->type = xdb_header_buffer; + buffer->name = "header"; + buffer->ptr = header; + buffer->closer = xdb_close_header; + + // set the metatable of the header buffer object and push onto the stack + luaL_getmetatable(L, XDB_BUFFER_METATABLE_NAME); + lua_setmetatable(L, -2); + + return 1; +} + +static int lua_xdb_load_vector_index_from_file(lua_State *L) { + const char *db_path; + xdb_vector_index_t *v_index; + xdb_buffer_t *buffer; + + luaL_argcheck(L, lua_gettop(L) == 1, 1, "call via '.' and the xdb path expected"); + db_path = luaL_checkstring(L, 1); + v_index = xdb_load_vector_index_from_file(db_path); + if (v_index == NULL) { + lua_pushnil(L); + return 1; + } + + // alloc the buffer. + buffer = (xdb_buffer_t *) lua_newuserdata(L, sizeof(xdb_buffer_t)); + if (buffer == NULL) { + return luaL_error(L, "failed to alloc xdb buffer entry"); + } + + // init the buffer + buffer->type = xdb_vector_index_buffer; + buffer->name = "v_index"; + buffer->ptr = v_index; + buffer->closer = xdb_close_vector_index; + + // set the metatable of the header buffer object and push onto the stack + luaL_getmetatable(L, XDB_BUFFER_METATABLE_NAME); + lua_setmetatable(L, -2); + + return 1; +} + +static int lua_xdb_load_content_from_file(lua_State *L) { + const char *db_path; + xdb_content_t *content; + xdb_buffer_t *buffer; + + luaL_argcheck(L, lua_gettop(L) == 1, 1, "call via '.' and xdb path expected"); + db_path = luaL_checkstring(L, 1); + content = xdb_load_content_from_file(db_path); + if (content == NULL) { + lua_pushnil(L); + return 1; + } + + // alloc the buffer. + buffer = (xdb_buffer_t *) lua_newuserdata(L, sizeof(xdb_buffer_t)); + if (buffer == NULL) { + return luaL_error(L, "failed to alloc xdb buffer entry"); + } + + // init the buffer + buffer->type = xdb_content_buffer; + buffer->name = "content"; + buffer->ptr = content; + buffer->closer = xdb_close_content; + + // set the metatable of the header buffer object and push onto the stack + luaL_getmetatable(L, XDB_BUFFER_METATABLE_NAME); + lua_setmetatable(L, -2); + + return 1; +} + +// --- End of buffer api + + +// --- xdb searcher api static int lua_xdb_new_with_file_only(lua_State *L) { int err; xdb_searcher_t *searcher; const char *db_path = NULL; + luaL_argcheck(L, lua_gettop(L) == 1, 1, "call via '.' and xdb file path expected"); + // check the db path db_path = luaL_checkstring(L, 1); - if (db_path == NULL) { - return luaL_error(L, "xdb file path expected"); - } + // alloc for the searcher searcher = (xdb_searcher_t *) lua_newuserdata(L, sizeof(xdb_searcher_t)); if (searcher == NULL) { return luaL_error(L, "failed to alloc xdb searcher entry"); @@ -38,7 +255,7 @@ static int lua_xdb_new_with_file_only(lua_State *L) { // push the metatable onto the stack and // set it as the metatable of the current searcher - luaL_getmetatable(L, XDB_METATABLE_NAME); + luaL_getmetatable(L, XDB_SEARCHER_METATABLE_NAME); lua_setmetatable(L, -2); return 1; @@ -46,22 +263,17 @@ static int lua_xdb_new_with_file_only(lua_State *L) { static int lua_xdb_new_with_vector_index(lua_State *L) { xdb_searcher_t *searcher; - const char *v_index; + xdb_buffer_t *xBuffer; const char *db_path; - int err, top_len; + int err; - top_len = lua_gettop(L); - luaL_argcheck(L, top_len >= 2, 1, "xdb file path and vector index buffer expected"); + luaL_argcheck(L, lua_gettop(L) == 2, 1, "call via '.', xdb file path and vector index buffer expected"); // check the db path and vector index buffer db_path = luaL_checkstring(L, 1); - if (db_path == NULL) { - return luaL_error(L, "xdb file path expected"); - } - - v_index = luaL_checkstring(L, 2); - if (v_index == NULL) { - return luaL_error(L, "vector index buffer expected"); + xBuffer = luaL_checkudata(L, 2, XDB_BUFFER_METATABLE_NAME); + if (xBuffer->type != xdb_vector_index_buffer) { + return luaL_error(L, "invalid vector index buffer"); } // alloc the searcher @@ -71,14 +283,14 @@ static int lua_xdb_new_with_vector_index(lua_State *L) { } // init the xdb searcher - err = xdb_new_with_vector_index(searcher, db_path, v_index); + err = xdb_new_with_vector_index(searcher, db_path, (xdb_vector_index_t *) xBuffer->ptr); if (err != 0) { return luaL_error(L, "failed to init vector index cached xdb searcher on `%s` with errcode=%d", db_path, err); } // push the metatable onto the stack and // set it as the metatable of the current searcher - luaL_getmetatable(L, XDB_METATABLE_NAME); + luaL_getmetatable(L, XDB_SEARCHER_METATABLE_NAME); lua_setmetatable(L, -2); return 1; @@ -86,12 +298,13 @@ static int lua_xdb_new_with_vector_index(lua_State *L) { static int lua_xdb_new_with_buffer(lua_State *L) { xdb_searcher_t *searcher; - const char *c_buffer; + xdb_buffer_t *xBuffer; int err; - c_buffer = luaL_checkstring(L, 1); - if (c_buffer == NULL) { - return luaL_error(L, "xdb content buffer expected"); + luaL_argcheck(L, lua_gettop(L) == 1, 1, "call via '.' and xdb content buffer expected"); + xBuffer = (xdb_buffer_t *) luaL_checkudata(L, 1, XDB_BUFFER_METATABLE_NAME); + if (xBuffer->type != xdb_content_buffer) { + return luaL_error(L, "invalid xdb content buffer"); } // alloc the searcher @@ -101,14 +314,14 @@ static int lua_xdb_new_with_buffer(lua_State *L) { } // init the xdb searcher - err = xdb_new_with_buffer(searcher, c_buffer); + err = xdb_new_with_buffer(searcher, (xdb_content_t *) xBuffer->ptr); if (err != 0) { return luaL_error(L, "failed to init content cached xdb searcher with errcode=%d", err); } // push the metatable onto the stack and // set it as the metatable of the current searcher - luaL_getmetatable(L, XDB_METATABLE_NAME); + luaL_getmetatable(L, XDB_SEARCHER_METATABLE_NAME); lua_setmetatable(L, -2); return 1; @@ -117,13 +330,13 @@ static int lua_xdb_new_with_buffer(lua_State *L) { static int lua_xdb_close(lua_State *L) { xdb_searcher_t *searcher; - searcher = (xdb_searcher_t *) luaL_checkudata(L, 1, XDB_METATABLE_NAME); + luaL_argcheck(L, lua_gettop(L) == 1, 1, "call via ':'"); + searcher = (xdb_searcher_t *) luaL_checkudata(L, 1, XDB_SEARCHER_METATABLE_NAME); if (searcher == NULL) { return luaL_error(L, "broken xdb searcher instance"); } xdb_close(searcher); - return 0; } @@ -134,14 +347,10 @@ static int lua_xdb_search(lua_State *L) { char region_buffer[1024] = {'\0'}; xdb_searcher_t *searcher; - int top_len = lua_gettop(L); - luaL_argcheck(L, top_len >= 2, 2, "string or long ip address expected"); + luaL_argcheck(L, lua_gettop(L) == 2, 2, "call via ':' and string or long ip address expected"); // get the searcher - searcher = (xdb_searcher_t *) luaL_checkudata(L, 1, XDB_METATABLE_NAME); - if (searcher == NULL) { - return luaL_error(L, "call via ':' or xdb searcher was broken"); - } + searcher = (xdb_searcher_t *) luaL_checkudata(L, 1, XDB_SEARCHER_METATABLE_NAME); // input ip type checking if (lua_isinteger(L, 2)) { @@ -172,11 +381,8 @@ static int lua_xdb_search(lua_State *L) { static int lua_xdb_get_io_count(lua_State *L) { xdb_searcher_t *searcher; - searcher = (xdb_searcher_t *) luaL_checkudata(L, 1, XDB_METATABLE_NAME); - if (searcher == NULL) { - return luaL_error(L, "call method via ':' or xdb searcher was broken"); - } - + luaL_argcheck(L, lua_gettop(L) == 1, 1, "call via ':' or xdb searcher was broken"); + searcher = (xdb_searcher_t *) luaL_checkudata(L, 1, XDB_SEARCHER_METATABLE_NAME); lua_pushinteger(L, xdb_get_io_count(searcher)); return 1; } @@ -186,102 +392,6 @@ static int lua_xdb_tostring(lua_State *L) { return 1; } -// -- buffer util function - -static int lua_xdb_load_header_from_file(lua_State *L) { - int err; - const char *db_path; - xdb_header_t header; - - db_path = luaL_checkstring(L, 1); - if (db_path == NULL) { - return luaL_error(L, "xdb file path expected"); - } - - err = xdb_load_header_from_file(db_path, &header); - if (err != 0) { - lua_pushnil(L); - lua_pushfstring(L, "failed to load header from `%s` with errcode=%d", db_path, err); - return 2; - } - - // push the header table onto the stack as return - lua_newtable(L); - lua_pushinteger(L, header.version); - lua_setfield(L, -2, "version"); - - lua_pushinteger(L, header.index_policy); - lua_setfield(L, -2, "index_policy"); - - lua_pushinteger(L, header.created_at); - lua_setfield(L, -2, "created_at"); - - lua_pushinteger(L, header.start_index_ptr); - lua_setfield(L, -2, "start_index_ptr"); - - lua_pushinteger(L, header.end_index_ptr); - lua_setfield(L, -2, "end_index_ptr"); - - lua_pushnil(L); // empty error - return 2; -} - -static int lua_xdb_load_vector_index_from_file(lua_State *L) { - char *v_index; - const char *db_path; - - db_path = luaL_checkstring(L, 1); - if (db_path == NULL) { - return luaL_error(L, "xdb file path expected"); - } - - v_index = xdb_load_vector_index_from_file(db_path); - if (v_index == NULL) { - lua_pushnil(L); - lua_pushfstring(L, "load xdb vector index from `%s`", db_path); - return 2; - } - - // push the vector index onto the stack - lua_pushstring(L, v_index); - lua_pushnil(L); - - // free the local vector index allocation. - // the lua engine will manager the allocation in the VM - xdb_free(v_index); - v_index = NULL; - - return 2; -} - -static int lua_xdb_load_content_from_file(lua_State *L) { - char *c_buffer; - const char *db_path; - - db_path = luaL_checkstring(L, 1); - if (db_path == NULL) { - return luaL_error(L, "xdb file path expected"); - } - - c_buffer = xdb_load_content_from_file(db_path); - if (c_buffer == NULL) { - lua_pushnil(L); - lua_pushfstring(L, "load xdb content from `%s`", db_path); - return 2; - } - - // push the content buffer onto the stack - lua_pushstring(L, c_buffer); - lua_pushnil(L); - - // free the local content buffer allocation. - // let the lua VM manager it. - xdb_free(c_buffer); - c_buffer = NULL; - - return 2; -} - // -- static util function static int lua_xdb_check_ip(lua_State *L) { @@ -289,11 +399,8 @@ static int lua_xdb_check_ip(lua_State *L) { unsigned int ip; const char *ip_str; + luaL_argcheck(L, lua_gettop(L) == 1, 1, "call via '.' and string ip expected, eg: 1.2.3.4"); ip_str = luaL_checkstring(L, 1); - if (ip_str == NULL) { - return luaL_error(L, "ip expected, eg: 1.2.3.4"); - } - err = xdb_check_ip(ip_str, &ip); if (err != 0) { lua_pushinteger(L, err); @@ -310,6 +417,7 @@ static int lua_xdb_long2ip(lua_State *L) { unsigned int ip; char ip_buff[16] = {'\0'}; + luaL_argcheck(L, lua_gettop(L) == 1, 1, "call via '.' and long ip expected"); ip = luaL_checkinteger(L, 1); xdb_long2ip(ip, ip_buff); lua_pushstring(L, ip_buff); @@ -322,6 +430,7 @@ static int lua_xdb_now(lua_State *L) { return 1; } +// --- End of static util // module method define, should be access via ':' static const struct luaL_Reg xdb_searcher_methods[] = { @@ -350,19 +459,16 @@ static const struct luaL_Reg xdb_searcher_functions[] = { // module register function int luaopen_xdb_searcher(lua_State *L) { - // create a metatable and push it onto the stack - luaL_newmetatable(L, XDB_METATABLE_NAME); - - // Duplicate the metatable on the stack + // create a metatable for xdb buffer object + luaL_newmetatable(L, XDB_BUFFER_METATABLE_NAME); lua_pushvalue(L, -1); - - // Pop the first metatable off the stack - // and assign it to the __index of the second one. - // so we set the metatable to the table itself. lua_setfield(L, -2, "__index"); + luaL_setfuncs(L, xdb_buffer_methods, 0); - // Set the methods fo the metatable that could and should be - // access via object:func in lua block + // create a metatable for xdb searcher object + luaL_newmetatable(L, XDB_SEARCHER_METATABLE_NAME); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); luaL_setfuncs(L, xdb_searcher_methods, 0); luaL_setfuncs(L, xdb_searcher_functions, 0);