diff options
Diffstat (limited to 'lib')
39 files changed, 1262 insertions, 640 deletions
diff --git a/lib/Makefile b/lib/Makefile index 7f4c309da9..98d746925f 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -83,19 +83,15 @@ endif ifdef BOOTSTRAP SUB_DIRECTORIES = \ - kernel stdlib compiler orber/include + kernel stdlib compiler else ifdef SECONDARY_BOOTSTRAP SUB_DIRECTORIES = hipe parsetools asn1/src else ifdef TERTIARY_BOOTSTRAP - SUB_DIRECTORIES = snmp - else - ifdef FOURTH_BOOTSTRAP - SUB_DIRECTORIES = sasl jinterface ic syntax_tools - else # Not bootstrap build - SUB_DIRECTORIES = $(ERTS_SUB_DIRECTORIES) $(OTHER_SUB_DIRECTORIES) - endif + SUB_DIRECTORIES = snmp sasl jinterface ic syntax_tools + else # Not bootstrap build + SUB_DIRECTORIES = $(ERTS_SUB_DIRECTORIES) $(OTHER_SUB_DIRECTORIES) endif endif endif diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index c781ccb302..83772d9023 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -43,6 +43,7 @@ #include <openssl/aes.h> #include <openssl/md5.h> #include <openssl/md4.h> +#include <openssl/md2.h> #include <openssl/sha.h> #include <openssl/bn.h> #include <openssl/objects.h> @@ -267,6 +268,7 @@ static ERL_NIF_TERM atom_true; static ERL_NIF_TERM atom_false; static ERL_NIF_TERM atom_sha; static ERL_NIF_TERM atom_md5; +static ERL_NIF_TERM atom_md2; static ERL_NIF_TERM atom_ripemd160; static ERL_NIF_TERM atom_error; static ERL_NIF_TERM atom_rsa_pkcs1_padding; @@ -337,6 +339,7 @@ static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) atom_false = enif_make_atom(env,"false"); atom_sha = enif_make_atom(env,"sha"); atom_md5 = enif_make_atom(env,"md5"); + atom_md2 = enif_make_atom(env,"md2"); atom_ripemd160 = enif_make_atom(env,"ripemd160"); atom_error = enif_make_atom(env,"error"); atom_rsa_pkcs1_padding = enif_make_atom(env,"rsa_pkcs1_padding"); @@ -1047,16 +1050,28 @@ static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv return(i > 0) ? atom_true : atom_false; } +struct hash_def { + int type; + unsigned int m_len; + unsigned char * (*func) (const unsigned char *d, size_t n, unsigned char *md); +}; + +static const struct hash_def md2_hash_def = { NID_md2, MD2_DIGEST_LENGTH, &MD2}; +static const struct hash_def md5_hash_def = { NID_md5, MD5_DIGEST_LENGTH, &MD5}; +static const struct hash_def sha1_hash_def = { NID_sha1, SHA_DIGEST_LENGTH, &SHA1}; + static ERL_NIF_TERM rsa_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Type, Data, Signature, Key=[E,N]) */ ErlNifBinary data_bin, sign_bin; unsigned char hmacbuf[SHA_DIGEST_LENGTH]; ERL_NIF_TERM head, tail, ret; - int i, is_sha; + int i; RSA* rsa = RSA_new(); + const struct hash_def *hash_def = NULL; - if (argv[0] == atom_sha) is_sha = 1; - else if (argv[0] == atom_md5) is_sha = 0; + if (argv[0] == atom_sha) hash_def = &sha1_hash_def; + else if (argv[0] == atom_md5) hash_def = &md5_hash_def; + else if (argv[0] == atom_md2) hash_def = &md2_hash_def; else goto badarg; if (!inspect_mpint(env, argv[1], &data_bin) @@ -1070,16 +1085,9 @@ static ERL_NIF_TERM rsa_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv ret = enif_make_badarg(env); } else { - if (is_sha) { - SHA1(data_bin.data+4, data_bin.size-4, hmacbuf); - i = RSA_verify(NID_sha1, hmacbuf, SHA_DIGEST_LENGTH, - sign_bin.data+4, sign_bin.size-4, rsa); - } - else { - MD5(data_bin.data+4, data_bin.size-4, hmacbuf); - i = RSA_verify(NID_md5, hmacbuf, MD5_DIGEST_LENGTH, - sign_bin.data+4, sign_bin.size-4, rsa); - } + (void) *hash_def->func(data_bin.data+4, data_bin.size-4, hmacbuf); + i = RSA_verify(hash_def->type, hmacbuf, hash_def->m_len, + sign_bin.data+4, sign_bin.size-4, rsa); ret = (i==1 ? atom_true : atom_false); } RSA_free(rsa); @@ -1221,10 +1229,12 @@ static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar unsigned char hmacbuf[SHA_DIGEST_LENGTH]; unsigned rsa_s_len; RSA *rsa = RSA_new(); - int i, is_sha; + int i; + const struct hash_def *hash_def = NULL; - if (argv[0] == atom_sha) is_sha = 1; - else if (argv[0] == atom_md5) is_sha = 0; + if (argv[0] == atom_sha) hash_def = &sha1_hash_def; + else if (argv[0] == atom_md5) hash_def = &md5_hash_def; + else if (argv[0] == atom_md2) hash_def = &md2_hash_def; else goto badarg; if (!inspect_mpint(env,argv[1],&data_bin) @@ -1240,18 +1250,10 @@ static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar return enif_make_badarg(env); } enif_alloc_binary(RSA_size(rsa), &ret_bin); - if (is_sha) { - SHA1(data_bin.data+4, data_bin.size-4, hmacbuf); - ERL_VALGRIND_ASSERT_MEM_DEFINED(hmacbuf, SHA_DIGEST_LENGTH); - i = RSA_sign(NID_sha1, hmacbuf, SHA_DIGEST_LENGTH, - ret_bin.data, &rsa_s_len, rsa); - } - else { - MD5(data_bin.data+4, data_bin.size-4, hmacbuf); - ERL_VALGRIND_ASSERT_MEM_DEFINED(hmacbuf, MD5_DIGEST_LENGTH); - i = RSA_sign(NID_md5, hmacbuf,MD5_DIGEST_LENGTH, - ret_bin.data, &rsa_s_len, rsa); - } + (void) *hash_def->func(data_bin.data+4, data_bin.size-4, hmacbuf); + ERL_VALGRIND_ASSERT_MEM_DEFINED(hmacbuf, hash_def->m_len); + i = RSA_sign(hash_def->type, hmacbuf, hash_def->m_len, + ret_bin.data, &rsa_s_len, rsa); RSA_free(rsa); if (i) { ERL_VALGRIND_MAKE_MEM_DEFINED(ret_bin.data, rsa_s_len); diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml index 179ba4498c..b593958264 100644 --- a/lib/crypto/doc/src/crypto.xml +++ b/lib/crypto/doc/src/crypto.xml @@ -347,7 +347,7 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]> </func> <func> <name>sha_mac_96(Key, Data) -> Mac</name> - <fsummary>Compute an <c>MD5 MAC</c>message authentification code</fsummary> + <fsummary>Compute an <c>SHA MAC</c>message authentification code</fsummary> <type> <v>Key = Data = iolist() | binary()</v> <v>Mac = binary()</v> @@ -744,7 +744,7 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]> <p>Generate a random number <c><![CDATA[N, Lo =< N < Hi.]]></c> Uses the <c>crypto</c> library pseudo-random number generator. The arguments (and result) can be either erlang integers or binary - multi-precision integers.</p> + multi-precision integers. <c>Hi</c> must be larger than <c>Lo</c>.</p> </desc> </func> <func> @@ -795,7 +795,7 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]> <v>E, N, D = Mpint</v> <d>Where <c>E</c> is the public exponent, <c>N</c> is public modulus and <c>D</c> is the private exponent.</d> - <v>DigestType = md5 | sha</v> + <v>DigestType = md2 | md5 | sha</v> <d>The default <c>DigestType</c> is sha.</d> <v>Mpint = binary()</v> <v>Signature = binary()</v> @@ -817,7 +817,7 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]> <v>Key = [E, N]</v> <v>E, N = Mpint</v> <d>Where <c>E</c> is the public exponent and <c>N</c> is public modulus.</d> - <v>DigestType = md5 | sha</v> + <v>DigestType = md2 | md5 | sha</v> <d> The default <c>DigestType</c> is sha.</d> <v>Mpint = binary()</v> </type> diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index c35dfcebab..ddad00f4b4 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -91,7 +91,7 @@ aes_ctr_stream_init, aes_ctr_stream_encrypt, aes_ctr_stream_decrypt, info_lib]). --type rsa_digest_type() :: 'md5' | 'sha'. +-type rsa_digest_type() :: 'md2' | 'md5' | 'sha'. -type dss_digest_type() :: 'none' | 'sha'. -type crypto_integer() :: binary() | integer(). @@ -415,6 +415,13 @@ rand_uniform(From,To) when is_binary(From), is_binary(To) -> Whatever end; rand_uniform(From,To) when is_integer(From),is_integer(To) -> + if From < 0 -> + rand_uniform_pos(0, To - From) + From; + true -> + rand_uniform_pos(From, To) + end. + +rand_uniform_pos(From,To) when From < To -> BinFrom = mpint(From), BinTo = mpint(To), case rand_uniform(BinFrom, BinTo) of @@ -422,7 +429,9 @@ rand_uniform(From,To) when is_integer(From),is_integer(To) -> erlint(Result); Other -> Other - end. + end; +rand_uniform_pos(_,_) -> + error(badarg). rand_uniform_nif(_From,_To) -> ?nif_stub. diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index 283aadb6ea..2fa058c852 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -878,10 +878,17 @@ rand_uniform_aux_test(0) -> rand_uniform_aux_test(N) -> ?line L = N*1000, ?line H = N*100000+1, + ?line crypto_rand_uniform(L, H), + ?line crypto_rand_uniform(-L, L), + ?line crypto_rand_uniform(-H, -L), + ?line crypto_rand_uniform(-H, L), + ?line rand_uniform_aux_test(N-1). + +crypto_rand_uniform(L,H) -> ?line R1 = crypto:rand_uniform(L, H), ?line t(R1 >= L), - ?line t(R1 < H), - ?line rand_uniform_aux_test(N-1). + ?line t(R1 < H). + %% %% @@ -1075,16 +1082,30 @@ rsa_sign_test(Config) when is_list(Config) -> PrivKey = [crypto:mpint(PubEx), crypto:mpint(Mod), crypto:mpint(PrivEx)], PubKey = [crypto:mpint(PubEx), crypto:mpint(Mod)], - ?line Sig1 = crypto:rsa_sign(sized_binary(Msg), PrivKey), - ?line m(crypto:rsa_verify(sized_binary(Msg), sized_binary(Sig1),PubKey), true), + ?line Sig = crypto:rsa_sign(sized_binary(Msg), PrivKey), + ?line m(crypto:rsa_verify(sized_binary(Msg), sized_binary(Sig),PubKey), true), - ?line Sig2 = crypto:rsa_sign(md5, sized_binary(Msg), PrivKey), - ?line m(crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig2),PubKey), true), - - ?line m(Sig1 =:= Sig2, false), - ?line m(crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig1),PubKey), false), - ?line m(crypto:rsa_verify(sha, sized_binary(Msg), sized_binary(Sig1),PubKey), true), + ?line Sig_md2 = crypto:rsa_sign(md2, sized_binary(Msg), PrivKey), + ?line Sig_md5 = crypto:rsa_sign(md5, sized_binary(Msg), PrivKey), + ?line Sig_sha = crypto:rsa_sign(sha, sized_binary(Msg), PrivKey), + + ?line m(Sig =:= Sig_sha, true), + ?line m(Sig_md2 =:= Sig_md5, false), + ?line m(Sig_md2 =:= Sig_sha, false), + ?line m(Sig_md5 =:= Sig_sha, false), + ?line m(crypto:rsa_verify(md2, sized_binary(Msg), sized_binary(Sig_md2),PubKey), true), + ?line m(crypto:rsa_verify(md2, sized_binary(Msg), sized_binary(Sig_md5),PubKey), false), + ?line m(crypto:rsa_verify(md2, sized_binary(Msg), sized_binary(Sig_sha),PubKey), false), + + ?line m(crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig_md2),PubKey), false), + ?line m(crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig_md5),PubKey), true), + ?line m(crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig_sha),PubKey), false), + + ?line m(crypto:rsa_verify(sha, sized_binary(Msg), sized_binary(Sig_md2),PubKey), false), + ?line m(crypto:rsa_verify(sha, sized_binary(Msg), sized_binary(Sig_md5),PubKey), false), + ?line m(crypto:rsa_verify(sha, sized_binary(Msg), sized_binary(Sig_sha),PubKey), true), + ok. dsa_sign_test(doc) -> diff --git a/lib/diameter/src/transport/diameter_sctp.erl b/lib/diameter/src/transport/diameter_sctp.erl index 92aa8488a0..46473e7bf1 100644 --- a/lib/diameter/src/transport/diameter_sctp.erl +++ b/lib/diameter/src/transport/diameter_sctp.erl @@ -525,7 +525,22 @@ recv({[#sctp_sndrcvinfo{stream = Id}], Bin}, #transport{parent = Pid}) recv({[], #sctp_shutdown_event{assoc_id = Id}}, #transport{assoc_id = Id}) -> - stop. + stop; + +%% Note that diameter_sctp(3) documents that sctp_events cannot be +%% specified in the list of options passed to gen_sctp and that +%% gen_opts/1 guards against this. This is to ensure that we know what +%% events to expect and also to ensure that we receive +%% #sctp_sndrcvinfo{} with each incoming message (data_io_event = +%% true). Adaptation layer events (ie. #sctp_adaptation_event{}) are +%% disabled by default so don't handle it. We could simply disable +%% events we don't react to but don't. + +recv({[], #sctp_paddr_change{}}, _) -> + ok; + +recv({[], #sctp_pdapi_event{}}, _) -> + ok. %% up/1 @@ -591,7 +606,7 @@ f([], _, _) -> %% assoc_id/1 -assoc_id(#sctp_shutdown_event{assoc_id = Id}) -> %% undocumented +assoc_id(#sctp_shutdown_event{assoc_id = Id}) -> Id; assoc_id(#sctp_assoc_change{assoc_id = Id}) -> Id; diff --git a/lib/gs/contribs/bonk/sounder.erl b/lib/gs/contribs/bonk/sounder.erl index 11ab03d167..899f20d4e0 100644 --- a/lib/gs/contribs/bonk/sounder.erl +++ b/lib/gs/contribs/bonk/sounder.erl @@ -72,13 +72,13 @@ stop() -> sounder ! {stop}, ok end. -new(File) when list(File) -> new(list_to_atom(File)); -new(File) when atom(File) -> +new(File) when is_list(File) -> new(list_to_atom(File)); +new(File) when is_atom(File) -> catch begin check(), sounder ! {new,File,self()}, wait_for_ack(sounder) end. -play(No) when integer(No) -> +play(No) when is_integer(No) -> catch begin check(), sounder ! {play, No, self()}, wait_for_ack(sounder) end. @@ -94,14 +94,14 @@ go() -> loop(Port) -> receive - {new, File, From} when atom(File) -> + {new, File, From} when is_atom(File) -> Port ! {self(),{command,lists:append([0],atom_to_list(File))}}, From ! {sounder,wait_for_ack(Port)}, loop(Port); {play,silent,From} -> From ! {sounder,false}, loop(Port); - {play,No,From} when integer(No) -> + {play,No,From} when is_integer(No) -> Port ! {self(),{command,[No]}}, From ! {sounder,wait_for_ack(Port)}, loop(Port); @@ -118,13 +118,13 @@ loop(Port) -> nosound() -> receive - {new,File,From} when atom(File) -> + {new,File,From} when is_atom(File) -> From ! {sounder,{ok,silent}}, nosound(); {play,silent,From} -> From ! {sounder,true}, nosound(); - {play,No,From} when integer(No) -> + {play,No,From} when is_integer(No) -> From ! {sounder,{error,no_audio_cap}}, nosound(); {stop} -> @@ -135,7 +135,7 @@ nosound() -> wait_for_ack(sounder) -> receive {sounder,Res} -> Res end; -wait_for_ack(Port) when port(Port) -> +wait_for_ack(Port) when is_port(Port) -> receive {Port,{data,"ok"}} -> ok; @@ -149,7 +149,7 @@ wait_for_ack(Port) when port(Port) -> check() -> case whereis(sounder) of - Pid when pid(Pid) -> + Pid when is_pid(Pid) -> ok; undefined -> throw({error,sounder_not_started}) diff --git a/lib/gs/contribs/cols/cols.erl b/lib/gs/contribs/cols/cols.erl index 67b46d0dfb..439eb717f7 100644 --- a/lib/gs/contribs/cols/cols.erl +++ b/lib/gs/contribs/cols/cols.erl @@ -278,7 +278,7 @@ fall_column([], _X, _Y, ColumnAcc, ChecksAcc) -> fall_column([black|Colors], X, Y, ColumnAcc, ChecksAcc) -> case find_box(Colors) of false -> {ColumnAcc, ChecksAcc}; - NewColors when list(NewColors) -> + NewColors when is_list(NewColors) -> fall_one_step(NewColors, X, Y, ColumnAcc, ChecksAcc) end; fall_column([Color|Colors], X, Y, ColumnAcc, ChecksAcc) -> @@ -330,7 +330,7 @@ new_column_list([], _, _) -> []. %%---------------------------------------------------------------------- %% Returns: a reversed list of colors. %%---------------------------------------------------------------------- -columntuple_to_list(ColumnTuple) when tuple(ColumnTuple) -> +columntuple_to_list(ColumnTuple) when is_tuple(ColumnTuple) -> columntuple_to_list(tuple_to_list(ColumnTuple),[]). columntuple_to_list([],Acc) -> Acc; diff --git a/lib/gs/contribs/mandel/mandel.erl b/lib/gs/contribs/mandel/mandel.erl index d4d2452463..579f8e487b 100644 --- a/lib/gs/contribs/mandel/mandel.erl +++ b/lib/gs/contribs/mandel/mandel.erl @@ -119,7 +119,7 @@ start_client(Opts,Nodes) -> try_random(random,Low,High) -> random:uniform()*(High-Low)+Low; -try_random(Float,_Low,_High) when number(Float) -> Float. +try_random(Float,_Low,_High) when is_number(Float) -> Float. %%----------------------------------------------------------------- diff --git a/lib/gs/contribs/othello/othello_board.erl b/lib/gs/contribs/othello/othello_board.erl index 0206ba2ded..6ccb79b7e4 100644 --- a/lib/gs/contribs/othello/othello_board.erl +++ b/lib/gs/contribs/othello/othello_board.erl @@ -147,7 +147,7 @@ but_pressed("Help",_ButtId,_User,GamePid,_Shell,_Wids,_Op) -> but_pressed("Newgame",_ButtId,_User,GamePid,_Shell,Wids,Options) -> new_game(GamePid,Wids,Options); but_pressed([],ButtId,User,GamePid,_Shell,_Wids,_Op) - when pid(GamePid),User == player -> + when is_pid(GamePid),User == player -> [C,R] = atom_to_list(ButtId), GamePid ! {self(),position,othello_adt:pos(C-96,translate(R-48))}, GamePid; @@ -243,7 +243,7 @@ game_msg(Msg,User,GamePid,Shell,Wids,Options) -> end. -new_game(GamePid,Wids,Options) when pid(GamePid) -> +new_game(GamePid,Wids,Options) when is_pid(GamePid) -> exit(GamePid,kill), new_game(Wids,Options); new_game(_,Wids,Options) -> diff --git a/lib/gs/examples/calc2.erl b/lib/gs/examples/calc2.erl index d28780de01..9969a6c40f 100644 --- a/lib/gs/examples/calc2.erl +++ b/lib/gs/examples/calc2.erl @@ -54,7 +54,7 @@ calc() -> calc_loop(Lbl,M,V,Op) -> receive - {gs,_,click,D,_} when integer(D) -> + {gs,_,click,D,_} when is_integer(D) -> digit_press(Lbl,M,V*10+D,Op); {gs,_,click,'C',_} -> c(Lbl,M,V,Op); diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl index 10d60a4c9a..827fa79ec5 100644 --- a/lib/hipe/cerl/erl_bif_types.erl +++ b/lib/hipe/cerl/erl_bif_types.erl @@ -1203,6 +1203,7 @@ type(erlang, process_flag, 2, Xs) -> case t_atom_vals(Flag) of ['error_handler'] -> t_atom(); ['min_heap_size'] -> t_non_neg_integer(); + ['scheduler'] -> t_non_neg_integer(); ['monitor_nodes'] -> t_boolean(); ['priority'] -> t_process_priority_level(); ['save_calls'] -> t_non_neg_integer(); @@ -1903,7 +1904,7 @@ type(prim_file, internal_native2name, 1, Xs) -> fun (_) -> t_prim_file_name() end); type(prim_file, internal_normalize_utf8, 1, Xs) -> strict(arg_types(prim_file, internal_normalize_utf8, 1), Xs, - fun (_) -> t_binary() end); + fun (_) -> t_unicode_string() end); %%-- gen_tcp ------------------------------------------------------------------ %% NOTE: All type information for this module added to avoid loss of precision type(gen_tcp, accept, 1, Xs) -> @@ -3747,6 +3748,7 @@ arg_types(erlang, process_display, 2) -> arg_types(erlang, process_flag, 2) -> [t_sup([t_atom('trap_exit'), t_atom('error_handler'), t_atom('min_heap_size'), t_atom('priority'), t_atom('save_calls'), + t_atom('scheduler'), % undocumented t_atom('monitor_nodes'), % undocumented t_tuple([t_atom('monitor_nodes'), t_list()])]), % undocumented t_sup([t_boolean(), t_atom(), t_non_neg_integer()])]; @@ -3785,7 +3787,7 @@ arg_types(erlang, send, 3) -> arg_types(erlang, send_after, 3) -> [t_non_neg_integer(), t_sup(t_pid(), t_atom()), t_any()]; arg_types(erlang, seq_trace, 2) -> - [t_atom(), t_sup([t_boolean(), t_tuple([t_fixnum(), t_fixnum()]), t_nil()])]; + [t_atom(), t_sup([t_boolean(), t_tuple([t_fixnum(), t_fixnum()]), t_fixnum(), t_nil()])]; arg_types(erlang, seq_trace_info, 1) -> [t_seq_trace_info()]; arg_types(erlang, seq_trace_print, 1) -> @@ -4034,7 +4036,7 @@ arg_types(ets, match_object, 3) -> arg_types(ets, match_spec_compile, 1) -> [t_matchspecs()]; arg_types(ets, match_spec_run_r, 3) -> - [t_matchspecs(), t_any(), t_list()]; + [t_list(t_tuple()),t_matchspecs(), t_list()]; arg_types(ets, member, 2) -> [t_tab(), t_any()]; arg_types(ets, new, 2) -> @@ -4066,8 +4068,12 @@ arg_types(ets, select_reverse, 3) -> arg_types(ets, slot, 2) -> [t_tab(), t_non_neg_fixnum()]; % 2nd arg can be 0 arg_types(ets, setopts, 2) -> - Opt = t_sup(t_tuple([t_atom('heir'), t_pid(), t_any()]), - t_tuple([t_atom('heir'), t_atom('none')])), + Opt = t_sup([t_tuple([t_atom('heir'), t_pid(), t_any()]), + t_tuple([t_atom('heir'), t_atom('none')]), + t_tuple([t_atom('protection'), + t_sup([t_atom('protected'), + t_atom('private'), + t_atom('public')])])]), [t_tab(), t_sup(Opt, t_list(Opt))]; arg_types(ets, update_counter, 3) -> Int = t_integer(), @@ -4859,6 +4865,9 @@ t_ets_info_items() -> t_atom('owner'), t_atom('protection'), t_atom('size'), + t_atom('compressed'), + t_atom('heir'), + t_atom('stats'), t_atom('type')]). %% ===================================================================== diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml index b36c28e027..fad5af85bb 100644 --- a/lib/kernel/doc/src/inet.xml +++ b/lib/kernel/doc/src/inet.xml @@ -555,8 +555,14 @@ fe80::204:acff:fe17:bf38 mode will return <c>{ok, HttpPacket}</c> from <c>gen_tcp:recv</c> while an active socket will send messages like <c>{http, Socket, HttpPacket}</c>.</p> - <p>Note that the packet type <c>httph</c> is not - needed when reading from a socket.</p> + </item> + <tag><c>httph | httph_bin</c></tag> + <item> + <p>These two types are often not needed as the socket will + automatically switch from <c>http</c>/<c>http_bin</c> to + <c>httph</c>/<c>httph_bin</c> internally after the first line + has been read. There might be occasions however when they are + useful, such as parsing trailers from chunked encoding.</p> </item> </taglist> </item> diff --git a/lib/mnesia/src/Makefile b/lib/mnesia/src/Makefile index e032f563fa..1c8ec54605 100644 --- a/lib/mnesia/src/Makefile +++ b/lib/mnesia/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2009. All Rights Reserved. +# Copyright Ericsson AB 1996-2011. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -113,6 +113,8 @@ clean: docs: +$(TARGET_FILES): $(HRL_FILES) + # ---------------------------------------------------- # Special Build Targets # ---------------------------------------------------- diff --git a/lib/mnesia/src/mnesia_controller.erl b/lib/mnesia/src/mnesia_controller.erl index d4b2c7b5cc..1d3bd55b48 100644 --- a/lib/mnesia/src/mnesia_controller.erl +++ b/lib/mnesia/src/mnesia_controller.erl @@ -57,7 +57,8 @@ release_schema_commit_lock/0, create_table/1, get_disc_copy/1, - get_cstructs/0, + get_remote_cstructs/0, % new function + get_cstructs/0, % old function sync_and_block_table_whereabouts/4, sync_del_table_copy_whereabouts/2, block_table/1, @@ -278,9 +279,51 @@ rec_tabs([], _, _, Init) -> unlink(Init), ok. -get_cstructs() -> +%% New function that does exactly what get_cstructs() used to do. +%% When this function is called, we know that the calling node knows +%% how to convert cstructs on the receiving end (should they differ). +get_remote_cstructs() -> call(get_cstructs). +%% Old function kept for backwards compatibility; converts cstructs before sending. +get_cstructs() -> + {cstructs, Cstructs, Running} = call(get_cstructs), + Node = node(group_leader()), + {cstructs, normalize_cstructs(Cstructs, Node), Running}. + +normalize_cstructs(Cstructs, Node) -> + %% backward-compatibility hack; normalize before returning + case rpc:call(Node, mnesia_lib, val, [{schema,cstruct}]) of + {badrpc, _} -> + %% assume it's not a schema merge + Cstructs; + #cstruct{} -> + %% same format + Cstructs; + Cstruct -> + %% some other format + RemoteFields = [F || {F,_} <- rpc:call(Node, mnesia_schema, cs2list, [Cstruct])], + [convert_cs(Cs, RemoteFields) || Cs <- Cstructs] + end. + +convert_cs(Cs, Fields) -> + MyFields = record_info(fields, cstruct), + convert(tl(tuple_to_list(Cs)), MyFields, Fields, []). + +convert([H|T], [F|FsL], [F|FsR], Acc) -> + convert(T, FsL, FsR, [H|Acc]); +convert([H|T], [Fl|FsL] = L, [Fr|FsR] = R, Acc) -> + case {lists:member(Fl, FsR), lists:member(Fr, FsL)} of + {true, false} -> + convert(T, L, FsR, [H|Acc]); + {false, true} -> + %% Field Fl doesn't exist on receiver side; skip. + convert(T, FsL, R, Acc) + end; +convert([], _, _, Acc) -> + list_to_tuple([cstruct|lists:reverse(Acc)]). + + update(Fun) -> call({update,Fun}). diff --git a/lib/mnesia/src/mnesia_dumper.erl b/lib/mnesia/src/mnesia_dumper.erl index 92fd9dfade..daa9e6aff2 100644 --- a/lib/mnesia/src/mnesia_dumper.erl +++ b/lib/mnesia/src/mnesia_dumper.erl @@ -214,7 +214,12 @@ insert_rec(Rec, InPlace, InitBy, LogV) when is_record(Rec, commit) -> {Tid, committed} -> do_insert_rec(Tid, Rec, InPlace, InitBy, LogV); {Tid, aborted} -> - mnesia_schema:undo_prepare_commit(Tid, Rec) + case InitBy of + startup -> + mnesia_schema:undo_prepare_commit(Tid, Rec); + _ -> + ok + end end; insert_rec(H, _InPlace, _InitBy, _LogV) when is_record(H, log_header) -> CurrentVersion = mnesia_log:version(), diff --git a/lib/mnesia/src/mnesia_loader.erl b/lib/mnesia/src/mnesia_loader.erl index e785b795d1..eb83168498 100644 --- a/lib/mnesia/src/mnesia_loader.erl +++ b/lib/mnesia/src/mnesia_loader.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2010. All Rights Reserved. +%% Copyright Ericsson AB 1998-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -27,7 +27,6 @@ net_load_table/4, send_table/3]). --export([old_node_init_table/6]). %% Spawned old node protocol conversion hack -export([spawned_receiver/8]). %% Spawned lock taking process -import(mnesia_lib, [set/2, fatal/2, verbose/2, dbg_out/2]). @@ -36,7 +35,7 @@ val(Var) -> case ?catch_val(Var) of - {'EXIT', Reason} -> mnesia_lib:other_val(Var, Reason); + {'EXIT', Reason} -> mnesia_lib:other_val(Var, Reason); Value -> Value end. @@ -51,7 +50,7 @@ disc_load_table(Tab, Reason) -> ?eval_debug_fun({?MODULE, do_get_disc_copy}, [{tab, Tab}, {reason, Reason}, - {storage, Storage}, + {storage, Storage}, {type, Type}]), do_get_disc_copy2(Tab, Reason, Storage, Type). @@ -63,19 +62,19 @@ do_get_disc_copy2(Tab, Reason, Storage, Type) when Storage == disc_copies -> %% NOW we create the actual table Repair = mnesia_monitor:get_env(auto_repair), Args = [{keypos, 2}, public, named_table, Type], - case Reason of + case Reason of {dumper, _} -> %% Resources allready allocated ignore; _ -> mnesia_monitor:mktab(Tab, Args), - Count = mnesia_log:dcd2ets(Tab, Repair), + Count = mnesia_log:dcd2ets(Tab, Repair), case ets:info(Tab, size) of X when X < Count * 4 -> - ok = mnesia_log:ets2dcd(Tab); + ok = mnesia_log:ets2dcd(Tab); _ -> ignore end - end, + end, mnesia_index:init_index(Tab, Storage), snmpify(Tab, Storage), set({Tab, load_node}, node()), @@ -84,7 +83,7 @@ do_get_disc_copy2(Tab, Reason, Storage, Type) when Storage == disc_copies -> do_get_disc_copy2(Tab, Reason, Storage, Type) when Storage == ram_copies -> Args = [{keypos, 2}, public, named_table, Type], - case Reason of + case Reason of {dumper, _} -> %% Resources allready allocated ignore; _ -> @@ -94,12 +93,12 @@ do_get_disc_copy2(Tab, Reason, Storage, Type) when Storage == ram_copies -> Repair = mnesia_monitor:get_env(auto_repair), case mnesia_monitor:use_dir() of true -> - case mnesia_lib:exists(Fname) of + case mnesia_lib:exists(Fname) of true -> mnesia_log:dcd2ets(Tab, Repair); false -> case mnesia_lib:exists(Datname) of true -> - mnesia_lib:dets_to_ets(Tab, Tab, Datname, + mnesia_lib:dets_to_ets(Tab, Tab, Datname, Type, Repair, no); false -> false @@ -154,11 +153,11 @@ do_get_disc_copy2(Tab, Reason, Storage, Type) when Storage == disc_only_copies - %% Disable rehashing of table %% Release read lock on table %% Send table to receiver in chunks -%% +%% %% Grab read lock on table %% Block dirty updates %% Update wherabouts -%% +%% %% Cancel the update subscription %% Process the subscription events %% Optionally dump to disc @@ -166,7 +165,7 @@ do_get_disc_copy2(Tab, Reason, Storage, Type) when Storage == disc_only_copies - %% Release read lock on table %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --define(MAX_TRANSFER_SIZE, 7500). +-define(MAX_TRANSFER_SIZE, 7500). -define(MAX_RAM_FILE_SIZE, 1000000). -define(MAX_RAM_TRANSFERS, (?MAX_RAM_FILE_SIZE div ?MAX_TRANSFER_SIZE) + 1). -define(MAX_NOPACKETS, 20). @@ -187,14 +186,14 @@ try_net_load_table(Tab, Reason, Ns, Cs) -> do_get_network_copy(Tab, _Reason, _Ns, unknown, _Cs) -> verbose("Local table copy of ~p has recently been deleted, ignored.~n", [Tab]), {not_loaded, storage_unknown}; -do_get_network_copy(Tab, Reason, Ns, Storage, Cs) -> +do_get_network_copy(Tab, Reason, Ns, Storage, Cs) -> [Node | Tail] = Ns, case lists:member(Node,val({current, db_nodes})) of true -> dbg_out("Getting table ~p (~p) from node ~p: ~p~n", [Tab, Storage, Node, Reason]), ?eval_debug_fun({?MODULE, do_get_network_copy}, - [{tab, Tab}, {reason, Reason}, + [{tab, Tab}, {reason, Reason}, {nodes, Ns}, {storage, Storage}]), case init_receiver(Node, Tab, Storage, Cs, Reason) of ok -> @@ -208,7 +207,7 @@ do_get_network_copy(Tab, Reason, Ns, Storage, Cs) -> restart -> try_net_load_table(Tab, Reason, Tail ++ [Node], Cs); down -> - try_net_load_table(Tab, Reason, Tail, Cs) + try_net_load_table(Tab, Reason, Tail, Cs) end; false -> try_net_load_table(Tab, Reason, Tail, Cs) @@ -223,10 +222,10 @@ do_snmpify(Tab, Us, Storage) -> Snmp = mnesia_snmp_hook:create_table(Us, Tab, Storage), set({Tab, {index, snmp}}, Snmp). -%% Start the recieiver +%% Start the recieiver init_receiver(Node, Tab, Storage, Cs, Reas={dumper,add_table_copy}) -> case start_remote_sender(Node, Tab, Storage) of - {SenderPid, TabSize, DetsData} -> + {SenderPid, TabSize, DetsData} -> start_receiver(Tab,Storage,Cs,SenderPid,TabSize,DetsData,Reas); Else -> Else @@ -234,21 +233,21 @@ init_receiver(Node, Tab, Storage, Cs, Reas={dumper,add_table_copy}) -> init_receiver(Node, Tab,Storage,Cs,Reason) -> %% Grab a schema lock to avoid deadlock between table_loader and schema_commit dumping. %% Both may grab tables-locks in different order. - Load = - fun() -> - {_,Tid,Ts} = get(mnesia_activity_state), + Load = + fun() -> + {_,Tid,Ts} = get(mnesia_activity_state), mnesia_locker:rlock(Tid, Ts#tidstore.store, {schema, Tab}), - %% Check that table still exists + %% Check that table still exists Active = val({Tab, active_replicas}), %% Check that we havn't loaded it already case val({Tab,where_to_read}) == node() of true -> ok; _ -> - %% And that sender still got a copy - %% (something might have happend while + %% And that sender still got a copy + %% (something might have happend while %% we where waiting for the lock) true = lists:member(Node, Active), - {SenderPid, TabSize, DetsData} = + {SenderPid, TabSize, DetsData} = start_remote_sender(Node,Tab,Storage), Init = table_init_fun(SenderPid), Args = [self(),Tab,Storage,Cs,SenderPid, @@ -258,18 +257,18 @@ init_receiver(Node, Tab,Storage,Cs,Reason) -> wait_on_load_complete(Pid) end end, - Res = + Res = case mnesia:transaction(Load, 20) of - {atomic, {error,Result}} when - element(1,Reason) == dumper -> + {atomic, {error,Result}} when + element(1,Reason) == dumper -> {error,Result}; - {atomic, {error,Result}} -> + {atomic, {error,Result}} -> fatal("Cannot create table ~p: ~p~n", [[Tab, Storage], Result]); {atomic, Result} -> Result; {aborted, nomore} -> restart; - {aborted, _Reas} -> - verbose("Receiver failed on ~p from ~p:~nReason: ~p~n", + {aborted, _Reas} -> + verbose("Receiver failed on ~p from ~p:~nReason: ~p~n", [Tab,Node,_Reas]), down %% either this node or sender is dying end, @@ -279,7 +278,7 @@ init_receiver(Node, Tab,Storage,Cs,Reason) -> start_remote_sender(Node,Tab,Storage) -> mnesia_controller:start_remote_sender(Node, Tab, self(), Storage), put(mnesia_table_sender_node, {Tab, Node}), - receive + receive {SenderPid, {first, TabSize}} -> {SenderPid, TabSize, false}; {SenderPid, {first, TabSize, DetsData}} -> @@ -291,22 +290,14 @@ start_remote_sender(Node,Tab,Storage) -> end. table_init_fun(SenderPid) -> - PConv = mnesia_monitor:needs_protocol_conversion(node(SenderPid)), - MeMyselfAndI = self(), fun(read) -> - Receiver = - if - PConv == true -> - MeMyselfAndI ! {actual_tabrec, self()}, - MeMyselfAndI; %% Old mnesia - PConv == false -> self() - end, + Receiver = self(), SenderPid ! {Receiver, more}, get_data(SenderPid, Receiver) end. %% Add_table_copy get's it's own locks. -start_receiver(Tab,Storage,Cs,SenderPid,TabSize,DetsData,{dumper,add_table_copy}) -> +start_receiver(Tab,Storage,Cs,SenderPid,TabSize,DetsData,{dumper,add_table_copy}) -> Init = table_init_fun(SenderPid), case do_init_table(Tab,Storage,Cs,SenderPid,TabSize,DetsData,self(), Init) of Err = {error, _} -> @@ -317,8 +308,8 @@ start_receiver(Tab,Storage,Cs,SenderPid,TabSize,DetsData,{dumper,add_table_copy} end. spawned_receiver(ReplyTo,Tab,Storage,Cs, SenderPid,TabSize,DetsData, Init) -> - process_flag(trap_exit, true), - Done = do_init_table(Tab,Storage,Cs, + process_flag(trap_exit, true), + Done = do_init_table(Tab,Storage,Cs, SenderPid,TabSize,DetsData, ReplyTo, Init), ReplyTo ! {self(),Done}, @@ -327,17 +318,17 @@ spawned_receiver(ReplyTo,Tab,Storage,Cs, SenderPid,TabSize,DetsData, Init) -> exit(normal). wait_on_load_complete(Pid) -> - receive - {Pid, Res} -> + receive + {Pid, Res} -> Res; - {'EXIT', Pid, Reason} -> + {'EXIT', Pid, Reason} -> exit(Reason); - Else -> + Else -> Pid ! Else, wait_on_load_complete(Pid) end. -do_init_table(Tab,Storage,Cs,SenderPid, +do_init_table(Tab,Storage,Cs,SenderPid, TabSize,DetsInfo,OrigTabRec,Init) -> case create_table(Tab, TabSize, Storage, Cs) of {Storage,Tab} -> @@ -345,11 +336,9 @@ do_init_table(Tab,Storage,Cs,SenderPid, Node = node(SenderPid), put(mnesia_table_receiver, {Tab, Node, SenderPid}), mnesia_tm:block_tab(Tab), - PConv = mnesia_monitor:needs_protocol_conversion(Node), - - case init_table(Tab,Storage,Init,PConv,DetsInfo,SenderPid) of - ok -> - tab_receiver(Node,Tab,Storage,Cs,PConv,OrigTabRec); + case init_table(Tab,Storage,Init,DetsInfo,SenderPid) of + ok -> + tab_receiver(Node,Tab,Storage,Cs,OrigTabRec); Reason -> Msg = "[d]ets:init table failed", verbose("~s: ~p: ~p~n", [Msg, Tab, Reason]), @@ -360,7 +349,7 @@ do_init_table(Tab,Storage,Cs,SenderPid, end. create_table(Tab, TabSize, Storage, Cs) -> - if + if Storage == disc_only_copies -> mnesia_lib:lock_table(Tab), Tmp = mnesia_lib:tab2tmp(Tab), @@ -390,54 +379,30 @@ create_table(Tab, TabSize, Storage, Cs) -> end end. -tab_receiver(Node, Tab, Storage, Cs, PConv, OrigTabRec) -> +tab_receiver(Node, Tab, Storage, Cs, OrigTabRec) -> receive - {SenderPid, {no_more, DatBin}} when PConv == false -> + {SenderPid, {no_more, DatBin}} -> finish_copy(Storage,Tab,Cs,SenderPid,DatBin,OrigTabRec); - - %% Protocol conversion hack - {SenderPid, {no_more, DatBin}} when is_pid(PConv) -> - PConv ! {SenderPid, no_more}, - receive - {old_init_table_complete, ok} -> - finish_copy(Storage, Tab, Cs, SenderPid, DatBin,OrigTabRec); - {old_init_table_complete, Reason} -> - Msg = "OLD: [d]ets:init table failed", - verbose("~s: ~p: ~p~n", [Msg, Tab, Reason]), - down(Tab, Storage) - end; - - {actual_tabrec, Pid} -> - tab_receiver(Node, Tab, Storage, Cs, Pid,OrigTabRec); - - {SenderPid, {more, [Recs]}} when is_pid(PConv) -> - PConv ! {SenderPid, {more, Recs}}, %% Forward Msg to OldNodes - tab_receiver(Node, Tab, Storage, Cs, PConv,OrigTabRec); - {'EXIT', PConv, Reason} -> %% [d]ets:init process crashed - Msg = "Receiver crashed", - verbose("~s: ~p: ~p~n", [Msg, Tab, Reason]), - down(Tab, Storage); - %% Protocol conversion hack {copier_done, Node} -> verbose("Sender of table ~p crashed on node ~p ~n", [Tab, Node]), down(Tab, Storage); - + {'EXIT', Pid, Reason} -> handle_exit(Pid, Reason), - tab_receiver(Node, Tab, Storage, Cs, PConv,OrigTabRec) + tab_receiver(Node, Tab, Storage, Cs, OrigTabRec) end. make_table_fun(Pid, TabRec) -> fun(close) -> ok; (read) -> - get_data(Pid, TabRec) + get_data(Pid, TabRec) end. get_data(Pid, TabRec) -> - receive + receive {Pid, {more_z, CompressedRecs}} when is_binary(CompressedRecs) -> Pid ! {TabRec, more}, {zlib_uncompress(CompressedRecs), make_table_fun(Pid,TabRec)}; @@ -448,7 +413,7 @@ get_data(Pid, TabRec) -> end_of_input; {copier_done, Node} -> case node(Pid) of - Node -> + Node -> {copier_done, Node}; _ -> get_data(Pid, TabRec) @@ -458,10 +423,10 @@ get_data(Pid, TabRec) -> get_data(Pid, TabRec) end. -init_table(Tab, disc_only_copies, Fun, false, DetsInfo,Sender) -> +init_table(Tab, disc_only_copies, Fun, DetsInfo,Sender) -> ErtsVer = erlang:system_info(version), case DetsInfo of - {ErtsVer, DetsData} -> + {ErtsVer, DetsData} -> Res = (catch dets:is_compatible_bchunk_format(Tab, DetsData)), case Res of {'EXIT',{undef,[{dets,_,_}|_]}} -> @@ -481,28 +446,19 @@ init_table(Tab, disc_only_copies, Fun, false, DetsInfo,Sender) -> _ -> dets:init_table(Tab, Fun) end; -init_table(Tab, _, Fun, false, _DetsInfo,_) -> +init_table(Tab, _, Fun, _DetsInfo,_) -> case catch ets:init_table(Tab, Fun) of true -> ok; {'EXIT', Else} -> Else - end; -init_table(Tab, Storage, Fun, true, _DetsInfo, Sender) -> %% Old Nodes - spawn_link(?MODULE, old_node_init_table, - [Tab, Storage, Fun, self(), false, Sender]), - ok. + end. -old_node_init_table(Tab, Storage, Fun, TabReceiver, DetsInfo,Sender) -> - Res = init_table(Tab, Storage, Fun, false, DetsInfo,Sender), - TabReceiver ! {old_init_table_complete, Res}, - unlink(TabReceiver), - ok. finish_copy(Storage,Tab,Cs,SenderPid,DatBin,OrigTabRec) -> TabRef = {Storage, Tab}, subscr_receiver(TabRef, Cs#cstruct.record_name), case handle_last(TabRef, Cs#cstruct.type, DatBin) of - ok -> + ok -> mnesia_index:init_index(Tab, Storage), snmpify(Tab, Storage), %% OrigTabRec must not be the spawned tab-receiver @@ -534,7 +490,7 @@ subscr_receiver(TabRef = {_, Tab}, RecName) -> ok end. -handle_event(TabRef, write, Rec) -> +handle_event(TabRef, write, Rec) -> db_put(TabRef, Rec); handle_event(TabRef, delete, {_Tab, Key}) -> db_erase(TabRef, Key); @@ -545,8 +501,8 @@ handle_event(TabRef, clear_table, {_Tab, _Key}) -> handle_last({disc_copies, Tab}, _Type, nobin) -> Ret = mnesia_log:ets2dcd(Tab), - Fname = mnesia_lib:tab2dat(Tab), - case mnesia_lib:exists(Fname) of + Fname = mnesia_lib:tab2dat(Tab), + case mnesia_lib:exists(Fname) of true -> %% Remove old .DAT files. file:delete(Fname); false -> @@ -653,31 +609,29 @@ send_table(Pid, Tab, RemoteS) -> {error, {no_exists, Tab}}; Storage -> %% Send first - TabSize = mnesia:table_info(Tab, size), - Pconvert = mnesia_monitor:needs_protocol_conversion(node(Pid)), + TabSize = mnesia:table_info(Tab, size), KeysPerTransfer = calc_nokeys(Storage, Tab), ChunkData = dets:info(Tab, bchunk_format), - UseDetsChunk = - Storage == RemoteS andalso - Storage == disc_only_copies andalso - ChunkData /= undefined andalso - Pconvert == false, - if + UseDetsChunk = + Storage == RemoteS andalso + Storage == disc_only_copies andalso + ChunkData /= undefined, + if UseDetsChunk == true -> DetsInfo = erlang:system_info(version), Pid ! {self(), {first, TabSize, {DetsInfo, ChunkData}}}; true -> Pid ! {self(), {first, TabSize}} end, - + %% Debug info put(mnesia_table_sender, {Tab, node(Pid), Pid}), {Init, Chunk} = reader_funcs(UseDetsChunk, Tab, Storage, KeysPerTransfer), - + SendIt = fun() -> prepare_copy(Pid, Tab, Storage), - send_more(Pid, 1, Chunk, Init(), Tab, Pconvert), + send_more(Pid, 1, Chunk, Init(), Tab), finish_copy(Pid, Tab, Storage, RemoteS) end, @@ -698,7 +652,7 @@ send_table(Pid, Tab, RemoteS) -> {error, Reason} end end. - + prepare_copy(Pid, Tab, Storage) -> Trans = fun() -> @@ -717,11 +671,11 @@ prepare_copy(Pid, Tab, Storage) -> update_where_to_write(Tab, Node) -> case val({Tab, access_mode}) of - read_only -> + read_only -> ignore; - read_write -> + read_write -> Current = val({current, db_nodes}), - Ns = + Ns = case lists:member(Node, Current) of true -> Current; false -> [Node | Current] @@ -729,27 +683,27 @@ update_where_to_write(Tab, Node) -> update_where_to_write(Ns, Tab, Node) end. -update_where_to_write([], _, _) -> +update_where_to_write([], _, _) -> ok; update_where_to_write([H|T], Tab, AddNode) -> - rpc:call(H, mnesia_controller, call, + rpc:call(H, mnesia_controller, call, [{update_where_to_write, [add, Tab, AddNode], self()}]), update_where_to_write(T, Tab, AddNode). -send_more(Pid, N, Chunk, DataState, Tab, OldNode) -> +send_more(Pid, N, Chunk, DataState, Tab) -> receive {NewPid, more} -> - case send_packet(N - 1, NewPid, Chunk, DataState, OldNode) of - New when is_integer(New) -> + case send_packet(N - 1, NewPid, Chunk, DataState) of + New when is_integer(New) -> New - 1; NewData -> - send_more(NewPid, ?MAX_NOPACKETS, Chunk, NewData, Tab, OldNode) + send_more(NewPid, ?MAX_NOPACKETS, Chunk, NewData, Tab) end; {_NewPid, {old_protocol, Tab}} -> Storage = val({Tab, storage_type}), - {Init, NewChunk} = + {Init, NewChunk} = reader_funcs(false, Tab, Storage, calc_nokeys(Storage, Tab)), - send_more(Pid, 1, NewChunk, Init(), Tab, OldNode); + send_more(Pid, 1, NewChunk, Init(), Tab); {copier_done, Node} when Node == node(Pid)-> verbose("Receiver of table ~p crashed on ~p (more)~n", [Tab, Node]), @@ -770,7 +724,7 @@ dets_bchunk(Tab, Chunk) -> %% Arrg case dets:bchunk(Tab, Chunk) of {Cont, Data} -> {Data, Cont}; Else -> Else - end. + end. zlib_compress(Data, Level) -> BinData = term_to_binary(Data), @@ -793,28 +747,20 @@ compression_level() -> Val -> Val end. -send_packet(N, Pid, _Chunk, '$end_of_table', OldNode) -> - case OldNode of - true -> ignore; %% Old nodes can't handle the new no_more - false -> Pid ! {self(), no_more} - end, +send_packet(N, Pid, _Chunk, '$end_of_table') -> + Pid ! {self(), no_more}, N; -send_packet(N, Pid, Chunk, {[], Cont}, OldNode) -> - send_packet(N, Pid, Chunk, Chunk(Cont), OldNode); -send_packet(N, Pid, Chunk, {Recs, Cont}, OldNode) when N < ?MAX_NOPACKETS -> - case OldNode of - true -> - Pid ! {self(), {more, [Recs]}}; %% Old need's wrapping list - false -> - case compression_level() of - 0 -> - Pid ! {self(), {more, Recs}}; - Level -> - Pid ! {self(), {more_z, zlib_compress(Recs, Level)}} - end +send_packet(N, Pid, Chunk, {[], Cont}) -> + send_packet(N, Pid, Chunk, Chunk(Cont)); +send_packet(N, Pid, Chunk, {Recs, Cont}) when N < ?MAX_NOPACKETS -> + case compression_level() of + 0 -> + Pid ! {self(), {more, Recs}}; + Level -> + Pid ! {self(), {more_z, zlib_compress(Recs, Level)}} end, - send_packet(N+1, Pid, Chunk, Chunk(Cont), OldNode); -send_packet(_N, _Pid, _Chunk, DataState, _OldNode) -> + send_packet(N+1, Pid, Chunk, Chunk(Cont)); +send_packet(_N, _Pid, _Chunk, DataState) -> DataState. finish_copy(Pid, Tab, Storage, RemoteS) -> @@ -855,5 +801,5 @@ dat2bin(_Tab, _LocalS, _RemoteS) -> handle_exit(Pid, Reason) when node(Pid) == node() -> exit(Reason); -handle_exit(_Pid, _Reason) -> %% Not from our node, this will be handled by +handle_exit(_Pid, _Reason) -> %% Not from our node, this will be handled by ignore. %% mnesia_down soon. diff --git a/lib/mnesia/src/mnesia_monitor.erl b/lib/mnesia/src/mnesia_monitor.erl index b6eda9ad3a..e110ad3241 100644 --- a/lib/mnesia/src/mnesia_monitor.erl +++ b/lib/mnesia/src/mnesia_monitor.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -76,13 +76,13 @@ -include("mnesia.hrl"). --record(state, {supervisor, pending_negotiators = [], +-record(state, {supervisor, pending_negotiators = [], going_down = [], tm_started = false, early_connects = [], connecting, mq = []}). --define(current_protocol_version, {7,6}). +-define(current_protocol_version, {8,0}). --define(previous_protocol_version, {7,5}). +-define(previous_protocol_version, {7,6}). start() -> gen_server:start_link({local, ?MODULE}, ?MODULE, @@ -151,12 +151,12 @@ check_protocol([{Node, {accept, Mon, Version, Protocol}} | Tail], Protocols) -> case lists:member(Protocol, Protocols) of true -> case Protocol == protocol_version() of - true -> + true -> set({protocol, Node}, {Protocol, false}); false -> set({protocol, Node}, {Protocol, true}) end, - [node(Mon) | check_protocol(Tail, Protocols)]; + [node(Mon) | check_protocol(Tail, Protocols)]; false -> verbose("Failed to connect with ~p. ~p protocols rejected. " "expected version = ~p, expected protocol = ~p~n", @@ -179,7 +179,7 @@ check_protocol([], [Protocol | _Protocols]) -> set(protocol_version, Protocol), []. -protocol_version() -> +protocol_version() -> case ?catch_val(protocol_version) of {'EXIT', _} -> ?current_protocol_version; Version -> Version @@ -189,14 +189,14 @@ protocol_version() -> %% preferred protocols are first in the list acceptable_protocol_versions() -> [protocol_version(), ?previous_protocol_version]. - + needs_protocol_conversion(Node) -> case {?catch_val({protocol, Node}), protocol_version()} of {{'EXIT', _}, _} -> false; - {{_, Bool}, ?current_protocol_version} -> + {{_, Bool}, ?current_protocol_version} -> Bool; - {{_, Bool}, _} -> + {{_, Bool}, _} -> not Bool end. @@ -255,15 +255,15 @@ terminate_proc(Who, Reason, _State) -> %%---------------------------------------------------------------------- init([Parent]) -> process_flag(trap_exit, true), - ?ets_new_table(mnesia_gvar, [set, public, named_table]), - ?ets_new_table(mnesia_stats, [set, public, named_table]), + ?ets_new_table(mnesia_gvar, [set, public, named_table]), + ?ets_new_table(mnesia_stats, [set, public, named_table]), set(subscribers, []), set(activity_subscribers, []), mnesia_lib:verbose("~p starting: ~p~n", [?MODULE, self()]), Version = mnesia:system_info(version), set(version, Version), dbg_out("Version: ~p~n", [Version]), - + case catch process_config_args(env()) of ok -> mnesia_lib:set({'$$$_report', current_pos}, 0), @@ -283,7 +283,7 @@ init([Parent]) -> set(checkpoints, []), set(pending_checkpoints, []), set(pending_checkpoint_pids, []), - + {ok, #state{supervisor = Parent}}; {'EXIT', Reason} -> mnesia_lib:report_fatal("Bad configuration: ~p~n", [Reason]), @@ -398,9 +398,9 @@ handle_call({unsafe_close_log, Name}, _From, State) -> disk_log:close(Name), {reply, ok, State}; -handle_call({negotiate_protocol, Mon, _Version, _Protocols}, _From, State) +handle_call({negotiate_protocol, Mon, _Version, _Protocols}, _From, State) when State#state.tm_started == false -> - State2 = State#state{early_connects = [node(Mon) | State#state.early_connects]}, + State2 = State#state{early_connects = [node(Mon) | State#state.early_connects]}, {reply, {node(), {reject, self(), uninitialized, uninitialized}}, State2}; %% From remote monitor.. @@ -412,7 +412,7 @@ handle_call({negotiate_protocol, Mon, Version, Protocols}, From, State) true -> accept_protocol(Mon, MyVersion, Protocol, From, State); false -> - %% in this release we should be able to handle the previous + %% in this release we should be able to handle the previous %% protocol case hd(Protocols) of ?previous_protocol_version -> @@ -427,7 +427,7 @@ handle_call({negotiate_protocol, Mon, Version, Protocols}, From, State) end; %% Local request to negotiate with other monitors (nodes). -handle_call({negotiate_protocol, Nodes}, From, State) -> +handle_call({negotiate_protocol, Nodes}, From, State) -> case mnesia_lib:intersect(State#state.going_down, Nodes) of [] -> spawn_link(?MODULE, negotiate_protocol_impl, [Nodes, From]), @@ -461,7 +461,7 @@ accept_protocol(Mon, Version, Protocol, From, State) -> %% No need for wait link(Mon), %% link to remote Monitor case Protocol == protocol_version() of - true -> + true -> set({protocol, Node}, {Protocol, false}); false -> set({protocol, Node}, {Protocol, true}) @@ -509,7 +509,7 @@ handle_cast({disconnect, Node}, State) -> ignore; undefined -> ignore; - RemoteMon when is_pid(RemoteMon) -> + RemoteMon when is_pid(RemoteMon) -> unlink(RemoteMon) end, {noreply, State}; @@ -534,7 +534,7 @@ handle_info({'EXIT', Pid, R}, State) when Pid == State#state.supervisor -> dbg_out("~p was ~p by supervisor~n",[?MODULE, R]), {stop, R, State}; -handle_info({'EXIT', Pid, fatal}, State) when node(Pid) == node() -> +handle_info({'EXIT', Pid, fatal}, State) when node(Pid) == node() -> dbg_out("~p got FATAL ERROR from: ~p~n",[?MODULE, Pid]), exit(State#state.supervisor, shutdown), {noreply, State}; @@ -550,7 +550,7 @@ handle_info(Msg = {'EXIT',Pid,_}, State) -> Node /= node() -> {noreply, State#state{mq = State#state.mq ++ [{info, Msg}]}}; true -> - %% We have probably got an exit signal from + %% We have probably got an exit signal from %% disk_log or dets Hint = "Hint: check that the disk still is writable", fatal("~p got unexpected info: ~p; ~p~n", @@ -567,10 +567,10 @@ handle_info({nodeup, Node}, State) -> %% Let's check if Mnesia is running there in order %% to detect if the network has been partitioned %% due to communication failure. - + HasDown = mnesia_recover:has_mnesia_down(Node), ImRunning = mnesia_lib:is_running(), - + if %% If I'm not running the test will be made later. HasDown == true, ImRunning == yes -> @@ -589,7 +589,7 @@ handle_info({disk_log, _Node, Log, Info}, State) -> {truncated, _No} -> ok; _ -> - mnesia_lib:important("Warning Log file ~p error reason ~s~n", + mnesia_lib:important("Warning Log file ~p error reason ~s~n", [Log, disk_log:format_error(Info)]) end, {noreply, State}; @@ -681,38 +681,38 @@ env() -> send_compressed ]. -default_env(access_module) -> +default_env(access_module) -> mnesia; -default_env(auto_repair) -> +default_env(auto_repair) -> true; -default_env(backup_module) -> +default_env(backup_module) -> mnesia_backup; -default_env(debug) -> +default_env(debug) -> none; default_env(dir) -> Name = lists:concat(["Mnesia.", node()]), filename:absname(Name); -default_env(dump_log_load_regulation) -> +default_env(dump_log_load_regulation) -> false; -default_env(dump_log_time_threshold) -> +default_env(dump_log_time_threshold) -> timer:minutes(3); -default_env(dump_log_update_in_place) -> +default_env(dump_log_update_in_place) -> true; default_env(dump_log_write_threshold) -> 1000; -default_env(embedded_mnemosyne) -> +default_env(embedded_mnemosyne) -> false; -default_env(event_module) -> +default_env(event_module) -> mnesia_event; -default_env(extra_db_nodes) -> +default_env(extra_db_nodes) -> []; -default_env(ignore_fallback_at_startup) -> +default_env(ignore_fallback_at_startup) -> false; default_env(fallback_error_function) -> {mnesia, lkill}; -default_env(max_wait_for_decision) -> +default_env(max_wait_for_decision) -> infinity; -default_env(schema_location) -> +default_env(schema_location) -> opt_disc; default_env(core_dir) -> false; @@ -732,7 +732,7 @@ check_type(Env, Val) -> NewVal -> NewVal end. - + do_check_type(access_module, A) when is_atom(A) -> A; do_check_type(auto_repair, B) -> bool(B); do_check_type(backup_module, B) when is_atom(B) -> B; @@ -749,7 +749,7 @@ do_check_type(dump_log_update_in_place, B) -> bool(B); do_check_type(dump_log_write_threshold, I) when is_integer(I), I > 0 -> I; do_check_type(event_module, A) when is_atom(A) -> A; do_check_type(ignore_fallback_at_startup, B) -> bool(B); -do_check_type(fallback_error_function, {Mod, Func}) +do_check_type(fallback_error_function, {Mod, Func}) when is_atom(Mod), is_atom(Func) -> {Mod, Func}; do_check_type(embedded_mnemosyne, B) -> bool(B); do_check_type(extra_db_nodes, L) when is_list(L) -> @@ -804,8 +804,8 @@ detect_inconcistency(Nodes, Context) -> has_remote_mnesia_down(Node) -> HasDown = mnesia_recover:has_mnesia_down(Node), Master = mnesia_recover:get_master_nodes(schema), - if - HasDown == true, Master == [] -> + if + HasDown == true, Master == [] -> {true, node()}; true -> {false, node()} diff --git a/lib/mnesia/src/mnesia_schema.erl b/lib/mnesia/src/mnesia_schema.erl index fef72ad39c..05be474aea 100644 --- a/lib/mnesia/src/mnesia_schema.erl +++ b/lib/mnesia/src/mnesia_schema.erl @@ -100,7 +100,7 @@ ]). %% Needed outside to be able to use/set table_properties -%% from user (not supported) +%% from user (not supported) -export([schema_transaction/1, insert_schema_ops/2, do_create_table/1, @@ -118,9 +118,9 @@ %% Here comes the init function which also resides in %% this module, it is called upon by the trans server %% at startup of the system -%% +%% %% We have a meta table which looks like -%% {table, schema, +%% {table, schema, %% {type, set}, %% {disc_copies, all}, %% {arity, 2} @@ -149,14 +149,14 @@ exit_on_error(GoodRes) -> val(Var) -> case ?catch_val(Var) of - {'EXIT', Reason} -> mnesia_lib:other_val(Var, Reason); - Value -> Value + {'EXIT', Reason} -> mnesia_lib:other_val(Var, Reason); + Value -> Value end. %% This function traverses all cstructs in the schema and %% sets all values in mnesia_gvar accordingly for each table/cstruct -set_schema('$end_of_table') -> +set_schema('$end_of_table') -> []; set_schema(Tab) -> do_set_schema(Tab), @@ -253,8 +253,8 @@ version() -> incr_version(Cs) -> {{Major, Minor}, _} = Cs#cstruct.version, Nodes = mnesia_lib:intersect(val({schema, disc_copies}), - mnesia_lib:cs_to_nodes(Cs)), - V = + mnesia_lib:cs_to_nodes(Cs)), + V = case Nodes -- val({Cs#cstruct.name, active_replicas}) of [] -> {Major + 1, 0}; % All replicas are active _ -> {Major, Minor + 1} % Some replicas are inactive @@ -359,7 +359,7 @@ delete_schema2() -> {error, Reason} -> {error, Reason} end. - + ensure_no_schema([H|T]) when is_atom(H) -> case rpc:call(H, ?MODULE, remote_read_schema, []) of {badrpc, Reason} -> @@ -407,7 +407,7 @@ opt_create_dir(UseDir, Dir) when UseDir == true-> check_can_write(Dir); false -> case file:make_dir(Dir) of - ok -> + ok -> verbose("Create Directory ~p~n", [Dir]), ok; {error, Reason} -> @@ -417,7 +417,7 @@ opt_create_dir(UseDir, Dir) when UseDir == true-> end; opt_create_dir(false, _) -> {error, {has_no_disc, node()}}. - + check_can_write(Dir) -> case file:read_file_info(Dir) of {ok, FI} when FI#file_info.type == directory, @@ -450,7 +450,7 @@ read_schema(Keep) -> read_schema(Keep, IgnoreFallback) -> lock_schema(), - Res = + Res = case mnesia:system_info(is_running) of yes -> {ok, ram, get_create_list(schema)}; @@ -477,7 +477,7 @@ read_disc_schema(Keep, IgnoreFallback) -> case mnesia_bup:fallback_exists() of true when IgnoreFallback == false, Running /= yes -> mnesia_bup:fallback_to_schema(); - _ -> + _ -> %% If we're running, we read the schema file even %% if fallback exists Dat = mnesia_lib:tab2dat(schema), @@ -499,7 +499,7 @@ read_disc_schema(Keep, IgnoreFallback) -> end. do_read_disc_schema(Fname, Keep) -> - T = + T = case Keep of false -> Args = [{keypos, 2}, public, set], @@ -523,7 +523,7 @@ do_read_disc_schema(Fname, Keep) -> get_initial_schema(SchemaStorage, Nodes) -> Cs = #cstruct{name = schema, record_name = schema, - attributes = [table, cstruct]}, + attributes = [table, cstruct]}, Cs2 = case SchemaStorage of ram_copies -> Cs#cstruct{ram_copies = Nodes}; @@ -532,7 +532,7 @@ get_initial_schema(SchemaStorage, Nodes) -> cs2list(Cs2). read_cstructs_from_disc() -> - %% Assumptions: + %% Assumptions: %% - local schema lock in global %% - use_dir is true %% - Mnesia is not running @@ -552,14 +552,14 @@ read_cstructs_from_disc() -> end, Cstructs = dets:traverse(Tab, Fun), dets:close(Tab), - {ok, Cstructs}; + {ok, Cstructs}; {error, Reason} -> {error, Reason} end; false -> {error, "No schema file exists"} end. - + %% We run a very special type of transactions when we %% we want to manipulate the schema. @@ -593,20 +593,20 @@ schema_transaction(Fun) -> %% This process may dump the transaction log, and should %% therefore not be run in an application process -%% +%% schema_coordinator(Client, _Fun, undefined) -> Res = {aborted, {node_not_running, node()}}, Client ! {transaction_done, Res, self()}, unlink(Client); - + schema_coordinator(Client, Fun, Controller) when is_pid(Controller) -> %% Do not trap exit in order to automatically die %% when the controller dies link(Controller), unlink(Client), - - %% Fulfull the transaction even if the client dies + + %% Fulfull the transaction even if the client dies Res = mnesia:transaction(Fun), Client ! {transaction_done, Res, self()}, unlink(Controller), % Avoids spurious exit message @@ -619,7 +619,7 @@ schema_coordinator(Client, Fun, Controller) when is_pid(Controller) -> insert_schema_ops({_Mod, _Tid, Ts}, SchemaIOps) -> do_insert_schema_ops(Ts#tidstore.store, SchemaIOps). - + do_insert_schema_ops(Store, [Head | Tail]) -> ?ets_insert(Store, Head), do_insert_schema_ops(Store, Tail); @@ -628,15 +628,56 @@ do_insert_schema_ops(_Store, []) -> cs2list(Cs) when is_record(Cs, cstruct) -> Tags = record_info(fields, cstruct), - rec2list(Tags, 2, Cs); + rec2list(Tags, Tags, 2, Cs); cs2list(CreateList) when is_list(CreateList) -> - CreateList. - -rec2list([Tag | Tags], Pos, Rec) -> + CreateList; +%% 4.4.19 +cs2list(Cs) when element(1, Cs) == cstruct, tuple_size(Cs) == 18 -> + Tags = [name,type,ram_copies,disc_copies,disc_only_copies, + load_order,access_mode,majority,index,snmp,local_content, + record_name,attributes,user_properties,frag_properties, + cookie,version], + rec2list(Tags, Tags, 2, Cs); +%% 4.4.18 and earlier +cs2list(Cs) when element(1, Cs) == cstruct, tuple_size(Cs) == 17 -> + Tags = [name,type,ram_copies,disc_copies,disc_only_copies, + load_order,access_mode,index,snmp,local_content, + record_name,attributes,user_properties,frag_properties, + cookie,version], + rec2list(Tags, Tags, 2, Cs). + +cs2list(false, Cs) -> + cs2list(Cs); +cs2list(ver4_4_18, Cs) -> + Orig = record_info(fields, cstruct), + Tags = [name,type,ram_copies,disc_copies,disc_only_copies, + load_order,access_mode,index,snmp,local_content, + record_name,attributes,user_properties,frag_properties, + cookie,version], + rec2list(Tags, Orig, 2, Cs); +cs2list(ver4_4_19, Cs) -> + Orig = record_info(fields, cstruct), + Tags = [name,type,ram_copies,disc_copies,disc_only_copies, + load_order,access_mode,majority,index,snmp,local_content, + record_name,attributes,user_properties,frag_properties, + cookie,version], + rec2list(Tags, Orig, 2, Cs). + +rec2list([Tag | Tags], [Tag | Orig], Pos, Rec) -> Val = element(Pos, Rec), - [{Tag, Val} | rec2list(Tags, Pos + 1, Rec)]; -rec2list([], _Pos, _Rec) -> - []. + [{Tag, Val} | rec2list(Tags, Orig, Pos + 1, Rec)]; +rec2list([], _, _Pos, _Rec) -> + []; +rec2list(Tags, [_|Orig], Pos, Rec) -> + rec2list(Tags, Orig, Pos+1, Rec). + +api_list2cs(List) when is_list(List) -> + Name = pick(unknown, name, List, must), + Keys = check_keys(Name, List, record_info(fields, cstruct)), + check_duplicates(Name, Keys), + list2cs(List); +api_list2cs(Other) -> + mnesia:abort({badarg, Other}). list2cs(List) when is_list(List) -> Name = pick(unknown, name, List, must), @@ -667,10 +708,7 @@ list2cs(List) when is_list(List) -> Frag = pick(Name, frag_properties, List, []), verify({alt, [nil, list]}, mnesia_lib:etype(Frag), - {badarg, Name, {frag_properties, Frag}}), - - Keys = check_keys(Name, List, record_info(fields, cstruct)), - check_duplicates(Name, Keys), + {badarg, Name, {frag_properties, Frag}}), #cstruct{name = Name, ram_copies = Rc, disc_copies = Dc, @@ -687,9 +725,7 @@ list2cs(List) when is_list(List) -> user_properties = lists:sort(UserProps), frag_properties = lists:sort(Frag), cookie = Cookie, - version = Version}; -list2cs(Other) -> - mnesia:abort({badarg, Other}). + version = Version}. pick(Tab, Key, List, Default) -> case lists:keysearch(Key, 1, List) of @@ -708,7 +744,7 @@ attr_tab_to_pos(_Tab, Pos) when is_integer(Pos) -> Pos; attr_tab_to_pos(Tab, Attr) -> attr_to_pos(Attr, val({Tab, attributes})). - + %% Convert attribute name to integer if neccessary attr_to_pos(Pos, _Attrs) when is_integer(Pos) -> Pos; @@ -723,7 +759,7 @@ attr_to_pos(Attr, [_ | Attrs], Pos) -> attr_to_pos(Attr, Attrs, Pos + 1); attr_to_pos(Attr, _, _) -> mnesia:abort({bad_type, Attr}). - + check_keys(Tab, [{Key, _Val} | Tail], Items) -> case lists:member(Key, Items) of true -> [Key | check_keys(Tab, Tail, Items)]; @@ -759,7 +795,7 @@ verify_cstruct(Cs) when is_record(Cs, cstruct) -> {bad_type, Tab, {type, Type}}), %% Currently ordered_set is not supported for disk_only_copies. - if + if Type == ordered_set, Cs#cstruct.disc_only_copies /= [] -> mnesia:abort({bad_type, Tab, {not_supported, Type, disc_only_copies}}); true -> @@ -776,10 +812,10 @@ verify_cstruct(Cs) when is_record(Cs, cstruct) -> Arity = length(Attrs) + 1, verify(true, Arity > 2, {bad_type, Tab, {attributes, Attrs}}), - + lists:foldl(fun(Attr,_Other) when Attr == snmp -> mnesia:abort({bad_type, Tab, {attributes, [Attr]}}); - (Attr,Other) -> + (Attr,Other) -> verify(atom, mnesia_lib:etype(Attr), {bad_type, Tab, {attributes, [Attr]}}), verify(false, lists:member(Attr, Other), @@ -792,7 +828,7 @@ verify_cstruct(Cs) when is_record(Cs, cstruct) -> Index = Cs#cstruct.index, verify({alt, [nil, list]}, mnesia_lib:etype(Index), {bad_type, Tab, {index, Index}}), - + IxFun = fun(Pos) -> verify(true, fun() -> @@ -807,7 +843,7 @@ verify_cstruct(Cs) when is_record(Cs, cstruct) -> {bad_type, Tab, {index, [Pos]}}) end, lists:foreach(IxFun, Index), - + LC = Cs#cstruct.local_content, verify({alt, [true, false]}, LC, {bad_type, Tab, {local_content, LC}}), @@ -834,7 +870,7 @@ verify_cstruct(Cs) when is_record(Cs, cstruct) -> lists:foreach(CheckProp, Cs#cstruct.user_properties), case Cs#cstruct.cookie of - {{MegaSecs, Secs, MicroSecs}, _Node} + {{MegaSecs, Secs, MicroSecs}, _Node} when is_integer(MegaSecs), is_integer(Secs), is_integer(MicroSecs), is_atom(node) -> ok; @@ -870,15 +906,15 @@ verify_nodes(Cs) -> end, verify(integer, mnesia_lib:etype(LoadOrder), {bad_type, Tab, {load_order, LoadOrder}}), - + Nodes = Ram ++ Disc ++ DiscOnly, verify(list, mnesia_lib:etype(Nodes), {combine_error, Tab, [{ram_copies, []}, {disc_copies, []}, {disc_only_copies, []}]}), verify(false, has_duplicates(Nodes), {combine_error, Tab, Nodes}), - AtomCheck = fun(N) -> verify(atom, mnesia_lib:etype(N), {bad_type, Tab, N}) end, + AtomCheck = fun(N) -> verify(atom, mnesia_lib:etype(N), {bad_type, Tab, N}) end, lists:foreach(AtomCheck, Nodes). - + verify(Expected, Fun, Error) when is_function(Fun) -> do_verify(Expected, catch Fun(), Error); verify(Expected, Actual, Error) -> @@ -909,7 +945,7 @@ ensure_active(Cs, What) -> W = {Tab, What}, ensure_non_empty(W), Nodes = mnesia_lib:intersect(val({schema, disc_copies}), - mnesia_lib:cs_to_nodes(Cs)), + mnesia_lib:cs_to_nodes(Cs)), case Nodes -- val(W) of [] -> ok; @@ -936,7 +972,7 @@ ensure_non_empty({Tab, Vhat}) -> ensure_not_active(Tab = schema, Node) -> Active = val({Tab, active_replicas}), - case lists:member(Node, Active) of + case lists:member(Node, Active) of false when Active =/= [] -> ok; false -> @@ -970,7 +1006,7 @@ create_table(TabDef) -> do_multi_create_table(TabDef) -> get_tid_ts_and_lock(schema, write), ensure_writable(schema), - Cs = list2cs(TabDef), + Cs = api_list2cs(TabDef), case Cs#cstruct.frag_properties of [] -> do_create_table(Cs); @@ -999,7 +1035,7 @@ unsafe_make_create_table(Cs) -> {_Mod, Tid, Ts} = get_tid_ts_and_lock(schema, none), verify_cstruct(Cs), Tab = Cs#cstruct.name, - + %% Check that we have all disc replica nodes running DiscNodes = Cs#cstruct.disc_copies ++ Cs#cstruct.disc_only_copies, RunningNodes = val({current, db_nodes}), @@ -1017,7 +1053,7 @@ unsafe_make_create_table(Cs) -> check_if_exists(Tab) -> TidTs = get_tid_ts_and_lock(schema, write), {_, _, Ts} = TidTs, - Store = Ts#tidstore.store, + Store = Ts#tidstore.store, ets:foldl( fun({op, create_table, [{name, T}|_]}, _Acc) when T==Tab -> true; @@ -1054,7 +1090,7 @@ make_delete_table(Tab, Mode) -> %% nodes etc. TidTs = get_tid_ts_and_lock(schema, write), {_, _, Ts} = TidTs, - Store = Ts#tidstore.store, + Store = Ts#tidstore.store, Deleted = ets:select_delete( Store, [{{op,'$1',[{name,Tab}|'_']}, [{'or', @@ -1077,9 +1113,9 @@ make_delete_table(Tab, Mode) -> [] -> [make_delete_table2(Tab)]; _Props -> - %% Check if it is a base table - mnesia_frag:lookup_frag_hash(Tab), - + %% Check if it is a base table + mnesia_frag:lookup_frag_hash(Tab), + %% Check for foreigners F = mnesia_frag:lookup_foreigners(Tab), verify([], F, {combine_error, @@ -1101,7 +1137,7 @@ make_delete_table2(Tab) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Change fragmentation of a table - + change_table_frag(Tab, Change) -> schema_transaction(fun() -> do_change_table_frag(Tab, Change) end). @@ -1112,7 +1148,7 @@ do_change_table_frag(Tab, Change) when is_atom(Tab), Tab /= schema -> ok; do_change_table_frag(Tab, _Change) -> mnesia:abort({bad_type, Tab}). - + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Clear a table @@ -1150,7 +1186,7 @@ make_add_table_copy(Tab, Node, Storage) -> verify(false, lists:member(Node, Ns), {already_exists, Tab, Node}), Cs2 = new_cs(Cs, Node, Storage, add), verify_cstruct(Cs2), - + %% Check storage and if node is running IsRunning = lists:member(Node, val({current, db_nodes})), if @@ -1177,21 +1213,21 @@ del_table_copy(Tab, Node) -> do_del_table_copy(Tab, Node) when is_atom(Node) -> TidTs = get_tid_ts_and_lock(schema, write), -%% get_tid_ts_and_lock(Tab, write), +%% get_tid_ts_and_lock(Tab, write), insert_schema_ops(TidTs, make_del_table_copy(Tab, Node)); do_del_table_copy(Tab, Node) -> mnesia:abort({badarg, Tab, Node}). - + make_del_table_copy(Tab, Node) -> ensure_writable(schema), Cs = incr_version(val({Tab, cstruct})), Storage = mnesia_lib:schema_cs_to_storage_type(Node, Cs), - Cs2 = new_cs(Cs, Node, Storage, del), + Cs2 = new_cs(Cs, Node, Storage, del), case mnesia_lib:cs_to_nodes(Cs2) of [] when Tab == schema -> mnesia:abort({combine_error, Tab, "Last replica"}); [] -> - ensure_active(Cs), + ensure_active(Cs), dbg_out("Last replica deleted in table ~p~n", [Tab]), make_delete_table(Tab, whole_table); _ when Tab == schema -> @@ -1210,14 +1246,14 @@ remove_node_from_tabs([], _Node) -> []; remove_node_from_tabs([schema|Rest], Node) -> remove_node_from_tabs(Rest, Node); -remove_node_from_tabs([Tab|Rest], Node) -> - {Cs, IsFragModified} = +remove_node_from_tabs([Tab|Rest], Node) -> + {Cs, IsFragModified} = mnesia_frag:remove_node(Node, incr_version(val({Tab, cstruct}))), case mnesia_lib:schema_cs_to_storage_type(Node, Cs) of unknown -> case IsFragModified of true -> - [{op, change_table_frag, {del_node, Node}, cs2list(Cs)} | + [{op, change_table_frag, {del_node, Node}, cs2list(Cs)} | remove_node_from_tabs(Rest, Node)]; false -> remove_node_from_tabs(Rest, Node) @@ -1246,7 +1282,7 @@ new_cs(Cs, Node, ram_copies, del) -> new_cs(Cs, Node, disc_copies, del) -> Cs#cstruct{disc_copies = lists:delete(Node , Cs#cstruct.disc_copies)}; new_cs(Cs, Node, disc_only_copies, del) -> - Cs#cstruct{disc_only_copies = + Cs#cstruct{disc_only_copies = lists:delete(Node , Cs#cstruct.disc_only_copies)}; new_cs(Cs, _Node, Storage, _Op) -> mnesia:abort({badarg, Cs#cstruct.name, Storage}). @@ -1278,7 +1314,7 @@ make_move_table(Tab, FromNode, ToNode) -> Running = val({current, db_nodes}), Storage = mnesia_lib:schema_cs_to_storage_type(FromNode, Cs), verify(true, lists:member(ToNode, Running), {not_active, schema, ToNode}), - + Cs2 = new_cs(Cs, ToNode, Storage, add), Cs3 = new_cs(Cs2, FromNode, Storage, del), verify_cstruct(Cs3), @@ -1306,7 +1342,7 @@ make_change_table_copy_type(Tab, Node, unknown) -> make_change_table_copy_type(Tab, Node, ToS) -> ensure_writable(schema), Cs = incr_version(val({Tab, cstruct})), - FromS = mnesia_lib:storage_type_at_node(Node, Tab), + FromS = mnesia_lib:storage_type_at_node(Node, Tab), case compare_storage_type(false, FromS, ToS) of {same, _} -> @@ -1320,12 +1356,12 @@ make_change_table_copy_type(Tab, Node, ToS) -> Cs2 = new_cs(Cs, Node, FromS, del), Cs3 = new_cs(Cs2, Node, ToS, add), verify_cstruct(Cs3), - + [{op, change_table_copy_type, Node, FromS, ToS, cs2list(Cs3)}]. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% change index functions .... -%% Pos is allready added by 1 in both of these functions +%% Pos is allready added by 1 in both of these functions add_table_index(Tab, Pos) -> schema_transaction(fun() -> do_add_table_index(Tab, Pos) end). @@ -1412,14 +1448,14 @@ make_del_snmp(Tab) -> [{op, del_snmp, cs2list(Cs2)}]. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% +%% -transform_table(Tab, Fun, NewAttrs, NewRecName) - when is_function(Fun), is_list(NewAttrs), is_atom(NewRecName) -> +transform_table(Tab, Fun, NewAttrs, NewRecName) + when is_function(Fun), is_list(NewAttrs), is_atom(NewRecName) -> schema_transaction(fun() -> do_transform_table(Tab, Fun, NewAttrs, NewRecName) end); -transform_table(Tab, ignore, NewAttrs, NewRecName) - when is_list(NewAttrs), is_atom(NewRecName) -> +transform_table(Tab, ignore, NewAttrs, NewRecName) + when is_list(NewAttrs), is_atom(NewRecName) -> schema_transaction(fun() -> do_transform_table(Tab, ignore, NewAttrs, NewRecName) end); transform_table(Tab, Fun, NewAttrs, NewRecName) -> @@ -1438,7 +1474,7 @@ make_transform(Tab, Fun, NewAttrs, NewRecName) -> ensure_active(Cs), ensure_writable(Tab), case mnesia_lib:val({Tab, index}) of - [] -> + [] -> Cs2 = Cs#cstruct{attributes = NewAttrs, record_name = NewRecName}, verify_cstruct(Cs2), [{op, transform, Fun, cs2list(Cs2)}]; @@ -1464,7 +1500,7 @@ make_transform(Tab, Fun, NewAttrs, NewRecName) -> end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% +%% change_table_access_mode(Tab, Mode) -> schema_transaction(fun() -> do_change_table_access_mode(Tab, Mode) end). @@ -1598,9 +1634,9 @@ change_prop_in_existing_op(Tab, Prop, How, Store) -> false -> false end. - -update_existing_op([{op, Op, L = [{name,Tab}|_], _OldProp}|Ops], - Tab, Prop, How, Acc) when Op == write_property; + +update_existing_op([{op, Op, L = [{name,Tab}|_], _OldProp}|Ops], + Tab, Prop, How, Acc) when Op == write_property; Op == delete_property -> %% Apparently, mnesia_dumper doesn't care about OldProp here -- just L, %% so we will throw away OldProp (not that it matters...) and insert Prop. @@ -1625,7 +1661,7 @@ update_existing_op([], _, _, _, _) -> do_read_table_property(Tab, Key) -> TidTs = get_tid_ts_and_lock(schema, read), {_, _, Ts} = TidTs, - Store = Ts#tidstore.store, + Store = Ts#tidstore.store, Props = ets:foldl( fun({op, create_table, [{name, T}|Opts]}, _Acc) when T==Tab -> @@ -1689,7 +1725,7 @@ do_delete_table_property(Tab, PropKey) -> [Tab,PropKey]), %% this must be an existing table get_tid_ts_and_lock(Tab, none), - insert_schema_ops(TidTs, + insert_schema_ops(TidTs, make_delete_table_properties(Tab, [PropKey])) end. @@ -1711,17 +1747,17 @@ make_delete_table_properties(_Tab, [], _Cs) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Ensure that the transaction can be committed even +%% Ensure that the transaction can be committed even %% if the node crashes and Mnesia is restarted prepare_commit(Tid, Commit, WaitFor) -> case Commit#commit.schema_ops of [] -> {false, Commit, optional}; OrigOps -> - {Modified, Ops, DumperMode} = + {Modified, Ops, DumperMode} = prepare_ops(Tid, OrigOps, WaitFor, false, [], optional), InitBy = schema_prepare, - GoodRes = {Modified, + GoodRes = {Modified, Commit#commit{schema_ops = lists:reverse(Ops)}, DumperMode}, case DumperMode of @@ -1737,7 +1773,7 @@ prepare_commit(Tid, Commit, WaitFor) -> end end, case Ops of - [] -> + [] -> ignore; _ -> %% We need to grab a dumper lock here, the log may not @@ -1749,20 +1785,20 @@ prepare_commit(Tid, Commit, WaitFor) -> prepare_ops(Tid, [Op | Ops], WaitFor, Changed, Acc, DumperMode) -> case prepare_op(Tid, Op, WaitFor) of - {true, mandatory} -> + {true, mandatory} -> prepare_ops(Tid, Ops, WaitFor, Changed, [Op | Acc], mandatory); - {true, optional} -> + {true, optional} -> prepare_ops(Tid, Ops, WaitFor, Changed, [Op | Acc], DumperMode); - {true, Ops2, mandatory} -> + {true, Ops2, mandatory} -> prepare_ops(Tid, Ops, WaitFor, true, Ops2 ++ Acc, mandatory); - {true, Ops2, optional} -> + {true, Ops2, optional} -> prepare_ops(Tid, Ops, WaitFor, true, Ops2 ++ Acc, DumperMode); - {false, optional} -> + {false, optional} -> prepare_ops(Tid, Ops, WaitFor, true, Acc, DumperMode) end; prepare_ops(_Tid, [], _WaitFor, Changed, Acc, DumperMode) -> {Changed, Acc, DumperMode}. - + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Prepare for commit %% returns true if Op should be included, i.e. unmodified @@ -1781,8 +1817,8 @@ prepare_op(_Tid, {op, rec, unknown, Rec}, _WaitFor) -> prepare_op(_Tid, {op, announce_im_running, Node, SchemaDef, Running, RemoteRunning}, _WaitFor) -> SchemaCs = list2cs(SchemaDef), - if - Node == node() -> %% Announce has already run on local node + if + Node == node() -> %% Announce has already run on local node ignore; %% from do_merge_schema true -> %% If a node has restarted it may still linger in db_nodes, @@ -1794,9 +1830,9 @@ prepare_op(_Tid, {op, announce_im_running, Node, SchemaDef, Running, RemoteRunni end, {false, optional}; -prepare_op(_Tid, {op, sync_trans}, {part, CoordPid}) -> +prepare_op(_Tid, {op, sync_trans}, {part, CoordPid}) -> CoordPid ! {sync_trans, self()}, - receive + receive {sync_trans, CoordPid} -> {false, optional}; {mnesia_down, _Node} = Else -> @@ -1807,7 +1843,7 @@ prepare_op(_Tid, {op, sync_trans}, {part, CoordPid}) -> mnesia:abort(Else) end; -prepare_op(_Tid, {op, sync_trans}, {coord, Nodes}) -> +prepare_op(_Tid, {op, sync_trans}, {coord, Nodes}) -> case receive_sync(Nodes, []) of {abort, Reason} -> mnesia_lib:verbose("sync_op terminated due to ~p~n", [Reason]), @@ -1838,7 +1874,7 @@ prepare_op(Tid, {op, create_table, TabDef}, _WaitFor) -> create_ram_table(Tab, Cs#cstruct.type), create_disc_table(Tab), insert_cstruct(Tid, Cs, false), - {true, optional}; + {true, optional}; disc_only_copies -> mnesia_lib:set({Tab, create_table},true), create_disc_only_table(Tab,Cs#cstruct.type), @@ -1857,15 +1893,15 @@ prepare_op(Tid, {op, add_table_copy, Storage, Node, TabDef}, _WaitFor) -> if Tab == schema -> {true, optional}; - + Node == node() -> - case mnesia_lib:val({schema, storage_type}) of - ram_copies when Storage /= ram_copies -> + case mnesia_lib:val({schema, storage_type}) of + ram_copies when Storage /= ram_copies -> Error = {combine_error, Tab, "has no disc", Node}, mnesia:abort(Error); _ -> ok - end, + end, %% Tables are created by mnesia_loader get_network code insert_cstruct(Tid, Cs, true), case mnesia_controller:get_network_copy(Tab, Cs) of @@ -1902,22 +1938,22 @@ prepare_op(Tid, {op, add_table_copy, Storage, Node, TabDef}, _WaitFor) -> prepare_op(Tid, {op, del_table_copy, _Storage, Node, TabDef}, _WaitFor) -> Cs = list2cs(TabDef), Tab = Cs#cstruct.name, - + if %% Schema table lock is always required to run a schema op. %% No need to look it. - node(Tid#tid.pid) == node(), Tab /= schema -> + node(Tid#tid.pid) == node(), Tab /= schema -> Self = self(), Pid = spawn_link(fun() -> lock_del_table(Tab, Node, Cs, Self) end), put(mnesia_lock, Pid), - receive - {Pid, updated} -> + receive + {Pid, updated} -> {true, optional}; {Pid, FailReason} -> mnesia:abort(FailReason); {'EXIT', Pid, Reason} -> mnesia:abort(Reason) - end; + end; true -> {true, optional} end; @@ -1928,12 +1964,12 @@ prepare_op(_Tid, {op, change_table_copy_type, N, FromS, ToS, TabDef}, _WaitFor) Tab = Cs#cstruct.name, NotActive = mnesia_lib:not_active_here(Tab), - - if + + if NotActive == true -> mnesia:abort({not_active, Tab, node()}); - - Tab == schema -> + + Tab == schema -> case {FromS, ToS} of {ram_copies, disc_copies} -> case mnesia:system_info(schema_location) of @@ -1943,7 +1979,7 @@ prepare_op(_Tid, {op, change_table_copy_type, N, FromS, ToS, TabDef}, _WaitFor) mnesia:abort({combine_error, Tab, node(), "schema_location must be opt_disc"}) end, - Dir = mnesia_lib:dir(), + Dir = mnesia_lib:dir(), case opt_create_dir(true, Dir) of ok -> purge_dir(Dir, []), @@ -1967,18 +2003,18 @@ prepare_op(_Tid, {op, change_table_copy_type, N, FromS, ToS, TabDef}, _WaitFor) _ -> mnesia:abort({combine_error, Tab, ToS}) end; - - FromS == ram_copies -> + + FromS == ram_copies -> case mnesia_monitor:use_dir() of - true -> + true -> Dat = mnesia_lib:tab2dcd(Tab), case mnesia_lib:exists(Dat) of true -> mnesia:abort({combine_error, Tab, node(), "Table dump exists"}); false -> - case ToS of - disc_copies -> + case ToS of + disc_copies -> mnesia_log:ets2dcd(Tab, dmp); disc_only_copies -> mnesia_dumper:raw_named_dump_table(Tab, dmp) @@ -1988,7 +2024,7 @@ prepare_op(_Tid, {op, change_table_copy_type, N, FromS, ToS, TabDef}, _WaitFor) false -> mnesia:abort({has_no_disc, node()}) end; - + FromS == disc_copies, ToS == disc_only_copies -> mnesia_dumper:raw_named_dump_table(Tab, dmp); FromS == disc_only_copies -> @@ -2020,7 +2056,7 @@ prepare_op(_Tid, {op, dump_table, unknown, TabDef}, _WaitFor) -> case lists:member(node(), Cs#cstruct.ram_copies) of true -> case mnesia_monitor:use_dir() of - true -> + true -> mnesia_log:ets2dcd(Tab, dmp), Size = mnesia:table_info(Tab, size), {true, [{op, dump_table, Size, TabDef}], optional}; @@ -2058,7 +2094,7 @@ prepare_op(_Tid, {op, transform, Fun, TabDef}, _WaitFor) -> mnesia_lib:db_fixtable(Storage, Tab, true), Key = mnesia_lib:db_first(Tab), Op = {op, transform, Fun, TabDef}, - case catch transform_objs(Fun, Tab, RecName, + case catch transform_objs(Fun, Tab, RecName, Key, NewArity, Storage, Type, [Op]) of {'EXIT', Reason} -> mnesia_lib:db_fixtable(Storage, Tab, false), @@ -2072,7 +2108,7 @@ prepare_op(_Tid, {op, transform, Fun, TabDef}, _WaitFor) -> prepare_op(_Tid, {op, merge_schema, TabDef}, _WaitFor) -> Cs = list2cs(TabDef), case verify_merge(Cs) of - ok -> + ok -> {true, optional}; Error -> verbose("Merge_Schema ~p failed on ~p: ~p~n", [_Tid,node(),Error]), @@ -2093,7 +2129,7 @@ create_ram_table(Tab, Type) -> create_disc_table(Tab) -> File = mnesia_lib:tab2dcd(Tab), file:delete(File), - FArg = [{file, File}, {name, {mnesia,create}}, + FArg = [{file, File}, {name, {mnesia,create}}, {repair, false}, {mode, read_write}], case mnesia_monitor:open_log(FArg) of {ok,Log} -> @@ -2124,7 +2160,7 @@ receive_sync([], Pids) -> receive_sync(Nodes, Pids) -> receive {sync_trans, Pid} -> - Node = node(Pid), + Node = node(Pid), receive_sync(lists:delete(Node, Nodes), [Pid | Pids]); Else -> {abort, Else} @@ -2140,16 +2176,16 @@ lock_del_table(Tab, Node, Cs, Father) -> false; ({badrpc, {'EXIT', {undef, _}}}) -> %% This will be the case we talks with elder nodes - %% than 3.8.2, they will set where_to_read without - %% getting a lock. + %% than 3.8.2, they will set where_to_read without + %% getting a lock. false; (_) -> true end, case lists:filter(Filter, Res) of - [] -> + [] -> Father ! {self(), updated}, - %% When transaction is commited the process dies + %% When transaction is commited the process dies %% and the lock is released. receive _ -> ok end; Err -> @@ -2166,7 +2202,7 @@ lock_del_table(Tab, Node, Cs, Father) -> exit(normal). set_where_to_read(Tab, Node, Cs) -> - case mnesia_lib:val({Tab, where_to_read}) of + case mnesia_lib:val({Tab, where_to_read}) of Node -> case Cs#cstruct.local_content of true -> @@ -2185,16 +2221,16 @@ transform_objs(_Fun, _Tab, _RT, '$end_of_table', _NewArity, _Storage, _Type, Acc transform_objs(Fun, Tab, RecName, Key, A, Storage, Type, Acc) -> Objs = mnesia_lib:db_get(Tab, Key), NextKey = mnesia_lib:db_next_key(Tab, Key), - Oid = {Tab, Key}, + Oid = {Tab, Key}, NewObjs = {Ws, Ds} = transform_obj(Tab, RecName, Key, Fun, Objs, A, Type, [], []), - if - NewObjs == {[], []} -> + if + NewObjs == {[], []} -> transform_objs(Fun, Tab, RecName, NextKey, A, Storage, Type, Acc); - Type == bag -> + Type == bag -> transform_objs(Fun, Tab, RecName, NextKey, A, Storage, Type, [{op, rec, Storage, {Oid, Ws, write}}, {op, rec, Storage, {Oid, [Oid], delete}} | Acc]); - Ds == [] -> + Ds == [] -> %% Type is set or ordered_set, no need to delete the record first transform_objs(Fun, Tab, RecName, NextKey, A, Storage, Type, [{op, rec, Storage, {Oid, Ws, write}} | Acc]); @@ -2215,15 +2251,15 @@ transform_obj(Tab, RecName, Key, Fun, [Obj|Rest], NewArity, Type, Ws, Ds) -> NewObj == Obj -> transform_obj(Tab, RecName, Key, Fun, Rest, NewArity, Type, Ws, Ds); RecName == element(1, NewObj), Key == element(2, NewObj) -> - transform_obj(Tab, RecName, Key, Fun, Rest, NewArity, + transform_obj(Tab, RecName, Key, Fun, Rest, NewArity, Type, [NewObj | Ws], Ds); - NewObj == delete -> - case Type of + NewObj == delete -> + case Type of bag -> %% Just don't write that object - transform_obj(Tab, RecName, Key, Fun, Rest, - NewArity, Type, Ws, Ds); + transform_obj(Tab, RecName, Key, Fun, Rest, + NewArity, Type, Ws, Ds); _ -> - transform_obj(Tab, RecName, Key, Fun, Rest, NewArity, + transform_obj(Tab, RecName, Key, Fun, Rest, NewArity, Type, Ws, [NewObj | Ds]) end; true -> @@ -2247,7 +2283,7 @@ undo_prepare_commit(Tid, Commit) -> %% Undo in reverse order undo_prepare_ops(Tid, [Op | Ops]) -> - case element(1, Op) of + case element(1, Op) of TheOp when TheOp /= op, TheOp /= restore_op -> undo_prepare_ops(Tid, Ops); _ -> @@ -2274,7 +2310,7 @@ undo_prepare_op(Tid, {op, create_table, TabDef}) -> mnesia_lib:unset({Tab, create_table}), delete_cstruct(Tid, Cs), case mnesia_lib:cs_to_storage_type(node(), Cs) of - unknown -> + unknown -> ok; ram_copies -> ram_delete_table(Tab, ram_copies); @@ -2289,7 +2325,7 @@ undo_prepare_op(Tid, {op, create_table, TabDef}) -> %% disc_delete_table(Tab, Storage), file:delete(Dat) end; - + undo_prepare_op(Tid, {op, add_table_copy, Storage, Node, TabDef}) -> Cs = list2cs(TabDef), Tab = Cs#cstruct.name, @@ -2314,21 +2350,21 @@ undo_prepare_op(Tid, {op, add_table_copy, Storage, Node, TabDef}) -> Cs2 = new_cs(Cs, Node, Storage, del), insert_cstruct(Tid, Cs2, true) % Don't care about the version end; - -undo_prepare_op(_Tid, {op, del_table_copy, _, Node, TabDef}) + +undo_prepare_op(_Tid, {op, del_table_copy, _, Node, TabDef}) when Node == node() -> Cs = list2cs(TabDef), Tab = Cs#cstruct.name, mnesia_lib:set({Tab, where_to_read}, Node); -undo_prepare_op(_Tid, {op, change_table_copy_type, N, FromS, ToS, TabDef}) +undo_prepare_op(_Tid, {op, change_table_copy_type, N, FromS, ToS, TabDef}) when N == node() -> Cs = list2cs(TabDef), Tab = Cs#cstruct.name, mnesia_checkpoint:tm_change_table_copy_type(Tab, ToS, FromS), Dmp = mnesia_lib:tab2dmp(Tab), - + case {FromS, ToS} of {ram_copies, disc_copies} when Tab == schema -> file:delete(Dmp), @@ -2382,9 +2418,9 @@ ram_delete_table(Tab, Storage) -> ignore; disc_only_copies -> ignore; - _Else -> + _Else -> %% delete possible index files and data ..... - %% Got to catch this since if no info has been set in the + %% Got to catch this since if no info has been set in the %% mnesia_gvar it will crash catch mnesia_index:del_transient(Tab, Storage), case ?catch_val({Tab, {index, snmp}}) of @@ -2454,7 +2490,7 @@ has_known_suffix(File, [Suffix | Tail], false) -> has_known_suffix(File, Tail, lists:suffix(Suffix, File)); has_known_suffix(_File, [], Bool) -> Bool. - + known_suffixes() -> real_suffixes() ++ tmp_suffixes(). real_suffixes() -> [".DAT", ".LOG", ".BUP", ".DCL", ".DCD"]. @@ -2477,11 +2513,11 @@ info2(Tab, [{frag_hash, _V} | Tail]) -> % Ignore frag_hash info2(Tab, [{P, V} | Tail]) -> io:format("~-20w -> ~p~n",[P,V]), info2(Tab, Tail); -info2(_, []) -> +info2(_, []) -> io:format("~n", []). get_table_properties(Tab) -> - case catch mnesia_lib:db_match_object(ram_copies, + case catch mnesia_lib:db_match_object(ram_copies, mnesia_gvar, {{Tab, '_'}, '_'}) of {'EXIT', _} -> mnesia:abort({no_exists, Tab, all}); @@ -2509,9 +2545,9 @@ get_table_properties(Tab) -> recs = error_recs }). -restore(Opaque) -> +restore(Opaque) -> restore(Opaque, [], mnesia_monitor:get_env(backup_module)). -restore(Opaque, Args) when is_list(Args) -> +restore(Opaque, Args) when is_list(Args) -> restore(Opaque, Args, mnesia_monitor:get_env(backup_module)); restore(_Opaque, BadArg) -> {aborted, {badarg, BadArg}}. @@ -2522,7 +2558,7 @@ restore(Opaque, Args, Module) when is_list(Args), is_atom(Module) -> case mnesia_bup:read_schema(R#r.module, Opaque) of {error, Reason} -> {aborted, Reason}; - BupSchema -> + BupSchema -> schema_transaction(fun() -> do_restore(R, BupSchema) end) end; {'EXIT', Reason} -> @@ -2556,8 +2592,8 @@ check_restore_arg({keep_tables, List}, R) when is_list(List) -> check_restore_arg({skip_tables, List}, R) when is_list(List) -> TableList = [{Tab, skip_tables} || Tab <- List], R#r{table_options = R#r.table_options ++ TableList}; -check_restore_arg({default_op, Op}, R) -> - case Op of +check_restore_arg({default_op, Op}, R) -> + case Op of clear_tables -> ok; recreate_tables -> ok; keep_tables -> ok; @@ -2588,12 +2624,12 @@ restore_items([Rec | Recs], Header, Schema, R) -> case lists:keysearch(Tab, 1, R#r.tables) of {value, {Tab, Where0, Snmp, RecName}} -> Where = case Where0 of - undefined -> + undefined -> val({Tab, where_to_commit}); _ -> Where0 end, - {Rest, NRecs} = restore_tab_items([Rec | Recs], Tab, + {Rest, NRecs} = restore_tab_items([Rec | Recs], Tab, RecName, Where, Snmp, R#r.recs, R#r.insert_op), restore_items(Rest, Header, Schema, R#r{recs = NRecs}); @@ -2601,12 +2637,12 @@ restore_items([Rec | Recs], Header, Schema, R) -> Rest = skip_tab_items(Recs, Tab), restore_items(Rest, Header, Schema, R) end; - + restore_items([], _Header, _Schema, R) -> R. restore_func(Tab, R) -> - case lists:keysearch(Tab, 1, R#r.table_options) of + case lists:keysearch(Tab, 1, R#r.table_options) of {value, {Tab, OP}} -> OP; false -> @@ -2618,24 +2654,24 @@ where_to_commit(Tab, CsList) -> Disc = [{N, disc_copies} || N <- pick(Tab, disc_copies, CsList, [])], DiscO = [{N, disc_only_copies} || N <- pick(Tab, disc_only_copies, CsList, [])], Ram ++ Disc ++ DiscO. - + %% Changes of the Meta info of schema itself is not allowed restore_schema([{schema, schema, _List} | Schema], R) -> restore_schema(Schema, R); restore_schema([{schema, Tab, List} | Schema], R) -> case restore_func(Tab, R) of - clear_tables -> + clear_tables -> do_clear_table(Tab), - Snmp = val({Tab, snmp}), - RecName = val({Tab, record_name}), + Snmp = val({Tab, snmp}), + RecName = val({Tab, record_name}), R2 = R#r{tables = [{Tab, undefined, Snmp, RecName} | R#r.tables]}, restore_schema(Schema, R2); - recreate_tables -> + recreate_tables -> case ?catch_val({Tab, cstruct}) of - {'EXIT', _} -> + {'EXIT', _} -> TidTs = {_Mod, Tid, Ts} = get(mnesia_activity_state), RunningNodes = val({current, db_nodes}), - Nodes = mnesia_lib:intersect(mnesia_lib:cs_to_nodes(list2cs(List)), + Nodes = mnesia_lib:intersect(mnesia_lib:cs_to_nodes(list2cs(List)), RunningNodes), mnesia_locker:wlock_no_exist(Tid, Ts#tidstore.store, Tab, Nodes), TidTs; @@ -2643,20 +2679,20 @@ restore_schema([{schema, Tab, List} | Schema], R) -> TidTs = get_tid_ts_and_lock(Tab, write) end, NC = {cookie, ?unique_cookie}, - List2 = lists:keyreplace(cookie, 1, List, NC), + List2 = lists:keyreplace(cookie, 1, List, NC), Where = where_to_commit(Tab, List2), Snmp = pick(Tab, snmp, List2, []), RecName = pick(Tab, record_name, List2, Tab), insert_schema_ops(TidTs, [{op, restore_recreate, List2}]), R2 = R#r{tables = [{Tab, Where, Snmp, RecName} | R#r.tables]}, restore_schema(Schema, R2); - keep_tables -> + keep_tables -> get_tid_ts_and_lock(Tab, write), Snmp = val({Tab, snmp}), - RecName = val({Tab, record_name}), + RecName = val({Tab, record_name}), R2 = R#r{tables = [{Tab, undefined, Snmp, RecName} | R#r.tables]}, restore_schema(Schema, R2); - skip_tables -> + skip_tables -> restore_schema(Schema, R) end; @@ -2667,7 +2703,7 @@ restore_schema([{schema, Tab} | Schema], R) -> restore_schema([], R) -> R. -restore_tab_items([Rec | Rest], Tab, RecName, Where, Snmp, Recs, Op) +restore_tab_items([Rec | Rest], Tab, RecName, Where, Snmp, Recs, Op) when element(1, Rec) == Tab -> NewRecs = Op(Rec, Recs, RecName, Where, Snmp), restore_tab_items(Rest, Tab, RecName, Where, Snmp, NewRecs, Op); @@ -2675,7 +2711,7 @@ restore_tab_items([Rec | Rest], Tab, RecName, Where, Snmp, Recs, Op) restore_tab_items(Rest, _Tab, _RecName, _Where, _Snmp, Recs, _Op) -> {Rest, Recs}. -skip_tab_items([Rec| Rest], Tab) +skip_tab_items([Rec| Rest], Tab) when element(1, Rec) == Tab -> skip_tab_items(Rest, Tab); skip_tab_items(Recs, _) -> @@ -2710,7 +2746,6 @@ merge_schema() -> merge_schema(UserFun) -> schema_transaction(fun() -> UserFun(fun(Arg) -> do_merge_schema(Arg) end) end). - do_merge_schema(LockTabs0) -> {_Mod, Tid, Ts} = get_tid_ts_and_lock(schema, write), LockTabs = [{T, tab_to_nodes(T)} || T <- LockTabs0], @@ -2732,14 +2767,14 @@ do_merge_schema(LockTabs0) -> [mnesia_locker:wlock_no_exist( Tid, Store, T, mnesia_lib:intersect(Ns, OtherNodes)) || {T,Ns} <- LockTabs], - case rpc:call(Node, mnesia_controller, get_cstructs, []) of + case fetch_cstructs(Node) of {cstructs, Cstructs, RemoteRunning1} -> LockedAlready = Running ++ [Node], {New, Old} = mnesia_recover:connect_nodes(RemoteRunning1), RemoteRunning = mnesia_lib:intersect(New ++ Old, RemoteRunning1), - if + if RemoteRunning /= RemoteRunning1 -> - mnesia_lib:error("Mnesia on ~p could not connect to node(s) ~p~n", + mnesia_lib:error("Mnesia on ~p could not connect to node(s) ~p~n", [node(), RemoteRunning1 -- RemoteRunning]), mnesia:abort({node_not_running, RemoteRunning1 -- RemoteRunning}); true -> ok @@ -2749,24 +2784,24 @@ do_merge_schema(LockTabs0) -> [mnesia_locker:wlock_no_exist(Tid, Store, T, mnesia_lib:intersect(Ns,NeedsLock)) || {T,Ns} <- LockTabs], - {value, SchemaCs} = - lists:keysearch(schema, #cstruct.name, Cstructs), + NeedsConversion = need_old_cstructs(NeedsLock ++ LockedAlready), + {value, SchemaCs} = lists:keysearch(schema, #cstruct.name, Cstructs), + SchemaDef = cs2list(NeedsConversion, SchemaCs), %% Announce that Node is running - A = [{op, announce_im_running, node(), - cs2list(SchemaCs), Running, RemoteRunning}], + A = [{op, announce_im_running, node(), SchemaDef, Running, RemoteRunning}], do_insert_schema_ops(Store, A), - + %% Introduce remote tables to local node - do_insert_schema_ops(Store, make_merge_schema(Node, Cstructs)), - + do_insert_schema_ops(Store, make_merge_schema(Node, NeedsConversion, Cstructs)), + %% Introduce local tables to remote nodes Tabs = val({schema, tables}), Ops = [{op, merge_schema, get_create_list(T)} || T <- Tabs, not lists:keymember(T, #cstruct.name, Cstructs)], do_insert_schema_ops(Store, Ops), - + %% Ensure that the txn will be committed on all nodes NewNodes = RemoteRunning -- Running, mnesia_lib:set(prepare_op, {announce_im_running,NewNodes}), @@ -2782,19 +2817,49 @@ do_merge_schema(LockTabs0) -> not_merged end. +fetch_cstructs(Node) -> + case mnesia_monitor:needs_protocol_conversion(Node) of + true -> + case rpc:call(Node, mnesia_controller, get_cstructs, []) of + {cstructs, Cs0, RR} -> + {cstructs, [list2cs(cs2list(Cs)) || Cs <- Cs0], RR}; + Err -> Err + end; + false -> + rpc:call(Node, mnesia_controller, get_remote_cstructs, []) + end. + +need_old_cstructs(Nodes) -> + Filter = fun(Node) -> not mnesia_monitor:needs_protocol_conversion(Node) end, + case lists:dropwhile(Filter, Nodes) of + [] -> false; + [Node|_] -> + case rpc:call(Node, mnesia_lib, val, [{schema,cstruct}]) of + #cstruct{} -> + %% mnesia_lib:warning("Mnesia on ~p do not need to convert cstruct (~p)~n", + %% [node(), Node]), + false; + {badrpc, _} -> + need_old_cstructs(lists:delete(Node,Nodes)); + Cs when element(1, Cs) == cstruct, tuple_size(Cs) == 17 -> + ver4_4_18; % Without majority + Cs when element(1, Cs) == cstruct, tuple_size(Cs) == 18 -> + ver4_4_19 % With majority + end + end. + tab_to_nodes(Tab) when is_atom(Tab) -> Cs = val({Tab, cstruct}), mnesia_lib:cs_to_nodes(Cs). -make_merge_schema(Node, [Cs | Cstructs]) -> - Ops = do_make_merge_schema(Node, Cs), - Ops ++ make_merge_schema(Node, Cstructs); -make_merge_schema(_Node, []) -> +make_merge_schema(Node, NeedsConv, [Cs | Cstructs]) -> + Ops = do_make_merge_schema(Node, NeedsConv, Cs), + Ops ++ make_merge_schema(Node, NeedsConv, Cstructs); +make_merge_schema(_Node, _, []) -> []. %% Merge definitions of schema table -do_make_merge_schema(Node, RemoteCs) - when RemoteCs#cstruct.name == schema -> +do_make_merge_schema(Node, NeedsConv, RemoteCs = #cstruct{name = schema}) -> Cs = val({schema, cstruct}), Masters = mnesia_recover:get_master_nodes(schema), HasRemoteMaster = lists:member(Node, Masters), @@ -2804,15 +2869,15 @@ do_make_merge_schema(Node, RemoteCs) StCsLocal = mnesia_lib:cs_to_storage_type(node(), Cs), StRcsLocal = mnesia_lib:cs_to_storage_type(node(), RemoteCs), StCsRemote = mnesia_lib:cs_to_storage_type(Node, Cs), - StRcsRemote = mnesia_lib:cs_to_storage_type(Node, RemoteCs), - + StRcsRemote = mnesia_lib:cs_to_storage_type(Node, RemoteCs), + if Cs#cstruct.cookie == RemoteCs#cstruct.cookie, Cs#cstruct.version == RemoteCs#cstruct.version -> %% Great, we have the same cookie and version %% and do not need to merge cstructs []; - + Cs#cstruct.cookie /= RemoteCs#cstruct.cookie, Cs#cstruct.disc_copies /= [], RemoteCs#cstruct.disc_copies /= [] -> @@ -2823,14 +2888,14 @@ do_make_merge_schema(Node, RemoteCs) HasRemoteMaster == false -> %% Choose local cstruct, %% since it's the master - [{op, merge_schema, cs2list(Cs)}]; + [{op, merge_schema, cs2list(NeedsConv, Cs)}]; HasRemoteMaster == true, HasLocalMaster == false -> %% Choose remote cstruct, %% since it's the master - [{op, merge_schema, cs2list(RemoteCs)}]; - + [{op, merge_schema, cs2list(NeedsConv, RemoteCs)}]; + true -> Str = io_lib:format("Incompatible schema cookies. " "Please, restart from old backup." @@ -2838,12 +2903,12 @@ do_make_merge_schema(Node, RemoteCs) [Node, cs2list(RemoteCs), node(), cs2list(Cs)]), throw(Str) end; - + StCsLocal /= StRcsLocal, StRcsLocal /= unknown, StCsLocal /= ram_copies -> Str = io_lib:format("Incompatible schema storage types (local). " "on ~w storage ~w, on ~w storage ~w~n", [node(), StCsLocal, Node, StRcsLocal]), - throw(Str); + throw(Str); StCsRemote /= StRcsRemote, StCsRemote /= unknown, StRcsRemote /= ram_copies -> Str = io_lib:format("Incompatible schema storage types (remote). " "on ~w cs ~w, on ~w rcs ~w~n", @@ -2854,27 +2919,27 @@ do_make_merge_schema(Node, RemoteCs) %% Choose local cstruct, %% since it involves disc nodes MergedCs = merge_cstructs(Cs, RemoteCs, Force), - [{op, merge_schema, cs2list(MergedCs)}]; - + [{op, merge_schema, cs2list(NeedsConv, MergedCs)}]; + RemoteCs#cstruct.disc_copies /= [] -> %% Choose remote cstruct, %% since it involves disc nodes MergedCs = merge_cstructs(RemoteCs, Cs, Force), - [{op, merge_schema, cs2list(MergedCs)}]; + [{op, merge_schema, cs2list(NeedsConv, MergedCs)}]; Cs > RemoteCs -> %% Choose remote cstruct MergedCs = merge_cstructs(RemoteCs, Cs, Force), - [{op, merge_schema, cs2list(MergedCs)}]; - + [{op, merge_schema, cs2list(NeedsConv, MergedCs)}]; + true -> %% Choose local cstruct MergedCs = merge_cstructs(Cs, RemoteCs, Force), - [{op, merge_schema, cs2list(MergedCs)}] + [{op, merge_schema, cs2list(NeedsConv, MergedCs)}] end; %% Merge definitions of normal table -do_make_merge_schema(Node, RemoteCs) -> +do_make_merge_schema(Node, NeedsConv, RemoteCs = #cstruct{}) -> Tab = RemoteCs#cstruct.name, Masters = mnesia_recover:get_master_nodes(schema), HasRemoteMaster = lists:member(Node, Masters), @@ -2883,27 +2948,27 @@ do_make_merge_schema(Node, RemoteCs) -> case ?catch_val({Tab, cstruct}) of {'EXIT', _} -> %% A completely new table, created while Node was down - [{op, merge_schema, cs2list(RemoteCs)}]; + [{op, merge_schema, cs2list(NeedsConv, RemoteCs)}]; Cs when Cs#cstruct.cookie == RemoteCs#cstruct.cookie -> if Cs#cstruct.version == RemoteCs#cstruct.version -> %% We have exactly the same version of the %% table def []; - + Cs#cstruct.version > RemoteCs#cstruct.version -> %% Oops, we have different versions %% of the table def, lets merge them. %% The only changes that may have occurred %% is that new replicas may have been added. MergedCs = merge_cstructs(Cs, RemoteCs, Force), - [{op, merge_schema, cs2list(MergedCs)}]; - + [{op, merge_schema, cs2list(NeedsConv, MergedCs)}]; + Cs#cstruct.version < RemoteCs#cstruct.version -> %% Oops, we have different versions %% of the table def, lets merge them MergedCs = merge_cstructs(RemoteCs, Cs, Force), - [{op, merge_schema, cs2list(MergedCs)}] + [{op, merge_schema, cs2list(NeedsConv, MergedCs)}] end; Cs -> %% Different cookies, not possible to merge @@ -2912,14 +2977,14 @@ do_make_merge_schema(Node, RemoteCs) -> HasRemoteMaster == false -> %% Choose local cstruct, %% since it's the master - [{op, merge_schema, cs2list(Cs)}]; + [{op, merge_schema, cs2list(NeedsConv, Cs)}]; HasRemoteMaster == true, HasLocalMaster == false -> %% Choose remote cstruct, %% since it's the master - [{op, merge_schema, cs2list(RemoteCs)}]; - + [{op, merge_schema, cs2list(NeedsConv, RemoteCs)}]; + true -> Str = io_lib:format("Bad cookie in table definition" " ~w: ~w = ~w, ~w = ~w~n", @@ -2989,7 +3054,7 @@ compare_storage_type(true, One, Another) -> compare_storage_type(false, Another, One); compare_storage_type(false, _One, _Another) -> incompatible. - + change_storage_type(N, ram_copies, Cs) -> Nodes = [N | Cs#cstruct.ram_copies], Cs#cstruct{ram_copies = mnesia_lib:uniq(Nodes)}; @@ -3071,14 +3136,14 @@ verify_merge(RemoteCs) -> if StCsLocal == StRcsLocal -> ok; StCsLocal == unknown -> ok; - (StRcsLocal == unknown), (HasRemoteMaster == false) -> + (StRcsLocal == unknown), (HasRemoteMaster == false) -> {merge_error, Cs, RemoteCs}; %% Trust the merger true -> ok end end. -announce_im_running([N | Ns], SchemaCs) -> +announce_im_running([N | Ns], SchemaCs) -> {L1, L2} = mnesia_recover:connect_nodes([N]), case lists:member(N, L1) or lists:member(N, L2) of true -> @@ -3095,7 +3160,7 @@ announce_im_running([], _) -> unannounce_im_running([N | Ns]) -> mnesia_lib:del({current, db_nodes}, N), - mnesia_controller:del_active_replica(schema, N), + mnesia_controller:del_active_replica(schema, N), unannounce_im_running(Ns); unannounce_im_running([]) -> ok. diff --git a/lib/orber/include/Makefile b/lib/orber/include/Makefile deleted file mode 100644 index 219b7085e6..0000000000 --- a/lib/orber/include/Makefile +++ /dev/null @@ -1,66 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 1998-2009. All Rights Reserved. -# -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# %CopyrightEnd% -# -# -include $(ERL_TOP)/make/target.mk - -include $(ERL_TOP)/make/$(TARGET)/otp.mk - -# ---------------------------------------------------- -# Application version -# ---------------------------------------------------- -include ../vsn.mk -VSN=$(ORBER_VSN) - -# ---------------------------------------------------- -# Release directory specification -# ---------------------------------------------------- -RELSYSDIR = $(RELEASE_PATH)/lib/orber-$(VSN) - -# ---------------------------------------------------- -# Target Specs -# ---------------------------------------------------- - -EXTERNAL_HRL_FILES= ../include/corba.hrl \ - ../include/ifr_types.hrl \ - ../include/orber_pi.hrl - -# ---------------------------------------------------- -# FLAGS -# ---------------------------------------------------- - -# ---------------------------------------------------- -# Targets -# ---------------------------------------------------- -debug opt clean docs: - - -# ---------------------------------------------------- -# Release Target -# ---------------------------------------------------- -include $(ERL_TOP)/make/otp_release_targets.mk - - -release_spec: opt - $(INSTALL_DIR) $(RELSYSDIR)/include - $(INSTALL_DATA) $(EXTERNAL_HRL_FILES) $(RELSYSDIR)/include - - -release_docs_spec: - - diff --git a/lib/os_mon/c_src/cpu_sup.c b/lib/os_mon/c_src/cpu_sup.c index fbf318c614..e3bdbd1489 100644 --- a/lib/os_mon/c_src/cpu_sup.c +++ b/lib/os_mon/c_src/cpu_sup.c @@ -191,7 +191,10 @@ int main(int argc, char** argv) { static cpu_t *read_procstat(FILE *fp, cpu_t *cpu) { char buffer[BUFFERSIZE]; - fgets(buffer, BUFFERSIZE, fp); + if (fgets(buffer, BUFFERSIZE, fp) == NULL) { + memset(cpu, 0, sizeof(cpu_t)); + return cpu; + } sscanf(buffer, "cpu%u %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu", &(cpu->id), &(cpu->user), @@ -223,7 +226,11 @@ static void util_measure(unsigned int **result_vec, int *result_sz) { return; } - fgets(buffer, BUFFERSIZE, fp); /*ignore read*/ + /*ignore read*/ + if (fgets(buffer, BUFFERSIZE, fp) == NULL) { + *result_sz = 0; + return; + } rv = *result_vec; rv[0] = no_of_cpus; rv[1] = CU_VALUES; @@ -447,8 +454,12 @@ static void sendv(unsigned int data[], int ints) { } static void error(char* err_msg) { - write(FD_ERR, err_msg, strlen(err_msg)); - write(FD_ERR, "\n", 1); + /* + * if we get error here we have trouble, + * silence unnecessary warnings + */ + if(write(FD_ERR, err_msg, strlen(err_msg))); + if(write(FD_ERR, "\n", 1)); exit(-1); } diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml index 9a3832c68b..b3ce49e2ca 100644 --- a/lib/public_key/doc/src/public_key.xml +++ b/lib/public_key/doc/src/public_key.xml @@ -79,7 +79,7 @@ <p><code> rsa_padding() = 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding' | 'rsa_no_padding'</code></p> - <p><code> rsa_digest_type() = 'md5' | 'sha' </code></p> + <p><code> rsa_digest_type() = 'md2' | 'md5' | 'sha' </code></p> <p><code> dss_digest_type() = 'none' | 'sha' </code></p> diff --git a/lib/public_key/src/pubkey_cert.erl b/lib/public_key/src/pubkey_cert.erl index 5ab9642279..61082a1ec5 100644 --- a/lib/public_key/src/pubkey_cert.erl +++ b/lib/public_key/src/pubkey_cert.erl @@ -38,7 +38,7 @@ %%==================================================================== %%-------------------------------------------------------------------- --spec verify_data(DER::binary()) -> {md5 | sha, binary(), binary()}. +-spec verify_data(DER::binary()) -> {md2 | md5 | sha, binary(), binary()}. %% %% Description: Extracts data from DerCert needed to call public_key:verify/4. %%-------------------------------------------------------------------- @@ -378,6 +378,8 @@ digest_type(?sha1WithRSAEncryption) -> sha; digest_type(?md5WithRSAEncryption) -> md5; +digest_type(?md2WithRSAEncryption) -> + md2; digest_type(?'id-dsa-with-sha1') -> sha. diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index 33fcce2c44..940efffcd0 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -55,7 +55,7 @@ -type rsa_padding() :: 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding' | 'rsa_no_padding'. -type public_crypt_options() :: [{rsa_pad, rsa_padding()}]. --type rsa_digest_type() :: 'md5' | 'sha'. +-type rsa_digest_type() :: 'md2' | 'md5' | 'sha'. -type dss_digest_type() :: 'none' | 'sha'. -define(UINT32(X), X:32/unsigned-big-integer). @@ -307,7 +307,8 @@ encrypt_private(PlainText, #'RSAPrivateKey'{modulus = N, sign(PlainText, DigestType, #'RSAPrivateKey'{modulus = N, publicExponent = E, privateExponent = D}) when is_binary(PlainText), - (DigestType == md5 orelse + (DigestType == md2 orelse + DigestType == md5 orelse DigestType == sha) -> crypto:rsa_sign(DigestType, sized_binary(PlainText), [crypto:mpint(E), @@ -335,7 +336,10 @@ sign(PlainText, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) %%-------------------------------------------------------------------- verify(PlainText, DigestType, Signature, #'RSAPublicKey'{modulus = Mod, publicExponent = Exp}) - when is_binary (PlainText), DigestType == sha; DigestType == md5 -> + when is_binary(PlainText), + (DigestType == md2 orelse + DigestType == md5 orelse + DigestType == sha) -> crypto:rsa_verify(DigestType, sized_binary(PlainText), sized_binary(Signature), diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl index b11e4d092a..a9c198c581 100644 --- a/lib/public_key/test/public_key_SUITE.erl +++ b/lib/public_key/test/public_key_SUITE.erl @@ -537,7 +537,10 @@ rsa_sign_verify(Config) when is_list(Config) -> false = public_key:verify(Msg, sha, <<1:8, RSASign/binary>>, PublicRSA), RSASign1 = public_key:sign(Msg, md5, PrivateRSA), - true = public_key:verify(Msg, md5, RSASign1, PublicRSA). + true = public_key:verify(Msg, md5, RSASign1, PublicRSA), + + RSASign2 = public_key:sign(Msg, md2, PrivateRSA), + true = public_key:verify(Msg, md2, RSASign2, PublicRSA). %%-------------------------------------------------------------------- diff --git a/lib/sasl/src/release_handler_1.erl b/lib/sasl/src/release_handler_1.erl index ef95606bb5..8d0baf3ab1 100644 --- a/lib/sasl/src/release_handler_1.erl +++ b/lib/sasl/src/release_handler_1.erl @@ -21,7 +21,7 @@ %% External exports -export([eval_script/1, eval_script/5, check_script/2, check_old_processes/2]). --export([get_current_vsn/1]). %% exported because used in a test case +-export([get_current_vsn/1, get_supervised_procs/0]). %% exported because used in a test case -record(eval_state, {bins = [], stopped = [], suspended = [], apps = [], libdirs, unpurged = [], vsns = [], newlibs = [], @@ -493,6 +493,19 @@ start(Procs) -> %% supervisor module, we should load the new version, and then %% delete the old. Then we should perform the start changes %% manually, by adding/deleting children. +%% +%% Recent changes to this code cause the upgrade error out and +%% log the case where a suspended supervisor has which_children +%% called against it. This retains the behavior of causing a VM +%% restart to the *old* version of a release but has the +%% advantage of logging the pid and supervisor that had the +%% issue. +%% +%% A second case where this can occur is if a child spec is +%% incorrect and get_modules is called against a process that +%% can't respond to the gen:call. Again an error is logged, +%% an error returned and a VM restart is issued. +%% %% Returns: [{SuperPid, ChildName, ChildPid, Mods}] %%----------------------------------------------------------------- %% OTP-3452. For each application the first item contains the pid @@ -502,49 +515,81 @@ start(Procs) -> get_supervised_procs() -> lists:foldl( fun(Application, Procs) -> - case application_controller:get_master(Application) of - Pid when is_pid(Pid) -> - {Root, _AppMod} = application_master:get_child(Pid), - case get_supervisor_module(Root) of - {ok, SupMod} -> - get_procs(supervisor:which_children(Root), - Root) ++ - [{undefined, undefined, Root, [SupMod]} | - Procs]; - {error, _} -> - error_logger:error_msg("release_handler: " - "cannot find top " - "supervisor for " - "application ~w~n", - [Application]), - get_procs(supervisor:which_children(Root), - Root) ++ Procs - end; - _ -> Procs - end + get_master_procs(Application, + Procs, + application_controller:get_master(Application)) end, [], - lists:map(fun({Application, _Name, _Vsn}) -> - Application - end, - application:which_applications())). + get_application_names()). + +get_supervised_procs(_, Root, Procs, {ok, SupMod}) -> + get_procs(maybe_supervisor_which_children(get_proc_state(Root), SupMod, Root), Root) ++ + [{undefined, undefined, Root, [SupMod]} | Procs]; +get_supervised_procs(Application, Root, Procs, {error, _}) -> + error_logger:error_msg("release_handler: cannot find top supervisor for " + "application ~w~n", [Application]), + get_procs(maybe_supervisor_which_children(get_proc_state(Root), Application, Root), Root) ++ Procs. + +get_application_names() -> + lists:map(fun({Application, _Name, _Vsn}) -> + Application + end, + application:which_applications()). + +get_master_procs(Application, Procs, Pid) when is_pid(Pid) -> + {Root, _AppMod} = application_master:get_child(Pid), + get_supervised_procs(Application, Root, Procs, get_supervisor_module(Root)); +get_master_procs(_, Procs, _) -> + Procs. get_procs([{Name, Pid, worker, dynamic} | T], Sup) when is_pid(Pid) -> - Mods = get_dynamic_mods(Pid), + Mods = maybe_get_dynamic_mods(Name, Pid), [{Sup, Name, Pid, Mods} | get_procs(T, Sup)]; get_procs([{Name, Pid, worker, Mods} | T], Sup) when is_pid(Pid), is_list(Mods) -> [{Sup, Name, Pid, Mods} | get_procs(T, Sup)]; get_procs([{Name, Pid, supervisor, Mods} | T], Sup) when is_pid(Pid) -> - [{Sup, Name, Pid, Mods} | get_procs(T, Sup)] ++ - get_procs(supervisor:which_children(Pid), Pid); + [{Sup, Name, Pid, Mods} | get_procs(T, Sup)] ++ + get_procs(maybe_supervisor_which_children(get_proc_state(Pid), Name, Pid), Pid); get_procs([_H | T], Sup) -> get_procs(T, Sup); get_procs(_, _Sup) -> []. -get_dynamic_mods(Pid) -> - {ok,Res} = gen:call(Pid, self(), get_modules), - Res. +get_proc_state(Proc) -> + {status, _, {module, _}, [_, State, _, _, _]} = sys:get_status(Proc), + State. + +maybe_supervisor_which_children(suspended, Name, Pid) -> + error_logger:error_msg("release_handler: a which_children call" + " to ~p (~p) was avoided. This supervisor" + " is suspended and should likely be upgraded" + " differently. Exiting ...~n", [Name, Pid]), + error(suspended_supervisor); + +maybe_supervisor_which_children(State, Name, Pid) -> + case catch supervisor:which_children(Pid) of + Res when is_list(Res) -> + Res; + Other -> + error_logger:error_msg("release_handler: ~p~nerror during" + " a which_children call to ~p (~p)." + " [State: ~p] Exiting ... ~n", + [Other, Name, Pid, State]), + error(which_children_failed) + end. + +maybe_get_dynamic_mods(Name, Pid) -> + case catch gen:call(Pid, self(), get_modules) of + {ok, Res} -> + Res; + Other -> + error_logger:error_msg("release_handler: ~p~nerror during a" + " get_modules call to ~p (~p)," + " there may be an error in it's" + " childspec. Exiting ...~n", + [Other, Name, Pid]), + error(get_modules_failed) + end. %% XXXX %% Note: The following is a terrible hack done in order to resolve the diff --git a/lib/sasl/test/release_handler_SUITE.erl b/lib/sasl/test/release_handler_SUITE.erl index b44da72d35..af2183bfff 100644 --- a/lib/sasl/test/release_handler_SUITE.erl +++ b/lib/sasl/test/release_handler_SUITE.erl @@ -58,7 +58,7 @@ cases() -> [otp_2740, otp_2760, otp_5761, otp_9402, otp_9417, otp_9395_check_old_code, otp_9395_check_and_purge, otp_9395_update_many_mods, otp_9395_rm_many_mods, - instructions, eval_appup]. + instructions, eval_appup, supervisor_which_children_timeout]. groups() -> [{release,[], @@ -523,6 +523,29 @@ no_cc() -> %%%----------------------------------------------------------------- %%----------------------------------------------------------------- +%% release_handler_1:get_supervised_procs/0 test +%%----------------------------------------------------------------- +supervisor_which_children_timeout(Conf) -> + PrivDir = priv_dir(Conf), + Dir = filename:join(PrivDir,"supervisor_which_children_timeout"), + DataDir = ?config(data_dir,Conf), + LibDir = filename:join([DataDir,release_handler_timeouts]), + + Rel1 = create_and_install_fake_first_release(Dir,[{dummy,"0.1",LibDir}]), + + {ok, Node} = t_start_node(supervisor_which_children_timeout, Rel1, []), + Proc = rpc:call(Node, erlang, whereis, [dummy_sup_2]), + ok = rpc:call(Node, sys, suspend, [Proc]), + Result = {badrpc, {'EXIT', {suspended_supervisor, _}}} = + rpc:call(Node, release_handler_1, get_supervised_procs, []), + ?t:format("release_handler_1:get_supervised_procs/0: ~p~n", [Result]), + + ok. + +supervisor_which_children_timeout(cleanup, Conf) -> + stop_node(node_name(supervisor_which_children_timeout)). + +%%----------------------------------------------------------------- %% Ticket: OTP-2740 %% Slogan: vsn not numeric doesn't work so good in release_handling %%----------------------------------------------------------------- diff --git a/lib/sasl/test/release_handler_SUITE_data/Makefile.src b/lib/sasl/test/release_handler_SUITE_data/Makefile.src index 9b07e7ce0a..edb446413d 100644 --- a/lib/sasl/test/release_handler_SUITE_data/Makefile.src +++ b/lib/sasl/test/release_handler_SUITE_data/Makefile.src @@ -64,8 +64,13 @@ C= \ c/b.@EMULATOR@ \ c/c_sup.@EMULATOR@ +SUP= \ + release_handler_timeouts/dummy-0.1/ebin/dummy_app.@EMULATOR@ \ + release_handler_timeouts/dummy-0.1/ebin/dummy_server.@EMULATOR@ \ + release_handler_timeouts/dummy-0.1/ebin/dummy_sup.@EMULATOR@ \ + release_handler_timeouts/dummy-0.1/ebin/dummy_sup_2.@EMULATOR@ -all: $(P2B) $(LIB) $(APP) $(OTP2740) $(C) +all: $(P2B) $(LIB) $(APP) $(OTP2740) $(C) $(SUP) P2B/a-2.0/ebin/a.@EMULATOR@: P2B/a-2.0/src/a.erl erlc $(EFLAGS) -oP2B/a-2.0/ebin P2B/a-2.0/src/a.erl @@ -195,3 +200,12 @@ c/b.@EMULATOR@: c/b.erl erlc $(EFLAGS) -oc c/b.erl c/c_sup.@EMULATOR@: c/c_sup.erl erlc $(EFLAGS) -oc c/c_sup.erl + +release_handler_timeouts/dummy-0.1/ebin/dummy_app.@EMULATOR@: release_handler_timeouts/dummy-0.1/src/dummy_app.erl + erlc $(EFLAGS) -orelease_handler_timeouts/dummy-0.1/ebin release_handler_timeouts/dummy-0.1/src/dummy_app.erl +release_handler_timeouts/dummy-0.1/ebin/dummy_server.@EMULATOR@: release_handler_timeouts/dummy-0.1/src/dummy_server.erl + erlc $(EFLAGS) -orelease_handler_timeouts/dummy-0.1/ebin release_handler_timeouts/dummy-0.1/src/dummy_server.erl +release_handler_timeouts/dummy-0.1/ebin/dummy_sup.@EMULATOR@: release_handler_timeouts/dummy-0.1/src/dummy_sup.erl + erlc $(EFLAGS) -orelease_handler_timeouts/dummy-0.1/ebin release_handler_timeouts/dummy-0.1/src/dummy_sup.erl +release_handler_timeouts/dummy-0.1/ebin/dummy_sup_2.@EMULATOR@: release_handler_timeouts/dummy-0.1/src/dummy_sup_2.erl + erlc $(EFLAGS) -orelease_handler_timeouts/dummy-0.1/ebin release_handler_timeouts/dummy-0.1/src/dummy_sup_2.erl diff --git a/lib/sasl/test/release_handler_SUITE_data/release_handler_timeouts/dummy-0.1/ebin/dummy.app b/lib/sasl/test/release_handler_SUITE_data/release_handler_timeouts/dummy-0.1/ebin/dummy.app new file mode 100644 index 0000000000..9efdc2e5da --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/release_handler_timeouts/dummy-0.1/ebin/dummy.app @@ -0,0 +1,7 @@ +{application,dummy, + [{description,"a dummy app"}, + {vsn,"0.1"}, + {registered,[dummy_app]}, + {mod,{dummy_app,[]}}, + {applications,[kernel,stdlib,sasl]}, + {modules,[dummy_app,dummy_server,dummy_sup,dummy_sup_2]}]}.
\ No newline at end of file diff --git a/lib/sasl/test/release_handler_SUITE_data/release_handler_timeouts/dummy-0.1/src/dummy_app.erl b/lib/sasl/test/release_handler_SUITE_data/release_handler_timeouts/dummy-0.1/src/dummy_app.erl new file mode 100644 index 0000000000..51363b3630 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/release_handler_timeouts/dummy-0.1/src/dummy_app.erl @@ -0,0 +1,9 @@ +-module(dummy_app). +-behaviour(application). + +-export([start/2, stop/1]). + +start(_,_) -> + dummy_sup:start_link(). + +stop(_) -> ok. diff --git a/lib/sasl/test/release_handler_SUITE_data/release_handler_timeouts/dummy-0.1/src/dummy_server.erl b/lib/sasl/test/release_handler_SUITE_data/release_handler_timeouts/dummy-0.1/src/dummy_server.erl new file mode 100644 index 0000000000..382251eba7 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/release_handler_timeouts/dummy-0.1/src/dummy_server.erl @@ -0,0 +1,56 @@ +-module(dummy_server). +-behaviour(gen_server). + +-export([start_link/0, set_state/1, get_state/0]). + +-export([init/1, + handle_call/3, + handle_cast/2, + handle_info/2, + terminate/2, + code_change/3]). + +%% + +start_link() -> + gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). + +set_state(What) -> + gen_server:call(?MODULE, {set_state, What}). + +get_state() -> + gen_server:call(?MODULE, get_state). + + +%% + +init([]) -> + say("init, setting state to 0", []), + {ok, 0}. + + +handle_call({set_state, NewState}, _From, _State) -> + {reply, {ok, NewState}, NewState}; + +handle_call(get_state, _From, State) -> + {reply, State, State}. + +handle_cast('__not_implemented', State) -> + {noreply, State}. + +handle_info(_Info, State) -> + say("info ~p, ~p.", [_Info, State]), + {noreply, State}. + +terminate(_Reason, _State) -> + say("terminate ~p, ~p", [_Reason, _State]), + ok. + +code_change(_OldVsn, State, _Extra) -> + say("code_change ~p, ~p, ~p", [_OldVsn, State, _Extra]), + {ok, State}. + +%% Internal + +say(Format, Data) -> + io:format("~p:~p: ~s~n", [?MODULE, self(), io_lib:format(Format, Data)]). diff --git a/lib/sasl/test/release_handler_SUITE_data/release_handler_timeouts/dummy-0.1/src/dummy_sup.erl b/lib/sasl/test/release_handler_SUITE_data/release_handler_timeouts/dummy-0.1/src/dummy_sup.erl new file mode 100644 index 0000000000..3d7b5060df --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/release_handler_timeouts/dummy-0.1/src/dummy_sup.erl @@ -0,0 +1,15 @@ +-module(dummy_sup). +-behaviour(supervisor). + +-export([start_link/0]). +-export([init/1]). + +start_link() -> + supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +init([]) -> + DummySup2 = {dummy_sup_2, + {dummy_sup_2, start_link, []}, + permanent, 5000, supervisor, [dummy_sup_2]}, + + {ok, {{one_for_one, 10, 10}, [DummySup2]}}. diff --git a/lib/sasl/test/release_handler_SUITE_data/release_handler_timeouts/dummy-0.1/src/dummy_sup_2.erl b/lib/sasl/test/release_handler_SUITE_data/release_handler_timeouts/dummy-0.1/src/dummy_sup_2.erl new file mode 100644 index 0000000000..d936cbcbd6 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/release_handler_timeouts/dummy-0.1/src/dummy_sup_2.erl @@ -0,0 +1,15 @@ +-module(dummy_sup_2). +-behaviour(supervisor). + +-export([start_link/0]). +-export([init/1]). + +start_link() -> + supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +init([]) -> + Dummy = {dummy_server, + {dummy_server, start_link, []}, + permanent, 5000, worker, [dummy_server]}, + + {ok, {{one_for_one, 10, 10}, [Dummy]}}. diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 5187d0f78f..cec81d551b 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -1778,7 +1778,8 @@ format_reply(binary, _, N, Data) when N > 0 -> % Header mode format_reply(binary, _, _, Data) -> Data; format_reply(list, Packet, _, Data) - when Packet == http; Packet == {http, headers}; Packet == http_bin; Packet == {http_bin, headers} -> + when Packet == http; Packet == {http, headers}; Packet == http_bin; Packet == {http_bin, headers}; Packet == httph; + Packet == httph_bin-> Data; format_reply(list, _,_, Data) -> binary_to_list(Data). @@ -2090,7 +2091,9 @@ set_socket_opts(Socket, [{packet, Packet}| Opts], SockOpts, Other) when Packet = Packet == tpkt; Packet == line; Packet == http; - Packet == http_bin -> + Packet == httph; + Packet == http_bin; + Packet == httph_bin -> set_socket_opts(Socket, Opts, SockOpts#socket_options{packet = Packet}, Other); set_socket_opts(_, [{packet, _} = Opt| _], SockOpts, _) -> diff --git a/lib/ssl/test/ssl_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl index d22d5d2954..9d2599b778 100644 --- a/lib/ssl/test/ssl_packet_SUITE.erl +++ b/lib/ssl/test/ssl_packet_SUITE.erl @@ -151,6 +151,9 @@ all() -> packet_cdr_decode, packet_cdr_decode_list, packet_http_decode, packet_http_decode_list, packet_http_bin_decode_multi, packet_http_error_passive, + packet_httph_active, packet_httph_bin_active, + packet_httph_active_once, packet_httph_bin_active_once, + packet_httph_passive, packet_httph_bin_passive, packet_line_decode, packet_line_decode_list, packet_asn1_decode, packet_asn1_decode_list, packet_tpkt_decode, packet_tpkt_decode_list, @@ -1594,7 +1597,7 @@ client_http_decode(Socket, HttpRequest) -> %%-------------------------------------------------------------------- packet_http_decode_list(doc) -> ["Test setting the packet option {packet, http}, {mode, list}" - "(Body will be litst too)"]; + "(Body will be list too)"]; packet_http_decode_list(suite) -> []; packet_http_decode_list(Config) when is_list(Config) -> @@ -1804,7 +1807,304 @@ server_http_decode_error(Socket, HttpResponse) -> assert_packet_opt(Socket, http), ok = ssl:send(Socket, HttpResponse), ok. +%%-------------------------------------------------------------------- +packet_httph_active(doc) -> + ["Test setting the packet option {packet, httph}"]; +packet_httph_active(suite) -> + []; +packet_httph_active(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Trailer = "Content-Encoding: gzip\r\n" + "\r\n", + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, server_send_trailer, + [Trailer]}}, + {options, [{active, true}, binary | + ServerOpts]}]), + + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, client_http_decode_trailer_active, + []}}, + {options, [{active, true}, + {packet, httph}, + list | + ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +server_send_trailer(Socket, Trailer)-> + ssl:send(Socket, Trailer), + ok. + +client_http_decode_trailer_active(Socket) -> + receive + {ssl, Socket, + {http_header,36,'Content-Encoding',undefined,"gzip"}} -> + ok; + Other1 -> + exit({?LINE, Other1}) + end, + receive + {ssl, Socket, http_eoh} -> + ok; + Other2 -> + exit({?LINE, Other2}) + end, + ok. + +%%-------------------------------------------------------------------- +packet_httph_bin_active(doc) -> + ["Test setting the packet option {packet, httph_bin}"]; +packet_httph_bin_active(suite) -> + []; +packet_httph_bin_active(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Trailer = "Content-Encoding: gzip\r\n" + "\r\n", + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, server_send_trailer, + [Trailer]}}, + {options, [{active, true}, binary | + ServerOpts]}]), + + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, client_http_decode_trailer_bin_active, + []}}, + {options, [{active, true}, + {packet, httph_bin}, + list | + ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +client_http_decode_trailer_bin_active(Socket) -> + receive + {ssl, Socket, + {http_header,36,'Content-Encoding',undefined, <<"gzip">>}} -> + ok; + Other1 -> + exit({?LINE, Other1}) + end, + receive + {ssl, Socket, http_eoh} -> + ok; + Other2 -> + exit({?LINE, Other2}) + end, + ok. +%%-------------------------------------------------------------------- +packet_httph_active_once(doc) -> + ["Test setting the packet option {packet, httph}"]; +packet_httph_active_once(suite) -> + []; +packet_httph_active_once(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Trailer = "Content-Encoding: gzip\r\n" + "\r\n", + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, server_send_trailer, + [Trailer]}}, + {options, [{active, true}, binary | + ServerOpts]}]), + + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, client_http_decode_trailer_active_once, + []}}, + {options, [{active, false}, + {packet, httph}, + list | + ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + + +client_http_decode_trailer_active_once(Socket) -> + ssl:setopts(Socket, [{active, once}]), + receive + {ssl, Socket, + {http_header,36,'Content-Encoding',undefined,"gzip"}} -> + ok; + Other1 -> + exit({?LINE, Other1}) + end, + ssl:setopts(Socket, [{active, once}]), + receive + {ssl, Socket, http_eoh} -> + ok; + Other2 -> + exit({?LINE, Other2}) + end, + ok. +%%-------------------------------------------------------------------- +packet_httph_bin_active_once(doc) -> + ["Test setting the packet option {packet, httph_bin}"]; +packet_httph_bin_active_once(suite) -> + []; +packet_httph_bin_active_once(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Trailer = "Content-Encoding: gzip\r\n" + "\r\n", + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, server_send_trailer, + [Trailer]}}, + {options, [{active, true}, binary | + ServerOpts]}]), + + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, client_http_decode_trailer_bin_active_once, + []}}, + {options, [{active, false}, + {packet, httph_bin}, + list | + ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +client_http_decode_trailer_bin_active_once(Socket) -> + ssl:setopts(Socket, [{active, once}]), + receive + {ssl, Socket, + {http_header,36,'Content-Encoding',undefined, <<"gzip">>}} -> + ok; + Other1 -> + exit({?LINE, Other1}) + end, + ssl:setopts(Socket, [{active, once}]), + receive + {ssl, Socket, http_eoh} -> + ok; + Other2 -> + exit({?LINE, Other2}) + end, + ok. + +%%-------------------------------------------------------------------- + +packet_httph_passive(doc) -> + ["Test setting the packet option {packet, httph}"]; +packet_httph_passive(suite) -> + []; +packet_httph_passive(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Trailer = "Content-Encoding: gzip\r\n" + "\r\n", + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, server_send_trailer, + [Trailer]}}, + {options, [{active, true}, binary | + ServerOpts]}]), + + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, client_http_decode_trailer_passive, + []}}, + {options, [{active, false}, + {packet, httph}, + list | + ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +client_http_decode_trailer_passive(Socket) -> + {ok,{http_header,36,'Content-Encoding',undefined,"gzip"}} = ssl:recv(Socket, 0), + {ok, http_eoh} = ssl:recv(Socket, 0), + ok. + +%%-------------------------------------------------------------------- +packet_httph_bin_passive(doc) -> + ["Test setting the packet option {packet, httph_bin}"]; +packet_httph_bin_passive(suite) -> + []; +packet_httph_bin_passive(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Trailer = "Content-Encoding: gzip\r\n" + "\r\n", + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, server_send_trailer, + [Trailer]}}, + {options, [{active, true}, binary | + ServerOpts]}]), + + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, client_http_decode_trailer_bin_passive, + []}}, + {options, [{active, false}, + {packet, httph_bin}, + list | + ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +client_http_decode_trailer_bin_passive(Socket) -> + {ok,{http_header,36,'Content-Encoding',undefined,<<"gzip">>}} = ssl:recv(Socket, 0), + {ok, http_eoh} = ssl:recv(Socket, 0), + ok. %%-------------------------------------------------------------------- packet_line_decode(doc) -> diff --git a/lib/stdlib/doc/src/ets.xml b/lib/stdlib/doc/src/ets.xml index 8c952708c5..f19f92be6f 100644 --- a/lib/stdlib/doc/src/ets.xml +++ b/lib/stdlib/doc/src/ets.xml @@ -513,6 +513,9 @@ Error: fun containing local Erlang function calls the table has been fixed by the process.</p> <p>If the table never has been fixed, the call returns <c>false</c>.</p> + <item><c>Item=stats, Value=tuple()</c> <br></br> + Returns internal statistics about set, bag and duplicate_bag tables on an internal format used by OTP test suites. + Not for production use.</item> </item> </list> </desc> diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl index 3ac6da3d28..57df963ae2 100644 --- a/lib/stdlib/test/ets_SUITE.erl +++ b/lib/stdlib/test/ets_SUITE.erl @@ -819,6 +819,14 @@ t_delete_all_objects(Config) when is_list(Config) -> repeat_for_opts(t_delete_all_objects_do), ?line verify_etsmem(EtsMem). +get_kept_objects(T) -> + case ets:info(T,stats) of + false -> + 0; + {_,_,_,_,_,_,KO} -> + KO + end. + t_delete_all_objects_do(Opts) -> ?line T=ets_new(x,Opts), ?line filltabint(T,4000), @@ -828,10 +836,10 @@ t_delete_all_objects_do(Opts) -> ?line true = ets:delete_all_objects(T), ?line '$end_of_table' = ets:next(T,O), ?line 0 = ets:info(T,size), - ?line 4000 = ets:info(T,kept_objects), + ?line 4000 = get_kept_objects(T), ?line ets:safe_fixtable(T,false), ?line 0 = ets:info(T,size), - ?line 0 = ets:info(T,kept_objects), + ?line 0 = get_kept_objects(T), ?line filltabint(T,4000), ?line 4000 = ets:info(T,size), ?line true = ets:delete_all_objects(T), @@ -861,10 +869,10 @@ t_delete_object_do(Opts) -> ?line ets:delete_object(T,{First, integer_to_list(First)}), ?line Next = ets:next(T,First), ?line 3999 = ets:info(T,size), - ?line 1 = ets:info(T,kept_objects), + ?line 1 = get_kept_objects(T), ?line ets:safe_fixtable(T,false), ?line 3999 = ets:info(T,size), - ?line 0 = ets:info(T,kept_objects), + ?line 0 = get_kept_objects(T), ?line ets:delete(T), ?line T1 = ets_new(x,[ordered_set | Opts]), ?line filltabint(T1,4000), @@ -4971,7 +4979,7 @@ grow_pseudo_deleted_do(Type) -> [true]}]), Left = Mult*(Mod-1), ?line Left = ets:info(T,size), - ?line Mult = ets:info(T,kept_objects), + ?line Mult = get_kept_objects(T), filltabstr(T,Mult), spawn_opt(fun()-> ?line true = ets:info(T,fixed), Self ! start, @@ -4985,7 +4993,7 @@ grow_pseudo_deleted_do(Type) -> ?line true = ets:safe_fixtable(T,false), io:format("Unfix table done. ~p nitems=~p\n",[now(),ets:info(T,size)]), ?line false = ets:info(T,fixed), - ?line 0 = ets:info(T,kept_objects), + ?line 0 = get_kept_objects(T), ?line done = receive_any(), %%verify_table_load(T), % may fail if concurrency is poor (genny) ets:delete(T), @@ -5012,7 +5020,7 @@ shrink_pseudo_deleted_do(Type) -> [{'>', '$1', Half}], [true]}]), ?line Half = ets:info(T,size), - ?line Half = ets:info(T,kept_objects), + ?line Half = get_kept_objects(T), spawn_opt(fun()-> ?line true = ets:info(T,fixed), Self ! start, io:format("Starting to delete... ~p\n",[now()]), @@ -5025,7 +5033,7 @@ shrink_pseudo_deleted_do(Type) -> ?line true = ets:safe_fixtable(T,false), io:format("Unfix table done. ~p nitems=~p\n",[now(),ets:info(T,size)]), ?line false = ets:info(T,fixed), - ?line 0 = ets:info(T,kept_objects), + ?line 0 = get_kept_objects(T), ?line done = receive_any(), %%verify_table_load(T), % may fail if concurrency is poor (genny) ets:delete(T), @@ -5141,7 +5149,7 @@ smp_fixed_delete_do() -> ?line 0 = ets:info(T,size), ?line true = ets:info(T,fixed), ?line Buckets = num_of_buckets(T), - ?line NumOfObjs = ets:info(T,kept_objects), + ?line NumOfObjs = get_kept_objects(T), ets:safe_fixtable(T,false), %% Will fail as unfix does not shrink the table: %%?line Mem = ets:info(T,memory), @@ -5173,7 +5181,7 @@ smp_unfix_fix_do() -> Left = NumOfObjs - Deleted, ?line Left = ets:info(T,size), ?line true = ets:info(T,fixed), - ?line Deleted = ets:info(T,kept_objects), + ?line Deleted = get_kept_objects(T), {Child, Mref} = spawn_opt(fun()-> ?line true = ets:info(T,fixed), @@ -5190,7 +5198,7 @@ smp_unfix_fix_do() -> end, Deleted), ?line 0 = ets:info(T,size), - ?line true = ets:info(T,kept_objects) >= Left, + ?line true = get_kept_objects(T) >= Left, ?line done = receive_any() end, [link, monitor, {scheduler,2}]), @@ -5203,7 +5211,7 @@ smp_unfix_fix_do() -> Child ! done, {'DOWN', Mref, process, Child, normal} = receive_any(), ?line false = ets:info(T,fixed), - ?line 0 = ets:info(T,kept_objects), + ?line 0 = get_kept_objects(T), %%verify_table_load(T), ets:delete(T), process_flag(scheduler,0). @@ -5241,7 +5249,7 @@ otp_8166_do(WC) -> ZombieCrPid ! quit, {'DOWN', ZombieCrMref, process, ZombieCrPid, normal} = receive_any(), ?line false = ets:info(T,fixed), - ?line 0 = ets:info(T,kept_objects), + ?line 0 = get_kept_objects(T), %%verify_table_load(T), ets:delete(T), process_flag(scheduler,0). @@ -5308,7 +5316,7 @@ otp_8166_zombie_creator(T,Deleted) -> verify_table_load(T) -> ?line Stats = ets:info(T,stats), - ?line {Buckets,AvgLen,StdDev,ExpSD,_MinLen,_MaxLen} = Stats, + ?line {Buckets,AvgLen,StdDev,ExpSD,_MinLen,_MaxLen,_} = Stats, ?line ok = if AvgLen > 7 -> io:format("Table overloaded: Stats=~p\n~p\n", @@ -5920,7 +5928,7 @@ very_big_num(0, Result) -> ?line Result. make_port() -> - ?line open_port({spawn, efile}, [eof]). + ?line open_port({spawn, "efile"}, [eof]). make_pid() -> ?line spawn_link(?MODULE, sleeper, []). diff --git a/lib/stdlib/test/tar_SUITE.erl b/lib/stdlib/test/tar_SUITE.erl index 48f58cd05d..9ad3936928 100644 --- a/lib/stdlib/test/tar_SUITE.erl +++ b/lib/stdlib/test/tar_SUITE.erl @@ -283,17 +283,16 @@ long_names(doc) -> long_names(Config) when is_list(Config) -> ?line DataDir = ?config(data_dir, Config), ?line Long = filename:join(DataDir, "long_names.tar"), + run_in_short_tempdir(Config, + fun() -> do_long_names(Long) end). +do_long_names(Long) -> %% Try table/2 and extract/2. ?line case erl_tar:table(Long, [verbose]) of {ok,List} when is_list(List) -> ?line io:format("~p\n", [List]) end, - - %% To avoid getting too long paths for Windows to handle, extract into - %% the current directory (which is the test_server directory). Its path - %% is quite a bit shorter than the path to priv_dir. ?line {ok,Cwd} = file:get_cwd(), ?line ok = erl_tar:extract(Long), ?line Base = filename:join([Cwd, "original_software", "written_by", @@ -312,17 +311,16 @@ long_names(Config) when is_list(Config) -> ?line "Here"++_ = binary_to_list(First), ?line "And"++_ = binary_to_list(Second), - %% Clean up. - ?line delete_files([filename:join(Cwd, "original_software"),EmptyDir]), - ok. create_long_names(doc) -> ["Creates a tar file from a deep directory structure (filenames are ", "longer than 100 characters)."]; create_long_names(Config) when is_list(Config) -> - ?line PrivDir = ?config(priv_dir, Config), - ?line ok = file:set_cwd(PrivDir), + run_in_short_tempdir(Config, fun create_long_names/0). + +create_long_names() -> + ?line {ok,Dir} = file:get_cwd(), Dirs = ["aslfjkshjkhliuf", "asdhjfehnbfsky", "sahajfskdfhsz", @@ -334,7 +332,7 @@ create_long_names(Config) when is_list(Config) -> ?line AFile = filename:join(DeepDir, "a_file"), ?line Hello = "hello, world\n", ?line ok = file:write_file(AFile, Hello), - ?line TarName = filename:join(PrivDir, "my_tar_with_long_names.tar"), + ?line TarName = filename:join(Dir, "my_tar_with_long_names.tar"), ?line ok = erl_tar:create(TarName, [AFile]), %% Print contents. @@ -347,9 +345,6 @@ create_long_names(Config) when is_list(Config) -> ?line {ok, Bin} = file:read_file(filename:join(ExtractDir, AFile)), ?line Hello = binary_to_list(Bin), - %% Clean up. - ?line delete_files([ExtractDir,TarName,hd(Dirs)]), - ok. make_dirs([Dir|Rest], []) -> @@ -734,3 +729,42 @@ delete_files([Item|Rest]) -> end, delete_files(Rest). +%% Move to a temporary directory with as short name as possible and +%% execute Fun. Remove the directory and any files in it afterwards. +%% This is necessary because pathnames on Windows may be limited to +%% 260 characters. +run_in_short_tempdir(Config, Fun) -> + {ok,Cwd} = file:get_cwd(), + PrivDir0 = ?config(priv_dir, Config), + + %% Normalize name to make sure that there is no slash at the end. + PrivDir = filename:absname(PrivDir0), + + %% We need a base directory with a much shorter pathname than + %% priv_dir. We KNOW that priv_dir is located four levels below + %% the directory that common_test puts the ct_run.* directories + %% in. That fact is not documented, but an usually reliable source + %% assured me that the directory structure is unlikely to change + %% in future versions of common_test because of backward + %% compatibility (tools developed by users of common_test depend + %% on the current directory layout). + Base = lists:foldl(fun(_, D) -> + filename:dirname(D) + end, PrivDir, [1,2,3,4]), + + Dir = make_temp_dir(Base, 0), + ok = file:set_cwd(Dir), + io:format("Running test in ~s\n", [Dir]), + try + Fun() + after + file:set_cwd(Cwd), + delete_files([Dir]) + end. + +make_temp_dir(Base, I) -> + Name = filename:join(Base, integer_to_list(I, 36)), + case file:make_dir(Name) of + ok -> Name; + {error,eexist} -> make_temp_dir(Base, I+1) + end. diff --git a/lib/xmerl/src/xmerl_ucs.erl b/lib/xmerl/src/xmerl_ucs.erl index 7c45c838ab..feb16070a0 100644 --- a/lib/xmerl/src/xmerl_ucs.erl +++ b/lib/xmerl/src/xmerl_ucs.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% +%% %% Copyright Ericsson AB 2005-2009. All Rights Reserved. -%% +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -43,6 +43,7 @@ -export([to_utf16be/1, from_utf16be/1, from_utf16be/2]). -export([to_utf16le/1, from_utf16le/1, from_utf16le/2]). -export([to_utf8/1, from_utf8/1]). +-export([from_latin9/1]). %%% NB: Non-canonical UTF-8 encodings and incorrectly used %%% surrogate-pair codes are disallowed by this code. There are @@ -177,13 +178,27 @@ to_utf8(List) when is_list(List) -> lists:flatmap(fun to_utf8/1, List); to_utf8(Ch) -> char_to_utf8(Ch). from_utf8(Bin) when is_binary(Bin) -> from_utf8(binary_to_list(Bin)); -from_utf8(List) -> +from_utf8(List) -> case expand_utf8(List) of {Result,0} -> Result; {_Res,_NumBadChar} -> exit({ucs,{bad_utf8_character_code}}) end. +%%% Latin9 support +from_latin9(Bin) when is_binary(Bin) -> from_latin9(binary_to_list(Bin)); +from_latin9(List) -> + [ latin9_to_ucs4(Char) || Char <- List]. + +latin9_to_ucs4(16#A4) -> 16#20AC; +latin9_to_ucs4(16#A6) -> 16#160; +latin9_to_ucs4(16#A8) -> 16#161; +latin9_to_ucs4(16#B4) -> 16#17D; +latin9_to_ucs4(16#B8) -> 16#17E; +latin9_to_ucs4(16#BC) -> 16#152; +latin9_to_ucs4(16#BD) -> 16#153; +latin9_to_ucs4(16#BE) -> 16#178; +latin9_to_ucs4(Other) -> Other. @@ -238,7 +253,7 @@ from_ucs4le(Bin,Acc,Tail) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% UCS-2 support -%%% FIXME! Don't know how to encode UCS-2!! +%%% FIXME! Don't know how to encode UCS-2!! %%% Currently I just encode as UCS-4, but strips the 16 higher bits. char_to_ucs2be(Ch) -> true = is_iso10646(Ch), @@ -259,15 +274,15 @@ from_ucs2be(Bin,Acc,Tail) -> char_to_ucs2le(Ch) -> true = is_iso10646(Ch), - [(Ch bsr 16) band 16#FF, - (Ch bsr 24)]. + [Ch band 16#FF, + (Ch bsr 8) band 16#FF]. from_ucs2le(<<Ch:16/little-signed-integer, Rest/binary>>,Acc,Tail) -> if Ch < 0; Ch >= 16#D800, Ch < 16#E000; Ch =:= 16#FFFE; Ch =:= 16#FFFF -> exit({bad_character_code,Ch}); true -> - from_ucs4le(Rest,[Ch|Acc],Tail) + from_ucs2le(Rest,[Ch|Acc],Tail) end; from_ucs2le(<<>>,Acc,Tail) -> lists:reverse(Acc,Tail); @@ -476,6 +491,8 @@ to_unicode(Input,Cs) when Cs=='iso_8859-1:1987';Cs=='iso-ir-100'; Cs=='l1';Cs=='ibm819'; Cs=='cp819';Cs=='csisolatin1' -> Input; +to_unicode(Input,Cs) when Cs=='iso_8859-15';Cs=='iso-8859-15';Cs=='latin9' -> + from_latin9(Input); % to_unicode(Input,Cs) when Cs=='mnemonic';Cs=='"mnemonic+ascii+38'; % Cs=='mnem';Cs=='"mnemonic+ascii+8200' -> % from_mnemonic(Input); |