From 153fbb172722336027b3610e2c779edba2cead50 Mon Sep 17 00:00:00 2001 From: Kyrylo Silin Date: Tue, 9 Feb 2016 05:48:15 +0200 Subject: [PATCH] rmarshal: rework the library * no more "rmarshal_symstorage" BS (replaced by a simple map) * added a supervisor to the "rmarshal" module --- include/marshal.hrl | 2 +- src/rmarshal.erl | 130 ++++++++++++++++++++---------------- src/rmarshal_sup.erl | 26 ++++++++ src/rmarshal_symstorage.erl | 49 -------------- 4 files changed, 101 insertions(+), 106 deletions(-) create mode 100644 src/rmarshal_sup.erl delete mode 100644 src/rmarshal_symstorage.erl diff --git a/include/marshal.hrl b/include/marshal.hrl index 0879a6f..36da2f0 100644 --- a/include/marshal.hrl +++ b/include/marshal.hrl @@ -62,4 +62,4 @@ | rstring() | rarray(). --type binfrag(RTermType) :: {RTermType, Undecoded :: binary()}. +-type binfrag(RTermType) :: {RTermType, Undecoded :: binary(), map()}. diff --git a/src/rmarshal.erl b/src/rmarshal.erl index b59b693..f2daffb 100644 --- a/src/rmarshal.erl +++ b/src/rmarshal.erl @@ -6,38 +6,46 @@ -spec load(<<_:16, _:_*8>>) -> {'ok', rterm()}. load(<>) -> - rmarshal_symstorage:start(), - decode(Rest, []). + decode(Rest, [], maps:new()). --spec decode(<<_:8, _:_*8>>, Decoded) -> {Undecoded, Decoded} when +-spec decode(<<_:8, _:_*8>>, Decoded, SymRefs) -> {Undecoded, Decoded} when Decoded :: rarray(), + SymRefs :: map(), Undecoded :: binary(); - (<<>>, Decoded) -> {'ok', Decoded} when + (<<>>, Decoded, _SymRefs) -> {'ok', Decoded} when Decoded :: rarray(). -decode(<<>>, Decoded) -> - rmarshal_symstorage:stop(), +decode(<<>>, Decoded, _SymRefs) -> {ok, Decoded}; -decode(<>, Decoded) -> - {DecodedChunk, UndecodedRest} = decode_chunk(Type, Rest), - decode(UndecodedRest, [DecodedChunk|Decoded]). +decode(<>, Decoded, SymRefs) -> + {DecodedChunk, UndecodedRest, NewSymRefs} = decode_chunk(Type, Rest, SymRefs), + decode(UndecodedRest, [DecodedChunk|Decoded], NewSymRefs). --spec decode_chunk(Type, Undecoded) -> BinaryFragment when +-spec decode_chunk(Type, Undecoded, SymRefs) -> BinaryFragment when Type :: byte(), Undecoded :: binary(), + SymRefs :: map(), BinaryFragment :: binfrag(rterm()). -decode_chunk(?TYPE_NIL, Bin) -> {nil, Bin}; -decode_chunk(?TYPE_TRUE, Bin) -> {true, Bin}; -decode_chunk(?TYPE_FALSE, Bin) -> {false, Bin}; -decode_chunk(?TYPE_FIXNUM, Bin) -> decode_fixnum(Bin); -decode_chunk(?TYPE_BIGNUM, Bin) -> decode_bignum(Bin); -decode_chunk(?TYPE_IVAR, Bin) -> decode_ivar(Bin); -decode_chunk(?TYPE_ARRAY, Bin) -> decode_array(Bin); -decode_chunk(?TYPE_SYMBOL, Bin) -> decode_symbol(Bin); -decode_chunk(?TYPE_SYMLINK, Bin) -> decode_symlink(Bin); -decode_chunk(?TYPE_FLOAT, Bin) -> decode_float(Bin); -decode_chunk(?TYPE_HASH, Bin) -> decode_hash(Bin). +decode_chunk(?TYPE_NIL, Bin, SymRefs) -> {nil, Bin, SymRefs}; +decode_chunk(?TYPE_TRUE, Bin, SymRefs) -> {true, Bin, SymRefs}; +decode_chunk(?TYPE_FALSE, Bin, SymRefs) -> {false, Bin, SymRefs}; +decode_chunk(?TYPE_FIXNUM, Bin, SymRefs) -> + {Fixnum, Undecoded} = decode_fixnum(Bin), + {Fixnum, Undecoded, SymRefs}; +decode_chunk(?TYPE_BIGNUM, Bin, SymRefs) -> + {Bignum, Undecoded} = decode_bignum(Bin), + {Bignum, Undecoded, SymRefs}; +decode_chunk(?TYPE_IVAR, Bin, SymRefs) -> + {Ivar, Undecoded} = decode_ivar(Bin), + {Ivar, Undecoded, SymRefs}; +decode_chunk(?TYPE_ARRAY, Bin, SymRefs) -> decode_array(Bin, SymRefs); +decode_chunk(?TYPE_SYMBOL, Bin, SymRefs) -> decode_symbol(Bin, SymRefs); +decode_chunk(?TYPE_SYMLINK, Bin, SymRefs) -> decode_symlink(Bin, SymRefs); +decode_chunk(?TYPE_FLOAT, Bin, SymRefs) -> + {Float, Undecoded} = decode_float(Bin), + {Float, Undecoded, SymRefs}; +decode_chunk(?TYPE_HASH, Bin, SymRefs) -> decode_hash(Bin, SymRefs). -spec decode_fixnum(Undecoded) -> BinaryFragment when Undecoded :: binary(), @@ -115,42 +123,50 @@ decode_string(Bitstring, <<6, $;, 6, $T, Rest/binary>>) -> decode_string(Bitstring, <<6, $;, 0, $T, Rest/binary>>) -> {binary_to_list(Bitstring), Rest}. --spec decode_array(<<_:8, _:_*8>>) -> BinaryFragment when +-spec decode_array(<<_:8, _:_*8>>, SymRefs) -> BinaryFragment when + SymRefs :: map(), BinaryFragment :: binfrag(rterm()). -decode_array(<>) -> - decode_array(Size - ?OFFSET, Rest, []). +decode_array(<>, SymRefs) -> + decode_array(Size - ?OFFSET, Rest, [], SymRefs). --spec decode_array(Size, <<_:8, _:_*8>>, Decoded) -> BinaryFragment when +-spec decode_array(Size, <<_:8, _:_*8>>, Decoded, SymRefs) -> BinaryFragment when Size :: pos_integer(), Decoded :: rarray(), + SymRefs :: map(), BinaryFragment :: binfrag(rterm()). -decode_array(0, Bin, Decoded) -> - {lists:reverse(Decoded), Bin}; -decode_array(_Size, <<>>, _Decoded) -> - {[], <<>>}; -decode_array(Size, <>, Decoded) -> - decode_array(Size - 1, Rest, [[]|Decoded]); -decode_array(Size, <>, Decoded) -> - {DecodedChunk, Bin} = decode_chunk(Type, Rest), - decode_array(Size - 1, Bin, [DecodedChunk|Decoded]). - --spec decode_symbol(<<_:8, _:_*8>>) -> BinaryFragment when +decode_array(0, Bin, Decoded, SymRefs) -> + {lists:reverse(Decoded), Bin, SymRefs}; +decode_array(_Size, <<>>, _Decoded, SymRefs) -> + {[], <<>>, SymRefs}; +decode_array(Size, <>, Decoded, SymRefs) -> + decode_array(Size - 1, Rest, [[]|Decoded], SymRefs); +decode_array(Size, <>, Decoded, SymRefs) -> + {DecodedChunk, Bin, NewSymRefs} = decode_chunk(Type, Rest, SymRefs), + decode_array(Size - 1, Bin, [DecodedChunk|Decoded], NewSymRefs). + +-spec decode_symbol(<<_:8, _:_*8>>, SymRefs) -> BinaryFragment when + SymRefs :: map(), BinaryFragment :: binfrag(rsymbol()). -decode_symbol(<>) -> +decode_symbol(<>, SymRefs) -> {Sym, Bin} = split_binary(Rest, Len - ?OFFSET), Atom = list_to_atom(binary_to_list(Sym)), - rmarshal_symstorage:write(Atom), - {Atom, Bin}. - --spec decode_symlink(<<_:8, _:_*8>>) -> BinaryFragment when + SymRefSize = maps:size(SymRefs), + Offset = case SymRefSize of + 0 -> 0; + _ -> ?OFFSET + end, + NewSymRefs = maps:put(SymRefSize + Offset, Atom, SymRefs), + {Atom, Bin, NewSymRefs}. + +-spec decode_symlink(<<_:8, _:_*8>>, SymRefs) -> BinaryFragment when + SymRefs :: map(), BinaryFragment :: binfrag(rsymbol()). -decode_symlink(<>) -> - {ok, Atom} = rmarshal_symstorage:read(SymLink), - {Atom, Rest}. +decode_symlink(<>, SymRefs) -> + {maps:get(SymLink, SymRefs), Rest, SymRefs}. -spec decode_float(<<_:8, _:_*8>>) -> BinaryFragment when BinaryFragment :: binfrag(rfloat()). @@ -159,23 +175,25 @@ decode_float(<>) -> {Float, Bin} = split_binary(Rest, Len - ?OFFSET), {binary_to_float(Float), Bin}. --spec decode_hash(<<_:8, _:_*8>>) -> BinaryFragment when +-spec decode_hash(<<_:8, _:_*8>>, SymRefs) -> BinaryFragment when + SymRefs :: map(), BinaryFragment :: binfrag(rhash()). -decode_hash(<>) -> - decode_hash(Size - ?OFFSET, Rest, maps:new()). +decode_hash(<>, SymRefs) -> + decode_hash(Size - ?OFFSET, Rest, maps:new(), SymRefs). --spec decode_hash(Size, <<_:8, _:_*8>>, Decoded) -> BinaryFragment when +-spec decode_hash(Size, <<_:8, _:_*8>>, Decoded, SymRefs) -> BinaryFragment when Size :: pos_integer(), Decoded :: rhash(), + SymRefs :: map(), BinaryFragment :: binfrag(rhash()). -decode_hash(Size, Bin, Decoded) when Size =< 0 -> - {Decoded, Bin}; -decode_hash(_Size, <<>>, _Decoded) -> - {#{}, <<>>}; -decode_hash(Size, <>, Decoded) -> - {DecodedKey, Bin} = decode_chunk(Type, Rest), +decode_hash(Size, Bin, Decoded, SymRefs) when Size =< 0 -> + {Decoded, Bin, SymRefs}; +decode_hash(_Size, <<>>, _Decoded, SymRefs) -> + {#{}, <<>>, SymRefs}; +decode_hash(Size, <>, Decoded, SymRefs) -> + {DecodedKey, Bin, NewSymRefs} = decode_chunk(Type, Rest, SymRefs), <> = Bin, - {DecodedVal, Bin2} = decode_chunk(Type2, Rest2), - decode_hash(Size - 1, Bin2, maps:put(DecodedKey, DecodedVal, Decoded)). + {DecodedVal, Bin2, NewSymRefs2} = decode_chunk(Type2, Rest2, NewSymRefs), + decode_hash(Size - 1, Bin2, maps:put(DecodedKey, DecodedVal, Decoded), NewSymRefs2). diff --git a/src/rmarshal_sup.erl b/src/rmarshal_sup.erl new file mode 100644 index 0000000..ed371ee --- /dev/null +++ b/src/rmarshal_sup.erl @@ -0,0 +1,26 @@ +-module(rmarshal_sup). + +-behaviour(supervisor). + +%% API +-export([start_link/0]). + +%% Supervisor callbacks +-export([init/1]). + +-define(SERVER, ?MODULE). + +%% Helper macro for declaring children of supervisor +-define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 2000, Type, [I]}). + +%%==================================================================== +%% API functions +%%==================================================================== + +start_link() -> + supervisor:start_link({local, ?SERVER}, ?MODULE, []). + +%% Child :: {Id,StartFunc,Restart,Shutdown,Type,Modules} +init([]) -> + Procs = [?CHILD(rmarshal_symbols, worker)], + {ok, { {one_for_one, 0, 1}, Procs} }. diff --git a/src/rmarshal_symstorage.erl b/src/rmarshal_symstorage.erl deleted file mode 100644 index 1cbc1a3..0000000 --- a/src/rmarshal_symstorage.erl +++ /dev/null @@ -1,49 +0,0 @@ --module(rmarshal_symstorage). --export([start/0, stop/0, write/1, read/1]). - -start() -> - register(symstorage, spawn(fun() -> loop(dict:new()) end)). - -stop() -> - {symstorage ! terminate, unregister(symstorage)}. - -loop(SymDict) -> - receive - {From, {write, Sym}} -> - From ! {self(), ok}, - NewSymDict = store_in_dict(dict:size(SymDict), Sym, SymDict), - loop(NewSymDict); - {From, {read, SymLink}} -> - case dict:is_key(SymLink, SymDict) of - true -> From ! {self(), {ok, dict:fetch(SymLink, SymDict)}}; - false -> From ! {self(), not_found} - end, - loop(SymDict); - terminate -> - ok - end. - -store_in_dict(0, Sym, SymDict) -> - dict:store(0, Sym, SymDict); -store_in_dict(Size, Sym, SymDict) -> - dict:store(Size + 5, Sym, SymDict). - -write(Atom) -> - Pid = whereis(symstorage), - symstorage ! {self(), {write, Atom}}, - receive - {Pid, Msg} -> Msg - after - 3000 -> - timeout - end. - -read(SymLink) -> - Pid = whereis(symstorage), - symstorage ! {self(), {read, SymLink}}, - receive - {Pid, Msg} -> Msg - after - 3000 -> - timeout - end.