4 Session Examples
4.1 Example Introduction
In this and the following chapter several examples of the usage of the
Mnesia Session
interface will be introduced. The examples will first be written in Erlang and than the same functionality will be shown in a foreign language.The examples will contain some basic operations, create_table, write and read records both via the
mnesia_session
and themnesia_corba_session
interfaces.4.1.1 Data definition
A simple database has been created, with people as the subject. The person record containing other data types will be demonstrated in the rest of the examples. To begin with we define the data types that will be used in IDL.
// // A simple example on different structures used to access mnesia from the outside // // If the tables and structures should be accessed through a corba interface, they need // to be defined in a IDL specification so that the mnesia_session interface can access // the types needed to use corba type any. // module persons { enum Sex {male, female}; struct data { Sex sex; long age; long phone; }; struct person { string name; // Used as key data personData; // A reference to other data structure string married_to; // A relation sequencechildren; // A list }; }; Observe that the struct person, when mapping from IDL to Erlang, is prefixed with the module name followed by '_'. In this example, the table name would be
persons_person
. If this is not wanted the struct definition should be placed on the top level, i.e. above the module definition.4.2 A Session example in Erlang
A simplified example of a client written in Erlang to access
Mnesia
via the session interface is shown below.Compile the person data definitions with:
erlc +'{be, erl_genserv}' person.idlInclude the necessary files:
%% Include to get the mnesia types, used in create table -include_lib("mnesia_session/include/mnesia.hrl"). %% Include my own definitions -include("persons.hrl").Find the connector and create a private session:
start_session(Node) -> ConnPid = rpc:call(Node, mnesia_session_lib, lookup_connector, []), %% Use the factory to create a session SessPid = mnesia_connector:connect(ConnPid), {ConnPid, SessPid}.In this example, we used
mnesia_session_lib:lookup_connector/0
but it is also possible to useerlang:whereis(mnesia_connector)
. In Erlang, objects are represented as processes. To access the method of the object, call the method where the first argument is the object reference, as inmnesia_connector:connect(ConnPid)
.All functions in the IDL specification have an additional first argument which is the object reference. More information is given in the
IC
andOrber
documentation.To create a table with the structure defined in the IDL definition, we use the function create_person_table.
Define the table properties and call the function:
create_person_table(ObjKey) -> %% Define the table properties Attrs = [atom_to_list(F) || F <- record_info(fields, persons_person)], TabDef = #mnesia_TableDef{type = bag, mode = read_write, ram_copies = [], disc_copies = [], disc_only_copies = [], index_list = [4], %% Index on married_to attributes = Attrs, %% OBSERVE that the record_name must be exactly %% the same as the name of the structure/record record_name = "persons_person"}, Res = mnesia_session:create_table(ObjKey, "persons", TabDef), case Res of {ok, ""} -> ok; Else-> io:format("ERROR: ~s~n", [Else]) end.The example insert and a read operation looks like:
insert_person(SessionKey, Name, Sex, Age, Phone, Mt, Ch) when list(Name), atom(Sex), integer(Age), integer(Phone), list(Mt), list(Ch) -> Data = #persons_data{sex = Sex, age = Age, phone = Phone}, Person = #persons_person{name = Name, personData = Data, married_to = Mt, children = Ch}, {ok, ""} = mnesia_session:dirty_write(SessionKey, "persons", Person), Person.get_person(SessionKey, Name) when list(Name) -> {ok, RObj, ""} = mnesia_session:dirty_read(SessionKey, "persons", Name), hd(RObj).4.3 A Session example in C
Compile the person data definitions:
erlc +'{be, c_genserv}' person.idlInclude the necessary files.
#include#include "mnesia_session.h" #include "mnesia_connector.h" #include "persons.h" #include Find the connector and create a private session:
erlang_pid start_session(CORBA_Environment * env) { erlang_pid session_pid; session_pid = mnesia_connector_connect(NULL, env); if(env->_major != CORBA_NO_EXCEPTION) handle_error("connector_connect", env); return session_pid; }To create a table with the structure defined in the IDL definition, we use the function create_person_table. Define the table properties and call the function.
void create_person_table(CORBA_Environment * env) { int err; char * reason; mnesia_Status result; mnesia_TableDef tabdef; mnesia_Indices idxs; long idx_list[1] = {4}; char * attrs[4] = {"name", "personData", "married_to", "children"}; tabdef.type = mnesia_bag; tabdef.mode = mnesia_read_write; tabdef.ram_copies._maximum = 0; tabdef.ram_copies._length = 0; tabdef.ram_copies._buffer = NULL; tabdef.disc_copies._maximum = 0; tabdef.disc_copies._length = 0; tabdef.disc_copies._buffer = NULL; tabdef.disc_only_copies._maximum = 0; tabdef.disc_only_copies._length = 0; tabdef.disc_only_copies._buffer = NULL; tabdef.index_list._maximum = 5; tabdef.index_list._length = 1; tabdef.index_list._buffer = idx_list; tabdef.attributes._maximum = 5; tabdef.attributes._length = 4; tabdef.attributes._buffer = attrs; tabdef.record_name = "persons_person"; /* The name of the stored type/struct */ result = mnesia_session_create_table(NULL, "persons", &tabdef, &reason, env); if(env->_major != CORBA_NO_EXCEPTION) { fprintf(stderr,"\n error in create_table: %d\n", env->_major); exit(1); } else if(result != mnesia_ok) { fprintf(stderr, "Create table failed with reason %s", reason); } CORBA_free(reason); }The example insert and a read operation looks like:
void insert_person(CORBA_Environment * env, char *name, persons_Sex sex, int age, int phone, char * mt, persons_person_children * ch) { ETERM *person, *children, *temp; int err, i; char * reason; mnesia_Status result; extern char * oe_persons_Sex[]; children = erl_mk_empty_list(); if(ch != NULL) for(i = 0; i < ch->_length; i++) { temp = erl_mk_string(ch->_buffer[i]); children = erl_cons(temp, children); erl_free_term(temp); }; person = erl_format("{persons_person,~s,{persons_data,~a,~i,~i}, ~s, ~w}", name, oe_persons_Sex[sex], age, phone, mt, children); result = mnesia_session_dirty_write(NULL, "persons", person, &reason, env); if(env->_major != CORBA_NO_EXCEPTION) { fprintf(stderr,"\n error in insert_person: %d\n", env->_major); exit(1); } else if(result != mnesia_ok) { fprintf(stderr, "Insert person failed with reason %s", reason); exit(-1); } erl_free_term(children); erl_free_term(person); CORBA_free(reason); }void get_person(CORBA_Environment * env, char * name, persons_person * person) { int err, i; char * reason; mnesia_Status result; mnesia_Recordlist *rec_list; ETERM * key; key = erl_mk_string(name); result = mnesia_session_dirty_read(NULL, "persons", key, &rec_list, &reason, env); if(env->_major != CORBA_NO_EXCEPTION) { fprintf(stderr,"\n error in get_person: %d\n", env->_major); exit(1); } else if(result != mnesia_ok) { fprintf(stderr, "Get person failed with reason %s", reason); exit(-1); } if(rec_list->_length > 0) { /* Only interrested in the first match */ decode_person(rec_list->_buffer[0], person); for(i=0; i < rec_list->_length; i++) erl_free_term(rec_list->_buffer[i]); } else { fprintf(stderr, "Insert person failed empty_list returned "); exit(-1); } CORBA_free(rec_list); CORBA_free(reason); erl_free_term(key); }Note: the usage of
ETERM
differs when using C as the user must develop their own code to create and extract information from theETERM
structures, whereas, CORBA does this automatically.