erlang各种有用的函数包括一些有用nif封装,还有一些性能测试case。
Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.

619 righe
16 KiB

  1. #include <string>
  2. #include <iostream>
  3. #include <vector>
  4. #include "erl_nif.h"
  5. #include "erlterm.h"
  6. #include "lru.h"
  7. using namespace std;
  8. namespace { /* anonymous namespace starts */
  9. typedef struct _obj_resource {
  10. bool allocated;
  11. void *object;
  12. ErlNifMutex *emtx;
  13. } object_resource;
  14. ErlNifResourceFlags resource_flags = (ErlNifResourceFlags)(ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER);
  15. ErlNifResourceType* lruResource;
  16. ErlNifResourceType* iteratorResource;
  17. /* atoms */
  18. ERL_NIF_TERM atom_ok;
  19. ERL_NIF_TERM atom_key;
  20. ERL_NIF_TERM atom_error;
  21. ERL_NIF_TERM atom_invalid;
  22. ERL_NIF_TERM atom_value;
  23. ERL_NIF_TERM atom_max_size;
  24. ERL_NIF_TERM atom_tab;
  25. ERL_NIF_TERM atom_lru_old;
  26. void lru_dtor(ErlNifEnv* env, void *lru);
  27. void iterator_dtor(ErlNifEnv* env, void *it);
  28. int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info){
  29. lruResource = enif_open_resource_type(env,
  30. "btreelru_nif",
  31. "lru",
  32. lru_dtor,
  33. resource_flags,
  34. NULL);
  35. iteratorResource = enif_open_resource_type(env,
  36. "btreelru_nif",
  37. "iterator",
  38. iterator_dtor,
  39. resource_flags,
  40. NULL);
  41. atom_ok = enif_make_atom(env, "ok");
  42. atom_key = enif_make_atom(env, "key");
  43. atom_error = enif_make_atom(env, "error");
  44. atom_invalid = enif_make_atom(env, "invalid");
  45. atom_value = enif_make_atom(env, "value");
  46. atom_max_size = enif_make_atom(env, "max_size");
  47. atom_tab = enif_make_atom(env, "tab");
  48. atom_lru_old = enif_make_atom(env, "lru_old");
  49. return 0;
  50. }
  51. int reload(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info){
  52. return 0;
  53. }
  54. int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data,ERL_NIF_TERM load_info){
  55. return 0;
  56. }
  57. void lru_dtor(ErlNifEnv* env, void* _lru_btree) {
  58. object_resource *lru_btree = (object_resource*) _lru_btree;
  59. if (lru_btree->allocated)
  60. delete (LRUBtree<ErlTerm,ErlTerm>*) lru_btree->object;
  61. }
  62. void iterator_dtor(ErlNifEnv* env, void* _lru_iterator) {
  63. object_resource *lru_iterator = (object_resource*) _lru_iterator;
  64. if (lru_iterator->allocated)
  65. delete (LRUBtree<ErlTerm,ErlTerm>::iterator*) lru_iterator->object;
  66. }
  67. void node_free(LRUBtree<ErlTerm,ErlTerm> *bt_lru, LRUNode<ErlTerm,ErlTerm> *node) {
  68. enif_free_env((ErlNifEnv*)node->kvenv);
  69. return;
  70. }
  71. void node_kickout(LRUBtree<ErlTerm,ErlTerm> *bt_lru, LRUNode<ErlTerm,ErlTerm> *node, void *currenv) {
  72. ErlNifEnv *env = (ErlNifEnv *) currenv;
  73. if (bt_lru->pid_set) {
  74. enif_send(env, &bt_lru->pid, NULL, enif_make_tuple3(env, atom_lru_old, node->key.t, node->data.t));
  75. }
  76. return;
  77. }
  78. ERL_NIF_TERM next(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
  79. object_resource *lru;
  80. LRUBtree<ErlTerm,ErlTerm> *bt_lru;
  81. LRUNode<ErlTerm,ErlTerm> *node;
  82. ErlTerm key;
  83. ErlTerm value;
  84. if (argc != 2) {
  85. return enif_make_badarg(env);
  86. }
  87. if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
  88. return enif_make_badarg(env);
  89. }
  90. bt_lru = (LRUBtree<ErlTerm,ErlTerm> *) lru->object;
  91. key.t = argv[1];
  92. node = bt_lru->get(key);
  93. if (!node)
  94. return enif_make_tuple2(env, atom_error, atom_invalid);
  95. node = node->next;
  96. if (!node)
  97. return enif_make_tuple2(env, atom_error, atom_invalid);
  98. key.t = enif_make_copy(env, node->key.t);
  99. value.t = enif_make_copy(env, node->data.t);
  100. return enif_make_tuple2(env, key.t, value.t);
  101. }
  102. ERL_NIF_TERM prev(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
  103. object_resource *lru;
  104. LRUBtree<ErlTerm,ErlTerm> *bt_lru;
  105. LRUNode<ErlTerm,ErlTerm> *node;
  106. ErlTerm key;
  107. ErlTerm value;
  108. if (argc != 2) {
  109. return enif_make_badarg(env);
  110. }
  111. if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
  112. return enif_make_badarg(env);
  113. }
  114. bt_lru = (LRUBtree<ErlTerm,ErlTerm> *) lru->object;
  115. key.t = argv[1];
  116. node = bt_lru->get(key);
  117. if (!node)
  118. return enif_make_tuple2(env, atom_error, atom_invalid);
  119. node = node->prev;
  120. if (!node)
  121. return enif_make_tuple2(env, atom_error, atom_invalid);
  122. key.t = enif_make_copy(env, node->key.t);
  123. value.t = enif_make_copy(env, node->data.t);
  124. return enif_make_tuple2(env, key.t, value.t);
  125. }
  126. ERL_NIF_TERM create(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
  127. unsigned long max_size;
  128. object_resource *lru;
  129. LRUBtree<ErlTerm,ErlTerm> *bt_lru;
  130. ERL_NIF_TERM lru_term;
  131. /* get max_size */
  132. if (enif_get_ulong(env, argv[0], &max_size) < 1){
  133. return enif_make_tuple2(env, atom_error, atom_max_size);
  134. }
  135. if (!(bt_lru = new LRUBtree<ErlTerm,ErlTerm>(max_size, node_free, node_kickout))) {
  136. return enif_make_tuple2(env, atom_error, enif_make_atom(env, "alloction"));
  137. }
  138. lru = (object_resource *) enif_alloc_resource(lruResource, sizeof(object_resource));
  139. lru->object = bt_lru;
  140. lru->allocated = true;
  141. lru_term = enif_make_resource(env, lru);
  142. enif_release_resource(lru);
  143. return enif_make_tuple2(env, atom_ok, lru_term);
  144. }
  145. ERL_NIF_TERM seek(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
  146. object_resource *lru;
  147. object_resource *it;
  148. LRUBtree<ErlTerm,ErlTerm> *bt_lru;
  149. LRUBtree<ErlTerm,ErlTerm>::iterator *bt_it_;
  150. LRUBtree<ErlTerm,ErlTerm>::iterator bt_it;
  151. ErlTerm key;
  152. ERL_NIF_TERM it_term;
  153. ERL_NIF_TERM kv;
  154. if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
  155. return enif_make_badarg(env);
  156. }
  157. key.t = argv[1];
  158. bt_lru = (LRUBtree<ErlTerm,ErlTerm> *)lru->object;
  159. bt_it = bt_lru->bmap.lower_bound(key);
  160. if ( bt_it == bt_lru->bmap.end() ) {
  161. return enif_make_tuple2(env, atom_error, atom_invalid);
  162. }
  163. bt_it_ = new LRUBtree<ErlTerm,ErlTerm>::iterator;
  164. *bt_it_ = bt_it;
  165. it = (object_resource *) enif_alloc_resource(iteratorResource, sizeof(object_resource));
  166. it->object = bt_it_;
  167. it->allocated = true;
  168. it_term = enif_make_resource(env, it);
  169. enif_release_resource(it);
  170. kv = enif_make_tuple2(env, bt_it->second->key.t, bt_it->second->data.t);
  171. return enif_make_tuple2(env, kv, it_term);
  172. }
  173. ERL_NIF_TERM iterate_next(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
  174. object_resource *lru;
  175. object_resource *it;
  176. LRUBtree<ErlTerm,ErlTerm>::iterator *bt_it_;
  177. LRUBtree<ErlTerm,ErlTerm> *bt_lru;
  178. ERL_NIF_TERM kv;
  179. if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
  180. return enif_make_badarg(env);
  181. }
  182. if (!enif_get_resource(env, argv[1], iteratorResource, (void **) &it)) {
  183. return enif_make_badarg(env);
  184. }
  185. bt_lru = (LRUBtree<ErlTerm,ErlTerm> *)lru->object;
  186. bt_it_ = (LRUBtree<ErlTerm,ErlTerm>::iterator *) it->object;
  187. if (bt_it_ == NULL)
  188. return enif_make_tuple2(env, atom_error, atom_invalid);
  189. (*bt_it_)++;
  190. if ( *bt_it_ == bt_lru->bmap.end() ) {
  191. it->allocated = false;
  192. delete bt_it_;
  193. it->object = NULL;
  194. return enif_make_tuple2(env, atom_error, atom_invalid);
  195. }
  196. kv = enif_make_tuple2(env, (*bt_it_)->second->key.t, (*bt_it_)->second->data.t);
  197. return enif_make_tuple2(env, atom_ok, kv);
  198. }
  199. ERL_NIF_TERM close(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
  200. object_resource *lru;
  201. LRUBtree<ErlTerm,ErlTerm> *bt_lru;
  202. if (argc != 1) {
  203. return enif_make_badarg(env);
  204. }
  205. if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
  206. return enif_make_badarg(env);
  207. }
  208. bt_lru = (LRUBtree<ErlTerm,ErlTerm> *)lru->object;
  209. lru->allocated = false;
  210. delete bt_lru;
  211. return atom_ok;
  212. }
  213. ERL_NIF_TERM read(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
  214. object_resource *lru;
  215. LRUBtree<ErlTerm,ErlTerm> *bt_lru;
  216. LRUNode<ErlTerm,ErlTerm> *node;
  217. ErlTerm key;
  218. ERL_NIF_TERM kv;
  219. if (argc != 2) {
  220. return enif_make_badarg(env);
  221. }
  222. if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
  223. return enif_make_badarg(env);
  224. }
  225. bt_lru = (LRUBtree<ErlTerm,ErlTerm> *) lru->object;
  226. key.t = argv[1];
  227. node = bt_lru->get(key);
  228. if (!node)
  229. return enif_make_tuple2(env, atom_error, atom_invalid);
  230. kv = enif_make_tuple2(env, enif_make_copy(env, node->key.t), enif_make_copy(env, node->data.t));
  231. return enif_make_tuple2(env, atom_ok, kv);
  232. }
  233. ERL_NIF_TERM remove(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
  234. object_resource *lru;
  235. LRUBtree<ErlTerm,ErlTerm> *bt_lru;
  236. ErlTerm key;
  237. if (argc != 2) {
  238. return enif_make_badarg(env);
  239. }
  240. if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
  241. return enif_make_badarg(env);
  242. }
  243. bt_lru = (LRUBtree<ErlTerm,ErlTerm> *) lru->object;
  244. key.t = argv[1];
  245. bt_lru->erase(key);
  246. return atom_ok;
  247. }
  248. ERL_NIF_TERM oldest(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
  249. object_resource *lru;
  250. LRUBtree<ErlTerm,ErlTerm> *bt_lru;
  251. LRUNode<ErlTerm,ErlTerm> *node;
  252. ERL_NIF_TERM key;
  253. ERL_NIF_TERM value;
  254. if (argc != 1) {
  255. return enif_make_badarg(env);
  256. }
  257. if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
  258. return enif_make_badarg(env);
  259. }
  260. bt_lru = (LRUBtree<ErlTerm,ErlTerm> *) lru->object;
  261. node = bt_lru->getOldest();
  262. if (!node)
  263. return enif_make_tuple2(env, atom_error, atom_invalid);
  264. key = enif_make_copy(env, node->key.t);
  265. value = enif_make_copy(env, node->data.t);
  266. return enif_make_tuple2(env, key, value);
  267. }
  268. ERL_NIF_TERM latest(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
  269. object_resource *lru;
  270. LRUBtree<ErlTerm,ErlTerm> *bt_lru;
  271. LRUNode<ErlTerm,ErlTerm> *node;
  272. ERL_NIF_TERM key;
  273. ERL_NIF_TERM value;
  274. if (argc != 1) {
  275. return enif_make_badarg(env);
  276. }
  277. if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
  278. return enif_make_badarg(env);
  279. }
  280. bt_lru = (LRUBtree<ErlTerm,ErlTerm> *) lru->object;
  281. // last is "last in" in the lru
  282. node = bt_lru->getLatest();
  283. if (!node)
  284. return enif_make_tuple2(env, atom_error, atom_invalid);
  285. key = enif_make_copy(env, node->key.t);
  286. value = enif_make_copy(env, node->data.t);
  287. return enif_make_tuple2(env, key, value);
  288. }
  289. ERL_NIF_TERM last(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
  290. object_resource *lru;
  291. LRUBtree<ErlTerm,ErlTerm> *bt_lru;
  292. LRUNode<ErlTerm,ErlTerm> *node;
  293. ERL_NIF_TERM key;
  294. ERL_NIF_TERM value;
  295. if (argc != 1) {
  296. return enif_make_badarg(env);
  297. }
  298. if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
  299. return enif_make_badarg(env);
  300. }
  301. bt_lru = (LRUBtree<ErlTerm,ErlTerm> *) lru->object;
  302. node = bt_lru->bmap.rbegin()->second;
  303. if (!node)
  304. return enif_make_tuple2(env, atom_error, atom_invalid);
  305. key = enif_make_copy(env, node->key.t);
  306. value = enif_make_copy(env, node->data.t);
  307. return enif_make_tuple2(env, key, value);
  308. }
  309. ERL_NIF_TERM first(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
  310. object_resource *lru;
  311. LRUBtree<ErlTerm,ErlTerm> *bt_lru;
  312. LRUNode<ErlTerm,ErlTerm> *node;
  313. ERL_NIF_TERM key;
  314. ERL_NIF_TERM value;
  315. if (argc != 1) {
  316. return enif_make_badarg(env);
  317. }
  318. if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
  319. return enif_make_badarg(env);
  320. }
  321. bt_lru = (LRUBtree<ErlTerm,ErlTerm> *) lru->object;
  322. node = bt_lru->bmap.begin()->second;
  323. if (!node)
  324. return enif_make_tuple2(env, atom_error, atom_invalid);
  325. key = enif_make_copy(env, node->key.t);
  326. value = enif_make_copy(env, node->data.t);
  327. return enif_make_tuple2(env, key, value);
  328. }
  329. ERL_NIF_TERM write(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
  330. object_resource *lru;
  331. LRUBtree<ErlTerm,ErlTerm> *bt_lru;
  332. ErlTerm key;
  333. ErlTerm value;
  334. ErlNifEnv *kv_env;
  335. size_t size;
  336. if (argc != 3) {
  337. return enif_make_badarg(env);
  338. }
  339. if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
  340. return enif_make_badarg(env);
  341. }
  342. bt_lru = (LRUBtree<ErlTerm, ErlTerm> *) lru->object;
  343. kv_env = enif_alloc_env();
  344. key.t = enif_make_copy(kv_env, argv[1]);
  345. value.t = enif_make_copy(kv_env, argv[2]);
  346. /* do not use the size of term
  347. size = enif_size_term(key.t);
  348. size += enif_size_term(value.t);
  349. */
  350. /* size based on entries */
  351. size = 1;
  352. bt_lru->put(key, value, kv_env, env, size);
  353. return atom_ok;
  354. }
  355. ERL_NIF_TERM register_pid(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
  356. object_resource *lru;
  357. LRUBtree<ErlTerm,ErlTerm> *bt_lru;
  358. if (argc != 2) {
  359. return enif_make_badarg(env);
  360. }
  361. if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
  362. return enif_make_badarg(env);
  363. }
  364. bt_lru = (LRUBtree<ErlTerm,ErlTerm> *) lru->object;
  365. if (!enif_get_local_pid(env, argv[1], &(bt_lru->pid))) {
  366. return enif_make_badarg(env);
  367. }
  368. bt_lru->pid_set = true;
  369. return atom_ok;
  370. }
  371. ERL_NIF_TERM unregister_pid(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
  372. object_resource *lru;
  373. LRUBtree<ErlTerm,ErlTerm> *bt_lru;
  374. if (argc != 1) {
  375. return enif_make_badarg(env);
  376. }
  377. if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
  378. return enif_make_badarg(env);
  379. }
  380. bt_lru = (LRUBtree<ErlTerm,ErlTerm> *) lru->object;
  381. bt_lru->pid_set = false;
  382. return atom_ok;
  383. }
  384. ERL_NIF_TERM get_registered_pid(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
  385. object_resource *lru;
  386. LRUBtree<ErlTerm,ErlTerm> *bt_lru;
  387. if (argc != 1) {
  388. return enif_make_badarg(env);
  389. }
  390. if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
  391. return enif_make_badarg(env);
  392. }
  393. bt_lru = (LRUBtree<ErlTerm,ErlTerm> *) lru->object;
  394. if (!bt_lru->pid_set) {
  395. return enif_make_tuple2(env, atom_error, atom_invalid);
  396. }
  397. return enif_make_pid(env, &(bt_lru->pid));
  398. }
  399. ERL_NIF_TERM get_size(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
  400. object_resource *lru;
  401. LRUBtree<ErlTerm,ErlTerm> *bt_lru;
  402. if (argc != 1) {
  403. return enif_make_badarg(env);
  404. }
  405. if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
  406. return enif_make_badarg(env);
  407. }
  408. bt_lru = (LRUBtree<ErlTerm,ErlTerm> *) lru->object;
  409. return enif_make_ulong(env, bt_lru->getSize());
  410. }
  411. ERL_NIF_TERM get_max_size(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
  412. object_resource *lru;
  413. LRUBtree<ErlTerm,ErlTerm> *bt_lru;
  414. if (argc != 1) {
  415. return enif_make_badarg(env);
  416. }
  417. if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
  418. return enif_make_badarg(env);
  419. }
  420. bt_lru = (LRUBtree<ErlTerm,ErlTerm> *) lru->object;
  421. return enif_make_ulong(env, bt_lru->getMaxSize());
  422. }
  423. ERL_NIF_TERM set_max_size(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
  424. object_resource *lru;
  425. unsigned long max_size;
  426. LRUBtree<ErlTerm,ErlTerm> *bt_lru;
  427. if (argc != 2) {
  428. return enif_make_badarg(env);
  429. }
  430. if (!enif_get_resource(env, argv[0], lruResource, (void **) &lru)) {
  431. return enif_make_badarg(env);
  432. }
  433. /* get max_size */
  434. if (enif_get_ulong(env, argv[1], &max_size) < 1){
  435. return enif_make_tuple2(env, atom_error, atom_max_size);
  436. }
  437. bt_lru = (LRUBtree<ErlTerm,ErlTerm> *) lru->object;
  438. bt_lru->setMaxSize(max_size);
  439. return atom_ok;
  440. }
  441. ErlNifFunc nif_funcs[] = {
  442. {"create", 1, create},
  443. {"close", 1, close, ERL_NIF_DIRTY_JOB_IO_BOUND},
  444. {"register_pid", 2, register_pid},
  445. {"unregister_pid", 1, unregister_pid},
  446. {"get_registered_pid", 1, get_registered_pid},
  447. {"get_size", 1, get_size},
  448. {"get_max_size", 1, get_max_size},
  449. {"set_max_size", 2, set_max_size},
  450. {"oldest", 1, oldest},
  451. {"latest", 1, latest},
  452. {"last", 1, last},
  453. {"first", 1, first},
  454. {"read", 2, read},
  455. {"next", 2, next},
  456. {"prev", 2, prev},
  457. {"seek", 2, seek},
  458. {"iterate_next", 2, iterate_next},
  459. {"remove", 2, remove},
  460. {"write", 3, write}
  461. };
  462. } /* anonymouse namespace ends */
  463. ERL_NIF_INIT(btree_lru, nif_funcs, load, reload, upgrade, NULL)