Creating cursor with erlang rpc with mnesia activity - erlang

Hi I'm trying to make a cursor in mnesia from a remote node, for example:
I have the node which is the mnesia database owner and runs important processes in a dedicated server machine, and another node which have a process running in other computer and have to go through all the items to make some simple operations with the data. The thing is that I can make the miscellaneous process work if runs in the same node of mnesia but not remotely.
This is my code that runs locally:
make_cursor_local() ->
QD = qlc:sort(mnesia:table(customer, [{traverse, select}])),
mnesia:activity(async_dirty, fun() -> qlc:cursor(QD) end, mnesia_frag).
get_next_local(Cursor) ->
Get = fun() -> qlc:next_answers(Cursor,100) end,
mnesia:activity(async_dirty, Get, mnesia_frag).
del_cursor_local(Cursor) ->
qlc:delete_cursor(Cursor).
This is my actual code using rpc:
make_cursor() ->
Sort = rpc:call(?NamespaceNode, mnesia, table, [customer, [{traverse, select}]]),
QD = rpc:call(?NamespaceNode, qlc, sort, [Sort]),
CursorCreation = fun() -> qlc:cursor(qlc:sort(Sort)) end,
Cursor = rpc:call(?NamespaceNode, mnesia, activity, [async_dirty, CursorCreation, mnesia_frag]),
Cursor.
get_next(Cursor) ->
Get = fun() -> rpc:call(?NamespaceNode, qlc, next_answers, [Cursor, 100]) end,
Next = rpc:call(?NamespaceNode, mnesia, activity, [async_dirty, Get, mnesia_frag]),
Next.
del_cursor(Cursor) ->
rpc:call(?NamespaceNode, qlc, delete_cursor, [Cursor]).
This code is generating this error making the mnesia activity call in the make_cursor function:
{badrpc,
{'EXIT',
{undef,
[{#Fun<cleaner_app.2.116369932>,[],[]},
{mnesia_tm,non_transaction,5,
[{file,"mnesia_tm.erl"},{line,738}]},
{rpc,'-handle_call_call/6-fun-0-',5,
[{file,"rpc.erl"},{line,205}]}]}}} {badrpc,{'EXIT',{undef,[{#Fun<misc_app.2.116369932>,[],
[]},
{mnesia_tm,non_transaction,5,
[{file,"mnesia_tm.erl"},{line,738}]},
{rpc,'-handle_call_call/6-fun-0-',5,
[{file,"rpc.erl"},{line,205}]}]}}}

I found that the remote node can't execute anonymous functions created in another node so the error posted can be solved this way:
make_cursor() ->
Sort = rpc:call(?NamespaceNode, mnesia, table, [customer, [{traverse, select}]]),
QD = rpc:call(?NamespaceNode, qlc, sort, [Sort]),
rpc:call(?NamespaceNode, mnesia, activity, [sync_transaction, fun qlc:cursor/1, [QD], mnesia_frag]).
I found the answer here what kind of types can be sent on an erlang message?
Now I have to solve the Cursor ownership because I cant execute it from the remote node.
This is the error:
{badrpc,
{'EXIT',
{aborted,
{not_cursor_owner,
[{qlc,next_answers,
[{qlc_cursor,{<6920.991.0>,<6920.990.0>}},100],
[{file,"qlc.erl"},{line,515}]},
{mnesia_tm,apply_fun,3,[{file,"mnesia_tm.erl"},{line,833}]},
{mnesia_tm,execute_transaction,5,
[{file,"mnesia_tm.erl"},{line,813}]},
{mnesia,wrap_trans,6,[{file,"mnesia.erl"},{line,394}]},
{rpc,'-handle_call_call/6-fun-0-',5,
[{file,"rpc.erl"},{line,205}]}]}}}}

Related

How to assign tasks to a remote machines actors in Erlang to achieve distributed computing?

Here is what I am trying to achieve, I have an application that is mining bitcoins. I wish to improve its functionality by introducing a remote machine which connects to the server and the server assigns some work to it.
On a single machine, I initially spawn all the processes and store their ids (of actors), then loop through the Pids and assign the mining job to them. Here each of the actor's mines and tries to find the target hash that satisfies the difficulty.
Here is the code for the same:
-module(server).
-export([start/2, spawnMiners/4, mineCoins/3]).
start(LeadingZeroes, InputString) ->
MinersPIDList = spawnMiners(1000, [], LeadingZeroes, InputString),
mineCoins(MinersPIDList, LeadingZeroes, InputString).
spawnMiners(0, PIDs, LeadingZeroes, InputString) -> PIDs;
spawnMiners(NumberOfMiners, PIDs, LeadingZeroes, InputString) ->
PID = spawn(miner, findTargetHash, [LeadingZeroes, InputString]),
spawnMiners(NumberOfMiners - 1, [PID|PIDs], LeadingZeroes, InputString).
mineCoins([], LeadingZeroes, InputString) -> io:format("");
mineCoins([PID|PIDs], LeadingZeroes, InputString) ->
PID ! {self(), {mine}},
receive
{found, InputWithNonce, GeneratedHash} ->
io:format(“Found something!”);
{not_found} ->
io:format("");
Other ->
io:fwrite("In Other!")
end,
mineCoins(PIDs, LeadingZeroes, InputString).
Here, findTargetHash(LeadingZeroes, InputString) is the task miner/ process/ actor will run and return the result if found. So if a 1000 processes are being invoked, all of these are processed on the same machine.
This is what I wish to achieve next: Imagine a new machine with an IP address is connected to this server and after connecting, the server divides these 1000 processes between this machine and the remote machine (500 each, for literally performing distributed computing). I do not know where to start and how to achieve this. Any leads will be appreciated. (Maybe something to do with gen_tcp())

Extract values from list of tuples continuously in Erlang

I am learning Erlang from a Ruby background and having some difficulty grasping the thought process. The problem I am trying to solve is the following:
I need to make the same request to an api, each time I receive a unique ID in the response which I need to pass into the next request until there is not ID returned. From each response I need to extract certain data and use it for other things as well.
First get the iterator:
ShardIteratorResponse = kinetic:get_shard_iterator(GetShardIteratorPayload).
{ok,[{<<"ShardIterator">>,
<<"AAAAAAAAAAGU+v0fDvpmu/02z5Q5OJZhPo/tU7fjftFF/H9M7J9niRJB8MIZiB9E1ntZGL90dIj3TW6MUWMUX67NEj4GO89D"...>>}]}
Parse out the shard_iterator..
{_, [{_, ShardIterator}]} = ShardIteratorResponse.
Make the request to kinesis for the streams records...
GetRecordsPayload = [{<<"ShardIterator">>, <<ShardIterator/binary>>}].
[{<<"ShardIterator">>,
<<"AAAAAAAAAAGU+v0fDvpmu/02z5Q5OJZhPo/tU7fjftFF/H9M7J9niRJB8MIZiB9E1ntZGL90dIj3TW6MUWMUX67NEj4GO89DETABlwVV"...>>}]
14> RecordsResponse = kinetic:get_records(GetRecordsPayload).
{ok,[{<<"NextShardIterator">>,
<<"AAAAAAAAAAFy3dnTJYkWr3gq0CGo3hkj1t47ccUS10f5nADQXWkBZaJvVgTMcY+nZ9p4AZCdUYVmr3dmygWjcMdugHLQEg6x"...>>},
{<<"Records">>,
[{[{<<"Data">>,<<"Zmlyc3QgcmVjb3JkISEh">>},
{<<"PartitionKey">>,<<"BlanePartitionKey">>},
{<<"SequenceNumber">>,
<<"49545722516689138064543799042897648239478878787235479554">>}]}]}]}
What I am struggling with is how do I write a loop that keeps hitting the kinesis endpoint for that stream until there are no more shard iterators, aka I want all records. Since I can't re-assign the variables as I would in Ruby.
WARNING: My code might be bugged but it's "close". I've never ran it and don't see how last iterator can look like.
I see you are trying to do your job entirely in shell. It's possible but hard. You can use named function and recursion (since release 17.0 it's easier), for example:
F = fun (ShardIteratorPayload) ->
{_, [{_, ShardIterator}]} = kinetic:get_shard_iterator(ShardIteratorPayload),
FunLoop =
fun Loop(<<>>, Accumulator) -> % no clue how last iterator can look like
lists:reverse(Accumulator);
Loop(ShardIterator, Accumulator) ->
{ok, [{_, NextShardIterator}, {<<"Records">>, Records}]} =
kinetic:get_records([{<<"ShardIterator">>, <<ShardIterator/binary>>}]),
Loop(NextShardIterator, [Records | Accumulator])
end,
FunLoop(ShardIterator, [])
end.
AllRecords = F(GetShardIteratorPayload).
But it's too complicated to type in shell...
It's much easier to code it in modules.
A common pattern in erlang is to spawn another process or processes to fetch your data. To keep it simple you can spawn another process by calling spawn or spawn_link but don't bother with links now and use just spawn/3.
Let's compile simple consumer module:
-module(kinetic_simple_consumer).
-export([start/1]).
start(GetShardIteratorPayload) ->
Pid = spawn(kinetic_simple_fetcher, start, [self(), GetShardIteratorPayload]),
consumer_loop(Pid).
consumer_loop(FetcherPid) ->
receive
{FetcherPid, finished} ->
ok;
{FetcherPid, {records, Records}} ->
consume(Records),
consumer_loop(FetcherPid);
UnexpectedMsg ->
io:format("DROPPING:~n~p~n", [UnexpectedMsg]),
consumer_loop(FetcherPid)
end.
consume(Records) ->
io:format("RECEIVED:~n~p~n",[Records]).
And fetcher:
-module(kinetic_simple_fetcher).
-export([start/2]).
start(ConsumerPid, GetShardIteratorPayload) ->
{ok, [ShardIterator]} = kinetic:get_shard_iterator(GetShardIteratorPayload),
fetcher_loop(ConsumerPid, ShardIterator).
fetcher_loop(ConsumerPid, {_, <<>>}) -> % no clue how last iterator can look like
ConsumerPid ! {self(), finished};
fetcher_loop(ConsumerPid, ShardIterator) ->
{ok, [NextShardIterator, {<<"Records">>, Records}]} =
kinetic:get_records(shard_iterator(ShardIterator)),
ConsumerPid ! {self(), {records, Records}},
fetcher_loop(ConsumerPid, NextShardIterator).
shard_iterator({_, ShardIterator}) ->
[{<<"ShardIterator">>, <<ShardIterator/binary>>}].
As you can see both processes can do their job concurrently.
Try from your shell:
kinetic_simple_consumer:start(GetShardIteratorPayload).
Now your see that your shell process turns to consumer and you will have your shell back after fetcher will send {ItsPid, finished}.
Next time instead of
kinetic_simple_consumer:start(GetShardIteratorPayload).
run:
spawn(kinetic_simple_consumer, start, [GetShardIteratorPayload]).
You should play with spawning processes - it's erlang main strength.
In Erlang, you can write loop using tail recursive functions. I don't know the kinetic API, so for simplicity, I just assume, that kinetic:next_iterator/1 return {ok, NextIterator} or {error, Reason} when there are no more shards.
loop({error, Reason}) ->
ok;
loop({ok, Iterator}) ->
do_something_with(Iterator),
Result = kinetic:next_iterator(Iterator),
loop(Result).
You are replacing loop with iteration. First clause deals with case, where there are no more shards left (always start recursion with the end condition). Second clause deals with case, where we got some iterator, we do something with it and call next.
The recursive call is last instruction in the function body, which is called tail recursion. Erlang optimizes such calls - they don't use call stack, so they can run infinitely in constant memory (you will not get anything like "Stack level too deep")

