Erlang's dets doesn't create file with open_file

399 views Asked by At

It's my first attempt to write anything in Erlang, so maybe the question is silly.

I'm writing a quite simple HTTP server using cowboy

db_name() -> "DB_test".

timestamp() ->
    calendar:datetime_to_gregorian_seconds(calendar:universal_time()).

sha(Str) ->
    <<X:256/big-unsigned-integer>> = crypto:hash(sha256, Str),
    lists:flatten(io_lib:format("~64.16.0b", [X])).

handle_post(Req0, State) -> 
    Link = binary_to_list(cowboy_req:header(<<"link">>, Req0)),
    dets:open_file(db_name(), []),
    dets:insert(db_name(), {hashed_url(Link), Link, timestamp()}),

    Req = cowboy_req:reply(200,
        #{<<"content-type">> => <<"text/plain">>},
        sha(Link),
        Req0),
    {ok, Req, State}.

The idea is that a POST HTTP request contains a 'link' header with some link. After recieving such request my server should store it's hash in dets table along with the link and its timestamp. The problem is that the "DB_test" file isn't created. Why?

1

There are 1 answers

0
Sölvi Páll Ásgeirsson On

Based on your example code, it's hard to say exactly why, since you're ignoring the return values from both dets:open_file/2 and dets:insert/2. Both of them return different values for the success and failure cases; but do not throw exceptions. See the official documentation for more details: http://erlang.org/doc/man/dets.html

The simplest solution to this is to crash the cowboy connection handling process in non-success cases. You can do that by doing something like the following:

 {ok, Ref} = dets:open_file(db_name(), []),
 ok = dets:insert(Ref, {hashed_url(Link), Link, timestamp()}),

This will crash with a badmatch exception in the failure cases, when the value returned cannot be pattern matched to the left-hand side of the statement, subsequently causing cowboy to return HTTP 500 to the client. You'll then see details on what the actual error was in the stacktrace logged

A second solution would be to explicitly handle the failure cases, you can use the 'case' keyword for that. An example would be something like:

case dets:open_file(db_name(), []) of
   {ok, Ref} ->
       do_success_things();
   {error, Reason}=E ->
       io:format("Unable to open database file: ~p~n", [E]),
       do_failure_things();
end

For further reading, I'd highly recommend the Syntax in functions and Errors and exceptions chapters of Learn you some Erlang for great good: http://learnyousomeerlang.com/