Search code examples
weberlangmnesiayawserlang-shell

Mnesia can't create tables when ran by Yaws, but can when ran from the Erlang shell


I have a .yaws file which invokes the setup/0 function from the authenticate module I wrote, which I've placed in the ebin directory. When I call authenticate:setup/0 from the Erlang shell, it creates a table just fine, but when I load something.yaws in the browser, which calls the authenticate:setup/0 function, it returns {aborted,{bad_type,users,disc_copies,nonode@nohost}} (something.yaws just returns the return value of authenticate:setup/0 embedded in html for debugging purposes).

Here's the setup/0 function:

setup() ->
    mnesia:create_schema([node()]),
    mnesia:start(),
    mnesia:create_table(users, [{type, set}, {record_name, user}, {disc_copies, [node()]}, {attributes, record_info(fields, user)}]).

and here's the user record:

-record(user, {username, hashed_pw, salt}).

(I have tried calling it from the Erlang shell after I've tried it in the browser, so that couldn't have interfered with it.)

If I run yaws --mnesiadir /usr/local/lib/yaws-appmods/mnesia/, I get

Erlang/OTP 19 [erts-8.1] [source] [64-bit] [smp:8:8] [async-threads:10] [kernel-poll:true]

Eshell V8.1  (abort with ^G)
1> 
=INFO REPORT==== 7-Nov-2016::00:04:49 ===
Yaws: Using config file /etc/yaws/yaws.conf

=INFO REPORT==== 7-Nov-2016::00:04:49 ===
Yaws: Using global subconfig file /etc/yaws/conf.d/localhost.conf

=INFO REPORT==== 7-Nov-2016::00:04:49 ===
Ctlfile : /home/username/.yaws/yaws/default/CTL

=INFO REPORT==== 7-Nov-2016::00:04:49 ===
Yaws: Listening to 0.0.0.0:8080 for <1> virtual servers:
 - http://localhost:8080 under /usr/share/yaws/www
rd(user, {username, hashed_pw, salt}).
user
2> mnesia:create_schema([node()]), mnesia:start(), mnesia:create_table(users, [{type, set}, {record_name, user}, {disc_copies, [node()]}, {attributes, record_info(fields, user)}]).
{aborted,{bad_type,users,disc_copies,nonode@nohost}}

If I run the same erlang code in the Erlang shell started with erl -mnesia dir '"/usr/local/lib/yaws-appmods/mnesia/"', it works just fine.


Solution

  • When you run Yaws, pass the command-line option --mnesiadir dir to tell it where you want it to store mnesia data. The dir argument of the option should be the pathname of the directory where you want the data to live. For example, passing --mnesiadir /tmp will cause Yaws to store mnesia data in the /tmp directory.

    BTW, you can see the same error with the Erlang shell without Yaws if you pass it an mnesia dir option that sets the mnesia data directory to something nonexistent:

    $ erl -mnesia dir '"/xyzfoo"'
    Erlang/OTP 19 [erts-8.1] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:10] [hipe] [kernel-poll:false]
    
    Eshell V8.1  (abort with ^G)
    1> rd(user, {username, hashed_pw, salt}).
    user
    2> mnesia:create_schema([node()]), mnesia:start(), mnesia:create_table(users, [{type, set}, {record_name, user}, {disc_copies, [node()]}, {attributes, record_info(fields, user)}]).
    {aborted,{bad_type,users,disc_copies,nonode@nohost}}
    

    Here, we assume there's no such directory /xyzfoo. The first Erlang shell command defines the same user record you're using, and the second command performs the same steps as your authenticate:setup/0 function. As shown, it returns the same error you're seeing with Yaws.

    Note that the unusual quoting shown here for the directory name, '"/xyzfoo"', needed for passing the option properly to the Erlang shell (on typical UNIX-based systems, anyway), isn't necessary for the Yaws --mnesiadir option. Also note that the Erlang option is a single hyphen followed by two words, mnesia and dir, followed by the quoted directory name, whereas for Yaws the option is one word mnesiadir preceded by two hyphens and followed by a plain directory name.

    EDIT: if after setting the mnesia dir for Yaws you're still seeing problems, it's because you're trying to create your schema after mnesia is already running. When Yaws sees the --mnesiadir option, it starts the mnesia application. You should, therefore, either create your schema before you run Yaws, or stop mnesia before creating your schema. Change your authenticate:setup/0 function to the following, and it will work from Yaws:

    setup() ->
        mnesia:stop(),
        mnesia:create_schema([node()]),
        mnesia:start(),
        mnesia:create_table(users, [{type, set}, {record_name, user}, {disc_copies, [node()]}, {attributes, record_info(fields, user)}]).