Getting started with Mnesia

Though Mnesia, Erlang’s “built-in” database, has a lot going for it, one area that definitely doesn’t stand out is the documentation so here is the whirlwind tour I could have used when getting started. I won’t dwell on any particular subject, so consider this a starting point for further research - the documentation is actually ok once you know what it is you’re looking for!

Mnesia works best in conjunction with Erlang’s records. A simple record might look something like this:

-record(animal, {name,legs,noise}).

Here we’ve defined a record called “animal” with three fields. We can use this record definition to create an Mnesia table like this:

  mnesia:create_schema([node()]),
  mnesia:start(),
  mnesia:create_table(animal,
                         [{disc_copies, [node()]},
                          {attributes, record_info(fields,animal)}]).

When running this code, you will most likely want to use an Erlang command-line option like -mnesia dir ‘”db”‘ in order to specify the directory where the database will be created. It’s also important to pay attention to your node name and Erlang cookies if you intend to run a distributed Mnesia database.

Once we have a table, we can easily add records. The first point to note here is that ALL access to Mnesia goes within a transaction, which is defined in the form of a function. Here’s some simple code to add an item to the table we just defined:

  Fun = fun() ->
    mnesia:write(#animal{name="cow",legs=4,noise="moo"})
    end,
  mnesia:transaction(Fun).

Getting the data out again is also straightfoward, although there are many options. Firstly, note that by default Mnesia considers the first field in the record to be the key. With that in mind, you can use mnesia:read/2 to retreive a row by key:

  Fun = fun() ->
    mnesia:read({animal,"cow"})
    end,
  {atomic,[Row]}=mnesia:transaction(Fun),
  io:format("~p~n",[Row#animal.noise]).

All being well, the above should output “moo”. Another useful method for retreiving records is mnesia:match_object, which works as follows:

  Fun = fun() ->
    mnesia:match_object({animal,'_',4,'_'})
    end,
  {atomic,Results}=mnesia:transaction(Fun).

Here we end up with Results being a list of all the animals with four legs. Each entry in the list is a complete ‘animal’ record. Yet another option, and a very powerful one, is the Query List Comprehension. This uses the same concept as normal List Comprehensions, but mapped onto Mnesia, with some clever tricks behind the scenes to make it efficient. A quick example which simply retrieves all the animal records:

  mnesia:transaction(fun() -> qlc:eval(qlc:q([X || X <- mnesia:table(animal)])) end).

Finally, there is a very useful tool hidden away within the YAWS source that allows you to peruse your database from a browser. The code in question is ymnesia.erl, a YAWS appmod which can be found in the main src directory although it isn’t compiled by default. I found the easiest thing to do was to pull the file out into my project and run the appmod with YAWS in embedded mode as part of my application, which ensures it’s accessing the same database.

Any corrections to the above are welcome, since I’ve mostly typed it up from memory. I’ll no doubt cover more aspects of Mnesia at a later date, but in the meantime you can look at my earlier XML import code for a complete working example.

7 Responses to “Getting started with Mnesia”

  1. Mr eel Says:

    Thanks very much for writing this! It’s just the kick-off I needed to get started with Mnesia.

    I’m very impressed with it so far, but I’m really just fumbling about at the moment as I’m still trying to get a grasp of Erlang. Still, it’s all really interesting.

  2. Cadar Says:

    It’s a small error, this line

    io:format(”~p~n”,Row#animal.noise).

    should be

    io:format(”~p~n”,[Row#animal.noise]).

  3. CiaranG Says:

    Cadar, thanks for that - fixed it.

  4. Falko Says:

    Hi.

    Many thanks for the text. It s a nice intro.

    Two hints:

    1. The “Fun fun() …” (3 times) has to read “Fun = fun() …”.

    2. The query list comprehension thing needs an include. Something like
    -include(”qlc.hrl”).

    I had actually to provide the compülete path. At Windows something like
    -include(”C:\\Program Files\\erl5.5.5\\lib\\stdlib-1.14.5\\include\\qlc.hrl”).

    regards, f.

  5. CiaranG Says:

    Falko, thanks for that. The first fun() was correct and the second two wrong (now corrected) unless I missed something. I think in future I’d better just paste in from my working code instead of typing it up from memory!

  6. gp Says:

    So how many records can Mnesia hold?

    Is it stored on the hard drive or in memory?

    If you cluster Erlang nodes together, can they shared database space?

  7. CiaranG Says:

    @gp:

    1. Lots
    2. You can choose to set it up either way
    3. Yes

Leave a Reply

OpenID

Anonymous