From per@REDACTED Wed Jan 2 12:13:20 2002 From: per@REDACTED (Per Bergqvist) Date: Wed, 02 Jan 2002 12:13:20 +0100 Subject: Erlang and asn.1 In-Reply-To: <3C307DC6.4F307102@cmd.lu> Message-ID: <200201021113.g02BDLA06879@raven.levonline.com> Hi Segio, Put your ASN.1 definition in a .asn file and run it through the ASN compiler. i.e. erlc MyDefs.asn This will generate encoder and decoder logic in Erlang. To decode a BER encoded record of MyType: asn1rt:decode('MyDefs','MyType',BerEncRecord). Please not that the ASN compiler does not (at least did not prior to R8) support all ASN.1 constructs. Please let me know if you run into any problems. /Per > Hi, > > I am just about to discover erlang and ASN.1. I have a special need and > am wondering if erlang is able to solve my problem: we receive BER > encoded (according to a well defined ASN.1 grammar) files (called > "enc_file") and I will need to decode them. > > Where do I start? So far I have managed to compile the ASN.1 file and > have a module that provides encode and decode routines. > I have read the documentation but this did not bring me any further. > > How do I decode file "enc_file", do I have to define my own decoding > logic or do there exist out-of-the box tools? > > Any hints will be greatly appreciated. > > I nearly forgot to wish you a Happy New Year! > > Sergio da Silva > ========================================================= Per Bergqvist Synapse Systems AB Phone: +46 709 686 685 Email: per@REDACTED From per@REDACTED Wed Jan 2 12:13:53 2002 From: per@REDACTED (Per Bergqvist) Date: Wed, 02 Jan 2002 12:13:53 +0100 Subject: Erlang and asn.1 In-Reply-To: <3C307DC6.4F307102@cmd.lu> Message-ID: <200201021113.g02BDrA06979@raven.levonline.com> Hi Segio, Put your ASN.1 definition in a .asn file and run it through the ASN compiler. i.e. erlc MyDefs.asn This will generate encoder and decoder logic in Erlang. To decode a BER encoded record of MyType: asn1rt:decode('MyDefs','MyType',BerEncRecord). Please note that the ASN compiler does not (at least did not prior to R8) support all ASN.1 constructs. Please let me know if you run into any problems. /Per > Hi, > > I am just about to discover erlang and ASN.1. I have a special need and > am wondering if erlang is able to solve my problem: we receive BER > encoded (according to a well defined ASN.1 grammar) files (called > "enc_file") and I will need to decode them. > > Where do I start? So far I have managed to compile the ASN.1 file and > have a module that provides encode and decode routines. > I have read the documentation but this did not bring me any further. > > How do I decode file "enc_file", do I have to define my own decoding > logic or do there exist out-of-the box tools? > > Any hints will be greatly appreciated. > > I nearly forgot to wish you a Happy New Year! > > Sergio da Silva > ========================================================= Per Bergqvist Synapse Systems AB Phone: +46 709 686 685 Email: per@REDACTED From sergi_vare@REDACTED Wed Jan 2 20:14:58 2002 From: sergi_vare@REDACTED (Sergio Hidalgo Varela) Date: Wed, 02 Jan 2002 20:14:58 +0100 Subject: No subject Message-ID: An HTML attachment was scrubbed... URL: From sergi_vare@REDACTED Wed Jan 2 20:15:28 2002 From: sergi_vare@REDACTED (Sergio Hidalgo Varela) Date: Wed, 02 Jan 2002 20:15:28 +0100 Subject: No subject Message-ID: An HTML attachment was scrubbed... URL: From rv@REDACTED Thu Jan 3 17:05:34 2002 From: rv@REDACTED (Robert Virding) Date: Thu, 03 Jan 2002 17:05:34 +0100 Subject: Generic I/O and binary I/O Message-ID: <200201031605.g03G5Y407734@erik.virding.org> I have now written a first draft of a generic i/o module, gen_io. It provides a generic synchronous interface to the i/o protocol and uses callbacks for the device specific stuff. There is "some" documentation in the beginning of the file. I have also reworked my binary i/o module, bin_io, to use gen_io. It is reasonable small example of using gen_io. There is also a first draft of tcp_io which provides an i/o interface to a socket. It is not complete, specifically it does not correctly handle when the port closes for the generic i/o interface. I'll fix it. N.B. this is probably not the most efficient way of doing formatted i/o to a socket but it does allow writing using generic i/o functions. I am going to convert file_io_server, the main file interface, to use gen_io to see if gen_io is sufficient. If this works then I reckon that gen_io will do for synchronous i/o. Asynchronous i/o, like for the tty interface, is another matter and I think that it might be difficult to generalise it. I will try however. Comment? Robert -------------- next part -------------- %%% File : gen_io.erl %%% Author : Robert Virding %%% Purpose : %%% Created : 21 Nov 2001 by Robert Virding %% Mod:init([Argument]) -> %% {ok,State} %% {stop,Reason} %% %% Mod:handle_request(Request, State) -> %% {reply,From,Reply,State} %% {noreply,State} %% {stop,Reason,From,Reply,State} %% {stop,Reason,State} %% Request is the full unparsed request. %% %% Mod:terminate(Reason, State) -> ok %% %% Mod:read_chars(State) -> %% {ok,[Char],State} %% {error,Reason,State} %% %% Mod:push_chars([Char], State) -> %% {ok,State} %% {error,Reason,State} %% After we have read all the characters we need we push the rest %% back into the state. N.B. the char list may be empty. %% %% Mod:write_chars([Char], State) -> %% {ok,State} %% {error,Reason,State} -module(gen_io). -author('rv@REDACTED'). -compile(export_all). -export([start/3,start_link/3]). -export([request/2]). %% start(Mod, [Arg], [Option]) %% start_link(Mod, [Arg], [Option]) %% %% where %% Mod is the callback module %% [Arg] init arguments %% [Option] start(Mod, Args, Opts) -> do_start(spawn, Mod, Args, Opts). start_link(Mod, Args, Opts) -> do_start(spawn_link, Mod, Args, Opts). do_start(Spawn, Mod, Args, Opts) -> Self = self(), Ref = make_ref(), Pid = erlang:Spawn(fun () -> init(Self, Ref, Mod, Args, Opts) end), %% Monitor process and wait for reply or termination. Mref = erlang:monitor(process, Pid), receive {Ref,ok} -> erlang:demonitor(Mref), receive {'DOWN',Mref,_,_,Reason} -> {error,Reason} after 0 -> {ok,Pid} end; {'DOWN',Mref,_,_,Reason} -> {error,Reason} end. %% init(StarterPid, StartRef, IoModule, [Arg], [Opt]) init(Start, Ref, IoM, Args, Opts) -> case catch IoM:init(Args) of {ok,State} -> Start ! {Ref,ok}, loop(IoM, State); {stop,Reason} -> exit(Reason); {'EXIT',Reason} -> exit(Reason); Else -> Error = {bad_return_value,Else}, exit(Error) end. %% loop(IoModule, State) -> void. %% Main io loop. This never returns anything, just terminates. loop(IoM, St0) -> receive {io_request,From,ReplyAs,Req} when pid(From) -> %% Handle general io requests. case io_request(Req, IoM, St0) of {ok,Rep,St1} -> io_reply(From, ReplyAs, Rep), loop(IoM, St1); {error,Rep,St1} -> io_reply(From, ReplyAs, Rep), loop(IoM, St1); {stop,Reason,Rep,St1} -> terminate(Reason, From, {io_reply,ReplyAs,Rep}, IoM, St1) end; Request -> case catch IoM:handle_request(Request, St0) of {reply,From,Rep,St1} -> From ! Rep, loop(IoM, St1); {noreply,St1} -> loop(IoM, St1); {stop,Reason,From,Rep,St1} -> terminate(Reason, From, Rep, IoM, St1); {stop,Reason,St1} -> terminate(Reason, IoM, St1) end end. io_reply(From, ReplyAs, Reply) -> From ! {io_reply, ReplyAs, Reply}. terminate(Reason, From, Reply, IoM, St) -> From ! Reply, terminate(Reason, IoM, St). terminate(Reason, IoM, St) -> catch IoM:terminate(Reason, St), exit(Reason). %% io_request(Request, IoModule, State) -> %% {ok,Reply,State} | {error,Reply,State} | {stop,Reason,Reply,State}. %% %% Handle general io requests. io_request({put_chars,Chars}, IoM, St0) -> case catch IoM:write_chars(Chars, St0) of {ok,St1} -> {ok,ok,St1}; {error,Reason,St1} -> {stop,normal,{error,Reason},St1}; Other -> {stop,Other,{error,Other},St0} end; io_request({put_chars,Mod,Func,Args}, IoM, St) -> case catch apply(Mod, Func, Args) of {'EXIT',Reason} -> {error,{error,Func},St}; Cs -> io_request({put_chars,Cs}, IoM, St) end; io_request({get_until,Prompt,Mod,Func,ExtraArgs}, IoM, St) -> get_until(Mod, Func, ExtraArgs, IoM, St); io_request({requests,Reqs}, IoM, St) when list(Reqs) -> io_request_loop(Reqs, IoM, {ok,ok,St}); io_request(Unknown, IoM, St) -> Reason = {error,Unknown}, {error,{error,Reason},St}. %% io_request_loop([Request], IoModule, Result) -> Result. %% Process list of requests as long as results are ok. io_request_loop([], IoM, Res) -> Res; io_request_loop([Req|Reqs], IoM, {ok,Rep,St}) -> io_request_loop(Reqs, IoM, io_request(Req, IoM, St)); io_request_loop([Req|Reqs], IoM, Res) -> Res. %% get_until(Module, Func, [ExtraArg], IoModule, State) -> %% {ok,Reply,State} | {error,Reply,State} | {stop,Reason,Reply,State}. %% Apply the get_until loop scanning the binary until the scan %% function has enough. Buffer any remaining bytes until the next %% call. get_until(Mod, Func, ExtraArgs, IoM, St) -> get_until_loop(Mod, Func, ExtraArgs, IoM, St, {more,[]}). get_until_loop(M, F, As, IoM, St0, {more,Cont}) -> case catch IoM:read_chars(St0) of {ok,Cs,St1} -> get_until_loop(M, F, As, IoM, St1, catch apply(M, F, [Cont,Cs|As])); {error,Reason,St1} -> {stop,Reason,{error,Reason},St1}; Other -> {stop,Other,{error,Other},St0} end; get_until_loop(M, F, As, IoM, St0, {done,Res,Buf}) -> case catch IoM:push_chars(Buf, St0) of {ok,St1} -> {ok,Res,St1}; {error,Reason,St1} -> {stop,Reason,{error,Reason},St1}; Other -> {stop,Other,{error,Other},St0} end; get_until_loop(M, F, As, IoM, St, Other) -> {error,{error,F},St}. %% request(IoServer, Request) -> {ok,Reply} | {error,Reason}. %% Send a standard io request to to an io server and wait for the reply. request(Pid, Request) when pid(Pid) -> Mref = erlang:monitor(process,Pid), Pid ! {io_request,self(),Pid,Request}, wait_io_mon_reply(Pid,Mref); request(Name, Request) when atom(Name) -> case whereis(Name) of undefined -> {error, arguments}; Pid -> request(Pid, Request) end. wait_io_mon_reply(From, Mref) -> receive {io_reply,From,Reply} -> erlang:demonitor(Mref), receive {'DOWN', Mref, _, _, _} -> true after 0 -> true end, Reply; {'EXIT', From, _What} -> receive {'DOWN', Mref, _, _, _} -> true after 0 -> true end, {error,terminated}; {'DOWN', Mref, _, _, _} -> receive {'EXIT', From, _What} -> true after 0 -> true end, {error,terminated} end. -------------- next part -------------- %% File : bin_io.erl %% Author : Robert Virding %% Purpose : Open a binary for standard i/o requests. -module(bin_io). %% The main user interface. -export([open_read/1,open_create/0,open_append/1,close/1]). %% The gen_io callbacks. -export([init/1,terminate/2,handle_request/2, read_chars/1,write_chars/2,push_chars/2]). -record(bin_io, {mode,bin,buf}). -define(READ_SIZE, 256). %Bytes per chunk read %% The main interface. open_read(Bin) -> gen_io:start_link(?MODULE, [read,Bin], []). open_create() -> gen_io:start_link(?MODULE, [create], []). open_append(Bin) -> gen_io:start_link(?MODULE, [append,Bin], []). close(Io) -> Io ! {bin_request,self(),Io,close}, receive {bin_reply,Io,Rep} -> Rep end. %% init([Arg]) -> {ok,State}. init([read,Bin]) when binary(Bin) -> {ok,#bin_io{mode=read,bin=Bin,buf=[]}}; init([create]) -> {ok,#bin_io{mode=write,bin= <<>>,buf=[]}}; init([append,Bin]) when binary(Bin) -> {ok,#bin_io{mode=write,bin=Bin,buf=[]}}. %% terminate(Reason, State) -> ok. terminate(R, St) -> ok. %% handle_request(Request, State) -> %% {reply,From,Reply,State} | %% {noreply,State} | %% {stop,Reason,From,Reply,State} | %% {stop,Reason,State}. %% %% Handle bin_io specific requests. handle_request({bin_request,From,ReplyAs,close}, #bin_io{mode=Mode}=St) when pid(From) -> Rep = case Mode of read -> ok; write -> {ok,list_to_binary([St#bin_io.bin,St#bin_io.buf])} end, {stop,normal,From,{bin_reply,ReplyAs,Rep},St#bin_io{buf=[]}}; handle_request({bin_request,From,ReplyAs,Other}, #bin_io{}=St) when pid(From) -> Rep = {error,{request,Other}}, {reply,From,{bin_reply,ReplyAs,Rep},St}; handle_request(Unknown, State) -> %% Just ignore unknown requests. {noreply,State}. %% write_chars(Chars, State) -> %% {ok,State} | {error,Reason,State}. write_chars(Cs, #bin_io{mode=write,buf=Buf}=St) when binary(Cs) -> {ok,St#bin_io{buf=[Buf|Cs]}}; write_chars(Cs, #bin_io{mode=write,buf=Buf}=St) -> case catch list_to_binary(Cs) of {'EXIT',Reason} -> {error,Reason,St}; MoreBin -> {ok,St#bin_io{buf=[Buf|MoreBin]}} end; write_chars(Cs, #bin_io{mode=read}=St) -> {error,badmode,St}. %% read_chars(State) -> %% {ok,Chars,State} | {error,Reason,State}. read_chars(#bin_io{mode=read,buf=[],bin=Bin}=St) -> if Bin == <<>> -> {ok,eof,St}; size(Bin) < ?READ_SIZE -> {ok,binary_to_list(Bin),St#bin_io{bin= <<>>}}; true -> {B1,B2} = split_binary(Bin, ?READ_SIZE), {ok,binary_to_list(B1),St#bin_io{bin=B2}} end; read_chars(#bin_io{mode=read,buf=Buf}=St) -> {ok,Buf,St#bin_io{buf=[]}}; read_chars(#bin_io{mode=write}=St) -> {error,badmode,St}. %% push_chars([Char], State) -> %% {ok,State} | {error,Reason,State}. push_chars(Cs, #bin_io{buf=[]}=St) -> {ok,St#bin_io{buf=Cs}}. -------------- next part -------------- %% File : tcp_io.erl %% Author : Robert Virding %% Purpose : Open a tcp connection for standard i/o requests. -module(tcp_io). %% The main user interface. -export([open/2,open/3,close/1]). %% The gen_io callbacks. -export([init/1,terminate/2,handle_request/2, read_chars/1,write_chars/2,push_chars/2]). -record(tcp_io, {server, %Server port, %Port sock=none, %Socket ibuf=none}). open(Server, Port) -> open(Server, Port, []). open(Server, Port, SockOpts) -> gen_io:start_link(?MODULE, [Server,Port,SockOpts], []). close(Io) -> Io ! {tcp_request,self(),Io,close}, receive {tcp_reply,Io,Rep} -> Rep end. %% init([Arg]) -> {ok,State}. %% Try to open the socket with the given arguments. init([Server,Port,SockOpts]) -> case gen_tcp:connect(Server, Port, [list,{active,false}|SockOpts]) of {ok,S} -> {ok,#tcp_io{server=Server,port=Port,sock=S,ibuf=[]}}; {error,Reason} -> {stop,Reason} end. %% terminate(Reason, State) -> ok. %% This just closes the socket. terminate(Reason, #tcp_io{sock=S}) -> gen_tcp:close(S). %% handle_request(Request, State) -> %% {reply,From,Reply,State} | %% {stop,Reason,From,Reply,State} | %% {noreply,State}. handle_request({tcp_request,From,ReplyAs,close}, #tcp_io{}=St) when pid(From) -> {stop,normal,From,{tcp_reply,ReplyAs,ok},St}; handle_request({tcp_request,From,ReplyAs,Other}, #tcp_io{}=St) when pid(From) -> Rep = {error,{request,Other}}, {reply,From,{tcp_reply,ReplyAs,Rep},St}; handle_request(Unknown, St) -> %% Just ignore unknown requests. {noreply,St}. %% write_chars(Chars, State) -> %% {ok,State} | {error,Reason,State}. write_chars(Cs, #tcp_io{sock=S}=St) -> case gen_tcp:send(S, Cs) of ok -> {ok,St}; {error,Reason} -> {error,Reason,St} end. %% read_chars(State) -> %% {ok,Chars,State} | {error,Reason,State}. read_chars(#tcp_io{sock=S,ibuf=[]}=St) -> case gen_tcp:recv(S, 0) of {ok,Cs} -> {ok,Cs,St}; {error,closed} -> {ok,eof,St}; {error,Reason} -> {error,Reason,St} end; read_chars(#tcp_io{ibuf=Cs}=St) -> {ok,Cs,St#tcp_io{ibuf=[]}}. %% push_chars([Char], State) -> %% {ok,State} | {error,Reason,State}. push_chars(Cs, #tcp_io{ibuf=[]}=St) -> {ok,St#tcp_io{ibuf=Cs}}. From sekar@REDACTED Mon Jan 7 20:01:55 2002 From: sekar@REDACTED (sekar@REDACTED) Date: Mon, 7 Jan 2002 14:01:55 -0500 Subject: No subject Message-ID: <200201071901.g07J1tK20913@marple.lmc.cs.sunysb.edu> Senior Researcher Position Available We invite applications for a senior researcher position funded by a DoD University Research Initiative (URI) award in the area of Critical Infrastructure Protection and High Confidence Software (CIP/SW). This award is prestigious, with only 20 URI awards having been made nationwide. The position is available immediately for a period of upto two years at an annual salary between $65,000 and $75,000. The CIP/SW fellow will work with researchers from Stony Brook's Center for Cybersecurity, and especially the faculty from Secure and Reliable Systems Group and Formal Methods Group. The theme of our CIP/SW project is Model-Carrying Code (MCC), a new approach for ensuring security of mobile code. The MCC approach employs a combination of compile-time verification and runtime monitoring/enforcement techniques. Candidates must have a PhD in Computer Science or a closely related field. Masters Degree with exceptionally strong research experience will also be considered. Preference will be given to candidates specializing in one of the following areas: computer/network security, programming language/compilers, formal methods, operating systems and networks. Strong background in programming, and/or UNIX operating systems would be preferred. Applications should be forwarded to Prof. R. Sekar (sekar@REDACTED) Stony Brook is situated on Long Island, approximately 50 miles east of New York City. The University is two miles south of the Long Island Sound and 20 miles north of the Atlantic Ocean and picturesque Long Island beaches. The famous beaches and mansions of The Hamptons are about 40 miles to the southeast. For additional information, please visit our laboratory web pages at http://seclab.cs.sunysb.edu/seclab/onrsearch.html, http://seclab.cs.sunysb.edu and http://www.cs.sunysb.edu/~lmc. From hal@REDACTED Wed Jan 9 17:15:08 2002 From: hal@REDACTED (Hal Snyder) Date: 09 Jan 2002 10:15:08 -0600 Subject: report browser and error_logger Message-ID: <87y9j7o60j.fsf@gamera.vail> I think I am missing something obvious. The error_logger looks like a very useful thing for tracking events in OTP and in one's own applications. I think the way to use it is thus: - add the sasl app to your .rel file - tune error file settings by setting sasl_error_logger, error_logger_mf_dir, and so forth in your .config file - write messages with error_logger:error_msg/1 and error_logger:info_msg/1 - view results with rb: commands 1. Is the above typical in real OTP apps? 2. Is it common to use rb: interactively (not just start_log to a file) in a production environment? If so, how? Surely you don't leave an erlang shell open on a production node. (I suspect that most production nodes run erl .... -detached.) But, the interactive commands in rb: write to tty. So, in order to run them, you need an erlang shell on the node in question. Attaching from another node via Ctrl-g r [node] does not give you access to the interactive commands of rb:, which still want to go to the stdout of the original node. There is mention in the docs of copying log files from a running area to somewhere else and using an offline node (with error_logger configured to read/write in that copy area) to look at the copies. But that sounds very awkward. How do real OTP apps do this? Thanks! From etxuwig@REDACTED Wed Jan 9 17:48:25 2002 From: etxuwig@REDACTED (Ulf Wiger) Date: Wed, 9 Jan 2002 17:48:25 +0100 (MET) Subject: report browser and error_logger In-Reply-To: <87y9j7o60j.fsf@gamera.vail> Message-ID: On 9 Jan 2002, Hal Snyder wrote: >I think I am missing something obvious. I don't think so (at least I wouldn't call it obvious). ;) >The error_logger looks like a very useful thing for tracking >events in OTP and in one's own applications. > >I think the way to use it is thus: > > - add the sasl app to your .rel file > - tune error file settings by setting sasl_error_logger, > error_logger_mf_dir, and so forth in your .config file > - write messages with error_logger:error_msg/1 and > error_logger:info_msg/1 > - view results with rb: commands > >1. Is the above typical in real OTP apps? Yes, pretty much. >2. Is it common to use rb: interactively (not just start_log to >a file) in a production environment? If so, how? > >Surely you don't leave an erlang shell open on a production >node. (I suspect that most production nodes run erl .... >-detached.) We use start_erl and to_erl. http://www.erlang.org/doc/r8b/doc/embedded/embedded_solaris.html#1.4 If you start rb from your "remote shell" (the one you opened with Ctrl-G from another node), you should get printouts to the right shell. >But, the interactive commands in rb: write to tty. So, in order >to run them, you need an erlang shell on the node in question. Copy, or export, the sasl logs, and run rb against the copy in a fresh erlang node. /Uffe From Chandrashekhar.Mullaparthi@REDACTED Wed Jan 9 17:51:16 2002 From: Chandrashekhar.Mullaparthi@REDACTED (Chandrashekhar Mullaparthi) Date: Wed, 9 Jan 2002 16:51:16 -0000 Subject: report browser and error_logger Message-ID: <402DD461F109D411977E0008C791C31205E06399@imp02mbx.one2one.co.uk> Yes it is typical in real OTP apps. We use run_erl to start our production nodes - and if you need to connect to the shell - we use to_erl. We can then use all interactive commands of rb. rb can also redirect all output to a specified file. YOu can either specify options in rb:start/1 or use rb:start_log/1. We have another way of looking at the error logger reports on a live node. We have an application which installs a error_logger event handler so that it receives all error reports. Another process accepts connections on a socket and writes all error reports to that socket. So we just telnet to that port and we see all error reports. hope this helps. Chandru -----Original Message----- From: Hal Snyder [mailto:hal@REDACTED] Sent: 9 January 2002 16:15 To: erlang-questions@REDACTED Subject: report browser and error_logger I think I am missing something obvious. The error_logger looks like a very useful thing for tracking events in OTP and in one's own applications. I think the way to use it is thus: - add the sasl app to your .rel file - tune error file settings by setting sasl_error_logger, error_logger_mf_dir, and so forth in your .config file - write messages with error_logger:error_msg/1 and error_logger:info_msg/1 - view results with rb: commands 1. Is the above typical in real OTP apps? 2. Is it common to use rb: interactively (not just start_log to a file) in a production environment? If so, how? Surely you don't leave an erlang shell open on a production node. (I suspect that most production nodes run erl .... -detached.) But, the interactive commands in rb: write to tty. So, in order to run them, you need an erlang shell on the node in question. Attaching from another node via Ctrl-g r [node] does not give you access to the interactive commands of rb:, which still want to go to the stdout of the original node. There is mention in the docs of copying log files from a running area to somewhere else and using an offline node (with error_logger configured to read/write in that copy area) to look at the copies. But that sounds very awkward. How do real OTP apps do this? Thanks! NOTICE AND DISCLAIMER: This email (including attachments) is confidential. If you have received this email in error please notify the sender immediately and delete this email from your system without copying or disseminating it or placing any reliance upon its contents. We cannot accept liability for any breaches of confidence arising through use of email. Any opinions expressed in this email (including attachments) are those of the author and do not necessarily reflect our opinions. We will not accept responsibility for any commitments made by our employees outside the scope of our business. We do not warrant the accuracy or completeness of such information. From kent@REDACTED Wed Jan 9 20:49:08 2002 From: kent@REDACTED (Kent Boortz) Date: 09 Jan 2002 20:49:08 +0100 Subject: Daily R9 snapshots Message-ID: I don't know if you have noticed that there are daily R9 snapshots available from http://www.erlang.org/download/snapshots/ or if you are on the Ericsson intranet http://erlang.ericsson.se/opensource/download/snapshots/ We are working on finding a way to publish a notes file in some automatic way that describe the changes done in a snapshot. We also plan to include some sort of test summary. This is directly from our daily build and test process and may in the worst case not even build (99.999% of the time it will, but we can't promise it). Some features may have been added but not tested (one example is "to_erl" and friends for linux and freebsd). Some features may have been added but not documented or the other way around. kent From mbj@REDACTED Wed Jan 9 21:42:31 2002 From: mbj@REDACTED (Martin Bjorklund) Date: Wed, 09 Jan 2002 21:42:31 +0100 (CET) Subject: report browser and error_logger In-Reply-To: <87y9j7o60j.fsf@gamera.vail> References: <87y9j7o60j.fsf@gamera.vail> Message-ID: <20020109.214231.104031318.mbj@bluetail.com> Hal Snyder wrote: > I think I am missing something obvious. The error_logger looks like a > very useful thing for tracking events in OTP and in one's own > applications. > > I think the way to use it is thus: > > - add the sasl app to your .rel file > - tune error file settings by setting sasl_error_logger, > error_logger_mf_dir, and so forth in your .config file > - write messages with error_logger:error_msg/1 and > error_logger:info_msg/1 > - view results with rb: commands > > 1. Is the above typical in real OTP apps? Since I implemented this in OTP, I've done some rethinking - why bother to store the logs in binary format anyway? In most cases it's better to store the error log in plain text, but using a wrap log so the log won't grow. This is what we do in our systems. I've attached disk_log_h, a module which should have been implemented years ago. It's a gen_event handler for disk_log. This handler can be used e.g. for an error log, or whatever. This module could very well be part of OTP (it's intended to be). disk_log_h needs a small patch to disk_log.erl, also attached. Finally, I've included some code that uses this to format error_logger as plain text. /martin -------------- next part -------------- %%%---------------------------------------------------------------------- %%% File : disk_log_h.erl %%% Author : Martin Bjorklund %%% Purpose : gen_event handler for disk_log. The process which owns %%% the log is the gen_event process, thus no extra process %%% communcation overhead is involved. %%% The alternative is to let the gen_event process send the %%% message to a disk_log process, which then sends it to %%% disk. In this case, the disk_log process is avoided. %%% %%% This module is intended to replace log_mf_h.erl. %%% Created : 1 Dec 2000 by Martin Bjorklund %%%---------------------------------------------------------------------- -module(disk_log_h). -author('mbj@REDACTED'). -behaviour(gen_event). %% External exports -export([init/2, info/2]). %% gen_event callbacks -export([init/1, handle_event/2, handle_call/2, handle_info/2, terminate/2]). -record(state, {log, cnt, func}). -include_lib("kernel/src/disk_log.hrl"). %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- %%----------------------------------------------------------------- %% This module is intended to be used as a gen_event handler. Instead %% of duplicating the functions to gen_event (add_handler etc), it %% described here hoe to use these function with this module. %% %% The init function expects a list [Func, Opts], where: %% Func = fun(Event) -> false | binary() | [binary()] %% Opts = %% To add a hander to a gen_event process, call e.g.: %% gen_event:add_handler(EventMgr, disk_log_h, [Func, Opts]) %% %% No terminate arguments are needed. %% %% Here's a minimal but working example: %% %% tr_event(Event) -> %% list_to_binary(io_lib:format("tr_event: ~p\n", [Event])). %% %% start() -> %% Args = disk_log_h:init({?MODULE, tr_event}, [{name, tst}, %% {format, external}, %% {file, "/tmp/tst.log"}]), %% gen_event:add_handler(error_logger, {disk_log_h, tst}, Args). %% %% stop -> %% gen_event:delete_handler(error, logger, {disk_log_h, tst}). %% %%----------------------------------------------------------------- init(Func, DiskLogOpts) -> [Func, DiskLogOpts]. info(EventMgr, Handler) -> gen_event:call(EventMgr, Handler, info). %%%---------------------------------------------------------------------- %%% Callback functions from gen_event %%%---------------------------------------------------------------------- %%---------------------------------------------------------------------- %% Func: init/1 %% Returns: {ok, S} | %% Other %%---------------------------------------------------------------------- init([Func, Opts]) -> case disk_log:ll_open(Opts) of {ok, _, Log, Cnt} -> {ok, #state{log = Log, cnt = Cnt, func = Func}}; Error -> Error end. %%---------------------------------------------------------------------- %% Func: handle_event/2 %% Returns: {ok, S} | %% {swap_handler, Args1, S1, Mod2, Args2} | %% remove_handler %%---------------------------------------------------------------------- handle_event(Event, S) -> case (S#state.func)(Event) of false -> {ok, S}; Bin -> case disk_log:do_log(S#state.log, Bin) of {N, L1} when integer(N) -> {ok, S#state{cnt = S#state.cnt+N, log = L1}}; {error, {error, {full, _Name}}, L1, 0} -> {ok, S#state{log = L1}}; {error, Error, L1, N} -> Error; Error -> Error end end. %%---------------------------------------------------------------------- %% Func: handle_call/2 %% Returns: {ok, Reply, S} | %% {swap_handler, Reply, Args1, S1, Mod2, Args2} | %% {remove_handler, Reply} %%---------------------------------------------------------------------- handle_call(info, S) -> Reply = disk_log:do_info(S#state.log, S#state.cnt), {ok, Reply, S}. %%---------------------------------------------------------------------- %% Func: handle_info/2 %% Returns: {ok, S} | %% {swap_handler, Args1, S1, Mod2, Args2} | %% remove_handler %%---------------------------------------------------------------------- handle_info({emulator, GL, Chars}, S) -> %% this is very unfortunate... handle_event({emulator, GL, Chars}, S); handle_info(Info, S) -> {ok, S}. %%---------------------------------------------------------------------- %% Func: terminate/2 %% Purpose: Shutdown the server %% Returns: any %%---------------------------------------------------------------------- terminate(Arg, S) -> disk_log:ll_close(S#state.log). %%%---------------------------------------------------------------------- %%% Internal functions %%%---------------------------------------------------------------------- -------------- next part -------------- *** disk_log.erl Mon Oct 8 10:37:59 2001 --- /tmp/disk_log.erl Wed Jan 9 21:30:53 2002 *************** *** 37,42 **** --- 37,45 ---- %% To be used by wrap_log_reader only. -export([ichunk_end/2]). + %% To be used by disk_log_h only. + -export([ll_open/1, ll_close/1, do_log/2, do_info/2]). + %% To be used for debugging only: -export([pid2name/1]). *************** *** 64,69 **** --- 67,81 ---- open(A) -> disk_log_server:open(check_arg(A, #arg{options = A})). + ll_open(A) -> + case check_arg(A, #arg{options = A}) of + {ok, L} -> do_open(L); + Error -> Error + end. + + ll_close(Log) -> + close_disk_log2(Log). + log(Log, Term) -> req(Log, {log, term_to_binary(Term)}). -------------- next part -------------- %%%------------------------------------------------------------------- %%% File : logger.erl %%% Created : 9 Jan 2002 by Martin Bjorklund %%% Purpose : Simple module to show how disk_log_h can be used %%% to format error_logger as plain text to a wrap log. %%%------------------------------------------------------------------- -module(logger). -author('magnus@REDACTED'). -author('mbj@REDACTED'). -export([add_error_logger_mf/4, delete_error_logger_mf/0]). -export([form_all/1, form_no_progress/1]). %% Type = all | error add_error_logger_mf(File, MaxB, MaxF, Type) -> Opts = [{name, logger}, {file, File}, {type, wrap}, {format, external}, {size, {MaxB, MaxF}}], gen_event:add_handler(error_logger, {disk_log_h, logger}, disk_log_h:init(form_func(Type), Opts)). delete_error_logger_mf() -> gen_event:delete_handler(error_logger, {disk_log_h, logger}, stop). form_func(all) -> {logger, form_all}; form_func(_) -> {logger, form_no_progress}. form_all({Type, GL, Msg}) when node(GL) /= node() -> false; form_all(Event) -> Str = case Event of {error_report, _GL, {Pid, Type, Report}} -> [mk_hdr("ERROR REPORT", Type, Pid), io_lib:format("~p\n", [Report])]; {info_report, _GL, {Pid, Type, Report}} -> [mk_hdr("INFO REPORT", Type, Pid), io_lib:format("~p\n", [Report])]; {error, _GL, {Pid, Format, Args}} -> [mk_hdr("ERROR", undefined, Pid), io_lib:format(Format, Args)]; {info_msg, _GL, {Pid, Format, Args}} -> [mk_hdr("INFO MSG", undefined, Pid), io_lib:format(Format, Args)]; {info, _GL, {Pid, Term, _Empty}} -> [mk_hdr("INFO", undefined, Pid), io_lib:format("~p\n", [Term])]; {emulator, _GL, EStr} -> [mk_hdr("EMULATOR", undefined, undefined), EStr]; _ -> [mk_hdr("UNKNOWN", undefined, undefined), io_lib:format("~p\n", [Event])] end, list_to_binary([Str, "\n"]). mk_hdr(HStr, Type, Who) -> ["== ", t2s(erlang:localtime()), " == ", HStr, " - ", pstr(Type), " ", pstr(Who), "\n"]. pstr(undefined) -> ""; pstr(T) -> io_lib:format("~p", [T]). t2s({{Year,Month,Day},{Hour,Minute,Second}}) -> io_lib:format("~w-~s-~w::~2..0w:~2..0w:~2..0w", [Day,m2s(Month),Year,Hour,Minute,Second]). m2s(1) -> "Jan"; m2s(2) -> "Feb"; m2s(3) -> "Mar"; m2s(4) -> "Apr"; m2s(5) -> "May"; m2s(6) -> "Jun"; m2s(7) -> "Jul"; m2s(8) -> "Aug"; m2s(9) -> "Sep"; m2s(10) -> "Oct"; m2s(11) -> "Nov"; m2s(12) -> "Dec". form_no_progress({Type, GL, Msg}) when node(GL) /= node() -> false; form_no_progress({info_report, _, {_, progress, [{application,_}, {started_at, _}]}} = Event) -> form_all(Event); form_no_progress({info_report, _, {_, progress, _}}) -> false; form_no_progress(Event) -> form_all(Event). From martin@REDACTED Thu Jan 10 00:13:39 2002 From: martin@REDACTED (Martin J. Logan) Date: Wed, 09 Jan 2002 17:13:39 -0600 Subject: report browser and error_logger References: <402DD461F109D411977E0008C791C31205E06399@imp02mbx.one2one.co.uk> Message-ID: <3C3CCEA3.A7BE4E26@vailsys.com> Hello, I have a question about atoms. I realize that it is not a good idea to use list_to_atom to create atoms dynamically. I have a situation in which I need to communicate with a spawned process on a remote node. I can have thousands of these processes. The knee jerk solution that I came up with was to locally register each spawned process and then send across the net its registered name and node. The receiving process can then {name, node} ! message the remote process. Are atoms ever cleaned up? I thought that when a process dies that all atoms associated with it would be destroyed. I am getting atom_tab filled errors. Does anyone know how the atom table is dealt with and if atoms are around for the life of the node could someone suggest a good solution for talking to these individual processes across nodes? Thanks, Martin From matthias@REDACTED Thu Jan 10 00:31:01 2002 From: matthias@REDACTED (matthias@REDACTED) Date: Thu, 10 Jan 2002 00:31:01 +0100 Subject: erl -detached doesn't properly detach itself (or does it?) Message-ID: <15420.53941.535652.803441@corelatus.se> Hi, I was trying to get an erlang process to run as a daemon on my linux box using the '-detached' option at startup. This doesn't seem to work quite right---a background emulator is started, but it is killed whenever I log out of the system. >From the 'erl' manpage: -detached: Starts the Erlang system detached from the system console. Useful for running daemons and backgrounds processes. Looking at the source in erlexec.c, I see the fork() calls, but I don't see a setsid() call. My (rusty) recollections of unix process groups is that you need to call setsid() to make sure you don't eventually get a SIGHUP. Or is there a reason for not calling setsid()? Matthias From francesco@REDACTED Thu Jan 10 00:45:42 2002 From: francesco@REDACTED (Francesco Cesarini) Date: Wed, 09 Jan 2002 23:45:42 +0000 Subject: report browser and error_logger References: <402DD461F109D411977E0008C791C31205E06399@imp02mbx.one2one.co.uk> <3C3CCEA3.A7BE4E26@vailsys.com> Message-ID: <3C3CD626.7060502@erlang-consulting.com> Atoms are not garbage collected in the system, so for every atom you create, you will be allocating a few bytes that are never released. To solve your problem, the first solution that comes to my mind is an ets table where you you retrieve and store the pids of the dynamic processes, and if the traffic is not too intensive, a name server on every node. The only processes you should register are unique ones which handle a single task in the system. The rule of thumb is that if several processes run the same code, then they should not be registered. Regards, Francesco -- http://www.erlang-consulting.com Martin J. Logan wrote: >Hello, > I have a question about atoms. I realize that it is not a good idea to use >list_to_atom to create atoms dynamically. I have a situation in which I need to >communicate with a spawned process on a remote node. I can have thousands of >these processes. The knee jerk solution that I came up with was to locally >register each spawned process and then send across the net its registered name >and node. The receiving process can then {name, node} ! message the remote >process. Are atoms ever cleaned up? I thought that when a process dies that all >atoms associated with it would be destroyed. I am getting atom_tab filled >errors. Does anyone know how the atom table is dealt with and if atoms are >around for the life of the node could someone suggest a good solution for >talking to these individual processes across nodes? > > Thanks, > Martin > > > From dne@REDACTED Thu Jan 10 01:09:18 2002 From: dne@REDACTED (Daniel =?iso-8859-1?q?N=E9ri?=) Date: Thu, 10 Jan 2002 01:09:18 +0100 Subject: Daily R9 snapshots In-Reply-To: (Kent Boortz's message of "09 Jan 2002 20:49:08 +0100") References: Message-ID: <87ofk3jccx.fsf@nowhere.mayonnaise.net> Kent Boortz writes: > Some features may have been added but not tested (one example is > "to_erl" and friends for linux and freebsd). Great! The "Install" script seems to have been forgotten though (patch below). Best wishes, --Daniel -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: text/x-patch Size: 1330 bytes Desc: Install.src patch URL: -------------- next part -------------- -- Daniel Neri dne@REDACTED From kent@REDACTED Thu Jan 10 03:56:23 2002 From: kent@REDACTED (Kent Boortz) Date: 10 Jan 2002 03:56:23 +0100 Subject: Daily R9 snapshots In-Reply-To: dne@mayonnaise.net's message of "Thu, 10 Jan 2002 01:09:18 +0100" References: <87ofk3jccx.fsf@nowhere.mayonnaise.net> Message-ID: Thanks, I have included you patch. We probably need some sort of configure test to deside if we can build to_erl and run_erl, now the build will probably break on some Unix platforms. kent From eleberg@REDACTED Thu Jan 10 07:46:02 2002 From: eleberg@REDACTED (Bengt Kleberg) Date: Thu, 10 Jan 2002 07:46:02 +0100 (MET) Subject: erl -detached doesn't properly detach itself (or does it?) Message-ID: <200201100646.g0A6k2P09446@cbe.ericsson.se> > MIME-Version: 1.0 > Content-Transfer-Encoding: 7bit > Date: Thu, 10 Jan 2002 00:31:01 +0100 > From: matthias@REDACTED ...deleted > Looking at the source in erlexec.c, I see the fork() calls, but I > don't see a setsid() call. My (rusty) recollections of unix process > groups is that you need to call setsid() to make sure you don't > eventually get a SIGHUP. According to Stevens (Advanced UNIX Programing) it is even neccessary with a second fork() after the setsid(). Provided that you have an old system. Presumably a modern UNIX does not need either? bengt From daniel.neri@REDACTED Thu Jan 10 10:04:24 2002 From: daniel.neri@REDACTED (Daniel =?iso-8859-1?q?N=E9ri?=) Date: 10 Jan 2002 09:04:24 +0000 Subject: erl -detached doesn't properly detach itself (or does it?) In-Reply-To: <200201100646.g0A6k2P09446@cbe.ericsson.se> References: <200201100646.g0A6k2P09446@cbe.ericsson.se> Message-ID: Bengt Kleberg writes: > > Looking at the source in erlexec.c, I see the fork() calls, but I > > don't see a setsid() call. My (rusty) recollections of unix process > > groups is that you need to call setsid() to make sure you don't > > eventually get a SIGHUP. > > According to Stevens (Advanced UNIX Programing) it is even > neccessary with a second fork() after the setsid(). >From what I understand, POSIX/SUSv2/Stevens says that SIGHUP is sent to *stopped* processes when the process group is orphaned. On Linux, however, there's at least some evidence[*] of a different interpretation. On BSD derived systems, one might want to use the daemon(3) function instead of rolling your own. Regards, --Daniel [*] http://www.gnu.org/manual/glibc-2.2.3/html_node/libc_566.html -- Daniel Neri mailto:dn@REDACTED Sigicom AB, Sweden http://www.sigicom.com From etxuwig@REDACTED Thu Jan 10 10:47:06 2002 From: etxuwig@REDACTED (Ulf Wiger) Date: Thu, 10 Jan 2002 10:47:06 +0100 (MET) Subject: report browser and error_logger In-Reply-To: <3C3CD626.7060502@erlang-consulting.com> Message-ID: I agree with Francesco. Another thought is to use global. While it may not seem like an obvious choice, global does support process registration using any Erlang term (instead of just atoms), and the semantics of global:register_name() and global:send() are basically the same as for your preferred approach. I've used this on occasion in order to globally register process instances, using {ProcName, Node}. The feature I was after at the time was a global registry where I could easily find all instances of ProcName (via global:registered_names()). This saves you the trouble of implementing your own name server, and then monitoring processes to make sure that _your_ registry is properly "garbage collected". /Uffe On Wed, 9 Jan 2002, Francesco Cesarini wrote: >Atoms are not garbage collected in the system, so for every atom you >create, you will be allocating a few bytes that are never released. > >To solve your problem, the first solution that comes to my mind is an >ets table where you you retrieve and store the pids of the dynamic >processes, and if the traffic is not too intensive, a name server on >every node. > >The only processes you should register are unique ones which handle a >single task in the system. The rule of thumb is that if several >processes run the same code, then they should not be registered. > >Regards, >Francesco > From etxuwig@REDACTED Thu Jan 10 10:53:17 2002 From: etxuwig@REDACTED (Ulf Wiger) Date: Thu, 10 Jan 2002 10:53:17 +0100 (MET) Subject: erl -detached doesn't properly detach itself (or does it?) In-Reply-To: <15420.53941.535652.803441@corelatus.se> Message-ID: I'm to lazy to restart my PC in order to try this on Linux, but doesn't "nohup erl ... -detached" to the trick? It works on Solaris. /Uffe On Thu, 10 Jan 2002 matthias@REDACTED wrote: >Hi, > >I was trying to get an erlang process to run as a daemon on my linux >box using the '-detached' option at startup. This doesn't seem to >work quite right---a background emulator is started, but it is killed >whenever I log out of the system. > >From the 'erl' manpage: > > -detached: > Starts the Erlang system detached from the system > console. Useful for running daemons and backgrounds > processes. > >Looking at the source in erlexec.c, I see the fork() calls, but I >don't see a setsid() call. My (rusty) recollections of unix process >groups is that you need to call setsid() to make sure you don't >eventually get a SIGHUP. > >Or is there a reason for not calling setsid()? > >Matthias > From richardc@REDACTED Thu Jan 10 12:01:49 2002 From: richardc@REDACTED (Richard Carlsson) Date: Thu, 10 Jan 2002 12:01:49 +0100 (MET) Subject: report browser and error_logger In-Reply-To: Message-ID: On Thu, 10 Jan 2002, Ulf Wiger wrote: > I agree with Francesco. Another thought is to use global. While it > may not seem like an obvious choice, global does support process > registration using any Erlang term (instead of just atoms), and the > semantics of global:register_name() and global:send() are basically > the same as for your preferred approach. Just one thought: does anybody know how well the global name registry scales? Is it feasible to register thousands or tens of thousands of processes? How does it scale with the number of connected nodes? /Richard Richard Carlsson (richardc@REDACTED) (This space intentionally left blank.) E-mail: Richard.Carlsson@REDACTED WWW: http://www.csd.uu.se/~richardc/ From francesco@REDACTED Thu Jan 10 12:07:40 2002 From: francesco@REDACTED (Francesco Cesarini) Date: Thu, 10 Jan 2002 11:07:40 +0000 Subject: report browser and error_logger References: Message-ID: <3C3D75FC.9070502@erlang-consulting.com> That is the exact reason why I did not suggest global. Martin's application sounded like it was handling massive concurrency. Due to the atomic implications of registering a process on all nodes, it sounds like a rather expensive operation. Martin knew on what node the process was running on, so using a local name server, data duplication and global registering could be avoided (At the expense of having to handle the operations himself). The thought of tens of thousands of registered processes sends shivers down my spine.... I'll pass on that :-) Francesco -- http://www.erlang-consulting.com Richard Carlsson wrote: >On Thu, 10 Jan 2002, Ulf Wiger wrote: > >>I agree with Francesco. Another thought is to use global. While it >>may not seem like an obvious choice, global does support process >>registration using any Erlang term (instead of just atoms), and the >>semantics of global:register_name() and global:send() are basically >>the same as for your preferred approach. >> > >Just one thought: does anybody know how well the global name registry >scales? Is it feasible to register thousands or tens of thousands of >processes? How does it scale with the number of connected nodes? > > /Richard > > >Richard Carlsson (richardc@REDACTED) (This space intentionally left blank.) >E-mail: Richard.Carlsson@REDACTED WWW: http://www.csd.uu.se/~richardc/ > > > From etxuwig@REDACTED Thu Jan 10 13:07:03 2002 From: etxuwig@REDACTED (Ulf Wiger) Date: Thu, 10 Jan 2002 13:07:03 +0100 (MET) Subject: report browser and error_logger In-Reply-To: Message-ID: On Thu, 10 Jan 2002, Richard Carlsson wrote: >On Thu, 10 Jan 2002, Ulf Wiger wrote: > >> I agree with Francesco. Another thought is to use global. While it >> may not seem like an obvious choice, global does support process >> registration using any Erlang term (instead of just atoms), and the >> semantics of global:register_name() and global:send() are basically >> the same as for your preferred approach. > >Just one thought: does anybody know how well the global name >registry scales? Is it feasible to register thousands or tens >of thousands of processes? How does it scale with the number of >connected nodes? > > /Richard It does not scale very well with the number of connected nodes, particularly in regard to global name registration. If one were to use global:set_lock({Myname, self()}), it would scale much better, but then there is no provision for finding out the Pid of the process that holds the lock (with which one could mimic global:send(LockHolder, Msg). The problem lies in the backoff mechanism. Name registration always takes place using the global lock 'global'. Therefore, the risk of lock conflicts in a busy system is fairly large. /Uffe From eedtag@REDACTED Thu Jan 10 16:45:19 2002 From: eedtag@REDACTED (Tanja Godau) Date: Thu, 10 Jan 2002 16:45:19 +0100 (MET) Subject: HTTP1.1 Message-ID: <200201101545.QAA14998@granus41.eed.ericsson.se> G'day, I've been happily using the HTTP1.1 client from Johan Blom contained in the sowap application to PUT and GET images and text, and to POST data to a form. But have discovered that if I setup several PPP connections and attempt to PUT or GET large numbers of files, e.g. do a few hundred GETs or PUTs one after the other, then I eventually get the following error: ?error("Couldn't create TCP connection ~p",[Tag],tcp_connect), The tcp connection is opened with: gen_tcp:connect(Host,Port,TCPArgs) After this I am unable to create any new TCP connections, i.e. I can no longer do any http or ftp down- or uploads. I think the problem may be that I have reached the max. number of sockets I can open with Erlang. How many sockets can I open in Erlang? How can I check that the socket I have just used has been closed again properly or reset before I continue? Is there anything else new on the HTTP1.1 front? (I am working on a PC with RedHat Linux 7.0.) Thankyou Tanja Godau :-) From Chandrashekhar.Mullaparthi@REDACTED Thu Jan 10 17:05:47 2002 From: Chandrashekhar.Mullaparthi@REDACTED (Chandrashekhar Mullaparthi) Date: Thu, 10 Jan 2002 16:05:47 -0000 Subject: HTTP1.1 Message-ID: <402DD461F109D411977E0008C791C31205E0639D@imp02mbx.one2one.co.uk> On UNIX, generally there is a per process limit on the number of open files. Probably this is what is limiting you more than anything else. On Solaris I would do something like this: shutdown the erlang node In the UNIX shell type "ulimit -n" to see the current limit (which is usually 64) ulimit -n 256 (to set the limit to 256) Start the erlang node again. hope this helps. Chandru -----Original Message----- From: Tanja Godau [mailto:eedtag@REDACTED] Sent: 10 January 2002 15:45 To: erlang-questions@REDACTED Subject: HTTP1.1 G'day, I've been happily using the HTTP1.1 client from Johan Blom contained in the sowap application to PUT and GET images and text, and to POST data to a form. But have discovered that if I setup several PPP connections and attempt to PUT or GET large numbers of files, e.g. do a few hundred GETs or PUTs one after the other, then I eventually get the following error: ?error("Couldn't create TCP connection ~p",[Tag],tcp_connect), The tcp connection is opened with: gen_tcp:connect(Host,Port,TCPArgs) After this I am unable to create any new TCP connections, i.e. I can no longer do any http or ftp down- or uploads. I think the problem may be that I have reached the max. number of sockets I can open with Erlang. How many sockets can I open in Erlang? How can I check that the socket I have just used has been closed again properly or reset before I continue? Is there anything else new on the HTTP1.1 front? (I am working on a PC with RedHat Linux 7.0.) Thankyou Tanja Godau :-) NOTICE AND DISCLAIMER: This email (including attachments) is confidential. If you have received this email in error please notify the sender immediately and delete this email from your system without copying or disseminating it or placing any reliance upon its contents. We cannot accept liability for any breaches of confidence arising through use of email. Any opinions expressed in this email (including attachments) are those of the author and do not necessarily reflect our opinions. We will not accept responsibility for any commitments made by our employees outside the scope of our business. We do not warrant the accuracy or completeness of such information. From johan.blom@REDACTED Thu Jan 10 17:38:05 2002 From: johan.blom@REDACTED (Johan Blom) Date: 10 Jan 2002 17:38:05 +0100 Subject: HTTP1.1 In-Reply-To: <200201101545.QAA14998@granus41.eed.ericsson.se> References: <200201101545.QAA14998@granus41.eed.ericsson.se> Message-ID: <1010680686.1271.21.camel@localhost.localdomain> Hi Tanja, On Thu, 2002-01-10 at 16:45, Tanja Godau wrote: > G'day, > > I've been happily using the HTTP1.1 client from Johan Blom contained in the > sowap application to PUT and GET images and text, and to POST data to a form. > > But have discovered that if I setup several PPP connections and attempt to PUT > or GET large numbers of files, e.g. do a few hundred GETs or PUTs one after the > other, then I eventually get the following error: > > ?error("Couldn't create TCP connection ~p",[Tag],tcp_connect), > > The tcp connection is opened with: > > gen_tcp:connect(Host,Port,TCPArgs) > > After this I am unable to create any new TCP connections, i.e. I can no longer > do any http or ftp down- or uploads. > > I think the problem may be that I have reached the max. number of sockets I can > open with Erlang. How many sockets can I open in Erlang? Yes, you are right. I didn't close sockets properly... Don't know how many sockets (was it typically max 1024 in a Unix process?) > > How can I check that the socket I have just used has been closed again properly > or reset before I continue? A quick fix is to just add a gen_tcp:close(Socket) after a message has been read in properly. > > Is there anything else new on the HTTP1.1 front? Yes, I have rewritten the inets-3.0 server and integrated (and rewritten) the client into inets-3.0. Doing some final debugging, before release in this very moment... Johan Blom Mobile Arts From Erik.Johansson@REDACTED Fri Jan 11 14:09:12 2002 From: Erik.Johansson@REDACTED (Erik.Johansson) Date: Fri, 11 Jan 2002 14:09:12 +0100 Subject: Syntactic sugar poll Message-ID: <020c01c19aa1$2bcb23f0$980cee82@it.uu.se> I have a suggestion for a very small change that seems to arouse strong feelings. Since I am doing a lot of assembly hacking I often need to use hexadecimal constants. All my debuggers and C compilers write hexadecimal constants as 0xN, but in Erlang I have to write it as 16#N. There are two problems with this, I can not copy and paste hexadecimal numbers between Erlang and other applications, and it looks really ugly. Now, don't get me wrong the general base#number syntax is flexible and useful but would it not be nice to have 0xN as syntactic sugar for 16#N in Erlang. What do you think? Would it be nice to have this feature? Are there any reasons for not allowing this feature? I use it in the shell in my system (together with my fixes for printing hexadecimal numbers) but since it is not a part of standard Erlang I can't use it in Erlang code that I write (at least not in portable code ;) which is a shame. All that is need to get it to work is this little patch: ------------------------------------------------------------------- lib/stdlib/src/erl_scan.erl 505a506,512 + scan_after_int([$x|Cs], Ncs, Toks, SPos, CPos) -> + case list_to_integer(reverse(Ncs)) of + 0 -> + scan_based_int(Cs, 0, 16, Toks, SPos, CPos); + Base -> + scan_error({base,Base}, CPos) + end; ------------------------------------------------------------------- Please, support this bill today! /Erik -------------------------------------- N. Erik M. Johansson Studentv?gen 13:33 752 34 Uppsala (Sweden) happi@REDACTED Work: +46 - (0)18 - 4711 033 GSM : +46 - (0)70 - 631 42 59 Home: +46 - (0)18 - 51 13 29 http://www.csd.uu.se/~happi/ Eric Conspiracy Secret Laboratories -------------------------------------- I'm Happi, you should be happy. Praeterea censeo 0xCA scribere Erlang posse. From sword@REDACTED Fri Jan 11 14:17:09 2002 From: sword@REDACTED (sword@REDACTED) Date: Fri, 11 Jan 2002 19:17:09 +0600 Subject: Megaco/H.248 encoding comparison Message-ID: Gentlemen, your Megaco/H.248 comparison report looks very interested to me! Indeed, it seems your Erlang-based tool is very quick. However, before starting its learning and using we want to doubly check results that you've recieved with our BER encoder/decoder tool. We've downloaded Win32 version of Erlang/R8 tool but have a lot of difficulties with understanding how to use it for performance measuring. Could you please to send us a project which was used by you for measuring of performance of encoder/decoder? We will write an application of the same structure with our BER encoder/decoder and will compare results... Hopefully, finally it will be just an excellent promotion for your project. thank you in advance! Alex Sklyaroff, Novosoft Inc. From enano@REDACTED Fri Jan 11 19:55:58 2002 From: enano@REDACTED (Miguel Barreiro Paz) Date: Fri, 11 Jan 2002 19:55:58 +0100 (CET) Subject: Syntactic sugar poll In-Reply-To: <020c01c19aa1$2bcb23f0$980cee82@it.uu.se> Message-ID: Hi, > Since I am doing a lot of assembly hacking I often need to use > hexadecimal constants. All my debuggers and C compilers write > hexadecimal constants as 0xN, but in Erlang I have to write it as > 16#N. There are two problems with this, I can not copy and paste I for one would like the 0xN syntax, maybe just for the sake of old assembly tradition. On the other hand I'm very happy that Erlang keeps the needed features and (usually) drops what is superfluous (so we have .erl instead of .perl, you know); thus I would understand it if people felt this sugar unnecessary. Regards, Miguel From erik@REDACTED Fri Jan 11 20:05:56 2002 From: erik@REDACTED (Erik Pearson) Date: Fri, 11 Jan 2002 11:05:56 -0800 Subject: Moving mnesia schema to another node In-Reply-To: <402DD461F109D411977E0008C791C31205E0636F@IMP02MBX> References: <402DD461F109D411977E0008C791C31205E0636F@IMP02MBX> Message-ID: <5777750.1010747156@216-101-171-203.adaptations.com> Thanks for the pointer. I just returned from winter holiday and will apply this technique shortly. It seems like an awfully inefficient way of changing just the node for a table, especially if one is dealing with large tables. (Should there not be a simpler technique for moving disc based tables from one node to another? E.g. substitution of table attributes at either backup or restore (and a table creation option for restore)) Erik. --On Tuesday, December 25, 2001 9:17 AM +0000 Chandrashekhar Mullaparthi wrote: > Look in the Mnesia user guide in Section 6.9.1 > > The following example illustrates how mnesia:traverse_backup can be used > to rename a db_node in a backup file: > > change_node_name(Mod, From, To, Source, Target) -> > Switch = > fun(Node) when Node == From -> To; > (Node) when Node == To -> throw({error, already_exists}); > (Node) -> Node > end, > Convert = > fun({schema, db_nodes, Nodes}, Acc) -> > {[{schema, db_nodes, lists:map(Switch,Nodes)}], Acc}; > ({schema, version, Version}, Acc) -> > {[{schema, version, Version}], Acc}; > ({schema, cookie, Cookie}, Acc) -> > {[{schema, cookie, Cookie}], Acc}; > ({schema, Tab, CreateList}, Acc) -> > Keys = [ram_copies, disc_copies, disc_only_copies], > OptSwitch = > fun({Key, Val}) -> > case lists:member(Key, Keys) of > true -> {Key, lists:map(Switch, Val)}; > false-> {Key, Val} > end > end, > {[{schema, Tab, lists:map(OptSwitch, CreateList)}], Acc}; > (Other, Acc) -> > {[Other], Acc} > end, > mnesia:traverse_backup(Source, Mod, Target, Mod, Convert, switched). > > view(Source, Mod) -> > View = fun(Item, Acc) -> > io:format("~p.~n",[Item]), > {[Item], Acc + 1} > end, > mnesia:traverse_backup(Source, Mod, dummy, read_only, View, 0). > > cheers, > Chandru > >> -----Original Message----- >> From: Erik Pearson [mailto:erik@REDACTED] >> Sent: 25 December 2001 02:19 >> To: erlang-questions@REDACTED >> Subject: Moving mnesia schema to another node >> >> >> Hi, >> >> I need to move a mnesia database from one node to another, >> and haven't been >> able to figure out how. Mnesia is okay if you move it around >> on the same >> machine (different directories), but doesn't like to be moved >> to another >> machine -- (e.g. tar it up and untar it somehwere else) -- >> even if the >> database directory is accessed via a generic directory name >> through an >> explicit -mnesia dir 'dirname' or -config configfile. >> >> I've also tried restoring from a backup, but stopped that >> after it ate up >> all CPU on the server. I also tried using install_fallback, >> but mnesia >> complains with >> >> {"No disc resident schema on local node", [myoldnode]} >> >> The backup seems to keep a reference to the old node, and >> doens't like to >> be restored anywhere else... >> >> Does anyone know how to do a "redirected backup and restore" >> from one node >> to another? >> >> Thanks, >> >> Erik Pearson >> > > > > NOTICE AND DISCLAIMER: > This email (including attachments) is confidential. If you have received > this email in error please notify the sender immediately and delete this > email from your system without copying or disseminating it or placing any > reliance upon its contents. We cannot accept liability for any breaches > of confidence arising through use of email. Any opinions expressed in > this email (including attachments) are those of the author and do not > necessarily reflect our opinions. We will not accept responsibility for > any commitments made by our employees outside the scope of our business. > We do not warrant the accuracy or completeness of such information. > Erik Pearson @ Adaptations email : erik@REDACTED voice/fax : +1 510 527 5437 text page : page.erik@REDACTED From matthias@REDACTED Thu Jan 10 00:37:08 2002 From: matthias@REDACTED (matthias@REDACTED) Date: Thu, 10 Jan 2002 00:37:08 +0100 Subject: atom table overflow In-Reply-To: <3C3CCEA3.A7BE4E26@vailsys.com> References: <402DD461F109D411977E0008C791C31205E06399@imp02mbx.one2one.co.uk> <3C3CCEA3.A7BE4E26@vailsys.com> Message-ID: <15420.54308.727616.610309@corelatus.se> > I am getting atom_tab filled > errors. Does anyone know how the atom table is dealt with The last time I looked at this (probably in R6), the atom table was not cleaned up in any way, i.e. there is no garbage collection in the atom table. Matthias From svg@REDACTED Sun Jan 13 19:00:23 2002 From: svg@REDACTED (Vladimir Sekissov) Date: Sun, 13 Jan 2002 23:00:23 +0500 (YEKT) Subject: Avoid case nesting Message-ID: <20020113.230023.47713126.svg@surnet.ru> Good day, To avoid many nested cases I use following simple constract: case catch begin {ok, MgrPid} = start_link(), %if wrong we'll get badmatch here ... {ok, GoodResult} end of {'EXIT', {{badmatch, {error, Error}}, _}} -> {error, Error}; {'EXIT', {{badmatch, Error}, _}} -> {error, Error}; {'EXIT', Error} -> {error, Error}; {ok, Result} -> Result end. Is there better and more elegant approaches? Best Regards, Vladimir Sekissov From maurice@REDACTED Mon Jan 14 02:52:13 2002 From: maurice@REDACTED (Maurice Castro) Date: Mon, 14 Jan 2002 12:52:13 +1100 (EST) Subject: Syntactic sugar poll In-Reply-To: <020c01c19aa1$2bcb23f0$980cee82@it.uu.se> from "Erik.Johansson" at "Jan 11, 2002 02:09:12 pm" Message-ID: <200201140152.g0E1qDY08800@parallel.serc.rmit.edu.au> Vote NO! to adding 0x for hexadecimal constants. The case for leaving the language alone. In general I am against adding syntactic sugar to a language, in this case in particular I suspect that we might be on a slippery slope. Erlang has a well worked out consistent mechanism for handling constants with many bases. There is no need to extend the language to satisfy these programmers as they are free to pre-process their files to use their prefered convention. (eg. sed 's/0x/16#/g' file in this case) Furthermore, the case made for changing the language to include the 0x construct has the following additional problems: 1) We are giving a favored place to a particular assembler's convention. Assembler codes are far from standardised. Although GNU as borrowed C's convention other assemblers use other conventions. For example the very popular tasm used a number followed by an `h' is a heaxadecimal constant, `b' for binary, `o' for octal, `d' for decimal, or nothing use the radix defined in the code. 2) A better argument might be to adopt the C convention, however, if we are going to extend the language to embrace C's way of denoting a hexadecimal number we had best take the octal notation too ie 0x for hexadecimal 0 for octal. The octal extension may well break existing code. 3) Although embracing the 0x convention in the current popular compiler is simple, it may not be easy to implement it in other compilers (fortunately for me, ec -- my pet project -- would also be simple to modify to support the 0x convention) Please vote NO and save Erlang from the 0x convention. Written and presented by Maurice Castro for the NO case. From thomas.lindgren@REDACTED Mon Jan 14 10:14:08 2002 From: thomas.lindgren@REDACTED (Thomas Lindgren) Date: Mon, 14 Jan 2002 10:14:08 +0100 Subject: Avoid case nesting In-Reply-To: <20020113.230023.47713126.svg@surnet.ru> Message-ID: All I can think of is wrapping things up a bit more. case catch begin ... end of {ok, Res} -> Res; Err -> handle_error(Err) end return_error({'EXIT', ...}) -> %% and so on There is a common further difficulty, however: when you have a state that needs to be processed if there is an error, you also must ensure that the state is thrown with the rest of the error. (For the example above, if you want to log the current state record at an error inside the begin ... end, handle_error has to get that state record somehow.) The obvious solution to this "state visibility problem" is to write the log where the error occurs, which naturally leads to nested cases. Perhaps someone has a better solution? -- Thomas -----Original Message----- From: owner-erlang-questions@REDACTED [mailto:owner-erlang-questions@REDACTED]On Behalf Of Vladimir Sekissov Sent: den 13 januari 2002 19:00 To: erlang-questions@REDACTED Subject: Avoid case nesting Good day, To avoid many nested cases I use following simple constract: case catch begin {ok, MgrPid} = start_link(), %if wrong we'll get badmatch here ... {ok, GoodResult} end of {'EXIT', {{badmatch, {error, Error}}, _}} -> {error, Error}; {'EXIT', {{badmatch, Error}, _}} -> {error, Error}; {'EXIT', Error} -> {error, Error}; {ok, Result} -> Result end. Is there better and more elegant approaches? Best Regards, Vladimir Sekissov From klacke@REDACTED Mon Jan 14 10:36:52 2002 From: klacke@REDACTED (Klacke) Date: Mon, 14 Jan 2002 10:36:52 +0100 Subject: Syntactic sugar poll In-Reply-To: <020c01c19aa1$2bcb23f0$980cee82@it.uu.se>; from Erik.Johansson@csd.uu.se on Fri, Jan 11, 2002 at 02:09:12PM +0100 References: <020c01c19aa1$2bcb23f0$980cee82@it.uu.se> Message-ID: <20020114103652.A22763@bluetail.com> > What do you think? Would it be nice to have this feature? > Are there any reasons for not allowing this feature? I vote yes (If I have a vote) /klacke -- Claes Wikstrom -- Caps lock is nowhere and Alteon WebSystems -- everything is under control http://www.bluetail.com/~klacke cellphone: +46 70 2097763 From Erik.Johansson@REDACTED Mon Jan 14 11:34:12 2002 From: Erik.Johansson@REDACTED (Erik.Johansson) Date: Mon, 14 Jan 2002 11:34:12 +0100 Subject: Syntactic sugar poll References: <200201140152.g0E1qDY08800@parallel.serc.rmit.edu.au> Message-ID: <02fb01c19ce7$02f0d2c0$980cee82@it.uu.se> ----- Original Message ----- From: "Maurice Castro" > > Vote NO! to adding 0x for hexadecimal constants. > > The case for leaving the language alone. > > In general I am against adding syntactic sugar to a language, Why? > in this case in particular I suspect that we might be on a slippery slope. Erlang has always been on a slippery slope. ;) But the reason Erlang is so useful is that the development has been pragmatic, only if a feature is nice and useful it is added. (Such nice features as records and higher order functions have been added first as preprocessed syntactic sugar then later as "real" parts of the language.) This approach has lead to some strange quirks, and some zealous people shun the language because it is "warty and ugly", but on the other hand this approach has lead to a very useful language. > > Erlang has a well worked out consistent mechanism for handling > constants with many bases. There is no need to extend the language to > satisfy these programmers as they are free to pre-process their files > to use their prefered convention. (eg. sed 's/0x/16#/g' file in this > case) You know this is not true. Your sed approach would change my strings and atoms too. Also, I would have no guarantee that my private notation would be consistent with future versions of Erlang. How often do you write Erlang constants in another base than 2, 10 or 16? Base 10 is probably most common and has its own syntax (no 10# prefix needed), base 16 is probaly the second most used base closely followed by base 2, why not give one or both of these a special syntax? > Furthermore, the case made for changing the language to include the > 0x construct has the following additional problems: > > 1) We are giving a favored place to a particular assembler's convention. > Assembler codes are far from standardised. Although GNU as borrowed C's > convention other assemblers use other conventions. For example the > very popular tasm used a number followed by an `h' is a heaxadecimal > constant, `b' for binary, `o' for octal, `d' for decimal, or nothing > use the radix defined in the code. Yes, but I belive the 0x notaion is the one most used today (in general not only in assemblers). I am sure there are other (Pascal, Prolog, etc) programmers who would like another syntax, but I am also sure that they still would recognize 0xN as a hexadecimal number. (I am an old tasm hacker myself but I have not used tasm for 10 years, and I do not miss the base suffix asl long as I can have a base prefix.) > > 2) A better argument might be to adopt the C convention, however, if we > are going to extend the language to embrace C's way of denoting a > hexadecimal number we had best take the octal notation too ie 0x for > hexadecimal 0 for octal. The octal extension may well break existing > code. Yes, but lets be pragmatic, who needs an octal number today? ;) (Hex on the other hand is a convenient way of writing numbers reprecented by bytes.) > > 3) Although embracing the 0x convention in the current popular compiler > is simple, it may not be easy to implement it in other compilers > (fortunately for me, ec -- my pet project -- would also be simple to > modify to support the 0x convention) Since the compiler have to handle 16# anyway, I don't see how 0x would make things more complicated. > Please vote NO and save Erlang from the 0x convention. Please vote YES and give Erlang the freedom 0x convention. > > Written and presented by Maurice Castro for the NO case. /Erik -------------------------------------- N. Erik M. Johansson Studentv?gen 13:33 752 34 Uppsala (Sweden) happi@REDACTED Work: +46 - (0)18 - 4711 033 GSM : +46 - (0)70 - 631 42 59 Home: +46 - (0)18 - 51 13 29 http://www.csd.uu.se/~happi/ Eric Conspiracy Secret Laboratories -------------------------------------- I'm Happi, you should be happy. Praeterea censeo 0xCA scribere Erlang posse. From enano@REDACTED Mon Jan 14 11:32:08 2002 From: enano@REDACTED (Miguel Barreiro Paz) Date: Mon, 14 Jan 2002 11:32:08 +0100 (CET) Subject: Syntactic sugar poll In-Reply-To: <200201140152.g0E1qDY08800@parallel.serc.rmit.edu.au> Message-ID: Hi, > constants with many bases. There is no need to extend the language to > satisfy these programmers as they are free to pre-process their files > to use their prefered convention. (eg. sed 's/0x/16#/g' file in this So net:ping('mynode@REDACTED') would yield interesting results :) Regards, Miguel From etxuwig@REDACTED Mon Jan 14 18:00:54 2002 From: etxuwig@REDACTED (Ulf Wiger) Date: Mon, 14 Jan 2002 18:00:54 +0100 (MET) Subject: Moving mnesia schema to another node In-Reply-To: <5777750.1010747156@216-101-171-203.adaptations.com> Message-ID: On Fri, 11 Jan 2002, Erik Pearson wrote: >Thanks for the pointer. I just returned from winter holiday and will apply >this technique shortly. It seems like an awfully inefficient way of >changing just the node for a table, especially if one is dealing with large >tables. > >(Should there not be a simpler technique for moving disc based tables from >one node to another? E.g. substitution of table attributes at either backup >or restore (and a table creation option for restore)) > >Erik. In a running system, you'd simply call mnesia:delete_table_copy(...) / mnesia:add_table_copy(...). The technique of traversing the backup is rather a means to relocate the entire database. /Uffe From etxuwig@REDACTED Mon Jan 14 18:04:23 2002 From: etxuwig@REDACTED (Ulf Wiger) Date: Mon, 14 Jan 2002 18:04:23 +0100 (MET) Subject: atom table overflow In-Reply-To: <15420.54308.727616.610309@corelatus.se> Message-ID: On Thu, 10 Jan 2002 matthias@REDACTED wrote: > > I am getting atom_tab filled > > errors. Does anyone know how the atom table is dealt with > >The last time I looked at this (probably in R6), the atom table was >not cleaned up in any way, i.e. there is no garbage collection in the >atom table. > >Matthias That's true. In BEAM, the size of the atom table is basically limited by available memory. Furthermore, there is no way to explicitly remove atoms. Still, dynamically creating atoms is not necessarily ineherently bad, as long as the algorithm operates on a finite namespace. /Uffe From etxuwig@REDACTED Mon Jan 14 18:12:55 2002 From: etxuwig@REDACTED (Ulf Wiger) Date: Mon, 14 Jan 2002 18:12:55 +0100 (MET) Subject: Avoid case nesting In-Reply-To: <20020113.230023.47713126.svg@surnet.ru> Message-ID: I've done this type of thing myself, and think it's a good solution esp. for tools, where you want a top-level catch and "pretty-print" error messages. If all you want to do is nest case statements, you can do something like this: case {is_cold_outside(), have_warm_clothes_on()} of {true, false} -> freezing; {true, true} -> fairly_comfy; {false, true} -> sweating end. The compiler will not construct the tuple used in the case pattern. /Uffe On Sun, 13 Jan 2002, Vladimir Sekissov wrote: >Good day, > >To avoid many nested cases I use following simple constract: > >case catch > begin > {ok, MgrPid} = start_link(), %if wrong we'll get badmatch here > ... > {ok, GoodResult} > end of > {'EXIT', {{badmatch, {error, Error}}, _}} -> > {error, Error}; > {'EXIT', {{badmatch, Error}, _}} -> > {error, Error}; > {'EXIT', Error} -> > {error, Error}; > {ok, Result} -> > Result >end. > >Is there better and more elegant approaches? > >Best Regards, > >Vladimir Sekissov > From erik@REDACTED Mon Jan 14 19:12:20 2002 From: erik@REDACTED (Erik Pearson) Date: Mon, 14 Jan 2002 10:12:20 -0800 Subject: Moving mnesia schema to another node In-Reply-To: References: Message-ID: <21174769.1011003140@216-101-171-203.adaptations.com> Doesn't this imply that the node that the table is being moved to is accessible from the node that the table currently exists on? In any case, I was being imprecise. I was just noting that a simple method of copying individual tables, a database, or a portion of a database from one node to another would be convenient. E.g. in a relational db like DB2, you can backup an active database, and restore it to another maching, disk, etc., or you can export an individual table from one database and import it into another. Perhaps my expectations are different because I'm not really using Erlang in its classic mode, but rather mostly for standalone applications. In my usage, it is common to develop an application on one machine (node) and then deploy on another, then make changes to the development, them update the production version, and so on. Normally the production version is not active, but only run periodically. In that usage model, it makes a lot of sense to make moving tables or entire databases as easy as moving source code files. Erik. --On Monday, January 14, 2002 6:00 PM +0100 Ulf Wiger wrote: > On Fri, 11 Jan 2002, Erik Pearson wrote: > >> Thanks for the pointer. I just returned from winter holiday and will >> apply this technique shortly. It seems like an awfully inefficient way of >> changing just the node for a table, especially if one is dealing with >> large tables. >> >> (Should there not be a simpler technique for moving disc based tables >> from one node to another? E.g. substitution of table attributes at >> either backup or restore (and a table creation option for restore)) >> >> Erik. > > In a running system, you'd simply call > mnesia:delete_table_copy(...) / mnesia:add_table_copy(...). The > technique of traversing the backup is rather a means to relocate > the entire database. > > /Uffe > Erik Pearson @ Adaptations email : erik@REDACTED voice/fax : +1 510 527 5437 text page : page.erik@REDACTED From etxuwig@REDACTED Mon Jan 14 19:22:48 2002 From: etxuwig@REDACTED (Ulf Wiger) Date: Mon, 14 Jan 2002 19:22:48 +0100 (MET) Subject: Moving mnesia schema to another node In-Reply-To: <21174769.1011003140@216-101-171-203.adaptations.com> Message-ID: On Mon, 14 Jan 2002, Erik Pearson wrote: >Doesn't this imply that the node that the table is being moved to is >accessible from the node that the table currently exists on? Yes, it does. Mnesia is a bit unusual in that it provides a lot of nice functions for dynamically reconfiguring and transforming the database in a running system, while being quite weak on offline configuration (compared to traditional RDBMSs). Hopefully, more offline tools will emerge as Mnesia makes it into other types of application. /Uffe From francesco@REDACTED Mon Jan 14 21:37:07 2002 From: francesco@REDACTED (Francesco Cesarini) Date: Mon, 14 Jan 2002 20:37:07 +0000 Subject: Syntactic sugar poll References: <200201140152.g0E1qDY08800@parallel.serc.rmit.edu.au> <02fb01c19ce7$02f0d2c0$980cee82@it.uu.se> Message-ID: <3C434173.2070106@erlang-consulting.com> If I have a vote and our most honorable jury will consider it, it is NO. Since I started using Erlang in 1993, more and more additions have come along making what at first was a simple and straight forward language more complex, in some cases inconsistent, and harder to understand. You were once given simple operations and if you needed more complex ones, you could use the simple constructs to build the complex ones. (for example, making synchronous messages through asynchronous message passing). With Erik's notation, we would be introducing two notations for doing the same thing. Not pretty. List comprehensions, bit syntax, funs/higher order functions, more Bifs, etc. etc. All of these constructs, even if powerful, have added a factor of complexity which scares and intimidates less experienced users and non programmers using the language. (oh no, here he goes again and defends his poor students :-) Sometimes, the new constructs do not follow the existing semantics of the language introducing even more special cases (Pattern matching of bin length's in function heads or shadowing of bound variables in funs as an example)... Or the differences between List comprehensions and Mnemosyne... Or even worse, notations that do not compile as combinations of characters and spaces can be interpreted differently by the parser (=<< in bit syntax must for example be written as = << otherwise the parser interprets it as =< <). To avoid making language more complex and avoid risking inserting more inconsistencies or ugly semantics, any extensions added should be a real necessity and kept a bare minimum. As the # notation exists today (Even if some people find it ugly or if it does not conform to any standard), I would rather stick to that. I rest my case and point out that all my views are not necessarily those of my employer :-) Francesco -- http://www.erlang-consulting.com Erik.Johansson wrote: >----- Original Message ----- >From: "Maurice Castro" > >>Vote NO! to adding 0x for hexadecimal constants. >> >>The case for leaving the language alone. >> >>In general I am against adding syntactic sugar to a language, >> > >Why? > >>in this case in particular I suspect that we might be on a slippery slope. >> > >Erlang has always been on a slippery slope. ;) >But the reason Erlang is so useful is that the development has been pragmatic, >only if a feature is nice and useful it is added. (Such nice features as records and >higher order functions have been added first as preprocessed syntactic sugar >then later as "real" parts of the language.) This approach has lead to some strange >quirks, and some zealous people shun the language because it is "warty and ugly", >but on the other hand this approach has lead to a very useful language. > >>Erlang has a well worked out consistent mechanism for handling >>constants with many bases. There is no need to extend the language to >>satisfy these programmers as they are free to pre-process their files >>to use their prefered convention. (eg. sed 's/0x/16#/g' file in this >>case) >> > >You know this is not true. Your sed approach would change my strings and >atoms too. Also, I would have no guarantee that my private notation would >be consistent with future versions of Erlang. > >How often do you write Erlang constants in another base than 2, 10 or 16? >Base 10 is probably most common and has its own syntax (no 10# prefix >needed), base 16 is probaly the second most used base closely followed by >base 2, why not give one or both of these a special syntax? > >>Furthermore, the case made for changing the language to include the >>0x construct has the following additional problems: >> >>1) We are giving a favored place to a particular assembler's convention. >>Assembler codes are far from standardised. Although GNU as borrowed C's >>convention other assemblers use other conventions. For example the >>very popular tasm used a number followed by an `h' is a heaxadecimal >>constant, `b' for binary, `o' for octal, `d' for decimal, or nothing >>use the radix defined in the code. >> > >Yes, but I belive the 0x notaion is the one most used today (in general not only >in assemblers). I am sure there are other (Pascal, Prolog, etc) programmers >who would like another syntax, but I am also sure that they still would recognize >0xN as a hexadecimal number. > >(I am an old tasm hacker myself but I have not used tasm for 10 years, and I do >not miss the base suffix asl long as I can have a base prefix.) > >>2) A better argument might be to adopt the C convention, however, if we >>are going to extend the language to embrace C's way of denoting a >>hexadecimal number we had best take the octal notation too ie 0x for >>hexadecimal 0 for octal. The octal extension may well break existing >>code. >> > >Yes, but lets be pragmatic, who needs an octal number today? ;) >(Hex on the other hand is a convenient way of writing numbers reprecented >by bytes.) > >>3) Although embracing the 0x convention in the current popular compiler >>is simple, it may not be easy to implement it in other compilers >>(fortunately for me, ec -- my pet project -- would also be simple to >>modify to support the 0x convention) >> > >Since the compiler have to handle 16# anyway, I don't see how 0x would >make things more complicated. > > >>Please vote NO and save Erlang from the 0x convention. >> > >Please vote YES and give Erlang the freedom 0x convention. > >>Written and presented by Maurice Castro for the NO case. >> > >/Erik >-------------------------------------- > N. Erik M. Johansson > Studentv?gen 13:33 > 752 34 Uppsala (Sweden) > happi@REDACTED > Work: +46 - (0)18 - 4711 033 > GSM : +46 - (0)70 - 631 42 59 > Home: +46 - (0)18 - 51 13 29 > http://www.csd.uu.se/~happi/ > Eric Conspiracy Secret Laboratories >-------------------------------------- >I'm Happi, you should be happy. >Praeterea censeo 0xCA scribere Erlang posse. > > > > From maurice@REDACTED Tue Jan 15 01:54:22 2002 From: maurice@REDACTED (Maurice Castro) Date: Tue, 15 Jan 2002 11:54:22 +1100 (EST) Subject: Syntactic sugar poll In-Reply-To: from Miguel Barreiro Paz at "Jan 14, 2002 11:32:08 am" Message-ID: <200201150054.g0F0sME18468@parallel.serc.rmit.edu.au> > > > Hi, > > > constants with many bases. There is no need to extend the language to > > satisfy these programmers as they are free to pre-process their files > > to use their prefered convention. (eg. sed 's/0x/16#/g' file in this > > So net:ping('mynode@REDACTED') would yield interesting results :) The trouble with simple examples is that they often overlook inconvenient complexities in order to maintain brevity. When writing the example I was aware of the atom, string and comment deficiencies that would result. Here are 2 solutions: 1) The script as provided can be used without change if programmers refrain from using 0x other than for hexadecimal ... very few programs will fail 2) A lex based preprocessor (attached) should handle all the cases mentioned which are also valid Erlang programs. Lex was chosen as a compact representation. The key issue is do you extend a language, increasing maintenance costs, and education costs for all, when those who have a specific need have the option of handling the problem themselves with preprocessing or metaprogramming. Maurice Castro -------------- next part -------------- %{ #include %} %x STRING %x ATOM %x COMMENT %% ' {BEGIN ATOM; ECHO;} ' {BEGIN INITIAL; ECHO;} \" {BEGIN STRING; ECHO;} \" {BEGIN INITIAL; ECHO;} % {BEGIN COMMENT; ECHO;} .*$ {BEGIN INITIAL; ECHO;} 0x {printf("16#");} %% int main(int argc, char *argv[]) { ++argv, --argc; /* skip over program name */ if (argc > 0) yyin = fopen(argv[0], "r"); else yyin = stdin; yylex(); } From etxhste@REDACTED Tue Jan 15 13:37:45 2002 From: etxhste@REDACTED (Hakan Stenholm) Date: Tue, 15 Jan 2002 13:37:45 +0100 (MET) Subject: Compiler warnings Message-ID: <200201151237.g0FCbjP13026@cbe.ericsson.se> I spent last week hunting stupid io_lib:format/2 and io:format/2 related bugs in the AXD301 code, the bugs where very simple - there was a missmatch between the number of arguments specified in the formating string and the number of parameters supplied in the parameter list e.g. io:format("~p ~p", [1]). The current io code generates exit signals when this ocures, which in itself is good, as we get to know that things are wrong, the problem is that I had to restart the simulated AXD301 enviroment each time I found such an error - this takes a lot of time, so I would like to propouse that the compiler should check for these kind of missmatches. There are several advantages to this: * the fault is caught earlier, which means it will take less time to test and fix the error * its easy to get inconsistency in the format string compared to the parameter list if io code is updated or 'copy & paste' is done Notes: * we should probably not issue a error but rather a warning about strange looking code, othervise we would have to be able to verify things like: f(Args) -> io:format("~p ~p ~p",Args). or ... Args = [1,2,3,4], io:format("~p~p~p~p",Args), ... From per@REDACTED Wed Jan 16 18:06:00 2002 From: per@REDACTED (Per Bergqvist) Date: Wed, 16 Jan 2002 18:06:00 +0100 Subject: ic bug ... Message-ID: <200201161706.g0GH62p14834@raven.levonline.com> Hi, there is a bit of "not so very forward compatible" code in ic. If gcc is used as preprocessor command (as mnesia session do) by ic, icpreproc.erl will check if the output begins with the string "# 1" as then treats this as an indication of succesful preprocessing. However, gcc 3.0 (and probably earlier versions as well) will generate "# " in this case. My quick fix is to replace the line : [$#, $ , $1 | Rest] -> % Ok output with: [$#, $ , C | Rest] when integer(C),C>$0,C=<$9 -> % Ok output A better and more future proof solution would be to actually check the return status from the command ;-). (I know you can't get it from os:cmd but the needed underlying mechanisms are present so we just need a "os:ext_cmd" that gives you return status as well.) The only user of this alternative preprocessor is mnesia_session. I am a bit puzzled that nobody detected this bug earlier. Are there any users of mnesia_session out there ? ========================================================= Per Bergqvist Synapse Systems AB Phone: +46 709 686 685 Email: per@REDACTED From marco.comini@REDACTED Wed Jan 16 18:58:02 2002 From: marco.comini@REDACTED (Marco Comini) Date: Wed, 16 Jan 2002 18:58:02 +0100 Subject: [E-CFP] WFLP2002 - Preliminary Call for Papers Message-ID: =============================================================================== CALL FOR PAPERS 11th International Workshop on Functional and (Constraint) Logic Programming Grado, Italy June 20 - 22, 2002 =============================================================================== GENERAL The international workshop on functional and (constraint) logic programming WFLP 2002 aims to bring together researchers interested in functional programming, (constraint) logic programming, as well as their integration. Recent edition of the workshop have been held in Kiel (Germany), Benicassim (Spain), Grenoble (France), Bad Honnef (Germany). This workshop aims to promote the cross-fertilizing exchange of ideas and experiences among researches and students from the different communities interested in the foundations, applications, software engineering techniques and combinations of high-level, declarative (constraint) programming languages and related areas. The technical program of the workshop will include invited talks, presentations of refereed papers and demo presentations. The WWW page of the workshop is: http://www.dimi.uniud.it/~wflp2002/ ------------------------------------------------------------------------------- TOPICS The topics of interest include (but are not limited to): * Functional programming * Logic programming * Constraint programming * Deductive databases * Extensions of declarative languages * Multi-paradigm declarative programming * Foundations, semantics, non-monotonic reasoning, dynamics * Parallelism, concurrency and narrowing * Program analysis, abstract interpretation * Program transformation, partial evaluation, meta-programming * Specification, verification, declarative debugging * Knowledge representation, machine learning * Declarative programming and software engineering * Implementation of declarative languages * Advanced programming environments and tools * Applications The primary focus is on new and original research results but submissions describing innovative products, prototypes under development or interesting experiments (e.g., benchmarks) are also encouraged. ------------------------------------------------------------------------------- IMPORTANT DATES Submission of papers: March 20, 2002 Notification of acceptance: April 28, 2002 Camera-ready papers: May 15, 2002 Workshop: June 20 - 22 , 2002 ------------------------------------------------------------------------------- SUBMISSION Authors are invited to submit an extended abstract (no longer than 10 pages including figures and references) or a system description (no longer than 3 pages) in postscript format (11pt) via email to wflp2002@REDACTED before March 20, 2002. Submissions should include the title, authors' names, affiliations, addresses, and e-mail. The proceedings with the full versions of all accepted contributions (no longer than 15 pages for regular contributions and 3 pages for system descriptions) will be published as a Technical Report of the University of Udine. A selection of the accepted papers will be considered for publication in the Electronic Proceedings of Theoretical Computer Science (Elsevier) after the workshop. ------------------------------------------------------------------------------- BEST NEWCOMER AWARD 0An award will be given to the best paper exclusively written by one or several young researchers who have not yet obtained their PhD degrees. Papers written in this category should be clearly marked "Student papers" in the submission. ------------------------------------------------------------------------------- PROGRAM The workshop will be a 3-day event including presentations of the accepted papers, system demos, and 2 INVITED TALKS (to be announced) ------------------------------------------------------------------------------- LOCATION WFLP 2002 will take place in Grado, Italy. Grado is an island located on the Adriatic coast in a beautiful lagoon. It is famous for its attractive beaches, for its Roman history, and for the pleasant middleuropean atmosphere. Venezia is 100 km away and Trieste is 60 km away. More details about the accommodation, traveling information, etc., will be available at the WFLP 2002 WWW page at http://www.dimi.uniud.it/~wflp2002/ ------------------------------------------------------------------------------- CONTACT WFLP 2002 Moreno Falaschi Dipartimento di Matematica e Informatica Universit? degli Studi di Udine Via delle Scienze, 206 33100 UDINE, Italy Phone: +39-0432-55-8472 or -8400 (Secr.) Fax: +39-0432-55-8499 Email: wflp2002@REDACTED WWW: http://www.dimi.uniud.it/~wflp2002/ ------------------------------------------------------------------------------- PROGRAM COMMITTEE Maria Alpuente (Technical University of Valencia) Sergio Antoy (Portland State University) Manuel Chakravarty (University of New South Wales, Sidney) Rachid Echahed (IMAG, Grenoble) Francois Fages (INRIA Rocquencourt) Moreno Falaschi (Univ. Udine, chair) Thom Fruewirth (LMU Munich) Robert Gl?ck (Waseda Univ., Japan and DIKU, Denmark) Michael Hanus (CAU Kiel) Tetsuo Ida (University of Tsukuba) Helene Kirchner (Univ. Nancy) Herbert Kuchen (Univ. Muenster) Michael Maher (Loyola University Chicago) Juan Jose Moreno Navarro (UP Madrid) Ernesto Pimentel (Univ. Malaga) Mario Rodriguez-Artalejo (UC Madrid) ------------------------------------------------------------------------------- LOCAL ORGANIZING COMMITTEE Gianluca Amato Demis Ballis Marco Comini Luca Di Gaspero Agostino Dovier Moreno Falaschi Alicia Villanueva ------------------------------------------------------------------------------- -------------- next part -------------- An HTML attachment was scrubbed... URL: From kent@REDACTED Wed Jan 16 19:14:55 2002 From: kent@REDACTED (Kent Boortz) Date: 16 Jan 2002 19:14:55 +0100 Subject: ic bug ... In-Reply-To: Per Bergqvist's message of "Wed, 16 Jan 2002 18:06:00 +0100" References: <200201161706.g0GH62p14834@raven.levonline.com> Message-ID: > A better and more future proof solution would be to actually check the > return status from the command ;-). > > (I know you can't get it from os:cmd but the needed underlying > mechanisms are present so we just need a > "os:ext_cmd" that gives you return status as well.) > > The only user of this alternative preprocessor is mnesia_session. > > I am a bit puzzled that nobody detected this bug earlier. Are there > any users of mnesia_session out there ? Thank you for finding the cause of this problem. We did detect that the preprocessor didn't work with gcc 3.0 in internal testing. We are (slowly) reviewing the IC application so input about other problems with IC and suggestions for improvements are welcome, kent From comini@REDACTED Wed Jan 16 19:40:41 2002 From: comini@REDACTED (Marco Comini) Date: Wed, 16 Jan 2002 19:40:41 +0100 Subject: [E-CFP] WFLP2002 - Preliminary Call for Papers Message-ID: =============================================================================== CALL FOR PAPERS 11th International Workshop on Functional and (Constraint) Logic Programming Grado, Italy June 20 - 22, 2002 =============================================================================== GENERAL The international workshop on functional and (constraint) logic programming WFLP 2002 aims to bring together researchers interested in functional programming, (constraint) logic programming, as well as their integration. Recent edition of the workshop have been held in Kiel (Germany), Benicassim (Spain), Grenoble (France), Bad Honnef (Germany). This workshop aims to promote the cross-fertilizing exchange of ideas and experiences among researches and students from the different communities interested in the foundations, applications, software engineering techniques and combinations of high-level, declarative (constraint) programming languages and related areas. The technical program of the workshop will include invited talks, presentations of refereed papers and demo presentations. The WWW page of the workshop is: http://www.dimi.uniud.it/~wflp2002/ ------------------------------------------------------------------------------- TOPICS The topics of interest include (but are not limited to): * Functional programming * Logic programming * Constraint programming * Deductive databases * Extensions of declarative languages * Multi-paradigm declarative programming * Foundations, semantics, non-monotonic reasoning, dynamics * Parallelism, concurrency and narrowing * Program analysis, abstract interpretation * Program transformation, partial evaluation, meta-programming * Specification, verification, declarative debugging * Knowledge representation, machine learning * Declarative programming and software engineering * Implementation of declarative languages * Advanced programming environments and tools * Applications The primary focus is on new and original research results but submissions describing innovative products, prototypes under development or interesting experiments (e.g., benchmarks) are also encouraged. ------------------------------------------------------------------------------- IMPORTANT DATES Submission of papers: March 20, 2002 Notification of acceptance: April 28, 2002 Camera-ready papers: May 15, 2002 Workshop: June 20 - 22 , 2002 ------------------------------------------------------------------------------- SUBMISSION Authors are invited to submit an extended abstract (no longer than 10 pages including figures and references) or a system description (no longer than 3 pages) in postscript format (11pt) via email to wflp2002@REDACTED before March 20, 2002. Submissions should include the title, authors' names, affiliations, addresses, and e-mail. The proceedings with the full versions of all accepted contributions (no longer than 15 pages for regular contributions and 3 pages for system descriptions) will be published as a Technical Report of the University of Udine. A selection of the accepted papers will be considered for publication in the Electronic Proceedings of Theoretical Computer Science (Elsevier) after the workshop. ------------------------------------------------------------------------------- BEST NEWCOMER AWARD 0An award will be given to the best paper exclusively written by one or several young researchers who have not yet obtained their PhD degrees. Papers written in this category should be clearly marked "Student papers" in the submission. ------------------------------------------------------------------------------- PROGRAM The workshop will be a 3-day event including presentations of the accepted papers, system demos, and 2 INVITED TALKS (to be announced) ------------------------------------------------------------------------------- LOCATION WFLP 2002 will take place in Grado, Italy. Grado is an island located on the Adriatic coast in a beautiful lagoon. It is famous for its attractive beaches, for its Roman history, and for the pleasant middleuropean atmosphere. Venezia is 100 km away and Trieste is 60 km away. More details about the accommodation, traveling information, etc., will be available at the WFLP 2002 WWW page at http://www.dimi.uniud.it/~wflp2002/ ------------------------------------------------------------------------------- CONTACT WFLP 2002 Moreno Falaschi Dipartimento di Matematica e Informatica Universit? degli Studi di Udine Via delle Scienze, 206 33100 UDINE, Italy Phone: +39-0432-55-8472 or -8400 (Secr.) Fax: +39-0432-55-8499 Email: wflp2002@REDACTED WWW: http://www.dimi.uniud.it/~wflp2002/ ------------------------------------------------------------------------------- PROGRAM COMMITTEE Maria Alpuente (Technical University of Valencia) Sergio Antoy (Portland State University) Manuel Chakravarty (University of New South Wales, Sidney) Rachid Echahed (IMAG, Grenoble) Francois Fages (INRIA Rocquencourt) Moreno Falaschi (Univ. Udine, chair) Thom Fruewirth (LMU Munich) Robert Gl?ck (Waseda Univ., Japan and DIKU, Denmark) Michael Hanus (CAU Kiel) Tetsuo Ida (University of Tsukuba) Helene Kirchner (Univ. Nancy) Herbert Kuchen (Univ. Muenster) Michael Maher (Loyola University Chicago) Juan Jose Moreno Navarro (UP Madrid) Ernesto Pimentel (Univ. Malaga) Mario Rodriguez-Artalejo (UC Madrid) ------------------------------------------------------------------------------- LOCAL ORGANIZING COMMITTEE Gianluca Amato Demis Ballis Marco Comini Luca Di Gaspero Agostino Dovier Moreno Falaschi Alicia Villanueva ------------------------------------------------------------------------------- -------------- next part -------------- An HTML attachment was scrubbed... URL: From shreyas@REDACTED Thu Jan 17 11:01:04 2002 From: shreyas@REDACTED (Shreyas Gune) Date: Thu, 17 Jan 2002 15:31:04 +0530 Subject: Building a simple application Message-ID: <02ce01c19f3d$ec68ff10$5a01a8c0@shreyas> Hi, I have downloaded the Win32 version of Erlang/R8 to see if it can help us in our project, but I am having problems building a simple application. Is there a URL or a sample file that you can provide me that shows how to build a simple application? -Shreyas -------------- next part -------------- An HTML attachment was scrubbed... URL: From vladdu@REDACTED Thu Jan 17 12:42:19 2002 From: vladdu@REDACTED (Vlad Dumitrescu) Date: Thu, 17 Jan 2002 12:42:19 +0100 Subject: Sharing data in a data structure Message-ID: Hi folks! I just begun a project where the main data structure is a graph that shares a lot of data across branches and also with other graphs. Since we have no pointers here :-) the simplest alternative I came up with is to use indexes in a list or table instead. But I am a little worried because there will be a lot of searching when traversing the structure... My question is: is there another way to do it? Maybe a different paradigm may be used, but myself I cannot escape from this one... Duplicating the data is not acceptable, because it is necessary that a change in one place will be reflected everywhere. And it would also result in a humungous amount of data. Thank you in advance. Regards, Vlad _________________________________________________________________ MSN Photos ?r det enklaste s?ttet att dela ut?och skriva ut foton: http://photos.msn.se/Support/WorldWide.aspx From francesco@REDACTED Thu Jan 17 12:47:30 2002 From: francesco@REDACTED (Francesco Cesarini) Date: Thu, 17 Jan 2002 11:47:30 +0000 Subject: Building a simple application References: <02ce01c19f3d$ec68ff10$5a01a8c0@shreyas> Message-ID: <3C46B9D2.1040702@erlang-consulting.com> There are many examples and samples of applications in the Erlang Contributions section of the Open Directory project at http://dmoz.org/Computers/Programming/Languages/Erlang/ (The examples mainly consist of pure Erlang. The best examples to look at are probably the Blue Tail ticket tracker and the Wings 3d projects. Before going there, however, read the OTP design principles. There are many examples in that document as well. http://www.erlang.org/doc/r8b/doc/design_principles/part_frame.html Hope this helps, Francesco -- http://www.erlang-consulting.com Shreyas Gune wrote: > Hi, > > > > I have downloaded the Win32 version of Erlang/R8 to see if it > can help us in our project, but I am having problems building a simple > > application. Is there a URL or a sample file that you can provide me > that shows how to build a simple application? > > -Shreyas > From Laszlo.Varga@REDACTED Thu Jan 17 13:40:51 2002 From: Laszlo.Varga@REDACTED (Laszlo Varga) Date: Thu, 17 Jan 2002 13:40:51 +0100 (MET) Subject: Sharing data in a data structure Message-ID: <200201171240.g0HCepC11744@duna273.eth.ericsson.se> Hello, what about a common database, and structures storing the selection patterns? /Laszlo Varga > X-Originating-IP: [194.237.142.13] > From: "Vlad Dumitrescu" > To: erlang-questions@REDACTED > Subject: Sharing data in a data structure > Date: Thu, 17 Jan 2002 12:42:19 +0100 > Mime-Version: 1.0 > X-OriginalArrivalTime: 17 Jan 2002 11:42:19.0329 (UTC) FILETIME=[04FFD310:01C19F4C] > > Hi folks! > > I just begun a project where the main data structure is a graph that shares > a lot of data across branches and also with other graphs. Since we have no > pointers here :-) the simplest alternative I came up with is to use indexes > in a list or table instead. But I am a little worried because there will be > a lot of searching when traversing the structure... > > My question is: is there another way to do it? Maybe a different paradigm > may be used, but myself I cannot escape from this one... > > Duplicating the data is not acceptable, because it is necessary that a > change in one place will be reflected everywhere. And it would also result > in a humungous amount of data. > > Thank you in advance. Regards, > Vlad > > _________________________________________________________________ > MSN Photos ?r det enklaste s?ttet att dela ut?och skriva ut foton: > http://photos.msn.se/Support/WorldWide.aspx > From fredrik.linder@REDACTED Fri Jan 18 18:51:43 2002 From: fredrik.linder@REDACTED (Fredrik Linder) Date: Fri, 18 Jan 2002 18:51:43 +0100 Subject: Sharing data in a data structure References: Message-ID: <001201c1a048$cb2d07e0$0db7f2d5@frelin> Have you considered digraph? I do not know how well is performs, though. /Fredrik ----- Original Message ----- From: "Vlad Dumitrescu" To: Sent: Thursday, January 17, 2002 12:42 PM Subject: Sharing data in a data structure > Hi folks! > > I just begun a project where the main data structure is a graph that shares > a lot of data across branches and also with other graphs. Since we have no > pointers here :-) the simplest alternative I came up with is to use indexes > in a list or table instead. But I am a little worried because there will be > a lot of searching when traversing the structure... > > My question is: is there another way to do it? Maybe a different paradigm > may be used, but myself I cannot escape from this one... > > Duplicating the data is not acceptable, because it is necessary that a > change in one place will be reflected everywhere. And it would also result > in a humungous amount of data. > > Thank you in advance. Regards, > Vlad > > _________________________________________________________________ > MSN Photos ?r det enklaste s?ttet att dela ut och skriva ut foton: > http://photos.msn.se/Support/WorldWide.aspx > > From hal@REDACTED Mon Jan 21 02:27:05 2002 From: hal@REDACTED (Hal Snyder) Date: 20 Jan 2002 19:27:05 -0600 Subject: report browser and error_logger In-Reply-To: <20020109.214231.104031318.mbj@bluetail.com> (Martin Bjorklund's message of "Wed, 09 Jan 2002 21:42:31 +0100 (CET)") References: <87y9j7o60j.fsf@gamera.vail> <20020109.214231.104031318.mbj@bluetail.com> Message-ID: <877kqclcie.fsf@gamera.vail> Martin Bjorklund writes: > Since I implemented this in OTP, I've done some rethinking - why > bother to store the logs in binary format anyway? In most cases it's > better to store the error log in plain text, but using a wrap log so > the log won't grow. This is what we do in our systems. > > I've attached disk_log_h, a module which should have been > implemented years ago. It's a gen_event handler for disk_log. This > handler can be used e.g. for an error log, or whatever. This module > could very well be part of OTP (it's intended to be). Great! This looks quite interesting. One small question, however. Attempts to use disk_log_h result in event handler crashes. Is it correct that disk_log:do_log/2 returns an integer? It returns 1 in the tests, and disk_log_h doesn't seem to like that. Also, what would be a good way to flush cached log entries to disk? Hope I'm not being a pest. The setup: 1. Using kit built from otp_src_R8B-20011015 plus the disk_log patch you provided. 2. Then in a directory where disk_log_h.beam and logger.beam exist, start an erl node as follows. >erl Erlang (BEAM) emulator version 5.1 [source] Eshell V5.1 (abort with ^G) 1> logger:add_error_logger_mf("/tmp/glotz", 10000, 4, all). ok 2> error_logger:error_msg("foo~n"). ok =ERROR REPORT==== 20-Jan-2002::18:05:05 === foo 3> =ERROR REPORT==== 20-Jan-2002::18:05:05 === ** gen_event handler {disk_log_h,logger} crashed. ** Was installed in error_logger ** Last event was: {error,<0.21.0>,{<0.23.0>,"foo~n",[]}} ** When handler state == {state,{log,ok, logger, none, 0, "/tmp/glotz", [], wrap, external, wrap_ext, none, read_write, {10000,4}, {handle, "/tmp/glotz", 10000, 4, 0, 1, {cache, {file_descriptor, prim_file, {#Port<0.32>,3}}, 0, []}, "/tmp/glotz.1", 0, 0, 0, 0, 0}}, 0, {logger,form_all}} ** Reason == 1 From pjs@REDACTED Mon Jan 21 03:27:08 2002 From: pjs@REDACTED (Peter Stuckey) Date: Mon, 21 Jan 2002 13:27:08 +1100 Subject: No subject Message-ID: <21510.1011580028.1@muldi.cs.mu.oz.au> ------- Blind-Carbon-Copy To: pjs Subject: Date: Mon, 21 Jan 2002 13:27:08 +1100 Message-ID: <21510.1011580028@REDACTED> From: Peter Stuckey Apologies for Receiving Multiple Copies of this Message - ---------------------------------------------------------- CALL FOR PAPERS ICLP'02 Eighteenth International Conference on Logic Programming Copenhagen, Denmark July 29th - August 1, 2002 http://floc02.diku.dk/ICLP/ ICLP'02, the Eighteenth International Conference on Logic Programming will be be held this year as part of the 2002 Federated Logic Conference (http://floc02.diku.dk/) in conjunction with CADE, CAV, FME, LICS, RTA and TABLEAUX. ICLP'02 is sponsored by IF/Prolog (http://www.ifcomputer.de). TOPICS Since the first ICLP, held in Marseilles in 1982, ICLP has been the premier international conference for presenting research into logic programming. Original papers are sought in all areas of logic programming including (but not restricted to): Theory Implementation Semantic Foundations Compilation Formalisms Memory Management Non-monotonic Reasoning Virtual Machines Knowledge Representation Parallelism Language Issues Environments Constraints Program Analysis Concurrency Program Transformation Objects Validation and Verification Coordination Debugging Mobilility Higher Order Applications Types Modes Deductive Databases Programming Techniques Software Engineering Natural Language Web tools Internet Agents Artificial Intelligence Papers describing innovative applications of logic programming (in the broadest sense, e.g. including constraint programming, non-monotonic systems, etc.) are particularly sought. We welcome submission in, but not limited to, the following topics: surveys of an application area, problems to which logic programming may be applied, experience in applying logic programming, software engineering aspects of logic programming and areas where further research is required to meet industrial needs. There will be an award for the best application paper sponsored by IF/Prolog. SUBMISSION Papers must describe original, previously unpublished work, be written and presented in English, not exceed 15 pages (A4 or letter format, up to 5,000 words), and not be simultaneously submitted for publication elsewhere. The proceedings will be published by Springer Verlag in the Lecture Notes in Computer Science series. Authors are strongly encouraged to use LaTeX2e and the Springer llncs class file, available at http://www.springer.de/comp/lncs/authors.html Submission is Web-based. In order to submit a paper, authors should upload it via the web at http://www.cs.mu.oz.au/~pjs/ICLP2002/ where more detailed instructions are given. If submission through the Web is not possible, five hard copies may be sent to the program chair. Authors intending to submit a paper are requested to submit an abstract of their paper, through the same web interface, before February 10, to help expedite the paper assignment process. Submission Agenda: Submission of abstracts: February 10, 2002 Submission of papers: February 17, 2002 Notification of acceptance: April 14, 2002 Camera-ready papers due: May 14, 2002 Workshops: The following workshops will be held in conjunction with ICLP'02. August 1: CLIMA - Computational Logic In Multi-Agent Systems July 28: CLPSE - (Constraint) Logic Programming and Software Engineering July 31: LPE - Workshop on Logic Programming Environments July 27-28: NLULP - Natural Language Understanding and Logic Programming July 27: PCL - Paraconsistent Computational Logic July 27: SAVE - Specification, Analysis and Validation for Emerging Technologies in Computational Logic July 28: UNKB - Updating Non-Monotonic Knowledge Bases Conference Location: The conference will be held at the University of Copenhagen. Program Chair: Conference Chair: Peter J. Stuckey Henning Christiansen Department of Computer Science Department of Computer Science and Software Engineering Roskilde University University of Melbourne PO Box 260 3010, AUSTRALIA DK-4000 Roskilde, DENMARK Email: pjs@REDACTED Email: henning@REDACTED Tel: +613-8344-9155 Tel: +45 46 74 38 32 Fax: +613-9348-1184 Programme Committee: Jose Alferes, Universidade Nova de Lisboa Francisco Bueno, Universidad Polytecnica de Madrid Henning Christiansen, Roskilde University Sandro Etalle, University of Twente Francois Fages, INRIA Maurizio Gabbrielli, University of Bologna Maria Garcia de la Banda, Monash University Michael Gelfond, Texas Tech University Gopal Gupta, UT Dallas Katsumi Inoue, Kobe University Joxan Jaffar, National University of Singapore Gerda Janssens, K.U.Leuven Bharat Jayaraman, State University of New York at Buffalo Michael Leuschel, University of Southampton Michael Maher, Loyola University Chicago Dale Miller, The Pennsylvania State University Ulf Nilsson, Linkoping University Francesca Rossi, Universita' di Padova Konstantinos Sagonas, Uppsala University Christian Schulte, Universitat des Saarlandes Harald Sondergaard, University of Melbourne Francesca Toni, Imperial College London Miroslaw Truszczynski, University of Kentucky Pascal Van Hentenryck, Brown University David S. Warren, State University of New York at Stony Brook ------- End of Blind-Carbon-Copy From mbj@REDACTED Mon Jan 21 14:38:20 2002 From: mbj@REDACTED (Martin Bjorklund) Date: Mon, 21 Jan 2002 14:38:20 +0100 (CET) Subject: report browser and error_logger In-Reply-To: <877kqclcie.fsf@gamera.vail> References: <87y9j7o60j.fsf@gamera.vail> <20020109.214231.104031318.mbj@bluetail.com> <877kqclcie.fsf@gamera.vail> Message-ID: <20020121.143820.74753807.mbj@bluetail.com> Hal Snyder wrote: > One small question, however. Attempts to use disk_log_h result in > event handler crashes. Is it correct that disk_log:do_log/2 returns an > integer? It returns 1 in the tests, and disk_log_h doesn't seem to > like that. Whoops, sorry, it was more than a year ago I did these changes, and forgot about some other changes I made. I had to rewrite disk_log.erl so that it doesn't use it's process dictionary. Find the complete disk_log.erl attached. However, this disk_log is for R7. It might work on R8 as well, i don't know. It also has some other features, like compressed logs. I could port this all to R8, but then it would be nice to know if the OTP guys are interested to include it in OTP. /martin -------------- next part -------------- %% ``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 via the world wide web 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. %% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB. %% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings %% AB. All Rights Reserved.'' %% -module(disk_log). %% Efficient file based log - process part -export([start/0, istart_link/0, log/2, log_terms/2, blog/2, blog_terms/2, alog/2, alog_terms/2, balog/2, balog_terms/2, close/1, lclose/1, lclose/2, sync/1, open/1, truncate/1, truncate/2, btruncate/2, reopen/2, reopen/3, breopen/3, inc_wrap_file/1, change_size/2, change_notify/3, change_header/2, chunk/2, chunk/3, chunk_step/3, chunk_info/1, block/1, block/2, unblock/1, info/0, info/1, format_error/1, accessible_logs/0]). %% Internal exports -export([init/1, internal_open/2, system_continue/3, system_terminate/4, system_code_change/4]). %% To be used by wrap_log_reader only. -export([ichunk_end/2]). %% To be used by disk_log_h only. -export([ll_open/1, ll_close/1, do_log/2, do_info/2]). -record(state, {queue = [], parent, cnt = 0, args, error_status = ok, %% ok | {error, Reason} log }). -include("disk_log.hrl"). -define(failure(Error, Function, Arg), {{failed, Error}, [{?MODULE, Function, Arg}]}). %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- %%----------------------------------------------------------------- %% This module implements the API, and the processes for each log. %% There is one process/log. %%----------------------------------------------------------------- open(A) -> disk_log_server:open(check_arg(A, #arg{options = A})). ll_open(A) -> case check_arg(A, #arg{options = A}) of {ok, L} -> do_open(L); Error -> Error end. ll_close(Log) -> close_disk_log2(Log). log(Log, Term) -> req(Log, {log, term_to_binary(Term)}). blog(Log, Bytes) -> req(Log, {blog, check_bytes(Bytes)}). log_terms(Log, Terms) -> Bs = lists:map(fun term_to_binary/1, Terms), req(Log, {log, Bs}). blog_terms(Log, Bytess) -> Bs = lists:map(fun check_bytes/1, Bytess), req(Log, {blog, Bs}). alog(Log, Term) -> notify(Log, {alog, term_to_binary(Term)}). alog_terms(Log, Terms) -> Bs = lists:map(fun term_to_binary/1, Terms), notify(Log, {alog, Bs}). balog(Log, Bytes) -> notify(Log, {balog, check_bytes(Bytes)}). balog_terms(Log, Bytess) -> Bs = lists:map(fun check_bytes/1, Bytess), notify(Log, {balog, Bs}). close(Log) -> req(Log, close). lclose(Log) -> lclose(Log, node()). lclose(Log, Node) -> lreq(Log, close, Node). truncate(Log) -> req(Log, {truncate, none, truncate, 1}). truncate(Log, Head) -> req(Log, {truncate, {ok, term_to_binary(Head)}, truncate, 2}). btruncate(Log, Head) -> req(Log, {truncate, {ok, check_bytes(Head)}, btruncate, 2}). reopen(Log, NewFile) -> req(Log, {reopen, NewFile, none, reopen, 2}). reopen(Log, NewFile, NewHead) -> req(Log, {reopen, NewFile, {ok, term_to_binary(NewHead)}, reopen, 3}). breopen(Log, NewFile, NewHead) -> req(Log, {reopen, NewFile, {ok, check_bytes(NewHead)}, breopen, 3}). inc_wrap_file(Log) -> req(Log, inc_wrap_file). change_size(Log, NewSize) -> req(Log, {change_size, NewSize}). change_notify(Log, Pid, NewNotify) -> req(Log, {change_notify, Pid, NewNotify}). change_header(Log, NewHead) -> req(Log, {change_header, NewHead}). sync(Log) -> req(Log, sync). block(Log) -> block(Log, true). block(Log, QueueLogRecords) -> req(Log, {block, QueueLogRecords}). unblock(Log) -> req(Log, unblock). format_error(Error) -> do_format_error(Error). info(Log) -> sreq(Log, info). info() -> % debug lists:map(fun({Log, _}) -> sreq(Log, info) end, ets:tab2list(disk_log_names)). %% This function Takes 3 args, a Log, a Continuation and N. %% It retuns a {Cont2, ObjList} | eof | {error, Reason} %% The initial continuation is the atom 'start' chunk(Log, Cont) -> chunk(Log, Cont, infinity). chunk(Log, Cont, infinity) -> %% There cannot be more than ?MAX_CHUNK_SIZE terms in a chunk. ichunk(Log, Cont, ?MAX_CHUNK_SIZE); chunk(Log, Cont, N) when integer(N), N > 0 -> ichunk(Log, Cont, N). ichunk(Log, start, N) -> R = sreq(Log, {chunk, 0, list_to_binary([]), N}), ichunk_end(R, Log); ichunk(Log, More, N) when record(More, continuation) -> R = req2(More#continuation.pid, {chunk, More#continuation.pos, More#continuation.b, N}), ichunk_end(R, Log); ichunk(_Log, Error, _) -> Error. ichunk_end({C, R}, Log) when record(C, continuation) -> ichunk_end(R, read_write, Log, C, 0, []); ichunk_end({C, R, Bad}, Log) when record(C, continuation) -> ichunk_end(R, read_only, Log, C, Bad, []); ichunk_end(R, _Log) -> R. %% Create the terms on the client's heap, not the server's. ichunk_end([B | Bs], Mode, Log, C, Bad, A) -> case catch binary_to_term(B) of {'EXIT', _} when read_write == Mode -> InfoList = info(Log), {value, {file, FileName}} = lists:keysearch(file, 1, InfoList), File = case C#continuation.pos of Pos when integer(Pos) -> FileName; % halt log {FileNo, _} -> add_ext(FileName, FileNo) % wrap log end, {error, {corrupt_log_file, File}}; {'EXIT', _} when read_only == Mode -> Reread = lists:foldl(fun(Bin, Sz) -> Sz+size(Bin)+?HEADERSZ end, 0, Bs), NewPos = case C#continuation.pos of Pos when integer(Pos) -> Pos-Reread; {FileNo, Pos} -> {FileNo, Pos-Reread} end, NewBad = Bad + ?HEADERSZ, % the whole header is deemed bad {C#continuation{pos = NewPos, b = B}, lists:reverse(A), NewBad}; T -> ichunk_end(Bs, Mode, Log, C, Bad, [T | A]) end; ichunk_end([], _Mode, _Log, C, Bad, A) when Bad > 0 -> {C, lists:reverse(A), Bad}; ichunk_end([], _Mode, _Log, C, Bad, A) when Bad == 0 -> {C, lists:reverse(A)}. chunk_step(Log, Cont, N) when integer(N) -> ichunk_step(Log, Cont, N). ichunk_step(Log, start, N) -> sreq(Log, {chunk_step, 0, N}); ichunk_step(_Log, More, N) when record(More, continuation) -> req2(More#continuation.pid, {chunk_step, More#continuation.pos, N}); ichunk_step(_Log, Error, _) -> Error. chunk_info(More) when record(More, continuation) -> [{node, node(More#continuation.pid)}]; chunk_info(BadCont) -> {error, {no_continuation, BadCont}}. accessible_logs() -> disk_log_server:accessible_logs(). istart_link() -> {ok, proc_lib:spawn_link(disk_log, init, [self()])}. %% Only for backwards compatibility, could probably be removed. start() -> disk_log_server:start(). internal_open(Pid, A) -> req2(Pid, {internal_open, A}). check_arg([], Res) -> Ret = case Res#arg.head of none -> {ok, Res}; _ -> case check_head(Res#arg.head, Res#arg.format) of {ok, Head} -> {ok, Res#arg{head = Head}}; Error -> Error end end, if %% check result Res#arg.name == 0 -> {error, {badarg, name}}; Res#arg.file == none -> case catch lists:concat([Res#arg.name, ".LOG"]) of {'EXIT',_} -> {error, {badarg, file}}; FName -> check_arg([], Res#arg{file = FName}) end; Res#arg.repair == truncate, Res#arg.mode == read_only -> {error, {badarg, repair_read_only}}; Res#arg.type == halt, tuple(Res#arg.size) -> {error, {badarg, size}}; Res#arg.type == wrap, Res#arg.size == infinity -> case disk_log_1:read_size_file(Res#arg.file) of {0, 0} -> {error, {badarg, size}}; {FileSz, NoOf} -> check_arg([], Res#arg{size = {FileSz, NoOf}}) end; Res#arg.type == wrap, tuple(Res#arg.size) -> case disk_log_1:read_size_file(Res#arg.file) of {0, 0} -> Ret; OldSize when OldSize == Res#arg.size -> Ret; _OldSize when Res#arg.repair == truncate -> Ret; OldSize -> {error, {size_mismatch, OldSize, Res#arg.size}} end; Res#arg.type == wrap -> {error, {badarg, size}}; true -> Ret end; check_arg([{file, F} | Tail], Res) when list(F) -> check_arg(Tail, Res#arg{file = F}); check_arg([{file, F} | Tail], Res) when atom(F) -> check_arg(Tail, Res#arg{file = F}); check_arg([{linkto, Pid} |Tail], Res) when pid(Pid) -> check_arg(Tail, Res#arg{linkto = Pid}); check_arg([{linkto, none} |Tail], Res) -> check_arg(Tail, Res#arg{linkto = none}); check_arg([{name, Name}|Tail], Res) -> check_arg(Tail, Res#arg{name =Name}); check_arg([{repair, true}|Tail], Res) -> check_arg(Tail, Res#arg{repair = true}); check_arg([{repair, false}|Tail], Res) -> check_arg(Tail, Res#arg{repair = false}); check_arg([{repair, truncate}|Tail], Res) -> check_arg(Tail, Res#arg{repair = truncate}); check_arg([{size, Int}|Tail], Res) when integer(Int), Int > 0 -> check_arg(Tail, Res#arg{size = Int}); check_arg([{size, infinity}|Tail], Res) -> check_arg(Tail, Res#arg{size = infinity}); check_arg([{size, {MaxB,MaxF}}|Tail], Res) when integer(MaxB), integer(MaxF), MaxB > 0, MaxF > 0, MaxF < ?MAX_FILES -> check_arg(Tail, Res#arg{size = {MaxB, MaxF}}); check_arg([{type, wrap}|Tail], Res) -> check_arg(Tail, Res#arg{type = wrap}); check_arg([{type, halt}|Tail], Res) -> check_arg(Tail, Res#arg{type = halt}); check_arg([{format, internal}|Tail], Res) -> check_arg(Tail, Res#arg{format = internal}); check_arg([{format, external}|Tail], Res) -> check_arg(Tail, Res#arg{format = external}); check_arg([{distributed, []}|Tail], Res) -> check_arg(Tail, Res#arg{distributed = false}); check_arg([{distributed, Nodes}|Tail], Res) when list(Nodes) -> check_arg(Tail, Res#arg{distributed = {true, Nodes}}); check_arg([{notify, true}|Tail], Res) -> check_arg(Tail, Res#arg{notify = true}); check_arg([{notify, false}|Tail], Res) -> check_arg(Tail, Res#arg{notify = false}); check_arg([{head_func, HeadFunc}|Tail], Res) -> check_arg(Tail, Res#arg{head = {head_func, HeadFunc}}); check_arg([{head, Term}|Tail], Res) -> check_arg(Tail, Res#arg{head = {head, Term}}); check_arg([{mode, read_only}|Tail], Res) -> check_arg(Tail, Res#arg{mode = read_only}); check_arg([{mode, read_write}|Tail], Res) -> check_arg(Tail, Res#arg{mode = read_write}); check_arg([{compressed, true}|Tail], Res) -> check_arg(Tail, Res#arg{compressed = true}); check_arg([{compressed, false}|Tail], Res) -> check_arg(Tail, Res#arg{compressed = false}); check_arg(Arg, _) -> {error, {badarg, Arg}}. %%%----------------------------------------------------------------- %%% Server functions %%%----------------------------------------------------------------- init(Parent) -> process_flag(trap_exit, true), loop(#state{parent = Parent}). loop(State) -> receive Message -> handle(Message, State) end. handle({From, {log, B}}, S) -> case S#state.log of L when L#log.mode == read_only -> reply(From, {error, {read_only_mode, L#log.name}}, S); L when L#log.status == ok, L#log.format == internal -> case do_log(L, B) of {N, L1} when integer(N) -> reply(From, ok, (state_ok(S))#state{cnt = S#state.cnt+N, log = L1}); {error, Error, L1, N} -> S1 = S#state{cnt = S#state.cnt + N, log = L1}, reply(From, Error, state_err(S1, Error)); Error -> F = if binary(B) -> log; true -> log_terms end, do_exit(S, From, Error, ?failure(Error, F, 2)) end; L when L#log.status == ok, L#log.format == external -> reply(From, {error, {format_external, L#log.name}}, S); L when L#log.status == {blocked, false} -> reply(From, {error, {blocked_log, L#log.name}}, S); L when L#log.blocked_by == From -> reply(From, {error, {blocked_log, L#log.name}}, S); _ -> loop(S#state{queue = [{From, {log, B}} | S#state.queue]}) end; handle({From, {blog, B}}, S) -> case S#state.log of L when L#log.mode == read_only -> reply(From, {error, {read_only_mode, L#log.name}}, S); L when L#log.status == ok -> case do_log(L, B) of {N, L1} when integer(N) -> reply(From, ok, (state_ok(S))#state{cnt = S#state.cnt+N, log = L1}); {error, Error, L1, N} -> S1 = S#state{cnt = S#state.cnt + N, log = L1}, reply(From, Error, state_err(S1, Error)); Error -> F = if binary(B) -> blog; true -> blog_terms end, do_exit(S, From, Error, ?failure(Error, F, 2)) end; L when L#log.status == {blocked, false} -> reply(From, {error, {blocked_log, L#log.name}}, S); L when L#log.blocked_by == From -> reply(From, {error, {blocked_log, L#log.name}}, S); _ -> loop(S#state{queue = [{From, {blog, B}} | S#state.queue]}) end; handle({alog, B}, S) -> case S#state.log of L when L#log.mode == read_only -> notify_owners({read_only,B}, L), loop(S); L when L#log.status == ok, L#log.format == internal -> case do_log(L, B) of {N, L1} when integer(N) -> loop((state_ok(S))#state{cnt = S#state.cnt + N, log = L1}); {error, {error, {full, _Name}}, L1, 0} -> loop(state_ok(S#state{log = L1})); {error, Error, L1, N} -> S1 = S#state{cnt = S#state.cnt + N, log = L1}, loop(state_err(S1, Error)); Error -> do_stop(S), F = if binary(B) -> alog; true -> alog_terms end, exit(?failure(Error, F, 2)) end; L when L#log.status == ok -> notify_owners({format_external, B}, L), loop(S); L when L#log.status == {blocked, false} -> notify_owners({blocked_log, B}, L), loop(S); _ -> loop(S#state{queue = [{alog, B} | S#state.queue]}) end; handle({balog, B}, S) -> case S#state.log of L when L#log.mode == read_only -> notify_owners({read_only,B}, L), loop(S); L when L#log.status == ok -> case do_log(L, B) of {N, L1} when integer(N) -> loop((state_ok(S))#state{cnt = S#state.cnt + N, log = L1}); {error, {error, {full, _Name}}, L1, 0} -> loop(state_ok(S#state{log = L1})); {error, Error, L1, N} -> S1 = S#state{cnt = S#state.cnt + N, log = L1}, loop(state_err(S1, Error)); Error -> do_stop(S), F = if binary(B) -> balog; true -> balog_terms end, exit(?failure(Error, F, 2)) end; L when L#log.status == {blocked, false} -> notify_owners({blocked_log, B}, L), loop(S); _ -> loop(S#state{queue = [{balog, B} | S#state.queue]}) end; handle({From, {block, QueueLogRecs}}, S) -> case S#state.log of L when L#log.status == ok -> L2 = do_block(From, QueueLogRecs, L), reply(From, ok, S#state{log = L2}); L when L#log.status == {blocked, false} -> reply(From, {error, {blocked_log, L#log.name}}, S); L when L#log.blocked_by == From -> reply(From, {error, {blocked_log, L#log.name}}, S); _ -> loop(S#state{queue = [{From, {block, QueueLogRecs}} | S#state.queue]}) end; handle({From, unblock}, S) -> case S#state.log of L when L#log.status == ok -> reply(From, {error, {not_blocked, L#log.name}}, S); L when L#log.blocked_by == From -> S2 = do_unblock(S), reply(From, ok, S2); L -> reply(From, {error, {not_blocked_by_pid, L#log.name}}, S) end; handle({From, sync}, S) -> case S#state.log of L when L#log.mode == read_only -> reply(From, {error, {read_only_mode, L#log.name}}, S); L when L#log.status == ok -> Res = do_sync(L), reply(From, Res, state_err(S, Res)); L when L#log.status == {blocked, false} -> reply(From, {error, {blocked_log, L#log.name}}, S); L when L#log.blocked_by == From -> reply(From, {error, {blocked_log, L#log.name}}, S); _ -> loop(S#state{queue = [{From, sync} | S#state.queue]}) end; handle({From, {truncate, Head, F, A}}, S) -> case S#state.log of L when L#log.mode == read_only -> reply(From, {error, {read_only_mode, L#log.name}}, S); L when L#log.status == ok -> H = merge_head(Head, L#log.head), case catch do_trunc(L, H) of {ok, L1} -> S1 = S#state{log = L1}, notify_owners({truncated, S1#state.cnt}, L), N = if Head == none -> 0; true -> 1 end, reply(From, ok, (state_ok(S1))#state{cnt = N}); Error -> do_exit(S, From, Error, ?failure(Error, F, A)) end; L when L#log.status == {blocked, false} -> reply(From, {error, {blocked_log, L#log.name}}, S); L when L#log.blocked_by == From -> reply(From, {error, {blocked_log, L#log.name}}, S); _ -> loop(S#state{queue = [{From, {truncate, Head, F, A}} | S#state.queue]}) end; handle({From, {chunk, Pos, B, N}}, S) -> case S#state.log of L when L#log.status == ok -> R = do_chunk(L, Pos, B, N), reply(From, R, S); L when L#log.blocked_by == From -> R = do_chunk(L, Pos, B, N), reply(From, R, S); L when L#log.status == {blocked, false} -> reply(From, {error, {blocked_log, L#log.name}}, S); L -> loop(S#state{queue = [{From, {chunk, Pos, B, N}} | S#state.queue]}) end; handle({From, {chunk_step, Pos, N}}, S) -> case S#state.log of L when L#log.status == ok -> R = do_chunk_step(L, Pos, N), reply(From, R, S); L when L#log.blocked_by == From -> R = do_chunk_step(L, Pos, N), reply(From, R, S); L when L#log.status == {blocked, false} -> reply(From, {error, {blocked_log, L#log.name}}, S); _ -> loop(S#state{queue = [{From, {chunk_step, Pos, N}} | S#state.queue]}) end; handle({From, {change_notify, Pid, NewNotify}}, S) -> case S#state.log of L when L#log.status == ok -> case do_change_notify(L, Pid, NewNotify) of {ok, L1} -> reply(From, ok, S#state{log = L1}); Error -> reply(From, Error, S) end; L when L#log.status == {blocked, false} -> reply(From, {error, {blocked_log, L#log.name}}, S); L when L#log.blocked_by == From -> reply(From, {error, {blocked_log, L#log.name}}, S); _ -> loop(S#state{queue = [{From, {change_notify, Pid, NewNotify}} | S#state.queue]}) end; handle({From, {change_header, NewHead}}, S) -> case S#state.log of L when L#log.mode == read_only -> reply(From, {error, {read_only_mode, L#log.name}}, S); L when L#log.status == ok -> case check_head(NewHead, L#log.format) of {ok, Head} -> L1 = L#log{head = mk_head(Head, L#log.format)}, reply(From, ok, S#state{log = L1}); Error -> reply(From, Error, S) end; L when L#log.status == {blocked, false} -> reply(From, {error, {blocked_log, L#log.name}}, S); L when L#log.blocked_by == From -> reply(From, {error, {blocked_log, L#log.name}}, S); _ -> loop(S#state{queue = [{From, {change_header, NewHead}} | S#state.queue]}) end; handle({From, {change_size, NewSize}}, S) -> case S#state.log of L when L#log.mode == read_only -> reply(From, {error, {read_only_mode, L#log.name}}, S); L when L#log.status == ok -> case check_size(L#log.type, NewSize) of ok -> case catch do_change_size(L, NewSize) of {ok, L1} -> reply(From, ok, S#state{log = L1}); {big, CurSize} -> reply(From, {error, {new_size_too_small, L#log.name, CurSize}}, S); Else -> reply(From, Else, state_err(S, Else)) end; not_ok -> reply(From, {error, {badarg, size}}, S) end; L when L#log.status == {blocked, false} -> reply(From, {error, {blocked_log, L#log.name}}, S); L when L#log.blocked_by == From -> reply(From, {error, {blocked_log, L#log.name}}, S); _ -> loop(S#state{queue = [{From, {change_size, NewSize}} | S#state.queue]}) end; handle({From, inc_wrap_file}, S) -> case S#state.log of L when L#log.mode == read_only -> reply(From, {error, {read_only_mode, L#log.name}}, S); L when L#log.type == halt -> reply(From, {error, {halt_log, L#log.name}}, S); L when L#log.status == ok -> case catch do_inc_wrap_file(L) of {ok, L2, Lost} -> notify_owners({wrap, Lost}, L2), reply(From, ok, S#state{cnt = S#state.cnt-Lost, log = L2}); {error, Error, L2} -> reply(From, Error, state_err(S#state{log = L2}, Error)); Error -> do_exit(S, From, Error, ?failure(Error, inc_wrap_file, 1)) end; L when L#log.status == {blocked, false} -> reply(From, {error, {blocked_log, L#log.name}}, S); L when L#log.blocked_by == From -> reply(From, {error, {blocked_log, L#log.name}}, S); _ -> loop(S#state{queue = [{From, inc_wrap_file} | S#state.queue]}) end; handle({From, {reopen, NewFile, Head, F, A}}, S) -> case S#state.log of L when L#log.mode == read_only -> reply(From, {error, {read_only_mode, L#log.name}}, S); L when L#log.status == ok, L#log.filename /= NewFile -> case catch close_disk_log2(L) of closed -> File = L#log.filename, case catch rename_file(File, NewFile, L#log.type) of ok -> H = merge_head(Head, L#log.head), case do_open((S#state.args)#arg{name = L#log.name, repair = truncate, head = H, file = File}) of {ok, Res, L2, Cnt} -> L3 = L2#log{owners = L#log.owners, head = L#log.head, users = L#log.users}, S1 = S#state{log = L3}, notify_owners({truncated, S1#state.cnt}, L3), case Res of {error, _} -> do_exit(S1, From, Res, ?failure(Res, F, A)); _ -> reply(From, ok, S1#state{cnt = Cnt}) end; Res -> do_exit(S, From, Res, ?failure(Res, F, A)) end; Error -> do_exit(S, From, Error, ?failure(Error, reopen, 2)) end; Error -> do_exit(S, From, Error, ?failure(Error, F, A)) end; L when L#log.status == ok -> reply(From, {error, {same_file_name, L#log.name}}, S); L -> reply(From, {error, {blocked_log, L#log.name}}, S) end; handle({From, {internal_open, A}}, S) -> case S#state.log of undefined -> case do_open(A) of {ok, Res, L, Cnt} -> L1 = opening_pid(A#arg.linkto, A#arg.notify, L), reply(From, Res, S#state{args=A, cnt=Cnt, log = L1}); Res -> do_fast_exit(S, From, Res, ?failure(Res, open, 1)) end; L -> TestH = mk_head(A#arg.head, A#arg.format), case compare_arg(A#arg.options, S#state.args, TestH, L#log.head) of ok -> case add_pid(A#arg.linkto, A#arg.notify, L) of {ok, L1} -> reply(From, {ok, L#log.name}, S#state{log = L1}); Error -> reply(From, Error, S) end; Error -> reply(From, Error, S) end end; handle({From, close}, S) -> case do_close(From, S) of {stop, S1} -> do_exit(S, From, ok, normal); {continue, S1} -> reply(From, ok, S1) end; handle({From, info}, S) -> reply(From, do_info(S#state.log, S#state.cnt), S); handle({'EXIT', From, Reason}, S) when From == S#state.parent -> %% Parent orders shutdown do_stop(S), exit(Reason); handle({'EXIT', From, _Reason}, S) -> L = S#state.log, case is_owner(From, L) of {true, _Notify} -> case close_owner(From, L, S) of {stop, S1} -> do_stop(S1), exit(normal); {continue, S1} -> loop(S1) end; false -> %% 'users' is not decremented. S1 = do_unblock(From, S), loop(S1) end; handle({system, From, Req}, S) -> sys:handle_system_msg(Req, From, S#state.parent, ?MODULE, [], S); handle(_, S) -> loop(S). %% -> {ok, Log} | Error do_change_notify(L, Pid, Notify) -> case is_owner(Pid, L) of {true, Notify} -> {ok, L}; {true, _OldNotify} when Notify /= true, Notify /= false -> {error, {badarg, notify}}; {true, _OldNotify} -> Owners = lists:keydelete(Pid, 1, L#log.owners), L1 = L#log{owners = [{Pid, Notify} | Owners]}, {ok, L1}; false -> {error, {not_owner, Pid}} end. %% -> {stop, S} | {continue, S} do_close(Pid, S) -> L = S#state.log, case is_owner(Pid, L) of {true, _Notify} -> close_owner(Pid, L, S); false -> close_user(Pid, L, S) end. %% -> {stop, S} | {continue, S} close_owner(Pid, L, S) -> L1 = L#log{owners = lists:keydelete(Pid, 1, L#log.owners)}, S2 = do_unblock(Pid, S#state{log = L1}), unlink(Pid), do_close2(L1, S2). %% -> {stop, S} | {continue, S} close_user(Pid, L, S) when L#log.users > 0 -> L1 = L#log{users = L#log.users - 1}, S2 = do_unblock(Pid, S#state{log = L1}), do_close2(L1, S2); close_user(_Pid, _L, S) -> {continue, S}. do_close2(L, S) when L#log.users == 0, L#log.owners == [] -> {stop, S}; do_close2(_L, S) -> {continue, S}. %%----------------------------------------------------------------- %% Callback functions for system messages handling. %%----------------------------------------------------------------- system_continue(_Parent, _, State) -> loop(State). system_terminate(Reason, _Parent, _, State) -> do_stop(State), exit(Reason). %%----------------------------------------------------------------- %% Temporay code for upgrade. %%----------------------------------------------------------------- system_code_change(State, _Module, _OldVsn, _Extra) -> {ok, State}. %%%---------------------------------------------------------------------- %%% Internal functions %%%---------------------------------------------------------------------- do_exit(S, From, Message, Reason) -> do_stop(S), disk_log_server:close(self()), From ! {disk_log, self(), Message}, exit(Reason). do_fast_exit(S, From, Message, Reason) -> do_stop(S), From ! {disk_log, self(), Message}, exit(Reason). do_stop(S) -> proc_q(S#state.queue), close_disk_log(S#state.log). proc_q([{From, _R}|Tail]) -> From ! {disk_log, self(), {error, disk_log_stopped}}, proc_q(Tail); proc_q([_|T]) -> %% async stuff proc_q(T); proc_q([]) -> ok. %% -> log() opening_pid(Pid, Notify, L) -> {ok, L1} = add_pid(Pid, Notify, L), L1. %% -> {ok, log()} | Error add_pid(Pid, Notify, L) when pid(Pid) -> case is_owner(Pid, L) of false -> link(Pid), {ok, L#log{owners = [{Pid, Notify} | L#log.owners]}}; {true, Notify} -> %% {error, {pid_already_connected, L#log.name}}; {ok, L}; {true, CurNotify} when Notify /= CurNotify -> {error, {arg_mismatch, notify, CurNotify, Notify}} end; add_pid(_NotAPid, _Notify, L) -> {ok, L#log{users = L#log.users + 1}}. unblock_pid(Pid, L) when pid(Pid) -> case is_owner(L#log.blocked_by, L) of {true, _Notify} -> ok; false -> unlink(L#log.blocked_by) end; unblock_pid(_NotAPid, _L) -> ok. %% -> true | false is_owner(Pid, L) -> case lists:keysearch(Pid, 1, L#log.owners) of {value, {_Pid, Notify}} -> {true, Notify}; false -> false end. %% ok | throw(Error) rename_file(File, NewFile, halt) -> file:rename(File, NewFile); rename_file(File, NewFile, wrap) -> rename_file(wrap_file_extensions(File), File, NewFile, ok). rename_file([Ext|Exts], File, NewFile, Res) -> NRes = case file:rename(add_ext(File, Ext), add_ext(NewFile, Ext)) of ok -> Res; Else -> Else end, rename_file(Exts, File, NewFile, NRes); rename_file([], _File, _NewFiles, Res) -> Res. %% "Old" error messages have been kept, arg_mismatch has been added. compare_arg([], _A, none, _OrigHead) -> % no header option given ok; compare_arg([], _A, Head, OrigHead) when Head /= OrigHead -> {error, {arg_mismatch, head, OrigHead, Head}}; compare_arg([], _A, _Head, _OrigHead) -> ok; compare_arg([{Attr, Val} | Tail], A, Head, OrigHead) -> case compare_arg(Attr, Val, A) of {not_ok, OrigVal} -> {error, {arg_mismatch, Attr, OrigVal, Val}}; ok -> compare_arg(Tail, A, Head, OrigHead); Error -> Error end. compare_arg(file, F, A) when F /= A#arg.file -> {error, {name_already_open, A#arg.name}}; compare_arg(mode, read_only, A) when A#arg.mode == read_write -> {error, {open_read_write, A#arg.name}}; compare_arg(mode, read_write, A) when A#arg.mode == read_only -> {error, {open_read_only, A#arg.name}}; compare_arg(type, T, A) when T /= A#arg.type -> {not_ok, A#arg.type}; compare_arg(format, F, A) when F /= A#arg.format -> {not_ok, A#arg.format}; compare_arg(repair, R, A) when R /= A#arg.repair -> %% not used, but check it anyway... {not_ok, A#arg.repair}; compare_arg(_Attr, _Val, _A) -> ok. %% -> {ok, Res, log(), Cnt} | Error do_open(A) -> L = #log{name = A#arg.name, filename = A#arg.file, size = A#arg.size, head = mk_head(A#arg.head, A#arg.format), mode = A#arg.mode, is_full = false}, do_open2(L, A). mk_head({head, Term}, internal) -> {ok, term_to_binary(Term)}; mk_head({head, Bytes}, external) -> {ok, check_bytes(Bytes)}; mk_head(H, _) -> H. check_bytes(Binary) when binary(Binary) -> Binary; check_bytes(Bytes) -> list_to_binary(Bytes). %%----------------------------------------------------------------- %% Change size of the logs in runtime. %%----------------------------------------------------------------- %% -> {ok, L'} | {big, CurSize} | throw(Error) do_change_size(L, NewSize) when L#log.type == halt -> Fd = (L#log.extra)#halt.fd, {ok, CurSize} = file:position(Fd, cur), if NewSize == infinity -> {ok, L#log{extra = #halt{fd = Fd, size = NewSize}, is_full = false}}; CurSize =< NewSize -> {ok, L#log{extra = #halt{fd = Fd, size = NewSize}, is_full = false}}; true -> {big, CurSize} end; do_change_size(L, NewSize) when L#log.type == wrap -> {ok, Handle} = disk_log_1:change_size_wrap(L#log.extra, NewSize), {ok, L#log{extra = Handle, is_full = false}}. %% -> {ok, Head} | Error; Head = none | {head, H} | {M,F,A} check_head({head, none}, _Format) -> {ok, none}; check_head({head_func, {M, F, A}}, _Format) when atom(M), atom(F), list(A) -> {ok, {M, F, A}}; check_head({head, Head}, external) -> case catch check_bytes(Head) of {'EXIT', _} -> {error, {badarg, head}}; _ -> {ok, {head, Head}} end; check_head({head, Term}, internal) -> {ok, {head, Term}}; check_head(_Head, _Format) -> {error, {badarg, head}}. check_size(wrap, {NewMaxB,NewMaxF}) when integer(NewMaxB), integer(NewMaxF), NewMaxB > 0, NewMaxF > 0, NewMaxF < ?MAX_FILES -> ok; check_size(halt, NewSize) when integer(NewSize), NewSize > 0 -> ok; check_size(halt, infinity) -> ok; check_size(_, _) -> not_ok. %%----------------------------------------------------------------- %% Increment a wrap log. %%----------------------------------------------------------------- %% -> {ok, log(), Lost} | {error, Error, log()} | throw(Error) do_inc_wrap_file(L) -> #log{format = Format, extra = Handle} = L, case Format of internal -> case disk_log_1:mf_int_inc(Handle, L#log.head) of {ok, Handle2, Lost} -> {ok, L#log{extra = Handle2}, Lost}; {error, Error, Handle2} -> {error, Error, L#log{extra = Handle2}} end; external -> case disk_log_1:mf_ext_inc(Handle, L#log.head) of {ok, Handle2, Lost} -> {ok, L#log{extra = Handle2}, Lost}; {error, Error, Handle2} -> {error, Error, L#log{extra = Handle2}} end end. %%----------------------------------------------------------------- %% Open a log file. %%----------------------------------------------------------------- %% -> {ok, Reply, log(), Cnt} | Error %% Note: the header is always written, even if the log size is too small. do_open2(L, #arg{type = halt, format = internal, name = Name, file = FName, repair = Repair, size = Size, mode = Mode}) -> case catch disk_log_1:int_open(FName, Repair, Mode, L#log.head) of {ok, {_Alloc, Fd, {NoItems, _NoBytes}}} -> {ok, {ok, Name}, L#log{format_type = halt_int, extra = #halt{fd = Fd, size =Size}}, NoItems}; {repaired, Fd, Rec, Bad} -> {ok, {repaired, Name, {recovered, Rec}, {badbytes, Bad}}, L#log{format_type = halt_int, extra = #halt{fd = Fd, size =Size}}, Rec}; Error -> Error end; do_open2(L, #arg{type = wrap, format = internal, size = {MaxB, MaxF}, name = Name, repair = Repair, file = FName, mode = Mode}) -> case catch disk_log_1:mf_int_open(FName, MaxB, MaxF, Repair, Mode, L#log.head) of {ok, Handle, Cnt} -> {ok, {ok, Name}, L#log{type = wrap, format_type = wrap_int, extra = Handle}, Cnt}; {repaired, Handle, Rec, Bad, Cnt} -> {ok, {repaired, Name, {recovered, Rec}, {badbytes, Bad}}, L#log{type = wrap, format_type = wrap_int, extra = Handle}, Cnt}; Error -> Error end; do_open2(L, #arg{type = halt, format = external, file = FName, name = Name, size = Size, repair = Repair, mode = Mode, compressed = Compressed}) -> case catch disk_log_1:ext_open(FName, Repair, Mode, Compressed, L#log.head) of {ok, {_Alloc, Fd, {NoItems, _NoBytes}}} -> {ok, {ok, Name}, L#log{format_type = halt_ext, format = external, extra = #halt{fd = Fd, size =Size}}, NoItems}; Error -> Error end; do_open2(L, #arg{type = wrap, format = external, size = {MaxB, MaxF}, name = Name, file = FName, repair = Repair, mode = Mode, compressed = Compressed}) -> case catch disk_log_1:mf_ext_open(FName, MaxB, MaxF, Repair, Mode, Compressed, L#log.head) of {ok, Handle, Cnt} -> {ok, {ok, Name}, L#log{type = wrap, format_type = wrap_ext, extra = Handle, format = external}, Cnt}; Error -> Error end. %% -> closed close_disk_log(undefined) -> closed; close_disk_log(L) -> unblock_pid(L#log.blocked_by, L), F = fun({Pid, _}) -> unlink(Pid) end, lists:foreach(F, L#log.owners), catch close_disk_log2(L), closed. %% -> closed | throw(Error) close_disk_log2(L) -> case L of #log{format_type = halt_int, extra = Halt} -> disk_log_1:close(Halt#halt.fd, L#log.filename); #log{format_type = wrap_int, mode = Mode, extra = Handle} -> disk_log_1:mf_int_close(Handle, Mode); #log{format_type = halt_ext, extra = Halt} -> file:close(Halt#halt.fd); #log{format_type = wrap_ext, mode = Mode, extra = Handle} -> disk_log_1:mf_ext_close(Handle, Mode) end, closed. do_format_error({error, Module, Error}) -> Module:format_error(Error); do_format_error({error, Reason}) -> do_format_error(Reason); do_format_error({Node, Error = {error, _Reason}}) -> lists:append(io_lib:format("~p: ", [Node]), do_format_error(Error)); do_format_error({badarg, Arg}) -> io_lib:format("The argument ~p is missing, not recognized or " "not wellformed~n", [Arg]); do_format_error({size_mismatch, OldSize, ArgSize}) -> io_lib:format("The given size ~p does not match the size ~p found on " "the disk log size file~n", [ArgSize, OldSize]); do_format_error({read_only_mode, Log}) -> io_lib:format("The disk log ~p has been opened read-only, but the " "requested operation needs read-write access~n", [Log]); do_format_error({format_external, Log}) -> io_lib:format("The requested operation can only be applied on internally " "formatted disk logs, but ~p is externally formatted~n", [Log]); do_format_error({blocked_log, Log}) -> io_lib:format("The blocked disk log ~p does not queue requests, or " "the log has been blocked by the calling process~n", [Log]); do_format_error({full, Log}) -> io_lib:format("The halt log ~p is full~n", [Log]); do_format_error({not_blocked, Log}) -> io_lib:format("The disk log ~p is not blocked~n", [Log]); do_format_error({not_owner, Pid}) -> io_lib:format("The pid ~p is not an owner of the disk log~n", [Pid]); do_format_error({not_blocked_by_pid, Log}) -> io_lib:format("The disk log ~p is blocked, but only the blocking pid " "can unblock a disk log~n", [Log]); do_format_error({new_size_too_small, Log, CurrentSize}) -> io_lib:format("The current size ~p of the halt log ~p is greater than the " "requested new size~n", [CurrentSize, Log]); do_format_error({halt_log, Log}) -> io_lib:format("The halt log ~p cannot be wrapped~n", [Log]); do_format_error({same_file_name, Log}) -> io_lib:format("Current and new file name of the disk log ~p " "are the same~n", [Log]); do_format_error({arg_mismatch, Option, FirstValue, ArgValue}) -> io_lib:format("The value ~p of the disk log option ~p does not match " "the current value ~p~n", [ArgValue, Option, FirstValue]); do_format_error({name_already_open, Log}) -> io_lib:format("The disk log ~p has already opened another file~n", [Log]); do_format_error({node_already_open, Log}) -> io_lib:format("The distribution option of the disk log ~p does not match " "already open log~n", [Log]); do_format_error({open_read_write, Log}) -> io_lib:format("The disk log ~p has already been opened read-write~n", [Log]); do_format_error({open_read_only, Log}) -> io_lib:format("The disk log ~p has already been opened read-only~n", [Log]); do_format_error({not_internal_wrap, Log}) -> io_lib:format("The requested operation cannot be applied since ~p is not " "an internally formatted disk log~n", [Log]); do_format_error(no_such_log) -> io_lib:format("There is no disk log with the given name~n", []); do_format_error(nonode) -> io_lib:format("There seems to be no node up that can handle " "the request~n", []); do_format_error(nodedown) -> io_lib:format("There seems to be no node up that can handle " "the request~n", []); do_format_error({corrupt_log_file, FileName}) -> io_lib:format("The wrap log file ~s contains corrupt data~n", [FileName]); do_format_error({need_repair, FileName}) -> io_lib:format("The wrap log file ~s has not been closed properly and " "needs repair~n", [FileName]); do_format_error({not_a_log_file, FileName}) -> io_lib:format("The file ~s is not a wrap log file~n", [FileName]); do_format_error({invalid_header, InvalidHeader}) -> io_lib:format("The disk log header is not wellformed: ~p~n", [InvalidHeader]); do_format_error(end_of_log) -> io_lib:format("An attempt was made to step outside a not yet " "full wrap log~n", []); do_format_error({invalid_index_file, FileName}) -> io_lib:format("The wrap log index file ~s cannot be used~n", [FileName]); do_format_error({no_continuation, BadCont}) -> io_lib:format("The term ~p is not a chunk continuation~n", [BadCont]); do_format_error({file_error, FileName, Reason}) -> io_lib:format("~s: ~p~n", [FileName, file:format_error(Reason)]); do_format_error(E) -> io_lib:format("~p~n", [E]). do_info(L, Cnt) -> #log{name = Name, type = Type, mode = Mode, filename = File, extra = Extra, status = Status, owners = Owners, users = Users, format = Format, head = Head} = L, Size = case Type of wrap -> disk_log_1:get_wrap_size(Extra); halt -> Extra#halt.size end, Distribution = case disk_log_server:get_log_pids(Name) of {local, _Pid} -> local; {distributed, Pids} -> lists:map(fun(P) -> node(P) end, Pids); undefined -> % "cannot happen" [] end, RW = case Type of wrap when Mode == read_write -> #handle{curB = CurB, curF = CurF, cur_cnt = CurCnt, acc_cnt = AccCnt, noFull = NoFull, accFull = AccFull} = Extra, %% info has side effects??? i don't get it... % NewAccFull = AccFull + NoFull, % NewExtra = Extra#handle{noFull = 0, accFull = NewAccFull}, % put(log, L#log{extra = NewExtra}), [{no_current_bytes, CurB}, {no_current_items, CurCnt}, {no_items, Cnt}, {no_written_items, CurCnt + AccCnt}, {current_file, CurF}, % {no_overflows, {NewAccFull, NoFull}} {no_overflows, {AccFull, NoFull}} ]; halt when Mode == read_write -> [{full, L#log.is_full}, {no_written_items, Cnt} ]; _ when Mode == read_only -> [] end, HeadL = case Mode of read_write -> [{head, Head}]; read_only -> [] end, Common = [{name, Name}, {file, File}, {type, Type}, {format, Format}, {size, Size}, {items, Cnt}, % kept for "backward compatibility" (undocumented) {owners, Owners}, {users, Users}] ++ HeadL ++ [{mode, Mode}, {status, Status}, {node, node()}, {distributed, Distribution} ], Common ++ RW. do_block(Pid, QueueLogRecs, L) -> L2 = L#log{status = {blocked, QueueLogRecs}, blocked_by = Pid}, case is_owner(Pid, L2) of {true, _Notify} -> L2; false -> link(Pid), L2 end. do_unblock(Pid, S) when (S#state.log)#log.blocked_by == Pid -> do_unblock(S); do_unblock(_Pid, S) -> S. do_unblock(S) -> L = S#state.log, unblock_pid(L#log.blocked_by, L), L2 = L#log{blocked_by = none, status = ok}, send_self(S#state.queue), S#state{queue = [], log = L2}. send_self(L) -> lists:foreach(fun(M) -> self() ! M end, lists:reverse(L)). %% -> {integer(), L'} | {error, Error, L', integer()} | FatalError do_log(#log{format_type = halt_int, filename = FileName, extra = Halt}=L, B) when Halt#halt.size == infinity -> log_bin(Halt#halt.fd, L, FileName, B); do_log(L, B) when L#log.format_type == halt_int -> #log{name = Name, filename = FileName, extra = Halt} = L, #halt{fd = Fd, size = Sz} = Halt, {ok, CurSize} = file:position(Fd, cur), BSize = sz(B), if L#log.is_full == true -> {error, {error, {full, Name}}, L, 0}; CurSize + BSize =< Sz -> log_bin(Fd, L, FileName, B); true -> L1 = L#log{is_full = true}, notify_owners(full, L1), {error, {error, {full, Name}}, L1, 0} end; do_log(L, B) when L#log.format_type == wrap_int -> case catch disk_log_1:mf_int_log(L#log.extra, B, L#log.head) of {ok, Handle, Logged, Lost} -> notify_owners({wrap, Lost}, L), {Logged - Lost, L#log{extra = Handle}}; {ok, Handle, Logged} -> {Logged, L#log{extra = Handle}}; {error, Error, Handle, Logged, Lost} -> L1 = L#log{extra = Handle}, {error, Error, L1, Logged - Lost}; FatalError -> FatalError end; do_log(L, B) when L#log.format_type == halt_ext -> #log{filename = FName, extra = Halt} = L, #halt{fd = Fd, size = Sz} = Halt, {ok, CurSize} = file:position(Fd, cur), BSize = xsz(B), if L#log.is_full == true -> {error, {error, {full, L#log.name}}, L, 0}; CurSize + BSize =< Sz -> if binary(B) -> write_bins([B], L, Fd, FName, 0); true -> write_bins(B, L, Fd, FName, 0) end; true -> L1 = L#log{is_full = true}, notify_owners(full, L1), {error, {error, {full, L1#log.name}}, L1, 0} end; do_log(L, B) when L#log.format_type == wrap_ext -> case disk_log_1:mf_ext_log(L#log.extra, B, L#log.head) of {ok, Handle, Logged, Lost} -> notify_owners({wrap, Lost}, L), {Logged - Lost, L#log{extra = Handle}}; {ok, Handle, Logged} -> {Logged, L#log{extra = Handle}}; {error, Error, Handle, Logged, Lost} -> L1 = L#log{extra = Handle}, {error, Error, L1, Logged - Lost} end. log_bin(Fd, L, FileName, B) -> case catch disk_log_1:log(Fd, FileName, B) of N when integer(N) -> {N, L}; Error -> {error, Error, L, 0} end. write_bins([], L, _Fd, _FName, N) -> {N, L}; write_bins([B|Bs], L, Fd, FName, N) -> case file:write(Fd, B) of ok -> write_bins(Bs, L, Fd, FName, N + 1); {error, Error} -> {error, {file_error, FName, Error}, L, N} end. sz(B) when binary(B) -> size(B) + ?HEADERSZ; sz([B|T]) when binary(B) -> size(B) + ?HEADERSZ + sz(T); sz([]) -> 0. xsz(B) when binary(B) -> size(B); xsz([B|T]) when binary(B) -> size(B) + xsz(T); xsz([]) -> 0. do_sync(#log{format_type = halt_int, extra = Halt}) -> disk_log_1:sync(Halt#halt.fd); do_sync(#log{format_type = wrap_int, extra = Handle}) -> disk_log_1:mf_int_sync(Handle); do_sync(#log{format_type = halt_ext, extra = Halt}) -> file:sync(Halt#halt.fd); do_sync(#log{format_type = wrap_ext, extra = Handle}) -> disk_log_1:mf_ext_sync(Handle). %% -> {ok, L'} | Error | throw(Error) do_trunc(L, Head) when L#log.format_type == halt_int -> Fd = (L#log.extra)#halt.fd, case disk_log_1:truncate(Fd, L#log.filename, Head) of ok -> {ok, L#log{is_full = false}}; Error -> Error end; do_trunc(L, Head) when L#log.format_type == halt_ext -> Fd = (L#log.extra)#halt.fd, file:position(Fd, bof), file:truncate(Fd), case Head of {ok, H} -> case file:write(Fd, H) of ok -> {ok, L#log{is_full = false}}; {error, Error} -> {error, {file_error, L#log.filename, Error}} end; none -> {ok, L#log{is_full = false}} end; do_trunc(L, Head) when L#log.type == wrap -> Handle = L#log.extra, OldHead = L#log.head, {MaxB, MaxF} = disk_log_1:get_wrap_size(Handle), {ok, L1} = do_change_size(L, {MaxB, 1}), L2 = trunc_wrap(L1#log{head = Head}), %% Just to remove all files with suffix > 1: L3 = trunc_wrap(L2), NewHandle = (L3#log.extra)#handle{noFull = 0, accFull = 0}, do_change_size(L3#log{extra = NewHandle, head = OldHead}, {MaxB, MaxF}). trunc_wrap(L) -> case do_inc_wrap_file(L) of {ok, L2, _Lost} -> L2; {error, Error, L2} -> throw(Error) end. do_chunk(L, Pos, B, N) when L#log.format_type == halt_int -> Fd = (L#log.extra)#halt.fd, case L#log.mode of read_only -> disk_log_1:chunk_read_only(Fd, L#log.filename, Pos, B, N); read_write -> disk_log_1:chunk(Fd, L#log.filename, Pos, B, N) end; do_chunk(#log{format_type = wrap_int, mode = read_only, extra = Handle}, Pos, B, N) -> disk_log_1:mf_int_chunk_read_only(Handle, Pos, B, N); do_chunk(#log{format_type = wrap_int, extra = Handle}, Pos, B, N) -> disk_log_1:mf_int_chunk(Handle, Pos, B, N); do_chunk(Log, _Pos, _B, _) -> {error, {format_external, Log#log.name}}. do_chunk_step(#log{format_type = wrap_int, extra = Handle}, Pos, N) -> disk_log_1:mf_int_chunk_step(Handle, Pos, N); do_chunk_step(Log, _Pos, _N) -> {error, {not_internal_wrap, Log#log.name}}. reply(To, Rep, S) -> To ! {disk_log, self(), Rep}, loop(S). req(Log, R) -> case disk_log_server:get_log_pids(Log) of {local, Pid} -> monitor_request(Pid, R); undefined -> {error, no_such_log}; {distributed, Pids} -> multi_req({self(), R}, Pids) end. multi_req(Msg, Pids) -> Refs = lists:map(fun(Pid) -> Ref = erlang:monitor(process, Pid), Pid ! Msg, {Pid, Ref} end, Pids), lists:foldl(fun({Pid, Ref}, Reply) -> receive {'DOWN', Ref, process, Pid, _Info} -> Reply; {disk_log, Pid, _Reply} -> erlang:demonitor(Ref), receive {'DOWN', Ref, process, Pid, _Reason} -> ok after 0 -> ok end end end, {error, nonode}, Refs). sreq(Log, R) -> case nearby_pid(Log, node()) of undefined -> {error, no_such_log}; Pid -> monitor_request(Pid, R) end. %% Local req - always talk to log on Node lreq(Log, R, Node) -> case nearby_pid(Log, Node) of Pid when pid(Pid), node(Pid) == Node -> monitor_request(Pid, R); _Else -> {error, no_such_log} end. nearby_pid(Log, Node) -> case disk_log_server:get_log_pids(Log) of undefined -> undefined; {local, Pid} -> Pid; {distributed, Pids} -> get_near_pid(Pids, Node) end. get_near_pid([Pid | _], Node) when node(Pid) == Node -> Pid; get_near_pid([Pid], _ ) -> Pid; get_near_pid([_ | T], Node) -> get_near_pid(T, Node). monitor_request(Pid, Req) -> Ref = erlang:monitor(process, Pid), Pid ! {self(), Req}, receive {'DOWN', Ref, process, Pid, _Info} -> {error, no_such_log}; {disk_log, Pid, Reply} -> erlang:demonitor(Ref), receive {'DOWN', Ref, process, Pid, normal} -> Reply after 0 -> Reply end end. req2(Pid, R) -> monitor_request(Pid, R). merge_head(none, Head) -> Head; merge_head(Head, _) -> Head. %% -> List of extensions of existing files (no dot included) | throw(FileError) wrap_file_extensions(File) -> {_CurF, _CurFSz, _TotSz, NoOfFiles} = disk_log_1:read_index_file(File), Fs = if NoOfFiles >= 1 -> lists:seq(1, NoOfFiles); NoOfFiles == 0 -> [] end, Fun = fun(Ext) -> case file:read_file_info(add_ext(File, Ext)) of {ok, _} -> true; _Else -> false end end, lists:filter(Fun, ["idx", "siz" | Fs]). add_ext(File, Ext) -> lists:concat([File, ".", Ext]). notify(Log, R) -> case disk_log_server:get_log_pids(Log) of undefined -> {error, no_such_log}; {local, Pid} -> Pid ! R, ok; {distributed, Pids} -> lists:foreach(fun(Pid) -> Pid ! R end, Pids), ok end. notify_owners(Note, L) -> Msg = {disk_log, node(), L#log.name, Note}, lists:foreach(fun({Pid, true}) -> Pid ! Msg; (_) -> ok end, L#log.owners). state_ok(S) when S#state.error_status == ok -> S; state_ok(S) -> notify_owners({error_status, ok}, S#state.log), S#state{error_status = ok}. %% Note: Err = ok | {error, Reason} state_err(S, Err) when S#state.error_status == Err -> S; state_err(S, Err) -> notify_owners({error_status, Err}, S#state.log), S#state{error_status = Err}. From Martin.Lindenthal@REDACTED Mon Jan 21 17:56:58 2002 From: Martin.Lindenthal@REDACTED (Martin Lindenthal) Date: Mon, 21 Jan 2002 17:56:58 +0100 Subject: Instrumentations Functions (SNMP Application) Message-ID: <3630000.1011632218@polyhymnia> hello, can anyone give an example of an instrumentation function for an Erlang SNMP agent so that the agent can "speak" with a "real" device (say a switch or a router)? ---kind regards, Martin --------------------------------------------------------------------------- This email is written with recycled electrons! --------------------------------------------------------------------------- Martin Lindenthal Computer Center,University of Osnabrueck,Networking Div. email: Martin.Lindenthal@REDACTED Tel.: +49-541-969-2304 Fax: +49-541-969-2470 GSM: +49-172-5227599 --------------------------------------------------------------------------- From Sean.Hinde@REDACTED Tue Jan 22 20:08:42 2002 From: Sean.Hinde@REDACTED (Sean Hinde) Date: Tue, 22 Jan 2002 19:08:42 -0000 Subject: Iterate n times Message-ID: <402DD461F109D411977E0008C791C312039F676E@imp02mbx.one2one.co.uk> Does anyone know if this function has a proper name or already exists anywhere? iter(F, St, 0) -> St; iter(F, St, N) when integer(N), N > 1 -> iter(F, F(St, N), N-1). Simple examples of usage might be: 1> iter(fun(St, N) -> N + St end, 0, 5). 15 2> iter(fun(St, N) -> [N|St] end, [], 5). [1,2,3,4,5] Sean NOTICE AND DISCLAIMER: This email (including attachments) is confidential. If you have received this email in error please notify the sender immediately and delete this email from your system without copying or disseminating it or placing any reliance upon its contents. We cannot accept liability for any breaches of confidence arising through use of email. Any opinions expressed in this email (including attachments) are those of the author and do not necessarily reflect our opinions. We will not accept responsibility for any commitments made by our employees outside the scope of our business. We do not warrant the accuracy or completeness of such information. From lehugo@REDACTED Tue Jan 22 17:56:21 2002 From: lehugo@REDACTED (L E H U G O INFORMATICA) Date: Tue, 22 Jan 2002 17:56:21 Subject: PROMOÇÃO CARNAVALESCA IMPERDIVEL !!! Message-ID: <200201221956.g0MJuQK00999@hades.cslab.ericsson.net> An HTML attachment was scrubbed... URL: From francesco@REDACTED Tue Jan 22 20:53:40 2002 From: francesco@REDACTED (Francesco Cesarini) Date: Tue, 22 Jan 2002 19:53:40 +0000 Subject: Iterate n times References: <402DD461F109D411977E0008C791C312039F676E@imp02mbx.one2one.co.uk> Message-ID: <3C4DC344.4010301@erlang-consulting.com> Another function I have often implemented and used in my private libraries is while(Fun, Arg) -> while(Fun(Arg), Fun). while({true, Arg}, Fun) -> while(Fun(Arg), Fun); while({false, Val}, _Fun) -> Val. Francesco -- http://www.erlang-consulting.com Sean Hinde wrote: >Does anyone know if this function has a proper name or already exists >anywhere? > >iter(F, St, 0) -> > St; >iter(F, St, N) when integer(N), N > 1 -> > iter(F, F(St, N), N-1). > >Simple examples of usage might be: > >1> iter(fun(St, N) -> N + St end, 0, 5). >15 >2> iter(fun(St, N) -> [N|St] end, [], 5). >[1,2,3,4,5] > >Sean > > > >NOTICE AND DISCLAIMER: >This email (including attachments) is confidential. If you have received >this email in error please notify the sender immediately and delete this >email from your system without copying or disseminating it or placing any >reliance upon its contents. We cannot accept liability for any breaches of >confidence arising through use of email. Any opinions expressed in this >email (including attachments) are those of the author and do not necessarily >reflect our opinions. We will not accept responsibility for any commitments >made by our employees outside the scope of our business. We do not warrant >the accuracy or completeness of such information. > > > > From johan.blom@REDACTED Thu Jan 24 17:27:10 2002 From: johan.blom@REDACTED (Johan Blom) Date: 24 Jan 2002 17:27:10 +0100 Subject: New inets-3.0 Beta Message-ID: <1011889630.2530.45.camel@localhost.localdomain> Hi, (sorry if you get multiple copies of this, but my first attempt seems to have disappeared somewhere.) I spent some time rewriting/adding/fixing a few things to the HTTP related parts in inets. The result is a rewritten HTTP 1.1 "core" (including a few bugfixes) incorporation of an HTTP 1.1 client and a URI parsing module. Hopefully this will eventually be smoothly incorporated in upcoming OTP P9/R9 releases as well! Some benchmark results and the Erlang source (also in the CVS tree) can be found at http://sowap.sourceforge.net/ Johan Blom Mobile Arts From baos@REDACTED Fri Jan 25 13:36:52 2002 From: baos@REDACTED (Bancroft Scott) Date: Fri, 25 Jan 2002 07:36:52 -0500 (EST) Subject: verifying encoding_comparison.html results Message-ID: Hi, I am trying to independently verify the results shown on http://www.erlang.org/project/megaco/encoding_comparison.html. Where can I get the source files (makefiles, test programs, etc.) used to produce the results shown on this comparison? Bancroft Scott From micael.karlberg@REDACTED Fri Jan 25 14:09:16 2002 From: micael.karlberg@REDACTED (Micael Karlberg) Date: Fri, 25 Jan 2002 14:09:16 +0100 Subject: verifying encoding_comparison.html results References: Message-ID: <3C5158FC.53387C6C@ericsson.com> Hi, Our measurement software is currently part of our test-suite, but we will extract it to make it a separate delivery. When we are done, we will announce it here and on our home page. Regards, /BMK Bancroft Scott wrote: > > Hi, > > I am trying to independently verify the results shown on > http://www.erlang.org/project/megaco/encoding_comparison.html. > Where can I get the source files (makefiles, test programs, etc.) > used to produce the results shown on this comparison? > > Bancroft Scott From elanda@REDACTED Sun Jan 27 00:11:58 2002 From: elanda@REDACTED (Ed Landa) Date: Sat, 26 Jan 2002 18:11:58 -0500 Subject: How to use gs:menu() as a pop-up inside a frame/canvas? Message-ID: <20020126181158.A1935@xeme.com> I've been trying to come up with the solution to this problem all day. Unfortunately, the docs only seem to hint at this feature being available and I can't find any similar contributed code anywhere. How can I create a pop-up menu inside of a frame? I have a canvas with several items on it, and I would like to bring up a menu when a user right-clicks on an item. I can build the menu just fine, but it never displays. I've tried config'ing the object with {map, true}, {active,true} and {post_at,{X,Y}} in all different combinations, but nothing happens. While looking thru the gs source, I noticed some comments about comments about some config options being "not implemented". Could it be that the pop-up stuff was never quite completed? Any assistance would be greatly appreciated. I can provide my test code if needed. Thanks, Ed -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 232 bytes Desc: not available URL: From gunilla@REDACTED Mon Jan 28 09:49:33 2002 From: gunilla@REDACTED (Gunilla Arendt) Date: Mon, 28 Jan 2002 09:49:33 +0100 Subject: How to use gs:menu() as a pop-up inside a frame/canvas? References: <3C542D54.5F25174D@arendt.se> Message-ID: <3C55109D.57D9CD3F@erix.ericsson.se> Hi, A popup menu can have a menubutton, window or frame as parent, but not a canvas. Below is a simple example of using a popup menu inside a frame. / Gunilla -module(gsmenu). -export([start/0, init/0]). start() -> spawn(?MODULE, init, []). init() -> GS = gs:start(), Win = gs:window(GS, [{width,200}, {height,100}, {buttonpress,true}, {map,true}]), Frm = gs:frame(Win, [{x,0}, {y,0}, {width,200}, {height,100}]), Menu = gs:menu(Frm), gs:menuitem(Menu, [{label,{text,"Item 1"}}]), gs:menuitem(Menu, [{label,{text,"Item 2"}}]), gs:menuitem(Menu, [{label,{text,"Item 3"}}]), loop(Menu). loop(Menu) -> receive {gs, _Obj, buttonpress, _Data, [_Button,X,Y|_]} -> gs:config(Menu, {post_at, {X,Y}}), loop(Menu); _ -> loop(Menu) end. Ed Landa wrote: > > I've been trying to come up with the solution to this problem all day. > Unfortunately, the docs only seem to hint at this feature being available and I > can't find any similar contributed code anywhere. > > How can I create a pop-up menu inside of a frame? I have a canvas with several > items on it, and I would like to bring up a menu when a user right-clicks on an > item. I can build the menu just fine, but it never displays. I've tried > config'ing the object with {map, true}, {active,true} and {post_at,{X,Y}} in > all different combinations, but nothing happens. > > While looking thru the gs source, I noticed some comments about comments about > some config options being "not implemented". Could it be that the pop-up stuff > was never quite completed? > > Any assistance would be greatly appreciated. I can provide my test code if > needed. > > Thanks, > Ed From joe@REDACTED Mon Jan 28 13:23:05 2002 From: joe@REDACTED (Joe Armstrong) Date: Mon, 28 Jan 2002 13:23:05 +0100 Subject: Behaviour of exit Message-ID: <200201281223.g0SCN5P15060@enfield.sics.se> Can anybody explain the behaviour of exit? If I write: fac(0) -> 1; fac(N) -> N*fac(N-1). g() -> (catch fac(abc)). Then the value of g() is {'EXIT',{badarith,[{examples,fac,1}, {examples,g,0}, {erl_eval,expr,3}, {erl_eval,exprs,4}, {shell,eval_loop,2}]}} But I had *expected* it to be something like:{'EXIT',{badarith,{examples,fac,1}} The error occurs in fac/1 and is caught in g/0 I had imagined that compiling g/0 would cause a "catch point" to be added to the stack, and that the exception would propagate up the stack and be caught in g/0. It seems very strange that the exception has contextual information about the stuff *above* g in the call sequence (i.e. that g was called from the shell) this is because wrapping a call in a catch (i.e. writing (catch fac(abc))) is supposed to complete contain the error in a "downwards" sence - so that the evaluation of g() is not in error. The example on pages 86 + 87 of the Erlang book (2'nd ed) is now invalid. 14> examples:demo(3). {caught_error,{badarg,[{erlang,tuple_to_list,[a]}, {examples,foo,1}, {examples,demo,1}, {erl_eval,expr,3}, {erl_eval,exprs,4}, {shell,eval_loop,2}]}} But the book says it should be {caught_error, badarg} Admittedly the *exact* arguments of {'EXIT', ....} have never been precisely defined - but I would have expected that an exception generated within (catch F) could never contain information from ouside the scope of the call to F. If we return to the fac/1 example, the error occurs when I try to do arithmetic on an atom i.e. I call fac(N) -> N*fac(N-1) with N = abc this makes the recursive call fac(N-1) and tries to compute abc-1. At this point I would expect the exception to be {badarith,'-',1,abc} (say) and I'd expect the *value* of (catch fac(abc)) to be {'EXIT',{badarith,'-',1,abc}}. I do not expect to be told the *context* of the call (from the shell) - this is irrelevant. It would seem desirable that the exeption given when '-' has an incorrect argument to be {badarith,'-',Arg1, Arg2}. I guess I can't ask "what does the spec say?" - since this area of the system doesn't seem to be documented (or is it?) /Joe From etxuwig@REDACTED Mon Jan 28 13:40:20 2002 From: etxuwig@REDACTED (Ulf Wiger) Date: Mon, 28 Jan 2002 13:40:20 +0100 (MET) Subject: Behaviour of exit In-Reply-To: <200201281223.g0SCN5P15060@enfield.sics.se> Message-ID: On Mon, 28 Jan 2002, Joe Armstrong wrote: >If we return to the fac/1 example, the error occurs when I try >to do arithmetic on an atom i.e. I call fac(N) -> N*fac(N-1) >with N = abc this makes the recursive call fac(N-1) and tries >to compute abc-1. > >At this point I would expect the exception to be >{badarith,'-',1,abc} (say) and I'd expect the *value* of (catch >fac(abc)) to be {'EXIT',{badarith,'-',1,abc}}. I do not expect >to be told the *context* of the call (from the shell) - this is >irrelevant. I do not agree that the context is irrelevant. However, I think value and context should be more clearly and consistently separated. The (full) context is often invaluable when trying to locate the root cause of an error in a large system - especially if the error occurs in non-pure code. /Uffe From garry@REDACTED Mon Jan 28 20:54:45 2002 From: garry@REDACTED (Garry Hodgson) Date: Mon, 28 Jan 2002 14:54:45 -0500 Subject: make rule to compile yecc grammars? Message-ID: <3C55AC85.E31BD5E9@sage.att.com> i'm using yecc to construct a parser, and would like to integrate it into the general build structure of the (larger) project. it's easy to generate the parser (say, foo_yecc) from within erlang, but i need to be able to do this from a Makefile line, and get the dependencies to the correcspoinding foo.yrl correct. does anyone have a little example of this i could look at? thanks. -- Garry Hodgson Let my inspiration flow Senior Hacker in token rhyme suggesting rhythm Software Innovation Services that will not forsake me AT&T Labs 'til my tale is told and done. garry@REDACTED From richardc@REDACTED Tue Jan 29 11:23:00 2002 From: richardc@REDACTED (Richard Carlsson) Date: Tue, 29 Jan 2002 11:23:00 +0100 (MET) Subject: make rule to compile yecc grammars? In-Reply-To: <3C55AC85.E31BD5E9@sage.att.com> Message-ID: 1) Put "my_parser.beam" in your target list some way or other. (I assume you have a rule ".erl.beam:" somewhere.) 2) Add ".yrl" to the .SUFFIXES pseudo-rule. 3) Include the following rule: .yrl.erl: echo "yecc:yecc($*,$*), halt()." | erl /Richard On Mon, 28 Jan 2002, Garry Hodgson wrote: > i'm using yecc to construct a parser, and would like to integrate > it into the general build structure of the (larger) project. > > it's easy to generate the parser (say, foo_yecc) from within erlang, > but i need to be able to do this from a Makefile line, and get the > dependencies to the correcspoinding foo.yrl correct. does anyone > have a little example of this i could look at? Richard Carlsson (richardc@REDACTED) (This space intentionally left blank.) E-mail: Richard.Carlsson@REDACTED WWW: http://www.csd.uu.se/~richardc/ From vlad.dumitrescu@REDACTED Tue Jan 29 13:50:43 2002 From: vlad.dumitrescu@REDACTED (Vlad Dumitrescu (QRV)) Date: Tue, 29 Jan 2002 13:50:43 +0100 Subject: Emacs TAGS Message-ID: <5F03ACA2F76DD411B8BC00508BE3B4D70997F84B@esemont203.gbg.edt.ericsson.se> Hi good folks, I have a wondering about the TAGS functionality present (or wanted) in erlang.el >From what I've dug up, right now "normal" TAGS functionality works fine most of the time. However there are some things that I'd like to be able to do and so far couldn't get them to work. Either because I haven't found them or because they aren't implementerd. If more people are interested, I can lend a hand for helping to implement them. They are (in no particular order): 1. lookup/complete tags of the form "module:func" 2. lookup/complete only exported functions from other modules than the one in the active buffer I think that #1 requires only some simple processing of the TAGS file. For #2 to work, the filtering of the TAGS file should have some knowledge of Erlang syntax... Not very difficult, but since it may already be done, I ask first and see what's to be done later. Best regards, Vlad From svg@REDACTED Tue Jan 29 14:37:38 2002 From: svg@REDACTED (Vladimir Sekissov) Date: Tue, 29 Jan 2002 18:37:38 +0500 (YEKT) Subject: Emacs TAGS In-Reply-To: <5F03ACA2F76DD411B8BC00508BE3B4D70997F84B@esemont203.gbg.edt.ericsson.se> References: <5F03ACA2F76DD411B8BC00508BE3B4D70997F84B@esemont203.gbg.edt.ericsson.se> Message-ID: <20020129.183738.125705057.svg@surnet.ru> Good day, vlad.dumitrescu> I have a wondering about the TAGS functionality present (or wanted) in erlang.el vlad.dumitrescu> ... vlad.dumitrescu> If more people are interested, I can lend a hand for helping to implement them. They are (in no particular order): vlad.dumitrescu> vlad.dumitrescu> 1. lookup/complete tags of the form "module:func" vlad.dumitrescu> 2. lookup/complete only exported functions from other modules than the one in the active buffer vlad.dumitrescu> vlad.dumitrescu> I think that #1 requires only some simple processing of the TAGS file. I wrote Erlang BNF gramma for Emacs Semantic package (http://cedet.sourceforge.net, used in Emacs JDE, ECB and other packages) some times ago so most Semantic functionality works well with Erlang: - menu of module definitions, records and functions; - navigation between function clauses (next, previous, jump to, search); - function doc generation. Many others could be easily added. I can post it to mail list if somebody is interested in it. Best Regards, Vladimir Sekissov From garry@REDACTED Tue Jan 29 15:36:04 2002 From: garry@REDACTED (Garry Hodgson) Date: Tue, 29 Jan 2002 09:36:04 -0500 Subject: make rule to compile yecc grammars? References: Message-ID: <3C56B354.A44E63E8@sage.att.com> Richard Carlsson wrote: > > 1) Put "my_parser.beam" in your target list some way or other. > (I assume you have a rule ".erl.beam:" somewhere.) > > 2) Add ".yrl" to the .SUFFIXES pseudo-rule. > > 3) Include the following rule: > > .yrl.erl: > echo "yecc:yecc($*,$*), halt()." | erl > > /Richard works just fine. thank you. -- Garry Hodgson Let my inspiration flow Senior Hacker in token rhyme suggesting rhythm Software Innovation Services that will not forsake me AT&T Labs 'til my tale is told and done. garry@REDACTED From vlad.dumitrescu@REDACTED Tue Jan 29 15:56:19 2002 From: vlad.dumitrescu@REDACTED (Vlad Dumitrescu (QRV)) Date: Tue, 29 Jan 2002 15:56:19 +0100 Subject: Emacs TAGS Message-ID: <5F03ACA2F76DD411B8BC00508BE3B4D70997F84C@esemont203.gbg.edt.ericsson.se> Hi, I only had little time to look at EDE and friends, but I am already impressed! Already Speedbar adds a lot of useability to Emacs. I for one am interested in Erlang bindings. And I will certainly ask a lot of questions if it doesn't install smoothly :-) best regards, Vlad -----Original Message----- From: Vladimir Sekissov [mailto:svg@REDACTED] Sent: tisdag den 29 januari 2002 14:38 To: vlad.dumitrescu@REDACTED Cc: erlang-questions@REDACTED Subject: Re: Emacs TAGS Good day, vlad.dumitrescu> I have a wondering about the TAGS functionality present (or wanted) in erlang.el vlad.dumitrescu> ... vlad.dumitrescu> If more people are interested, I can lend a hand for helping to implement them. They are (in no particular order): vlad.dumitrescu> vlad.dumitrescu> 1. lookup/complete tags of the form "module:func" vlad.dumitrescu> 2. lookup/complete only exported functions from other modules than the one in the active buffer vlad.dumitrescu> vlad.dumitrescu> I think that #1 requires only some simple processing of the TAGS file. I wrote Erlang BNF gramma for Emacs Semantic package (http://cedet.sourceforge.net, used in Emacs JDE, ECB and other packages) some times ago so most Semantic functionality works well with Erlang: - menu of module definitions, records and functions; - navigation between function clauses (next, previous, jump to, search); - function doc generation. Many others could be easily added. I can post it to mail list if somebody is interested in it. Best Regards, Vladimir Sekissov From svg@REDACTED Tue Jan 29 16:03:23 2002 From: svg@REDACTED (Vladimir Sekissov) Date: Tue, 29 Jan 2002 20:03:23 +0500 (YEKT) Subject: make rule to compile yecc grammars? In-Reply-To: <3C56B354.A44E63E8@sage.att.com> References: <3C56B354.A44E63E8@sage.att.com> Message-ID: <20020129.200323.51315206.svg@surnet.ru> Good day, garry> > garry> > 1) Put "my_parser.beam" in your target list some way or other. garry> > (I assume you have a rule ".erl.beam:" somewhere.) garry> > garry> > 2) Add ".yrl" to the .SUFFIXES pseudo-rule. garry> > garry> > 3) Include the following rule: garry> > garry> > .yrl.erl: garry> > echo "yecc:yecc($*,$*), halt()." | erl garry> > garry> > /Richard .yrl.erl: erlc $< Also work well for me. Best Regards, Vladimir Sekissov From micael.karlberg@REDACTED Tue Jan 29 17:11:36 2002 From: micael.karlberg@REDACTED (Micael Karlberg) Date: Tue, 29 Jan 2002 17:11:36 +0100 Subject: verifying encoding_comparison.html results References: Message-ID: <3C56C9B8.B9598883@ericsson.com> Bancroft Scott wrote: > > Hi, > > I am trying to independently verify the results shown on > http://www.erlang.org/project/megaco/encoding_comparison.html. > Where can I get the source files (makefiles, test programs, etc.) > used to produce the results shown on this comparison? Ok, now the first version of our measurement "tool" is available from our megaco site at: http://www.erlang.org/project/megaco/ Megaco 1.0.2 is also needed. The code has been compiled with R8. For use with R7, a recompilation is needed. > > Bancroft Scott Regards, /BMK From svg@REDACTED Tue Jan 29 19:01:27 2002 From: svg@REDACTED (Vladimir Sekissov) Date: Tue, 29 Jan 2002 23:01:27 +0500 (YEKT) Subject: Emacs TAGS In-Reply-To: <5F03ACA2F76DD411B8BC00508BE3B4D70997F84C@esemont203.gbg.edt.ericsson.se> References: <5F03ACA2F76DD411B8BC00508BE3B4D70997F84C@esemont203.gbg.edt.ericsson.se> Message-ID: <20020129.230127.104051233.svg@surnet.ru> Good day, vlad.dumitrescu> I only had little time to look at EDE and friends, but I am already impressed! Already Speedbar adds a lot of useability to Emacs. vlad.dumitrescu> vlad.dumitrescu> I for one am interested in Erlang bindings. And I will certainly ask a lot of questions if it doesn't install smoothly :-) In the attachment is a semantic support for erlang. Installation: 1. Unpack archive somewhere in your path. 2. If you want 'document-inline' function to work with into erlang files apply patch from archive to semantic direcotry. 3 Your .emacs 3.1 Add this directory to elisp load path (add-to-list 'load-path "path-to/semantic-erlang") 3.2 Add semantic as described in semantic doc 3.3 Hook for erlang-mode (autoload 'semantic-default-erlang-setup "semantic-erlang") (add-hook 'erlang-mode-hook 'semantic-default-erlang-setup) Send me your comments and suggestions. Best Regards, Vladimir Sekissov -------------- next part -------------- A non-text attachment was scrubbed... Name: semantic-erlang.tar.gz Type: application/octet-stream Size: 10143 bytes Desc: not available URL: From frank.derks@REDACTED Wed Jan 30 21:02:04 2002 From: frank.derks@REDACTED (Frank Derks) Date: Wed, 30 Jan 2002 21:02:04 +0100 Subject: Erlang's ASN.1 implementation fails to compile X.880 Message-ID: <3.0.6.32.20020130210204.008287c0@pop.xs4all.nl> I had hoped that X.880 would not present any problems for Erlang's implementation of the ASN.1 compiler, but it seems I am somewhat out of luck. X.880 defines the following in the Remote-Operations-Generic-ROS-PDUs module: Errors {OPERATION:Operations} ERROR ::= {Operations.&Errors} The Erlang ASN.1 compiler is not able to compile this. I tried compiling the below ASN.1 (which is a stripped down version of the X.880 module I referred to above): Test DEFINITIONS AUTOMATIC TAGS ::= BEGIN OPERATION ::= CLASS { &ArgumentType OPTIONAL, &argumentTypeOptional BOOLEAN OPTIONAL, &returnResult BOOLEAN DEFAULT TRUE, &ResultType OPTIONAL, &resultTypeOptional BOOLEAN OPTIONAL, &Errors ERROR OPTIONAL, &Linked OPERATION OPTIONAL, &synchronous BOOLEAN DEFAULT FALSE, &alwaysReturns BOOLEAN DEFAULT TRUE, &InvokePriority Priority OPTIONAL, &ResultPriority Priority OPTIONAL, &operationCode Code UNIQUE OPTIONAL } ERROR ::= CLASS { &ParameterType OPTIONAL, ¶meterTypeOptional BOOLEAN OPTIONAL, &ErrorPriority Priority OPTIONAL, &errorCode Code UNIQUE OPTIONAL } Code ::= CHOICE { local INTEGER, global OBJECT IDENTIFIER } Priority ::= INTEGER Errors {OPERATION:Operations} ERROR ::= {Operations.&Errors} END -- end of Remote-Operations-Apdus definitions And I get the following results: Erlang ASN.1 version "1.3.2" compiling "Test.asn" Compiler Options: [] {'EXIT',{{case_clause,{pvaluesetdef,false, 38, 'Errors', [{{type, [], {'Externaltypereference', 38, 'Test', 'OPERATION'}, [], []}, {'Externaltypereference', 38, 'Test', 'Operations'}}], {type, [], {'Externaltypereference', 38, 'Test', 'ERROR'}, [], []}, {valueset, {'SingleValue', {'ValueFromObject', {objectset, 38, {'Externaltypereference', 38|...}}, [{typefieldreference,'Errors'}]} }}}}, [{asn1ct_check,checko,5}, {asn1ct_check,check,2}, {asn1ct,check,8}, {asn1ct,compile1,2}, {asn1ct,compile,2}, {erl_eval,expr,3}, {erl_eval,exprs,4}, {shell,eval_loop,2}]}} 15> Does anyone have an idea what might be wrong, or is this a case of the ASN.1 compiler simply not supporting the definition of "Errors" Regards, Frank From thierry@REDACTED Thu Jan 31 11:36:21 2002 From: thierry@REDACTED (thierry@REDACTED) Date: Thu, 31 Jan 2002 11:36:21 +0100 Subject: native compiler Message-ID: <20020131113621.A1168@musashi.nekhem> Hi all, Is there a native code compiler for erlang, like ghc for Haskell ? Thanks for your answer, Best regards, Thierry. From bertil.karlsson@REDACTED Thu Jan 31 14:38:54 2002 From: bertil.karlsson@REDACTED (Bertil Karlsson) Date: Thu, 31 Jan 2002 14:38:54 +0100 Subject: Erlang's ASN.1 implementation fails to compile X.880 References: <3.0.6.32.20020130210204.008287c0@pop.xs4all.nl> Message-ID: <3C5948EE.4C612969@uab.ericsson.se> Hello, Your example fails on the parameterized information object set Errors. The last version of the asn1-compiler (asn1-1.3.2) did not support some of the asn1 productions used in X.880. For instance Parameterized Information Object productions and Value Sets. We have since that release extended the ability of the compiler so that it can manage X.880. There is no patch available yet, though. /Bertil Karlsson Frank Derks wrote: > > I had hoped that X.880 would not present any problems for Erlang's > implementation of the ASN.1 compiler, but it seems I am somewhat out of luck. > > X.880 defines the following in the Remote-Operations-Generic-ROS-PDUs module: > > Errors {OPERATION:Operations} ERROR ::= {Operations.&Errors} > > The Erlang ASN.1 compiler is not able to compile this. I tried compiling > the below ASN.1 (which is a stripped down version of the X.880 module I > referred to above): > > Test > DEFINITIONS AUTOMATIC TAGS ::= > BEGIN > > OPERATION ::= CLASS > { > &ArgumentType OPTIONAL, > &argumentTypeOptional BOOLEAN OPTIONAL, > &returnResult BOOLEAN DEFAULT TRUE, > &ResultType OPTIONAL, > &resultTypeOptional BOOLEAN OPTIONAL, > &Errors ERROR OPTIONAL, > &Linked OPERATION OPTIONAL, > &synchronous BOOLEAN DEFAULT FALSE, > &alwaysReturns BOOLEAN DEFAULT TRUE, > &InvokePriority Priority OPTIONAL, > &ResultPriority Priority OPTIONAL, > &operationCode Code UNIQUE OPTIONAL > } > > ERROR ::= CLASS > { > &ParameterType OPTIONAL, > ¶meterTypeOptional BOOLEAN OPTIONAL, > &ErrorPriority Priority OPTIONAL, > &errorCode Code UNIQUE OPTIONAL > } > > Code ::= CHOICE > { > local INTEGER, > global OBJECT IDENTIFIER > } > > Priority ::= INTEGER > > Errors {OPERATION:Operations} ERROR ::= {Operations.&Errors} > > END -- end of Remote-Operations-Apdus definitions > > And I get the following results: > > Erlang ASN.1 version "1.3.2" compiling "Test.asn" > Compiler Options: [] > {'EXIT',{{case_clause,{pvaluesetdef,false, > 38, > 'Errors', > [{{type, > [], > {'Externaltypereference', > 38, > 'Test', > 'OPERATION'}, > [], > []}, > {'Externaltypereference', > 38, > 'Test', > 'Operations'}}], > {type, > [], > {'Externaltypereference', > 38, > 'Test', > 'ERROR'}, > [], > []}, > {valueset, > {'SingleValue', > {'ValueFromObject', > {objectset, > 38, > {'Externaltypereference', > 38|...}}, > > [{typefieldreference,'Errors'}]} > }}}}, > [{asn1ct_check,checko,5}, > {asn1ct_check,check,2}, > {asn1ct,check,8}, > {asn1ct,compile1,2}, > {asn1ct,compile,2}, > {erl_eval,expr,3}, > {erl_eval,exprs,4}, > {shell,eval_loop,2}]}} > 15> > > Does anyone have an idea what might be wrong, or is this a case of the > ASN.1 compiler simply not supporting the definition of "Errors" > > Regards, > > Frank From stephen_purcell@REDACTED Thu Jan 31 14:44:21 2002 From: stephen_purcell@REDACTED (Steve Purcell) Date: Thu, 31 Jan 2002 14:44:21 +0100 Subject: native compiler In-Reply-To: <20020131113621.A1168@musashi.nekhem> References: <20020131113621.A1168@musashi.nekhem> Message-ID: <20020131134421.GA1442@publishers-market.com> thierry@REDACTED wrote: > Hi all, > > Is there a native code compiler for erlang, like ghc for Haskell ? Thanks to the magic of Google... http://www.google.com/search?q=native+erlang+compiler "Hipe" is what you're looking for. Best wishes, -Steve From hal@REDACTED Thu Jan 31 16:30:49 2002 From: hal@REDACTED (Hal Snyder) Date: 31 Jan 2002 09:30:49 -0600 Subject: CVS, -vsn(), .app Message-ID: <87k7tyfsgm.fsf@gamera.vail> We're working on a release system for our OTP modules using the "$SECOND_ROOT" capability mentioned in section 3 of the sasl:systools manual. So far, all is going well, but there are a few questions relating to module versions in the .app file. 1. The CVS $Revision$ tag is as close as we can get (easily) to a pure version control rev number in a .erl. It is autoexpanded to, e.g.: -vsn("$Revision: 1.7 $"). Will this sort of version attribute in a module break anything? 2. It would be nice to grab the vsn attributes from freshly made .beam files and use them to cook myapp.app from myapp.app.src. Is there a tool somewhere in OTP (did I miss it?) that allows one to pull the vsn attribute out of a .beam? 3. It seems version tagging of modules in the .app is not used in the releas of otp_src_R8B. Is there some reason we should not be using this feature? Thanks! From etxuwig@REDACTED Thu Jan 31 16:46:42 2002 From: etxuwig@REDACTED (Ulf Wiger) Date: Thu, 31 Jan 2002 16:46:42 +0100 (MET) Subject: CVS, -vsn(), .app In-Reply-To: <87k7tyfsgm.fsf@gamera.vail> Message-ID: On 31 Jan 2002, Hal Snyder wrote: >We're working on a release system for our OTP modules using the >"$SECOND_ROOT" capability mentioned in section 3 of the sasl:systools >manual. So far, all is going well, but there are a few questions >relating to module versions in the .app file. > >1. The CVS $Revision$ tag is as close as we can get (easily) to a pure >version control rev number in a .erl. It is autoexpanded to, e.g.: > >-vsn("$Revision: 1.7 $"). > >Will this sort of version attribute in a module break anything? If you look in the source files of the recent Erlang/OTP releases, the -vsn() tag has been removed. The (main) reason for this is that having automatically updated tags in the source code would cause problems for the ClearCase merge facility. Basically, a manual merge was always needed, if only due to the fact that the -vsn() and -date() tags differed. >2. It would be nice to grab the vsn attributes from freshly >made .beam files and use them to cook myapp.app from >myapp.app.src. Is there a tool somewhere in OTP (did I miss >it?) that allows one to pull the vsn attribute out of a .beam? You can always call Module:module_info(attributes), and extract the version attribute (if there is one there). >3. It seems version tagging of modules in the .app is not used >in the releas of otp_src_R8B. Is there some reason we should >not be using this feature? Actually, the {Module, Vsn} format was the only one allowed in the beginning, but since we at AXD 301 had (and still have) automatically generated -vsn() attributes, we felt that it was very cumbersome to manually update the .app files every time. Thus, OTP introduced the alternative format of only listing the module name. Now, since OTP has dropped the use of -vsn() attributes themselves, my guess is that they didn't feel the need to keep the original format anymore. Also, since you can load modules from a patch directory, you're bound to end up with inconsistencies between the versions listed in the .app file and the -vsn() attribute (if any) in the .beam. Personally, I think removing the -vsn() attribute was a sound decision. /Uffe From Chandrashekhar.Mullaparthi@REDACTED Thu Jan 31 16:48:19 2002 From: Chandrashekhar.Mullaparthi@REDACTED (Chandrashekhar Mullaparthi) Date: Thu, 31 Jan 2002 15:48:19 -0000 Subject: CVS, -vsn(), .app Message-ID: <402DD461F109D411977E0008C791C31205E06424@imp02mbx.one2one.co.uk> 1. We use -vsn('$Id: $ '). This has more information than the $Revision$ tag. NO this wont break anything. 2. You can use the ident utility to extract the contents of the RCS tags. This is part of the CVS distribution. cheers, Chandru -----Original Message----- From: Hal Snyder [mailto:hal@REDACTED] Sent: 31 January 2002 15:31 To: erlang-questions@REDACTED Subject: CVS, -vsn(), .app We're working on a release system for our OTP modules using the "$SECOND_ROOT" capability mentioned in section 3 of the sasl:systools manual. So far, all is going well, but there are a few questions relating to module versions in the .app file. 1. The CVS $Revision$ tag is as close as we can get (easily) to a pure version control rev number in a .erl. It is autoexpanded to, e.g.: -vsn("$Revision: 1.7 $"). Will this sort of version attribute in a module break anything? 2. It would be nice to grab the vsn attributes from freshly made .beam files and use them to cook myapp.app from myapp.app.src. Is there a tool somewhere in OTP (did I miss it?) that allows one to pull the vsn attribute out of a .beam? Thanks! NOTICE AND DISCLAIMER: This email (including attachments) is confidential. If you have received this email in error please notify the sender immediately and delete this email from your system without copying or disseminating it or placing any reliance upon its contents. We cannot accept liability for any breaches of confidence arising through use of email. Any opinions expressed in this email (including attachments) are those of the author and do not necessarily reflect our opinions. We will not accept responsibility for any commitments made by our employees outside the scope of our business. We do not warrant the accuracy or completeness of such information. From peter@REDACTED Thu Jan 31 17:19:51 2002 From: peter@REDACTED (Peter H|gfeldt) Date: Thu, 31 Jan 2002 17:19:51 +0100 (MET) Subject: CVS, -vsn(), .app In-Reply-To: <87k7tyfsgm.fsf@gamera.vail> Message-ID: On 31 Jan 2002, Hal Snyder wrote: [...] > 2. It would be nice to grab the vsn attributes from freshly made .beam > files and use them to cook myapp.app from myapp.app.src. Is there a > tool somewhere in OTP (did I miss it?) that allows one to pull the vsn > attribute out of a .beam? Use beam_lib:version/1. /Peter From Sean.Hinde@REDACTED Thu Jan 31 17:33:00 2002 From: Sean.Hinde@REDACTED (Sean Hinde) Date: Thu, 31 Jan 2002 16:33:00 -0000 Subject: CVS, -vsn(), .app Message-ID: <402DD461F109D411977E0008C791C312039F67AF@imp02mbx.one2one.co.uk> Hal, > 1. We use > -vsn('$Id: $ '). > > This has more information than the $Revision$ tag. NO this wont break > anything. > And not only that, Here attached are two modules which we use to build whole releases from cvs to tar.gz. The idea is that you give it a .app file and it pulls out all of the correct versions from cvs. It does some basic checks to make sure that you have the latest/most appropriate versions of all files, runs an xref check and then builds the whole thing. It needs a very recent version of cvs. It relies on tags in cvs in the format rel_1_4 to pull out all the files for e.g app version 1.4. - Not many docs - read the source Luke! (hint - you will need to change the path to cvs in more than one place..) Usage release:all("App_name"). We also have a tool which put all the versions found in a system up on a web page - both currently loaded and what is in the current path - vsn.erl helps with this. If you tart it up any (or find it useful) then let us know Rgds, Sean NOTICE AND DISCLAIMER: This email (including attachments) is confidential. If you have received this email in error please notify the sender immediately and delete this email from your system without copying or disseminating it or placing any reliance upon its contents. We cannot accept liability for any breaches of confidence arising through use of email. Any opinions expressed in this email (including attachments) are those of the author and do not necessarily reflect our opinions. We will not accept responsibility for any commitments made by our employees outside the scope of our business. We do not warrant the accuracy or completeness of such information. -------------- next part -------------- A non-text attachment was scrubbed... Name: vsn.erl Type: application/octet-stream Size: 2506 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: cvs.erl Type: application/octet-stream Size: 6964 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: release.erl Type: application/octet-stream Size: 5458 bytes Desc: not available URL: From mickael.remond@REDACTED Thu Jan 31 18:55:26 2002 From: mickael.remond@REDACTED (Mickael Remond) Date: 31 Jan 2002 18:55:26 +0100 Subject: native compiler In-Reply-To: <20020131134421.GA1442@publishers-market.com> References: <20020131113621.A1168@musashi.nekhem> <20020131134421.GA1442@publishers-market.com> Message-ID: <1012499727.2840.3.camel@louxor> On Thu, 2002-01-31 at 14:44, Steve Purcell wrote: > thierry@REDACTED wrote: > > Hi all, > > > > Is there a native code compiler for erlang, like ghc for Haskell ? > > Thanks to the magic of Google... > > http://www.google.com/search?q=native+erlang+compiler > > "Hipe" is what you're looking for. Hipe has been added to the latest Erlang release (OTP/R8) So if you have Erlang OTP R8B you have access to the native compilation feature (On Solaris and Linux x86) Have fun. -- Micka?l R?mond From baos@REDACTED Thu Jan 31 22:41:01 2002 From: baos@REDACTED (Bancroft Scott) Date: Thu, 31 Jan 2002 16:41:01 -0500 (EST) Subject: verifying encoding_comparison.html results Message-ID: Hi, I downloaded the Megaco measurement software from your website and ran it locally on my machine which is an Intel Celeron 900MHz box running RedHat Linux. The Erlang/OTP environment was compiled with "--enable-hipe" option. While checking the results, the following questions arose: 1) Your charts at http://www.erlang.org/project/megaco/encode_time.jpg refer to binary encoders as just "PER" and "BER". Exactly which variant of your encoders are being referenced here - "original" or "native"? As you can see in the attachment to this email, the tool that you provided reports results for both your "original" and "native" implementations. 2) According to my measurements, on average the erl_dist encoder is 11.7 times faster than the BER native encoder and 17.3 times faster than the ordinary (non-native) BER encoder. However, your charts at http://www.erlang.org/project/megaco/encoding_comparison/encode_time.jpg show that the erl_dist encoder is "only" 8.8 times faster then BER. How do you explain this difference where my results shows erl_dist is 17.3 times faster than BER, while yours show only 8.8? Is it that the version of your libraries that you provided has a more highly optimized version of the erl_dist encoder/decoder than the one that you used in your own reports? If that is not the case, do you have any idea why it performs significantly better than is reported on the website? You can find the full set of output from my test run in the attached file. Bancroft Scott -------------- next part -------------- A non-text attachment was scrubbed... Name: megaco.zip Type: application/zip Size: 2808 bytes Desc: URL: From erlang@REDACTED Fri Jan 4 16:39:40 2002 From: erlang@REDACTED (Inswitch Solutions - Erlang Evaluation) Date: Fri, 4 Jan 2002 12:39:40 -0300 Subject: New to Earlang Message-ID: <002b01c19536$087b8590$0300a8c0@print> Hi, I am new to Earlang, trying to evaluate if Erlang is appropiate for building a fault tolerance commercial telecom prepaid platform, based on computer telephony modules, with a replicated or distributed database of about 500.000 to 1 millon subscribers. Now, 1) Does anybody have a commercial good experience with Erlang? 2) Is it possible to obtain commercial email-support? If so, does anybody know how much it costs? Thanks!! Regards, daniel Daniel Fernandez Inswitch Solutions -------------- next part -------------- An HTML attachment was scrubbed... URL: