From 9a6e26db96f9af805fa1f2f76d3fc85ecd76953c Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Sat, 28 Feb 2015 16:42:47 +0800 Subject: [PATCH] add sharemap , an example of stm --- lualib-src/lua-stm.c | 31 ++++++++++++++++---- lualib/sharemap.lua | 69 ++++++++++++++++++++++++++++++++++++++++++++ lualib/sproto.lua | 4 +-- test/sharemap.sp | 5 ++++ test/testsm.lua | 48 ++++++++++++++++++++++++++++++ 5 files changed, 150 insertions(+), 7 deletions(-) create mode 100644 lualib/sharemap.lua create mode 100644 test/sharemap.sp create mode 100644 test/testsm.lua diff --git a/lualib-src/lua-stm.c b/lualib-src/lua-stm.c index b7bb5795..b38fbcd1 100644 --- a/lualib-src/lua-stm.c +++ b/lualib-src/lua-stm.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "rwlock.h" #include "skynet_malloc.h" @@ -126,8 +127,16 @@ lcopy(lua_State *L) { static int lnewwriter(lua_State *L) { - void * msg = lua_touserdata(L, 1); - uint32_t sz = (uint32_t)luaL_checkinteger(L, 2); + void * msg; + size_t sz; + if (lua_isuserdata(L,1)) { + msg = lua_touserdata(L, 1); + sz = (size_t)luaL_checkinteger(L, 2); + } else { + const char * tmp = luaL_checklstring(L,1,&sz); + msg = skynet_malloc(sz); + memcpy(msg, tmp, sz); + } struct boxstm * box = lua_newuserdata(L, sizeof(*box)); box->obj = stm_new(msg,sz); lua_pushvalue(L, lua_upvalueindex(1)); @@ -148,8 +157,16 @@ ldeletewriter(lua_State *L) { static int lupdate(lua_State *L) { struct boxstm * box = lua_touserdata(L, 1); - void * msg = lua_touserdata(L, 2); - uint32_t sz = (uint32_t)luaL_checkinteger(L, 3); + void * msg; + size_t sz; + if (lua_isuserdata(L, 2)) { + msg = lua_touserdata(L, 2); + sz = (size_t)luaL_checkinteger(L, 3); + } else { + const char * tmp = luaL_checklstring(L,2,&sz); + msg = skynet_malloc(sz); + memcpy(msg, tmp, sz); + } stm_update(box->obj, msg, sz); return 0; @@ -186,6 +203,7 @@ static int lread(lua_State *L) { struct boxreader * box = lua_touserdata(L, 1); luaL_checktype(L, 2, LUA_TFUNCTION); + struct stm_copy * copy = stm_copy(box->obj); if (copy == box->lastcopy) { // not update @@ -197,10 +215,13 @@ lread(lua_State *L) { stm_releasecopy(box->lastcopy); box->lastcopy = copy; if (copy) { + lua_settop(L, 3); + lua_replace(L, 1); lua_settop(L, 2); lua_pushlightuserdata(L, copy->msg); lua_pushinteger(L, copy->sz); - lua_call(L, 2, LUA_MULTRET); + lua_pushvalue(L, 1); + lua_call(L, 3, LUA_MULTRET); lua_pushboolean(L, 1); lua_replace(L, 1); return lua_gettop(L); diff --git a/lualib/sharemap.lua b/lualib/sharemap.lua new file mode 100644 index 00000000..5b0e5845 --- /dev/null +++ b/lualib/sharemap.lua @@ -0,0 +1,69 @@ +local stm = require "stm" +local sprotoloader = require "sprotoloader" +local sproto = require "sproto" +local setmetatable = setmetatable + +local sharemap = {} + +function sharemap.register(protofile) + -- use global slot 0 for type define + sprotoloader.register(protofile, 0) +end + +local sprotoobj +local function loadsp() + if sprotoobj == nil then + sprotoobj = sprotoloader.load(0) + end + return sprotoobj +end + +function sharemap:commit() + self.__obj(sprotoobj:encode(self.__typename, self.__data)) +end + +function sharemap:copy() + return stm.copy(self.__obj) +end + +function sharemap.writer(typename, obj) + local sp = loadsp() + obj = obj or {} + local stmobj = stm.new(sp:encode(typename,obj)) + obj.__typename = typename + obj.__obj = stmobj + obj.__data = obj + obj.commit = sharemap.commit + obj.copy = sharemap.copy + return setmetatable(obj, { __index = obj.__data, __newindex = obj.__data }) +end + +local function decode(msg, sz, self) + local data = self.__data + for k in pairs(data) do + data[k] = nil + end + return sprotoobj:decode(self.__typename, msg, sz, data) +end + +function sharemap:update() + return self.__obj(decode, self) +end + +function sharemap.reader(typename, stmcpy) + local sp = loadsp() + local stmobj = stm.newcopy(stmcpy) + local _, data = stmobj(function(msg, sz) + return sp:decode(typename, msg, sz) + end) + + local obj = { + __typename = typename, + __obj = stmobj, + __data = data, + update = sharemap.update, + } + return setmetatable(obj, { __index = obj.__data, __newindex = error }) +end + +return sharemap diff --git a/lualib/sproto.lua b/lualib/sproto.lua index 4351ba1d..98f88529 100644 --- a/lualib/sproto.lua +++ b/lualib/sproto.lua @@ -53,9 +53,9 @@ function sproto:encode(typename, tbl) return core.encode(st, tbl) end -function sproto:decode(typename, bin) +function sproto:decode(typename, ...) local st = querytype(self, typename) - return core.decode(st, bin) + return core.decode(st, ...) end function sproto:pencode(typename, tbl) diff --git a/test/sharemap.sp b/test/sharemap.sp new file mode 100644 index 00000000..a0a77f51 --- /dev/null +++ b/test/sharemap.sp @@ -0,0 +1,5 @@ +.foobar { + x 0 : integer + y 1 : integer + s 2 : string +} diff --git a/test/testsm.lua b/test/testsm.lua new file mode 100644 index 00000000..626952f8 --- /dev/null +++ b/test/testsm.lua @@ -0,0 +1,48 @@ +local skynet = require "skynet" +local sharemap = require "sharemap" + +local mode = ... + +if mode == "slave" then +--slave + +local function dump(reader) + reader:update() + print("x=", reader.x) + print("y=", reader.y) + print("s=", reader.s) +end + +skynet.start(function() + local reader + skynet.dispatch("lua", function(_,_,cmd,...) + if cmd == "init" then + reader = sharemap.reader(...) + else + assert(cmd == "ping") + dump(reader) + end + skynet.ret() + end) +end) + +else +-- master +skynet.start(function() + -- register share type schema + sharemap.register("./test/sharemap.sp") + local slave = skynet.newservice(SERVICE_NAME, "slave") + local writer = sharemap.writer("foobar", { x=0,y=0,s="hello" }) + skynet.call(slave, "lua", "init", "foobar", writer:copy()) + writer.x = 1 + writer:commit() + skynet.call(slave, "lua", "ping") + writer.y = 2 + writer:commit() + skynet.call(slave, "lua", "ping") + writer.s = "world" + writer:commit() + skynet.call(slave, "lua", "ping") +end) + +end \ No newline at end of file