Exceptions when running Erlang program on different terminal windows

I am developing a simple framework in Erlang to handle 2-player turn-based games. The code is the following:
-module(game).
-export([start_server/0,generate_server/0,add_player/0,remove_player/0]).
generate_server() ->
Table_num = 0,
Player_num = 0,
io:format("Server generated...~n", []),
io:format("The current number of tables is ~w~n", [Table_num]),
io:format("The current number of players is ~w~n", [Player_num]),
receive
login ->
io:format("A new player has connected!~n", []),
New = Player_num + 1,
io:format("The current number of players is ~w~n", [New]);
logout ->
io:format("You have beeen succesfully disconnected~n", [])
end.
start_server() ->
io:format("Welcome player!~nInitializing game...~n", []),
io:format("Generating server...~n", []),
register(server,spawn(game, generate_server, [])).
add_player() ->
server ! login.
remove_player() ->
server ! logout.
There are two main problems when I run this code:
When I execute add_player() and then remove_player(), this second function crashes with an exception
If I launch the program on one terminal window and then execute add_player() on a second terminal windows, I get an error. What should I do to be able to run it on more than one terminal window?
Any help would be highly appreciated.
1/
There is no loop in your server. When you start it, after some print, it waits on the receive statement.
When it receives the login message, it executes the operations, and then the server code is finished; the process die and is unregistered. All variables disappear and the VM clean up the memory...
So, later on, any process sending a message to the server will crash because you are using a name which is no more registered.
To make it works you should keep a list of connected players (in list for example) and recall the server loop with this list as parameter.
generate_server(Tlist,Plist) ->
io:format("The current number of tables is ~w~n", [length(Tlist)]),
io:format("The current number of players is ~w~n", [length(Plist)]),
receive
{login,Name} ->
io:format("A new player ~p has connected!~n", [Name]),
generate_server(Tlist,[Name|Plist]);
{logout,Name} ->
io:format("You have beeen succesfully disconnected~n", []),
generate_server(Tlist,lists:delete(Name,Plist))
end.
and the call to generate_server is done by
register(server,spawn(game, generate_server, [[],[]]))
2/
in order to use erlang messages between 2 different nodes, you need to:
share the same erlang coockie
discover the nodes (using netadm for example)
get the server pid or use golbal registered name
see example at http://learnyousomeerlang.com/distribunomicon#alone-in-the-dark
You missed out a loop body for the server. Your program crashes because the server receives only one message and exits. Consider another version of the server below:
generate_server() ->
Table_num = 0,
Player_num = 0,
io:format("Server generated...~n", []),
io:format("The current number of tables is ~w~n", [Table_num]),
io:format("The current number of players is ~w~n", [Player_num]),
loop([]).
loop(Players)->
receive
{From,{login,PlayerId}} ->
io:format("A new player has connected!~n", []),
io:format("The current number of players is ~w~n", [New]),
NewPlayers = case lists:member(PlayerId,Players) of
true ->
From ! {login_failed,exists},
Players;
false ->
From ! {login_success,true},
[PlayerId|Players]
end,
loop(NewPlayers);
{From,{logout,PlayerId}} ->
NewPlayers = case lists:member(PlayerId,Players) of
true ->
From ! {logout,ok},
Players -- [PlayerId];
false ->
From ! {logout,failed},
Players
end, loop(NewPlayers);
_ -> loop(Players)
end.
There; that looks much better.

