/src/sherk_ets.erl

https://github.com/jpgneves/eper · Erlang · 141 lines · 109 code · 19 blank · 13 comment · 0 complexity · 7c056a72289354476b989b9795947390 MD5 · raw file

  1. %%%-------------------------------------------------------------------
  2. %%% File : sherk_ets.erl
  3. %%% Author : Mats Cronqvist <etxmacr@cbe2077>
  4. %%% Description :
  5. %%%
  6. %%% Created : 14 Feb 2002 by Mats Cronqvist <etxmacr@cbe2077>
  7. %%%-------------------------------------------------------------------
  8. -module(sherk_ets).
  9. -export([assert/1]).
  10. -export([new/1,new/2]).
  11. -export([kill/1]).
  12. -export([upd/2,upd/3]).
  13. -export([lup/2]).
  14. -export([f2t/1,t2f/2]). %file2tab, tab2file but compressed
  15. -define(TAB(T), list_to_atom(atom_to_list(T)++"_tab")).
  16. assert(Tab) ->
  17. case whereis(?TAB(Tab)) of
  18. undefined -> new(Tab);
  19. _ -> ok
  20. end.
  21. new(Tab) -> new(Tab, [named_table,public,ordered_set]).
  22. new(Tab, Opts) ->
  23. kill(Tab),
  24. Mama = self(),
  25. Ref = make_ref(),
  26. E = fun() -> register(?TAB(Tab),self()),
  27. ets:new(Tab,Opts),
  28. Mama ! Ref,
  29. receive {quit, P} -> P ! Tab end
  30. end,
  31. spawn(E),
  32. receive Ref -> ok end,
  33. Tab.
  34. kill(Tab) ->
  35. try
  36. ?TAB(Tab) ! {quit, self()},
  37. receive Tab -> ok end
  38. catch _:_ -> ok
  39. end.
  40. upd(Tab, Key) -> upd(Tab, Key, 1).
  41. upd(Tab, Key, Inc) ->
  42. try ets:update_counter(Tab, Key, Inc)
  43. catch _:_ -> ets:insert(Tab, {Key, Inc}), Inc
  44. end.
  45. lup(Tab, Key) ->
  46. try ets:lookup(Tab, Key) of
  47. [{Key,Val}] -> Val;
  48. O -> O
  49. catch _:_ -> []
  50. end.
  51. %% tab2file/2 and file2tab/1 replacements
  52. %% stores multiple tabs in compressed files
  53. %% file format is;
  54. %% <<TabInfoSize:32/integer>>,<<TabInfo:TabInfoSize/binary>>,
  55. %% [<<ObjectSize:32/integer>>,<<Object:ObjectSize/binary>>,...]
  56. %% <<0:32/integer>>
  57. t2f(Tabs, File) when is_list(Tabs) ->
  58. case file:open(File,[write,compressed,raw,binary]) of
  59. {error,R} ->
  60. exit({error_opening,R,File});
  61. {ok,FD} ->
  62. try t2f(Tabs,FD,0)
  63. after file:close(FD)
  64. end
  65. end.
  66. t2f([],_FD,N) -> N;
  67. t2f([Tab|Tabs],FD,N) ->
  68. t2f_f(make_info(Tab),FD),
  69. ets:foldl(fun t2f_f/2,FD,Tab),
  70. file:write(FD,<<0:32/integer>>),
  71. t2f(Tabs,FD,N+1).
  72. make_info(Tab) ->
  73. undefined==ets:info(Tab,size) andalso exit({no_such_table,Tab}),
  74. {ets:info(Tab,name),
  75. [ets:info(Tab,type),
  76. ets:info(Tab,protection),
  77. {keypos,ets:info(Tab,keypos)}]++
  78. case ets:info(Tab,named_table) of true -> [named_table];_ -> [] end}.
  79. t2f_f(Term,FD) ->
  80. B = term_to_binary(Term),
  81. S = size(B),
  82. file:write(FD,<<S:32/integer,B/binary>>),
  83. FD.
  84. f2t(File) ->
  85. case file:open(File,[read,compressed,raw,binary]) of
  86. {error,R} ->
  87. exit({error_opening,R,File});
  88. {ok,FD} ->
  89. try do_tabs(get_tab_header(FD),FD,[])
  90. after file:close(FD)
  91. end
  92. end.
  93. do_tabs(eof,_FD,O) ->
  94. O;
  95. do_tabs({Name,Opts},FD,O) ->
  96. new(Name,Opts),
  97. Cnt = f2t(FD,Name,0),
  98. do_tabs(get_tab_header(FD),FD,[{Name,Cnt}|O]).
  99. get_tab_header(FD) ->
  100. try f2t_f(FD)
  101. catch
  102. throw:eof -> eof;
  103. _:X -> exit({bad_header,X})
  104. end.
  105. f2t(FD,Tab,N) ->
  106. try ets:insert(Tab,f2t_f(FD)) of
  107. _ -> f2t(FD,Tab,N+1)
  108. catch
  109. throw:delimiter -> N;
  110. throw:eof -> exit({unexpected_eof})
  111. end.
  112. f2t_f(FD) ->
  113. case file:read(FD,4) of
  114. eof -> throw(eof);
  115. {ok,<<0:32/integer>>} -> throw(delimiter);
  116. {ok,<<Size:32/integer>>} ->
  117. case file:read(FD,Size) of
  118. {ok,Bin} -> binary_to_term(Bin);
  119. R -> exit({error_reading_term,R})
  120. end;
  121. R -> exit({error_reading_size,R})
  122. end.