![]() ![]() |
ORB/ODBMS Integration |
The pseudopersistence and smart pointer-based persistence approaches are not restricted to "pure ODBMSs": through object-relational mapping, these approaches are applicable to relational DBMSs as well. Virtual persistence, however, applies only to the case of a virtual memory-based ODBMS (i.e., ObjectStore).
My PhD dissertation contains a performance evaluation of these three approaches. Pseudopersistence appears as the best performer, followed closely by smart pointer-based persistence.
id
(ReferenceData
)
field of a CORBA reference to a persistent object. It also
provides an object activation function that builds a tie object
given an ODBMS reference to the corresponding implementation object.
All relationships between CORBA objects in a database are actually relationships between the corresponding implementation objects. An in-memory table of "active pseudopersistent objects" is kept by the ODA, allowing it to provide a function that returns the CORBA object reference associated with a given implementation object.
Rather than a replacement of the BOA, the Sunrise ODA is an add-on to the BOA, implemented as a library that uses and extends the BOA services (see figure below).
The "standard version" of the Sunrise ODA is portable to whatever environments for which the supported ORBs and ODBMSs are available, and is currently being used on Solaris 2.x and IRIX 5.x. The portability of this ODA version across ODBMSs is pretty high. Its portability across ORBs is not as high, due to holes in the BOA specification.
The ODA keeps no ORB-specific information in the database; a change to another ORB requires no schema evolution. It is even possible for a a single database to be simultaneously accessed by CORBA servers based upon different ORBs.
Additional Information:
Even in its standard version, the Sunrise ODA also supports mere
persistence of implementation objects. This is a naive approach that
makes implementation objects (not full CORBA objects) persistent, but does
not make CORBA object references persistent. Hence, persistence of
implementation objects is not an actual solution to the problem of
object persistence. This option is present mostly for historical reasons;
it was the first approach we implemented. It is still has some utility today,
for top-level objects. Among the many objects implemented by a CORBA
server, there is usually a "top-level" one, which represents the server itself.
The top-level object of a server is known to its clients, which use it
to start interacting with the server. A top-level object uses simple
persistence of implementation and remains active as long as its server
is active, because under this approach it can be assigned an id
(marker
, in Orbix terminology) arbitrarily chosen by its server
(Note 2). With this scheme, a server can choose an
id
known to its clients, which in turn use this id
to locate the server's top-level object
(Note 3).
Sometimes multiple IDL operations must be performed within a single transaction. For these cases, the ODA API provides functions that allow a sequence of operations to be grouped in a single transaction.
Pseudopersistence uses only object identity (ODBMS object references), plus the ability to convert ODBMS references to strings and vice-versa. Because these are fairly common ODBMS features, other ODBMSs can be employed instead of ObjectStore. All that is needed is a simple adaptation of the ODA code. With the use of an object-relational mediator, even a relational DBMS can be employed. In this case, primary keys play the role of ODBMS references. The mSQL release of ODA demonstrates the applicability of the pseudopersistence scheme to relational DBMSs.
Virtual persistence, however, requires also a virtual memory-based ODBMS
that offers page fault hooks (i.e., ObjectStore's
os_access_hook
s). In the case of a smart pointer-based ODBMS,
smart pointer-based persistence
should be implemented instead.
The relationships between CORBA objects in a TeleMed database are therefore represented by links between implementation objects; ObjectStore allows the use of plain C++ pointers to implement these links. The relationships between CORBA objects in different TeleMed databases are represented by CORBA references converted to strings.
This scheme provides maximum efficiency and a good level of DBMS independency, at the cost of some increase in the complexity of the server code. As an example of this increase in code complexity, consider a situation in which it would be desirable to have a homogeneous list of CORBA references, whose elements may refer either to local or to remote objects. Instead of a single and homogeneous list, two separate lists must be introduced: one with pointers to local implementation objects, other with stringfied CORBA references to remote objects.
id
s are used in the
pseudopersistence and virtual persistence approaches.
id
s is an interim solution.
Such practice, supported by Orbix in substitution to an actual
name service, is not in the spirit of the OMG architecture:
according to CORBA, object id
s should only be meaningful
to the object implementations themselves. This use of id
s
will be dropped when Iona's implementation of the CORBA Name Service
becomes available.
book
and
library
. C++ interface classes with the same names are
generated by the IDL compiler.
interface book { readonly attribute string author; readonly attribute string title; }; typedef sequence<book> bookList; interface library { readonly attribute string name; void add_book(in string name, in string author); bookList book_list(); };
Book
and Library
are the implementation
classes for book
and library
, respectively.
So a book
is a CORBA object, and has a Book
as its implementation object.
#ifndef PLIB_H #define PLIB_H #ifndef _SCHEMA_ // see schema.cc #include <plib_s.hh> // IDL-generated skeletons #endif #include <oda.h> // ODA header file // auxiliary string class class String { public: String(const char* value = ""); virtual ~String() { delete[] _value; } static os_typespec* get_os_typespec(); // for ObjectStore const char* c_str() { return _value; } char* value() const { return strcpy(new char[strlen(_value)+1], _value); } private: char* _value; }; // implementation class for book class Book { public: Book(const char* author, const char* title); virtual ~Book() {} static os_typespec* get_os_typespec(); // for ObjectStore char* author() const { return _author.value(); } char* title() const { return _title.value(); } private: String _author; String _title; }; // implementation class for library class Library { public: Library(const char* name = ""); virtual ~Library() {} static os_typespec* get_os_typespec(); // for ObjectStore char* name() const { return _name.value(); } void add_book(const char* name, const char* author); #ifndef _SCHEMA_ // because bookList is an IDL-generated class bookList* book_list() const; #endif private: String _name; os_List<Book*>& _book_list; // n.b.: Book, not book }; #ifndef _SCHEMA_ // ODA directives ODA_def_server(library) // the top-level object in the server is a library ODA_def_persistent(book) // books are made persistent by the ODA // dummy class, just to force template instantiation with SunPro C++ 4.0 // (_oda_persistent_book is a template class whose definition // is generated by the directive ODA_def_persistent(book), above.) static void dummy() { _oda_persistent_book<Book>::force_template_instantiation(); } #endif #endif
Since we are using the pseudopersistence approach, persistent relationships
between CORBA objects are expressed in terms of the underlying implementation
objects. So the library keeps a list of Book
s, not a list of
book
s.
#include "plib.h" extern CORBA::ORB_var orb; String::String(const char* value) : _value(new(os_segment::of(this), os_typespec::get_char(), strlen(value) + 1) char[strlen(value) + 1]) { strcpy(_value, value); } Book::Book(const char* author, const char* title) : _author(author), _title(title) {} Library::Library(const char* name) : _name(name), _book_list(os_List<Book*>::create(os_segment::of(this))) {} void Library::add_book(const char* name, const char* author) { _book_list.insert(new(os_segment::of(this), Book::get_os_typespec()) Book(name, author)); } bookList* Library::book_list() const { CORBA::ULong len = _book_list.cardinality(); book_ptr* buf = bookList::allocbuf(len); for (CORBA::ULong i = 0; i < len; i++) { // get a CORBA reference a persistent object of interface class book // (The argument to ODA_persistent_book // is an implementation object, of class Book, // retrieved from the _book_list. // The code for ODA_persistent_book is automatically generated // by the directive ODA_def_persistent(book).) buf[i] = ODA_persistent_book(_book_list.retrieve(i)); // ******** book::_duplicate(buf[i]); } return new bookList(len, len, buf, 1); }
In the line marked with "********
", we are calling the ODA
to get a CORBA reference to a book
object. If this
book
is not currently active, the ODA creates a tie to the
implementation (Book
) object passed to
ODA_persistent_book
, and embeds a stringfied ODBMS reference
to this implementation object into the id
field of the
book
object reference. Object references
generated by the ODA are persistent, in the
sense specified by CORBA.
// This file is _not_ compiled with CC. // Instead, it is processed by ossg (ObjectStore's schema generator), // which creates the database schema. #include <ostore/ostore.hh> #include <ostore/manschem.hh> #ifndef _SCHEMA_ // Unfortunately ossg does not yet accept some C++ constructs // generally accepted by C++ compilers. Because such constructs // appear in ORBeline header files and IDL-generated C++ files, // these files cannot be exposed to ossg. We are currently // circunventing this problem with the _SCHEMA_ definition // below. #define _SCHEMA_ #endif // _SCHEMA_ will be #defined during schema generation only. // (There is nothing magic with this name, any valid identifier // could be used instead.) // Application header files included here should use #ifdefs // to hide from ossg any ORBeline header files, IDL-generated source // files, and interface types. #include "plib.h" // contains "#ifdef _SCHEMA_" directives // this is how we tell ossg about Library and Book objects void dummy() { OS_MARK_SCHEMA_TYPE(Library); OS_MARK_SCHEMA_TYPE(Book); }
#include "dbname.h" // one and only one source file must #define ODA_STATIC_DEFS before // including oda.h (since plib.h includes oda.h, we are doing it here) #define ODA_STATIC_DEFS #include "plib.h" CORBA::ORB_var orb; CORBA::BOA_var boa; int main(int argc, char * const *argv) { // ObjectStore setup objectstore::initialize(); os_collection::initialize(); OS_ESTABLISH_FAULT_HANDLER; // initialize ORB orb = CORBA::ORB_init(argc, argv); boa = orb->BOA_init(argc, argv); // setup the databse file name and open it os_database* db = os_database::open(app_db_name, 0, 0664); // initialize ODA // (The second parameter below is the number of tie objects // cached by the ODA. This parameter defaults to 1023. ODA::initialize("TestDB", 500); // The ODA ensures that every operation is performed within // a database transaction. The default mode is "transaction // per operation". The ODA starts and ends transactions // to encompass every operation by a transaction. Read-only // transactions are used by default. The call below tells the // ODA to use an update transaction in the case of the operation // add_book of the library interface. ODA::register_update_op("library", "add_book"); // start a database transaction and look for the Library object os_transaction::begin(os_transaction::update); os_database_root* a_root = db->find_root("Library"); if (!a_root) { // then create it a_root = db->create_root("Library"); a_root->set_value(new(db, Library::get_os_typespec()) Library(), Library::get_os_typespec()); } // get the Library object Library* lib_impl = (Library*) a_root->get_value(Library::get_os_typespec()); // create a tie to this Library _oda_library_server<Library> lib(lib_impl, "Test"); // end of transaction, changes are commited to the database os_transaction::commit(); // server is ready to handle requests boa->obj_is_ready(&lib); boa->impl_is_ready("TestDB", ODA::activator()); OS_END_FAULT_HANDLER; return 0; }
![]() |
![]() |