├── Makefile ├── README.md ├── atomdict.c ├── atomdict.h ├── lua-ad.c ├── test.lua ├── test_client.lua ├── test_server.lua ├── testinit.c └── testmt.c /Makefile: -------------------------------------------------------------------------------- 1 | linux : atomdict.so testinit testmt 2 | 3 | mingw : atomdict.dll 4 | 5 | testinit : testinit.c atomdict.c 6 | gcc -Wall -g -o $@ $^ 7 | 8 | testmt : testmt.c atomdict.so 9 | gcc -g -Wall -o $@ $< -I/usr/local/include -Wl,-E -llua -lpthread -lm -ldl 10 | 11 | atomdict.so : atomdict.c lua-ad.c 12 | gcc -Wall -g -fPIC --shared -o $@ -I/usr/local/include $^ 13 | 14 | atomdict.dll : atomdict.c lua-ad.c 15 | gcc -Wall -g -march=i686 --shared -o $@ -I/usr/local/include $^ -L/usr/local/bin -llua52 16 | 17 | clean : 18 | rm testinit testmt atomdict.so 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Atom Dict 2 | 3 | Atomdict implements a data structure for multi lua state. 4 | 5 | You can use it in multi-threads , create one lua state per thread. Atomdict will help you exchange a group data atomic between lua states. 6 | 7 | ## Quick Example 8 | 9 | In data server : 10 | 11 | ```Lua 12 | local ad = require "atomdict" 13 | local handle = ad.new_handle { HP = 100 , Name = "Alice" } 14 | 15 | -- Send handle (A integer) to other lua state in other thread 16 | ``` 17 | 18 | In data client : 19 | 20 | ```Lua 21 | local ad = require "atomdict" 22 | 23 | -- ... 24 | 25 | local obj = ad.new(handle) -- get data handle from other lua state before. 26 | 27 | -- You can use pairs in this object 28 | for k,v in pairs(obj) do 29 | print(k,v) 30 | end 31 | 32 | -- Set obj.Name in local state, others can't see it before call ad.barrier() 33 | obj.Name = "Bob" 34 | 35 | -- put barrier in your main loop of the program 36 | ad.barrier() 37 | ``` 38 | 39 | ## API 40 | 41 | ### atomdict.new_handle( { key = value(number or string) , ... } , [typename] ) 42 | 43 | Use a table to init atomdict . You can name the type. 44 | If you have many objects with the same structure , giving a typename will improve the performance. 45 | 46 | It returns an integer handle. 47 | 48 | ### atomdict.delete_handle( handle ) 49 | 50 | Delete an atomdict handle. You must delete it before none of the object binding to the handle. 51 | 52 | ### atomdict.new(handle) 53 | 54 | Create an object binding the atomdict handle. 55 | It returns an userdata like a table. 56 | 57 | ### atomdict.barrier() 58 | 59 | Call barrier to commit atomdict objects that their changes could be seen by others. 60 | 61 | ### atomdict.dump(object) 62 | 63 | Print the object to the stdout. (for debug) 64 | 65 | ### atomdict.dump_handle(handle) 66 | Print the handle to the stdout. (for debug) 67 | 68 | ## Question ? 69 | 70 | * Send me an email : http://www.codingnow.com/2000/gmail.gif 71 | * My Blog : http://blog.codingnow.com 72 | * Design : http://blog.codingnow.com/2012/07/dev_note_23.html (in Chinese) -------------------------------------------------------------------------------- /atomdict.c: -------------------------------------------------------------------------------- 1 | #include "atomdict.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define ATOMDICT_NUMBER 0 8 | #define ATOMDICT_STRING 1 9 | 10 | #define MAX_COL 32 11 | #define AVERAGE_STRING 64 12 | 13 | #define DIRTY_WRITE 1 14 | #define DIRTY_STRING 2 15 | 16 | #if 0 17 | 18 | static int g_count = 0; 19 | 20 | static void * 21 | my_malloc(size_t sz) { 22 | ++g_count; 23 | return malloc(sz); 24 | } 25 | 26 | static void 27 | my_free(void *p) { 28 | --g_count; 29 | free(p); 30 | } 31 | 32 | #define DUMP_MEM printf("memory count = %d\n",g_count); 33 | 34 | #define malloc my_malloc 35 | #define free my_free 36 | 37 | #else 38 | 39 | #define DUMP_MEM 40 | 41 | #endif 42 | 43 | union atomvalue { 44 | int s; 45 | float n; 46 | } ; 47 | 48 | struct atomcol { 49 | union atomvalue *v; 50 | char * stringbuffer; 51 | int sb_size; 52 | int dirty; 53 | int ref; 54 | }; 55 | 56 | #define COL_STRING(col, n) (col->stringbuffer + col->v[n].s) 57 | 58 | struct atomkey { 59 | const char *key; 60 | int type; 61 | }; 62 | 63 | struct atomdict { 64 | int current; 65 | int property_count; 66 | int stringbuffer; 67 | char * typename; 68 | struct atomkey * key; 69 | struct atomcol col[MAX_COL]; 70 | }; 71 | 72 | struct atomdict * 73 | atomdict_new(void) { 74 | struct atomdict * ad = malloc(sizeof(struct atomdict)); 75 | memset(ad, 0 , sizeof(*ad)); 76 | return ad; 77 | } 78 | 79 | static int 80 | _init_key(struct atomdict *ad, struct atomslot *slot, const char * typename) { 81 | int keybuffer_size = 0; 82 | int n=0; 83 | while (slot[n].key) { 84 | keybuffer_size += strlen(slot[n].key) + 1; 85 | ++n; 86 | } 87 | if (typename) { 88 | keybuffer_size += strlen(typename) + 1; 89 | } 90 | assert(n>0); 91 | ad->property_count = n; 92 | ad->key = malloc( n * sizeof(struct atomkey) + keybuffer_size); 93 | char * keybuffer = (char *)(ad->key + n); 94 | if (typename) { 95 | int len = strlen(typename) + 1; 96 | memcpy(keybuffer, typename , len); 97 | ad->typename = keybuffer; 98 | keybuffer += len; 99 | } 100 | int i; 101 | int stringkey = 0; 102 | for (i=0;ikey[i].key = keybuffer; 106 | keybuffer += len; 107 | if (slot[i].vs == NULL) { 108 | ad->key[i].type = ATOMDICT_NUMBER; 109 | } else { 110 | ++stringkey; 111 | ad->key[i].type = ATOMDICT_STRING; 112 | } 113 | } 114 | 115 | return stringkey; 116 | } 117 | 118 | static void 119 | _init_col(struct atomdict *ad, int n) { 120 | ad->stringbuffer = n * AVERAGE_STRING; 121 | int i; 122 | int pn = ad->property_count; 123 | for (i=0;icol[i].v = malloc(pn * sizeof(union atomvalue)); 125 | memset(ad->col[i].v, 0 , pn * sizeof(union atomvalue)); 126 | } 127 | if (n > 0) { 128 | for (i=0;icol[i].stringbuffer = malloc(ad->stringbuffer); 130 | ad->col[i].stringbuffer[0] = '\0'; 131 | } 132 | } 133 | } 134 | 135 | static int 136 | _insert_string(struct atomcol * col, const char *key, int cap) { 137 | int len = strlen(key) + 1; 138 | if (col->sb_size + len > cap) { 139 | return -1; 140 | } 141 | int ret = col->sb_size; 142 | memcpy(col->stringbuffer + ret , key, len); 143 | col->sb_size += len; 144 | 145 | return ret; 146 | } 147 | 148 | static int 149 | _init_value(struct atomdict *ad, struct atomslot *slot) { 150 | int pn = ad->property_count; 151 | int i; 152 | struct atomcol *c = &(ad->col[0]); 153 | for (i=0;istringbuffer); 156 | if (index < 0) { 157 | return -1; 158 | } 159 | c->v[i].s = index; 160 | } else { 161 | c->v[i].n = slot[i].vn; 162 | } 163 | } 164 | return 0; 165 | } 166 | 167 | int 168 | atomdict_init(struct atomdict *ad, struct atomslot *slot, const char *typename) { 169 | int stringkey = _init_key(ad, slot, typename); 170 | _init_col(ad, stringkey); 171 | return _init_value(ad, slot); 172 | } 173 | 174 | const char * 175 | atomdict_key(struct atomdict *ad, int n, struct atomslot *slot) { 176 | if (n>=ad->property_count) { 177 | return NULL; 178 | } 179 | const char * key = ad->key[n].key; 180 | if (slot) { 181 | slot->key = key; 182 | struct atomcol *c = &(ad->col[ad->current]); 183 | switch (ad->key[n].type) { 184 | case ATOMDICT_NUMBER: 185 | slot->vs = NULL; 186 | slot->vn = c->v[n].n; 187 | break; 188 | case ATOMDICT_STRING: 189 | slot->vs = COL_STRING(c, n); 190 | slot->vn = 0; 191 | break; 192 | } 193 | } 194 | return key; 195 | } 196 | 197 | const char * 198 | atomdict_typename(struct atomdict *ad) { 199 | return ad->typename; 200 | } 201 | 202 | void 203 | atomdict_delete(struct atomdict *ad) { 204 | if (ad == NULL) 205 | return; 206 | free(ad->key); 207 | int i; 208 | for (i=0;icol[i]); 210 | free(c->v); 211 | free(c->stringbuffer); 212 | } 213 | free(ad); 214 | } 215 | 216 | static void 217 | _dump_col(struct atomdict *ad, int n, int current) { 218 | struct atomcol *c = &(ad->col[n]); 219 | struct atomkey *key = ad->key; 220 | if (n == current) { 221 | printf(" *"); 222 | } else { 223 | if (c->ref == 0 && current >=0) { 224 | return; 225 | } else { 226 | printf(" "); 227 | } 228 | } 229 | 230 | printf("[%d] ref=%d dirty=%d string_size=%d\n",n,c->ref, c->dirty,c->sb_size); 231 | int i; 232 | for (i=0;iproperty_count;i++) { 233 | printf(" %s = ",key[i].key); 234 | switch(key[i].type) { 235 | case ATOMDICT_NUMBER: 236 | printf("%f",c->v[i].n); 237 | break; 238 | case ATOMDICT_STRING: 239 | printf("'%s'",COL_STRING(c,i)); 240 | break; 241 | } 242 | printf("\n"); 243 | } 244 | } 245 | 246 | void 247 | atomdict_dump(struct atomdict * ad, int col) { 248 | printf("ATOM DICT %p [%s]\n",ad, ad->typename); 249 | if (col >= 0) { 250 | printf(" current = %d\n",ad->current); 251 | if (col >= ad->property_count) { 252 | printf(" property_count = %d , request = %d \n",ad->property_count, col); 253 | return; 254 | } 255 | _dump_col(ad, col, -1); 256 | } else { 257 | col = atomdict_grab(ad); 258 | printf(" current = %d\n",col); 259 | printf(" property_count = %d\n",ad->property_count); 260 | printf(" stringbuffer_cap = %d\n",ad->stringbuffer); 261 | int i; 262 | for (i=0;icurrent; 273 | __sync_add_and_fetch(&(ad->col[current].ref), 1); 274 | if (current != ad->current) { 275 | __sync_sub_and_fetch(&(ad->col[current].ref), 1); 276 | } else { 277 | return current; 278 | } 279 | } 280 | } 281 | 282 | static int 283 | _get_free_col(struct atomdict * ad) { 284 | int i,j; 285 | for (j=0;j<4;j++) { 286 | for (i=0;icol[i].ref; 288 | if (ref > 0) 289 | continue; 290 | if (__sync_bool_compare_and_swap(&(ad->col[i].ref), 0 , 1)) { 291 | return i; 292 | } 293 | } 294 | } 295 | return -1; 296 | } 297 | 298 | static int 299 | _atomdict_dup(struct atomdict * ad, int copy) { 300 | int pn = ad->property_count; 301 | int c = _get_free_col(ad); 302 | if (c<0) { 303 | return -1; 304 | } 305 | struct atomcol * from = &(ad->col[copy]); 306 | struct atomcol * to = &(ad->col[c]); 307 | memcpy(to->v,from->v,pn * sizeof(union atomvalue)); 308 | if (to->stringbuffer) { 309 | to->dirty = 0; 310 | to->sb_size = from->sb_size; 311 | memcpy(to->stringbuffer, from->stringbuffer, from->sb_size); 312 | } 313 | return c; 314 | } 315 | 316 | int 317 | atomdict_set_string(struct atomdict * ad, int col, int idx, const char * v) { 318 | assert(idx < ad->property_count && col < MAX_COL); 319 | struct atomcol *c = &(ad->col[col]); 320 | if (c->dirty == 0) { 321 | int old = col; 322 | col = _atomdict_dup(ad, old); 323 | if (col < 0) { 324 | return -2; 325 | } 326 | c = &(ad->col[col]); 327 | assert(c->ref == 1); 328 | c->dirty = DIRTY_WRITE | DIRTY_STRING; 329 | 330 | int ref = __sync_sub_and_fetch(&(ad->col[old].ref), 1); 331 | assert(ref >= 0); 332 | } else { 333 | c->dirty |= DIRTY_STRING; 334 | } 335 | int index = _insert_string(c, v, ad->stringbuffer); 336 | if (index < 0) { 337 | return -2; 338 | } 339 | c->v[idx].s = index; 340 | 341 | return col; 342 | } 343 | 344 | int 345 | atomdict_set_number(struct atomdict * ad, int col, int idx, float v) { 346 | assert(idx < ad->property_count && col < MAX_COL); 347 | struct atomcol *c = &(ad->col[col]); 348 | if (c->v[idx].n == v) { 349 | return col; 350 | } 351 | if (c->dirty == 0) { 352 | int old = col; 353 | col = _atomdict_dup(ad, old); 354 | c = &(ad->col[col]); 355 | assert(c->ref == 1); 356 | c->v[idx].n = v; 357 | c->dirty = DIRTY_WRITE; 358 | 359 | int ref = __sync_sub_and_fetch(&(ad->col[old].ref), 1); 360 | assert(ref >= 0); 361 | } else { 362 | c->v[idx].n = v; 363 | } 364 | // printf("set col=%d idx=%d %f\n",col,idx,v); 365 | 366 | return col; 367 | } 368 | 369 | const char * 370 | atomdict_get_string(struct atomdict * ad, int col, int idx) { 371 | assert(idx < ad->property_count && col < MAX_COL); 372 | struct atomcol *c = &(ad->col[col]); 373 | return COL_STRING(c, idx); 374 | } 375 | 376 | float 377 | atomdict_get_number(struct atomdict * ad, int col, int idx) { 378 | assert(idx < ad->property_count && col < MAX_COL); 379 | struct atomcol *c = &(ad->col[col]); 380 | // printf("get col=%d idx=%d %f\n",col,idx,c->v[idx].n); 381 | return c->v[idx].n; 382 | } 383 | 384 | void 385 | atomdict_commit(struct atomdict * ad, int col) { 386 | struct atomcol *c = &(ad->col[col]); 387 | if (c->dirty == 0) { 388 | int ref = __sync_sub_and_fetch(&(ad->col[col].ref), 1); 389 | assert(ref >= 0); 390 | return; 391 | } 392 | assert(c->ref == 1); 393 | if (c->dirty | DIRTY_STRING) { 394 | // arrange string buffer 395 | char tmp[c->sb_size]; 396 | int pn = ad->property_count; 397 | int i; 398 | int cap = ad->stringbuffer; 399 | memcpy(tmp, c->stringbuffer, c->sb_size); 400 | c->sb_size = 0; 401 | for (i=0;ikey[i].type == ATOMDICT_STRING) { 403 | c->v[i].s = _insert_string(c, tmp+c->v[i].s , cap); 404 | } 405 | } 406 | c->dirty = 0; 407 | } 408 | __sync_synchronize(); 409 | c->ref = 0; 410 | ad->current = col; 411 | } 412 | 413 | -------------------------------------------------------------------------------- /atomdict.h: -------------------------------------------------------------------------------- 1 | #ifndef ATOMDICT_H 2 | #define ATOMDICT_H 3 | 4 | struct atomdict; 5 | 6 | struct atomslot { 7 | const char *key; 8 | const char *vs; 9 | float vn; 10 | }; 11 | 12 | struct atomdict * atomdict_new(void); 13 | int atomdict_init(struct atomdict *, struct atomslot *, const char * typename); 14 | const char * atomdict_key(struct atomdict *, int n, struct atomslot *); 15 | const char * atomdict_typename(struct atomdict *); 16 | void atomdict_delete(struct atomdict *); 17 | 18 | int atomdict_grab(struct atomdict *); 19 | void atomdict_commit(struct atomdict *, int col); 20 | 21 | int atomdict_set_string(struct atomdict *, int col, int idx, const char * v); 22 | int atomdict_set_number(struct atomdict *, int col, int idx, float v); 23 | const char * atomdict_get_string(struct atomdict *, int col, int idx); 24 | float atomdict_get_number(struct atomdict *, int col, int idx); 25 | 26 | // for debug 27 | void atomdict_dump(struct atomdict *, int col); 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /lua-ad.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | /* 7 | integer new_handle( { keyname = initvalue , ... } , typename or nil) -- create an atomdict handle 8 | delete_handle(integer handle) -- release an atomdict handle 9 | userdata:object new(integer handle) -- create an atomdict object from a handle 10 | barrier() -- call barrier to commit atomdict objects 11 | dump(object) -- dump for debug 12 | dump_handle(handle) 13 | */ 14 | 15 | #include "atomdict.h" 16 | 17 | #define MAX_HANDLE (1024 * 16) 18 | #define MAX_OBJECT 1024 19 | 20 | static struct atomdict * G[MAX_HANDLE]; 21 | 22 | struct barrier; 23 | 24 | struct ad_object { 25 | struct atomdict *ad; 26 | struct barrier *barrier; 27 | int version; 28 | int col; 29 | }; 30 | 31 | struct barrier { 32 | int version; 33 | int object; 34 | struct ad_object *obj[MAX_OBJECT]; 35 | }; 36 | 37 | static int 38 | _find_slot(lua_State *L , struct atomdict *ad) { 39 | int i,j; 40 | for (j=0;j<2;j++) { 41 | for (i=0;i 1) { 64 | typename = luaL_checkstring(L,2); 65 | } 66 | 67 | int n=0; 68 | lua_pushnil(L); /* first key */ 69 | while (lua_next(L, 1) != 0) { 70 | ++n; 71 | lua_pop(L, 1); 72 | } 73 | struct atomslot slot[n+1]; 74 | int i; 75 | lua_pushnil(L); 76 | for (i=0;ibarrier->version == object->version) {} else _update_object_(L,object->barrier,object) 121 | 122 | static void 123 | _update_object_(lua_State *L, struct barrier *b, struct ad_object *object) { 124 | if (b->object >= MAX_OBJECT) { 125 | luaL_error(L, "Commit object too many"); 126 | } 127 | object->version = b->version; 128 | b->obj[b->object++] = object; 129 | object->col = atomdict_grab(object->ad); 130 | } 131 | 132 | static void 133 | _gen_keyindex(lua_State *L, struct atomdict *ad) { 134 | lua_newtable(L); 135 | int i = 0; 136 | for (;;) { 137 | struct atomslot slot; 138 | const char * key = atomdict_key(ad, i , &slot); 139 | if (key == NULL) { 140 | return; 141 | } 142 | if (slot.vs == NULL) { 143 | lua_pushinteger(L,(i+1)); 144 | } else { 145 | lua_pushinteger(L,-(i+1)); 146 | } 147 | lua_setfield(L,-2,key); 148 | ++i; 149 | } 150 | } 151 | 152 | static void 153 | _gen_keyindex_from_meta(lua_State *L, struct atomdict *ad, const char *typename) { 154 | lua_getfield(L,-1,"type"); 155 | // stack now : ... , metatable , typecache 156 | lua_getfield(L, -1 , typename); 157 | if (lua_isnil(L,-1)) { 158 | lua_pop(L,-1); 159 | _gen_keyindex(L, ad); 160 | lua_pushvalue(L,-1); 161 | lua_setfield(L,-3,typename); 162 | // stack now : ... , metatable, typecache, keyindex 163 | } 164 | lua_remove(L,-2); 165 | } 166 | 167 | /* 168 | uv1: barrier 169 | uv2: metatable 170 | integer handle 171 | 172 | return userdata 173 | */ 174 | static int 175 | _new_object(lua_State *L) { 176 | struct barrier * b = lua_touserdata(L, lua_upvalueindex(1)); 177 | int index = luaL_checkinteger(L,1); 178 | struct atomdict *ad = G[index]; 179 | if (ad == NULL) { 180 | return luaL_error(L, "Atomdict binding a null handle"); 181 | } 182 | 183 | struct ad_object *object = lua_newuserdata(L,sizeof(struct ad_object)); 184 | object->ad = ad; 185 | object->barrier = b; 186 | object->version = -1; 187 | 188 | _update_object(L, object); 189 | 190 | lua_pushvalue(L, lua_upvalueindex(2)); 191 | // stack now : handle , ... , object, metatable 192 | const char * typename = atomdict_typename(ad); 193 | 194 | if (typename) { 195 | _gen_keyindex_from_meta(L, ad, typename); 196 | } else { 197 | _gen_keyindex(L, ad); 198 | } 199 | // stack now : handle , ... , object, metatable, keyindex 200 | lua_setuservalue(L,-3); 201 | lua_setmetatable(L,-2); 202 | 203 | return 1; 204 | } 205 | 206 | static int 207 | _name_object(lua_State *L) { 208 | struct ad_object *object = lua_touserdata(L,1); 209 | const char * typename = atomdict_typename(object->ad); 210 | if (typename == NULL) { 211 | lua_pushliteral(L, "[ATOMDICT]"); 212 | } else { 213 | luaL_Buffer b; 214 | luaL_buffinit(L, &b); 215 | luaL_addchar(&b, '['); 216 | luaL_addstring(&b, typename); 217 | luaL_addchar(&b, ']'); 218 | luaL_pushresult(&b); 219 | } 220 | return 1; 221 | } 222 | 223 | static int 224 | _get_object(lua_State *L) { 225 | struct ad_object *object = lua_touserdata(L,1); 226 | _update_object(L, object); 227 | lua_getuservalue(L,1); 228 | lua_pushvalue(L,2); 229 | lua_rawget(L,-2); 230 | if (lua_isnil(L,-1)) { 231 | return luaL_error(L, "Invalid key %s", luaL_checkstring(L,2)); 232 | } 233 | int index = lua_tointeger(L,-1); 234 | if (index > 0) { 235 | float v = atomdict_get_number(object->ad, object->col, index-1); 236 | lua_pushnumber(L,v); 237 | } else { 238 | const char * v = atomdict_get_string(object->ad, object->col, -(index+1)); 239 | lua_pushstring(L,v); 240 | } 241 | return 1; 242 | } 243 | 244 | static int 245 | _set_object(lua_State *L) { 246 | struct ad_object *object = lua_touserdata(L,1); 247 | _update_object(L, object); 248 | lua_getuservalue(L,1); 249 | lua_pushvalue(L,2); 250 | // stack now : object key value , ... , type , key 251 | lua_rawget(L,-2); 252 | if (lua_isnil(L,-1)) { 253 | return luaL_error(L, "Invalid key %s", luaL_checkstring(L,2)); 254 | } 255 | int index = lua_tointeger(L,-1); 256 | int new_col ; 257 | 258 | if (index > 0) { 259 | float v = luaL_checknumber(L,3); 260 | new_col = atomdict_set_number(object->ad, object->col, index-1, v); 261 | } else { 262 | const char * v = luaL_checkstring(L,3); 263 | new_col = atomdict_set_string(object->ad, object->col, -(index+1), v); 264 | } 265 | if (new_col < 0) { 266 | return luaL_error(L, "atomdict set %s error", lua_tostring(L,2)); 267 | } 268 | object->col = new_col; 269 | 270 | return 0; 271 | } 272 | 273 | /* 274 | userdata:object 275 | string or nil (key) 276 | */ 277 | static int 278 | _next_property(lua_State *L) { 279 | if (lua_gettop(L) == 1) { 280 | lua_getuservalue(L,1); 281 | lua_pushnil(L); 282 | } else { 283 | lua_getuservalue(L,1); 284 | lua_pushvalue(L,2); 285 | } 286 | int end = lua_next(L,-2); 287 | // stack now: object , keyindex, (nextkey , value) 288 | if (end == 0) { 289 | return 0; 290 | } 291 | int index = lua_tointeger(L,-1); 292 | lua_pop(L,1); 293 | struct ad_object *object = lua_touserdata(L,1); 294 | _update_object(L, object); 295 | if (index > 0) { 296 | float v = atomdict_get_number(object->ad, object->col, index-1); 297 | lua_pushnumber(L,v); 298 | } else { 299 | const char * v = atomdict_get_string(object->ad, object->col, -(index+1)); 300 | lua_pushstring(L,v); 301 | } 302 | return 2; 303 | } 304 | 305 | static int 306 | _pairs_object(lua_State *L) { 307 | lua_pushcfunction(L,_next_property); 308 | lua_pushvalue(L,1); 309 | lua_pushnil(L); 310 | return 3; 311 | } 312 | 313 | static int 314 | _create_meta(lua_State *L) { 315 | luaL_Reg meta[] = { 316 | { "__index", _get_object }, 317 | { "__newindex", _set_object }, 318 | { "__tostring", _name_object }, 319 | { "__pairs", _pairs_object }, 320 | { NULL , NULL }, 321 | }; 322 | luaL_newlib(L,meta); 323 | lua_newtable(L); 324 | lua_setfield(L,-2,"type"); 325 | return 1; 326 | } 327 | 328 | static int 329 | _barrier(lua_State *L) { 330 | struct barrier * b = lua_touserdata(L, lua_upvalueindex(1)); 331 | ++b->version; 332 | int i; 333 | for (i=0;iobject;i++) { 334 | atomdict_commit(b->obj[i]->ad, b->obj[i]->col); 335 | } 336 | b->object = 0; 337 | return 0; 338 | } 339 | 340 | static int 341 | _dump_object(lua_State *L) { 342 | struct ad_object * obj = lua_touserdata(L,1); 343 | atomdict_dump(obj->ad, obj->col); 344 | return 0; 345 | } 346 | 347 | static int 348 | _dump_handle(lua_State *L) { 349 | int idx = luaL_checkinteger(L,1); 350 | struct atomdict * ad = G[idx]; 351 | if (ad == NULL) { 352 | return luaL_error(L, "atomdict handle %d is invalid", idx); 353 | } 354 | atomdict_dump(ad, -1); 355 | return 0; 356 | } 357 | 358 | int 359 | luaopen_atomdict(lua_State *L) { 360 | luaL_checkversion(L); 361 | 362 | luaL_Reg l[] = { 363 | { "new_handle", _new_handle }, 364 | { "delete_handle", _delete_handle }, 365 | { "dump_handle", _dump_handle }, 366 | { "dump", _dump_object }, 367 | { NULL , NULL }, 368 | }; 369 | 370 | luaL_newlib(L,l); 371 | 372 | struct barrier * b = lua_newuserdata(L, sizeof(struct barrier)); 373 | b->version = 0; 374 | b->object = 0; 375 | 376 | // stack now : libtable barrier 377 | 378 | lua_pushvalue(L,-1); 379 | _create_meta(L); 380 | 381 | // stack now : libtable barrier barrier metatable 382 | 383 | lua_pushcclosure(L, _new_object, 2); 384 | lua_setfield(L,-3, "new"); 385 | 386 | // stack now : libtable barrier 387 | 388 | luaL_Reg l2[] = { 389 | { "barrier", _barrier }, 390 | { NULL , NULL }, 391 | }; 392 | luaL_setfuncs(L, l2, 1); 393 | 394 | return 1; 395 | } 396 | 397 | -------------------------------------------------------------------------------- /test.lua: -------------------------------------------------------------------------------- 1 | ad =require "atomdict" 2 | handle = ad.new_handle { HP = 1, name = "Hello" } 3 | obj = ad.new(handle) 4 | ad.dump_handle(handle) 5 | 6 | obj.HP = 2 7 | 8 | for k,v in pairs(obj) do 9 | print(k,v) 10 | end 11 | 12 | 13 | ad.dump_handle(handle) 14 | 15 | ad.barrier() 16 | 17 | obj.name = "World" 18 | 19 | ad.dump_handle(handle) 20 | 21 | ad.barrier() 22 | 23 | ad.dump_handle(handle) 24 | -------------------------------------------------------------------------------- /test_client.lua: -------------------------------------------------------------------------------- 1 | local ad = require "atomdict" 2 | 3 | local d = {} 4 | 5 | for k,v in ipairs(handles) do 6 | d[k] = ad.new(v) 7 | end 8 | 9 | local c = d[thread+1] 10 | 11 | local function dump_object(obj) 12 | local t = {} 13 | local s = 0 14 | for k,v in pairs(obj) do 15 | table.insert(t, k .. "=" .. v) 16 | s = s+v 17 | end 18 | return "thread["..thread.."]"..table.concat(t," ") 19 | end 20 | 21 | io.write(dump_object(c) .. "\n") 22 | 23 | local function sum_object(obj) 24 | local s = 0 25 | for _,v in pairs(obj) do 26 | s = s+v 27 | end 28 | if s~=100 then 29 | ad.dump(obj) 30 | end 31 | assert(s==100,s) 32 | return s 33 | end 34 | 35 | 36 | for i = 1, 1000 do 37 | c.A = math.random(80) 38 | c.B = math.random(80) 39 | c.C = math.random(80) 40 | 41 | c.D = 100 - c.A - c.B - c.C 42 | 43 | for _,v in pairs(d) do 44 | sum_object(v) 45 | end 46 | 47 | ad.barrier() 48 | end 49 | 50 | -------------------------------------------------------------------------------- /test_server.lua: -------------------------------------------------------------------------------- 1 | local ad = require "atomdict" 2 | 3 | handles = {} 4 | 5 | for i=1,30 do 6 | local init = {} 7 | init.A = math.random(50) 8 | init.B = math.random(50) 9 | init.C = math.random(50) 10 | init.D = 100-init.A-init.B-init.C 11 | handles[i] = ad.new_handle(init) 12 | end 13 | -------------------------------------------------------------------------------- /testinit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "atomdict.h" 3 | 4 | static void 5 | test() { 6 | struct atomdict * ad = atomdict_new(); 7 | struct atomslot s[] = { 8 | { "HP" , NULL, 100 }, 9 | { "NAME" , "Hello World", 0 }, 10 | { NULL , NULL , 0 }, 11 | }; 12 | atomdict_init(ad, s , "TYPE"); 13 | int i=0; 14 | for (;;) { 15 | struct atomslot as; 16 | const char * key = atomdict_key(ad, i, &as); 17 | if (key) { 18 | printf("%s = %s, %f\n",key, as.vs , as.vn); 19 | } else { 20 | break; 21 | } 22 | ++i; 23 | } 24 | atomdict_dump(ad, -1); 25 | 26 | int col = atomdict_grab(ad); 27 | col = atomdict_set_string(ad, col, 1, "Bingo"); 28 | 29 | atomdict_commit(ad, col); 30 | 31 | atomdict_dump(ad, -1); 32 | 33 | atomdict_delete(ad); 34 | } 35 | 36 | int 37 | main(int argc, char *argv[]) { 38 | 39 | test(); 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /testmt.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define MAX 30 10 | 11 | static int G[MAX]; 12 | 13 | static lua_State * 14 | _new(const char * name,int n) { 15 | lua_State * L = luaL_newstate(); 16 | lua_gc(L, LUA_GCSTOP, 0); 17 | luaL_openlibs(L); 18 | lua_gc(L, LUA_GCRESTART, 0); 19 | 20 | lua_newtable(L); 21 | int i; 22 | for (i=0;in); 49 | lua_close(L); 50 | return NULL; 51 | } 52 | 53 | int 54 | main() { 55 | lua_State * L = _new("test_server.lua", -1); 56 | 57 | lua_getglobal(L, "handles"); 58 | 59 | int i; 60 | for (i=0;in = i; 74 | pthread_create(&pid[i], NULL, thread_test, ud); 75 | } 76 | 77 | for (i=0;i