/apps/ecnty/src/ecnty_storage_leveldb.erl

https://github.com/benmmurphy/ecnty · Erlang · 91 lines · 68 code · 19 blank · 4 comment · 0 complexity · 90fcac60b4b2d418eef050b454051d75 MD5 · raw file

  1. -module(ecnty_storage_leveldb).
  2. -behaviour(ecnty_storage).
  3. -export([start/2, stop/1, put/3, get/2, drop/1, fold_objects/3, is_empty/1]).
  4. -record(state, {leveldb_handle, file}).
  5. parse_value(Binary) ->
  6. binary_to_term(Binary).
  7. create_value(Term) ->
  8. term_to_binary(Term).
  9. create_key(Term) ->
  10. term_to_binary(Term).
  11. parse_key(Binary) ->
  12. binary_to_term(Binary).
  13. start(Partition, Config) ->
  14. case config_value(data_root, Config) of
  15. undefined ->
  16. lager:error("Failed to get data_root"),
  17. {error, data_root};
  18. DataRoot ->
  19. File = filename:join(DataRoot, integer_to_list(Partition)),
  20. open(File, #state{file = File})
  21. end.
  22. config_value(Key, Config) ->
  23. config_value(Key, Config, undefined).
  24. config_value(Key, Config, Default) ->
  25. case proplists:get_value(Key, Config) of
  26. undefined ->
  27. app_helper:get_env(leveldb, Key, Default);
  28. Value ->
  29. Value
  30. end.
  31. open(File, State) ->
  32. ok = filelib:ensure_dir(filename:join(File, "X")),
  33. case eleveldb:open(File, [{create_if_missing, true}]) of
  34. {ok, LevelDBHandle} ->
  35. {ok, State#state{leveldb_handle = LevelDBHandle}};
  36. {error, Reason} ->
  37. {error, Reason}
  38. end.
  39. stop(_State) ->
  40. %% this looks very weird. when gc collects all the leveldb objects that hold onto the db ref
  41. %% the db ref will be deleted in c++ land and all the file locks will be released.
  42. %% this makes me feel really dirty..... maybe this is standard erlang way to do things
  43. %% but coming from other gc managed languages this smells funny.
  44. ok.
  45. get(#state{leveldb_handle=Handle}, Key) ->
  46. case eleveldb:get(Handle, create_key(Key), []) of
  47. not_found -> {error, not_found};
  48. {error, Reason} -> {error, Reason};
  49. {ok, Binary} -> {ok, parse_value(Binary)}
  50. end.
  51. put(#state{leveldb_handle=Handle}=State, Key, Value) ->
  52. {eleveldb:put(Handle, create_key(Key), create_value(Value), []), State}.
  53. is_empty(#state{leveldb_handle=Handle}) ->
  54. eleveldb:is_empty(Handle).
  55. drop(#state{file = File} = State) ->
  56. case eleveldb:destroy(File, []) of
  57. ok ->
  58. case open(File, State) of
  59. {error, Reason} ->
  60. {error, Reason, State};
  61. {ok, State1} ->
  62. {ok, State1}
  63. end;
  64. {error, Reason} ->
  65. {error, Reason, State}
  66. end.
  67. fold_fun(FoldFun) ->
  68. fun ({Key, Value}, Acc) ->
  69. FoldFun(parse_key(Key), parse_value(Value), Acc)
  70. end.
  71. fold_objects(#state{leveldb_handle = Handle}, FoldFun, Acc) ->
  72. {ok, eleveldb:fold(Handle, fold_fun(FoldFun), Acc, [])}.