%%%------------------------------------------------------------------- %%% File : sherk_ets.erl %%% Author : Mats Cronqvist %%% Description : %%% %%% Created : 14 Feb 2002 by Mats Cronqvist %%%------------------------------------------------------------------- -module(sherk_ets). -export([assert/1]). -export([new/1,new/2]). -export([kill/1]). -export([upd/2,upd/3]). -export([lup/2]). -export([f2t/1,t2f/2]). %file2tab, tab2file but compressed -define(TAB(T), list_to_atom(atom_to_list(T)++"_tab")). assert(Tab) -> case whereis(?TAB(Tab)) of undefined -> new(Tab); _ -> ok end. new(Tab) -> new(Tab, [named_table,public,ordered_set]). new(Tab, Opts) -> kill(Tab), Mama = self(), Ref = make_ref(), E = fun() -> register(?TAB(Tab),self()), ets:new(Tab,Opts), Mama ! Ref, receive {quit, P} -> P ! Tab end end, spawn(E), receive Ref -> ok end, Tab. kill(Tab) -> try ?TAB(Tab) ! {quit, self()}, receive Tab -> ok end catch _:_ -> ok end. upd(Tab, Key) -> upd(Tab, Key, 1). upd(Tab, Key, Inc) -> try ets:update_counter(Tab, Key, Inc) catch _:_ -> ets:insert(Tab, {Key, Inc}), Inc end. lup(Tab, Key) -> try ets:lookup(Tab, Key) of [{Key,Val}] -> Val; O -> O catch _:_ -> [] end. %% tab2file/2 and file2tab/1 replacements %% stores multiple tabs in compressed files %% file format is; %% <>,<>, %% [<>,<>,...] %% <<0:32/integer>> t2f(Tabs, File) when is_list(Tabs) -> case file:open(File,[write,compressed,raw,binary]) of {error,R} -> exit({error_opening,R,File}); {ok,FD} -> try t2f(Tabs,FD,0) after file:close(FD) end end. t2f([],_FD,N) -> N; t2f([Tab|Tabs],FD,N) -> t2f_f(make_info(Tab),FD), ets:foldl(fun t2f_f/2,FD,Tab), file:write(FD,<<0:32/integer>>), t2f(Tabs,FD,N+1). make_info(Tab) -> undefined==ets:info(Tab,size) andalso exit({no_such_table,Tab}), {ets:info(Tab,name), [ets:info(Tab,type), ets:info(Tab,protection), {keypos,ets:info(Tab,keypos)}]++ case ets:info(Tab,named_table) of true -> [named_table];_ -> [] end}. t2f_f(Term,FD) -> B = term_to_binary(Term), S = size(B), file:write(FD,<>), FD. f2t(File) -> case file:open(File,[read,compressed,raw,binary]) of {error,R} -> exit({error_opening,R,File}); {ok,FD} -> try do_tabs(get_tab_header(FD),FD,[]) after file:close(FD) end end. do_tabs(eof,_FD,O) -> O; do_tabs({Name,Opts},FD,O) -> new(Name,Opts), Cnt = f2t(FD,Name,0), do_tabs(get_tab_header(FD),FD,[{Name,Cnt}|O]). get_tab_header(FD) -> try f2t_f(FD) catch throw:eof -> eof; _:X -> exit({bad_header,X}) end. f2t(FD,Tab,N) -> try ets:insert(Tab,f2t_f(FD)) of _ -> f2t(FD,Tab,N+1) catch throw:delimiter -> N; throw:eof -> exit({unexpected_eof}) end. f2t_f(FD) -> case file:read(FD,4) of eof -> throw(eof); {ok,<<0:32/integer>>} -> throw(delimiter); {ok,<>} -> case file:read(FD,Size) of {ok,Bin} -> binary_to_term(Bin); R -> exit({error_reading_term,R}) end; R -> exit({error_reading_size,R}) end.