Mnesia Query Cursors - Working with them in Practical applications

In most applications, its hard to avoid the need to query large amounts of information which a user wants to browse through. This is what led me to cursors. With mnesia, cursors are implemented using qlc:cursor/1 or qlc:cursor/2. After working with them for a while and facing this problem many times,
11> qlc:next_answers(QC,3).
** exception error: {qlc_cursor_pid_no_longer_exists,<0.59.0>}
in function qlc:next_loop/3 (qlc.erl, line 1359)
12>
It has occured to me that the whole cursor thing has to be within one mnesia transaction: executes as a whole once. like this below
E:\>erl
Eshell V5.9 (abort with ^G)
1> mnesia:start().
ok
2> rd(obj,{key,value}).
obj
3> mnesia:create_table(obj,[{attributes,record_info(fields,obj)}]).
{atomic,ok}
4> Write = fun(Obj) -> mnesia:transaction(fun() -> mnesia:write(Obj) end) end.
#Fun<erl_eval.6.111823515>
5> [Write(#obj{key = N,value = N * 2}) || N <- lists:seq(1,100)],ok.
ok
6> mnesia:transaction(fun() ->
QC = cursor_server:cursor(qlc:q([XX || XX <- mnesia:table(obj)])),
Ans = qlc:next_answers(QC,3),
io:format("\n\tAns: ~p~n",[Ans])
end).
Ans: [{obj,20,40},{obj,21,42},{obj,86,172}]
{atomic,ok}
7>
When you attempt to call say: qlc:next_answers/2 outside a mnesia transaction, you will get an exception. Not only just out of the transaction, but even if that method is executed by a DIFFERENT process than the one which created the cursor, problems are bound to happen.
Another intresting finding is that, as soon as you get out of a mnesia transaction, one of the processes which are involved in a mnesia cursor (apparently mnesia spawns a process in the background), exits, causing the cursor to be invalid. Look at this below:
-module(cursor_server).
-compile(export_all).
cursor(Q)->
case mnesia:is_transaction() of
false ->
F = fun(QH)-> qlc:cursor(QH,[]) end,
mnesia:activity(transaction,F,[Q],mnesia_frag);
true -> qlc:cursor(Q,[])
end.
%% --- End of module -------------------------------------------
Then in shell, i use that method:
7> QC = cursor_server:cursor(qlc:q([XX || XX <- mnesia:table(obj)])).
{qlc_cursor,{<0.59.0>,<0.30.0>}}
8> erlang:is_process_alive(list_to_pid("<0.59.0>")).
false
9> erlang:is_process_alive(list_to_pid("<0.30.0>")).
true
10> self().
<0.30.0>
11> qlc:next_answers(QC,3).
** exception error: {qlc_cursor_pid_no_longer_exists,<0.59.0>}
in function qlc:next_loop/3 (qlc.erl, line 1359)
12>
So, this makes it very Extremely hard to build a web application in which a user needs to browse a particular set of results, group by group say: give him/her the first 20, then next 20 e.t.c. This involves, getting the first results, send them to the web page, then wait for the user to click NEXT then ask qlc:cursor/2 for the next 20 and so on. These operations cannot be done, while hanging inside a mnesia transaction !!! The only possible way, is by spawning a process which will hang there, receiving and sending back next answers as messages and receiving the next_answers requests as messages like this:
-define(CURSOR_TIMEOUT,timer:hours(1)).
%% initial request is made here below
request(PageSize)->
Me = self(),
CursorPid = spawn(?MODULE,cursor_pid,[Me,PageSize]),
receive
{initial_answers,Ans} ->
%% find a way of hidding the Cursor Pid
%% in the page so that the subsequent requests
%% come along with it
{Ans,pid_to_list(CursorPid)}
after ?CURSOR_TIMEOUT -> timedout
end.
cursor_pid(ParentPid,PageSize)->
F = fun(Pid,N)->
QC = cursor_server:cursor(qlc:q([XX || XX <- mnesia:table(obj)])),
Ans = qlc:next_answers(QC,N),
Pid ! {initial_answers,Ans},
receive
{From,{next_answers,Num}} ->
From ! {next_answers,qlc:next_answers(QC,Num)},
%% Problem here ! how to loop back
%% check: Erlang Y-Combinator
delete ->
%% it could have died already, so we be careful here !
try qlc:delete_cursor(QC) of
_ -> ok
catch
_:_ -> ok
end,
exit(normal)
after ?CURSOR_TIMEOUT -> exit(normal)
end
end,
mnesia:activity(transaction,F,[ParentPid,PageSize],mnesia_frag).
next_answers(CursorPid,PageSize)->
list_to_pid(CursorPid) ! {self(),{next_answers,PageSize}},
receive
{next_answers,Ans} ->
{Ans,pid_to_list(CursorPid)}
after ?CURSOR_TIMEOUT -> timedout
end.
That would create a more complex problem of managing process exits, tracking / monitoring e.t.c. I wonder why the mnesia implementers didnot see this !
Now, that brings me to my questions. I have been walking around the web for solutions and you could please check out these links from which the questions arise: mnemosyne, Ulf Wiger's Solution to Cursor Problems, AMNESIA - an RDBMS implementation of mnesia.
1. Does anyone have an idea on how to handle mnesia query cursors in a different way from what is documented, and is worth sharing ?
2. What are the reasons why mnesia implemeters decided to force the cursors within a single transaction: even the calls for the next_answers ?
3. Is there anything, from what i have presented, that i do not understand clearly (other than my bad buggy illustration code - please ignore those) ?
4. AMNESIA (on section 4.7 of the link i gave above), has a good implementation of cursors, because the subsequent calls for the next_answers, do not need to be in the same transaction, NOR by the same process. Would you advise anyone to switch from mnesia to amnesia due to this and also, is this library still supported ?
5. Ulf Wiger , (the author of many erlang libraries esp. GPROC), suggests the use of mnesia:select/4. How would i use it to solve cursor problems in a web application ? NOTE: Please do not advise me to leave mnesia and use something else, because i want to use mnesia for this specific problem. I appreciate your time to read through all this question.
The motivation is that transaction grabs (in your case) read locks.
Locks can not be kept outside of transactions.
If you want, you can run it in a dirty_context, but you loose the
transactional properties, i.e. the table may change between invocations.
make_cursor() ->
QD = qlc:sort(mnesia:table(person, [{traverse, select}])),
mnesia:activity(async_dirty, fun() -> qlc:cursor(QD) end, mnesia_frag).
get_next(Cursor) ->
Get = fun() -> qlc:next_answers(Cursor,5) end,
mnesia:activity(async_dirty, Get, mnesia_frag).
del_cursor(Cursor) ->
qlc:delete_cursor(Cursor).
I think this may help you :
use async_dirty instead of transaction
{Record,Cont}=mnesia:activity(async_dirty, fun mnesia:select/4,[md,[{Match_head,[Guard],[Result]}],Limit,read])
then read next Limit number of records:
mnesia:activity(async_dirty, fun mnesia:select/1,[Cont])
full code:
-record(md,{id,name}).
batch_delete(Id,Limit) ->
Match_head = #md{id='$1',name='$2'},
Guard = {'<','$1',Id},
Result = '$_',
{Record,Cont} = mnesia:activity(async_dirty, fun mnesia:select/4,[md,[{Match_head,[Guard],[Result]}],Limit,read]),
delete_next({Record,Cont}).
delete_next('$end_of_table') ->
over;
delete_next({Record,Cont}) ->
delete(Record),
delete_next(mnesia:activity(async_dirty, fun mnesia:select/1,[Cont])).
delete(Records) ->
io:format("delete(~p)~n",[Records]),
F = fun() ->
[ mnesia:delete_object(O) || O <- Records]
end,
mnesia:transaction(F).
remember you can not use cursor out of one transaction

Best way to print out Mnesia table

I tried this code snippet:
print_next(Current) ->
case mnesia:dirty_next(muppet, Current) of
'$end_of_table' ->
io:format("~n", []),
ok;
Next ->
[Muppet] = mnesia:dirty_read({muppet, Next}),
io:format("~p~n", [Muppet]),
print_next(Next),
ok
end.
print() ->
case mnesia:dirty_first(muppet) of
'$end_of_table' ->
ok;
First ->
[Muppet] = mnesia:dirty_read({muppet, First}),
io:format("~p~n", [Muppet]),
print_next(First),
ok
end.
But it is so long. Also I can use dirty_all_keys and then iterate through key list, but I want to know if there is a better way to print out Mnesia table contents.
If you just want a quick and dirty way to print the contents of a Mnesia table in the shell, and if your table is not of type disc_only_copies, then you can take advantage of the fact that Mnesia stores its data in ETS tables and run:
ets:tab2list(my_table).
or, if you think the shell truncates the data too much:
rp(ets:tab2list(my_table)).
Not recommended for "real" code, of course.
For a simple and quick look at your table contents you can use select function of mnesia with catch-all Match Specification as follows:
CatchAll = [{'_',[],['$_']}].
mnesia:dirty_select(TableName, CatchAll).
and also you can run it inside a transaction context:
CatchAll = [{'_',[],['$_']}].
SelectFun = fun() -> mnesia:select(TableName, CatchAll) end.
mnesia:transaction(SelectFun).
however be careful if you are in a production environment with a big data.
Well, if the intent is to see the contents of your table, there is the application called tv, which can view both ETS and mnesia tables.
If you wish to see all the table contents on your terminal, then try something like this:
traverse_table_and_show(Table_name)->
Iterator = fun(Rec,_)->
io:format("~p~n",[Rec]),
[]
end,
case mnesia:is_transaction() of
true -> mnesia:foldl(Iterator,[],Table_name);
false ->
Exec = fun({Fun,Tab}) -> mnesia:foldl(Fun, [],Tab) end,
mnesia:activity(transaction,Exec,[{Iterator,Table_name}],mnesia_frag)
end.
Then if your table is called muppet, you use the function as follows:
traverse_table_and_show(muppet).
Advantages of this:
If its executed within a transaction , it will have no problems of nested transactions. It is less work because its done within one mnesia transaction through mnesia iterator functionality as compared to your implementation of get_next_key -> do_read_with_key -> then read the record (these are many operations). With this, mnesia will automatically tell that it has covered all the records in your entire table. Also, if the table is fragmented, your functionality will only display records in the first fragment. This will iterate through all the fragments the belong to that table.
In this iteration mnesia method, i do nothing with the Accumulator variable which should go along with the Iterator fun and thats why you see the underscore for the second variable.
Details of this iteration can be found here: http://www.erlang.org/doc/man/mnesia.html#foldl-3
As Muzaaya told, you can you use tv (table visualizer tool) to view both mnesia and ets tables.
Alternatively, you can use the following code to get mnesia table data - Print on terminal or in case you want to store the result in a file :
select_all() ->
mnesia:transaction(
fun() ->
P=qlc:e(qlc:q([E || E <- mnesia:table(tableName)])), %query to select all data from table named 'tableName'
io:format(" ~p ~n ", [P]), % Prints table data on terminal
to_file("fileName.txt",P) % to_file method writes the data to file
end ).
to_file(File, L) ->
mnesia:transaction(
fun() ->
{ok, S} = file:open(File, write),
lists:foreach(fun(X) -> io:format(S, "~p.~n" ,[X]) end, L),
file:close(S)
end).

Resources