[Ericsson AB]

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 the mnesia_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 
    sequence <string> children;  // 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.idl

Include 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 use erlang: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 in mnesia_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 and Orber 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 Java

Compile the person data definitions:

erlc +'{be, java}' person.idl

Import the necessary files.

import com.ericsson.otp.ic.*;

Find the connector and create a private session:

  public static mnesia._sessionStub start_session(String args[])
    {
      String SNode = new String(args[0]);
      String PNode = new String(args[1]);
      String Cookie = new String(args[2]);

      mnesia._connectorStub mccRef = null;
      mnesia._sessionStub mcsRef = null;
               
      try
        {
          
          mccRef = new mnesia._connectorStub(SNode+"0",PNode,Cookie,
                                             "mnesia_connector");
          
          com.ericsson.otp.ic.Pid mccPid = mccRef.connect();
          
          mcsRef = new mnesia._sessionStub(SNode+"1",PNode,Cookie,mccPid);

          return mcsRef;
        }
      catch(Exception se)
        {
          System.out.println("Unexpected exception: " + se.toString());
          se.printStackTrace();
          return null;
        }
    }

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.

  public static void create_person_table(mnesia._sessionStub mcsRef)
    {
      try {
      
        String name = "persons";
        mnesia.TableDef def = new mnesia.TableDef();
        def.type = mnesia.SetOrBag.bag;
        def.mode = mnesia.AccessMode.read_write;
        def.ram_copies = new String[0];
        def.disc_copies = new String[0];
        def.disc_only_copies = new String[0];
        int[] idxs = new int[1];
        idxs[0] = 4;
        def.index_list = idxs;
        String[] attrs = new String[4];
        attrs[0] = "name";
        attrs[1] = "personData";
        attrs[2] = "married_to";
        attrs[3] = "children";
        def.attributes = attrs;
        def.record_name = "persons_person"; // The used IDL type
        
        StringHolder reason;
        reason = new StringHolder();
        
        if(mnesia.Status.ok != mcsRef.create_table(name, def, reason))
          System.out.println("Create Table Error " + reason.value); 
      }
      catch(Exception se)
        {
          System.out.println("Unexpected exception: " + se.toString());
          return;
        } 
    }

The example insert and a read operation looks like:

  public static void insert_person(mnesia._sessionStub mcsRef,
                                   String name,
                                   persons.Sex sex,
                                   int age,
                                   int phone,
                                   String mt,
                                   java.lang.String[] children)
    {
      persons.data data;
      data = new persons.data(sex, age, phone);
      persons.person person = new persons.person();
      person.name = name;
      person.personData = data;
      person.married_to = mt;
      person.children = children;
      
      try
        {
          StringHolder reason = new StringHolder();       
          Term object = new Term();
          persons.personHelper.insert(object,person);
          
          if(mnesia.Status.ok != mcsRef.dirty_write("persons", object, reason))
            System.out.println("Insert person Error " + reason.value);
        }
      catch(Exception se)
        {
          System.out.println("Unexpected exception: " + se.toString());
          return;
        }
    }

  public static persons.person 
    get_person(mnesia._sessionStub mcsRef, String name)
    {   
      try
        {
          StringHolder reason = new StringHolder();       
          Term key = new Term();
          mnesia.RecordlistHolder res = new mnesia.RecordlistHolder();
          key.insert_string(name);

          if(mnesia.Status.ok == mcsRef.dirty_read("persons", 
                                                   key, res, reason))
            {
              if(res.value.length > 0) 
                {
                  persons.person rec1 = 
                    persons.personHelper.extract(res.value[0]);

                  return rec1;
                }
              else
                return null;                        
            }
          else
            {
              System.out.println("Insert person Error " + reason.value);
              return null;
            }
        }
        catch(Exception se)
          {
            System.out.println("Unexpected exception: " + se.toString());
            return null;
          }     
    }

Note: the usage of ETERM differs a little to the CORBA case, when using Java it mapps to the Term class which inherits from Any class.

4.4 A Session Example in C

Compile the person data definitions:

erlc +'{be, c_genserv}' person.idl

Include the necessary files.

#include <erl_interface.h>
#include "mnesia_session.h"
#include "mnesia_connector.h"
#include "persons.h"
#include <ic.h>

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 the ETERM structures, whereas, CORBA does this automatically.


Copyright © 1991-2006 Ericsson AB