You can build an ObjectStore application on multiple platforms and then use it to store and update data interchangeably on any of these platforms. Applications that run on more than one platform are considered to be heterogeneous.
To make an application heterogeneous, you must neutralize its schema for all platforms and then build the application on each platform. Neutralization is the process of modifying a schema so that it has identical data formats on each platform that runs the application. This is necessary because different compilers lay out data in different ways.
When building a heterogeneous application, consider address space limitations on all platforms. Database access patterns might work on some platforms but not on others.
You can start with an application that runs on one platform or you can create a new application. If you are building a new application, see the limitations in Restrictions before you design your application.
When you use Visual C++, the schema generator creates the application schema object file directly. On all other platforms, you must compile the application schema source file yourself.
Normally, you cannot build an application that can run on both 32-bit and 64-bit platforms. The only exception to this rule is that Digital UNIX can operate heterogeneously with 32-bit platforms. The compiler on this 64-bit platform allows you to mix 32-bit and 64-bit pointers through pragma statements in the source code. When all pointers in persistent classes are forced to be of the 32-bit variety, you can share these classes with 32-bit platforms. The following table includes the supported compilers.
When Is a Schema Neutral?
When an application is heterogeneous, its persistent objects are laid out in memory in identical formats for all platforms accessing the objects. The sizes and offsets of all data elements must be identical in both the creating architecture and the accessing architecture. What Causes Data Formats to Vary?
Compilers on different platforms can use different rules for laying out objects. Machine architectures might have differing requirements for alignment of data types. This can cause differing object layouts. For example, the following class might have a different layout in memory if the required alignment of the int data type is two-byte alignment instead of four-byte alignment:
struct X { char status; int value; };Layout incompatibilities are related to
Other features that can cause data formats to vary are
The schema generator always proposes adding explicit padding to your classes to achieve neutralization. In many cases, however, you can reduce the size of the end result by reordering the members of a class to eliminate some or all padding. For example:
class X { char a; int i; char b; int j; };The best way to neutralize this code is to reorder the members:
class X { int i; int j; char a; char b; };Because some applications depend on the order of members within a class, it is up to you to decide whether or not this method is appropriate for each case.
After you neutralize a schema, a class in the schema is the same size on each platform on which you run the application. If you run the ossize utility, the returned value is the actual size of the object in the database. Objects belonging to a particular class are the same size on each platform on which they exist.
You cannot use virtual base classes when some but not all of your compilers use a cfront or SGI layout.
Applications compiled with Sun ProCompiler C++, AIX C Set ++, DEC C++, VisualAge C++, and Visual C++ can use virtual base classes in a heterogeneous environment.
If you expect to run a heterogeneous application on a Digital UNIX platform, avoid using the long data type. On the Alpha platform, long data types are 64 bits, rather than the usual 32 bits. Types can only be neutralized for architectures that use the same size for the type.
In general, you should use 32-bit integers and floating-point formats that are four or eight bytes.
Floating-Point Data Conversion
During database access, it is not known whether or not the data might have been written by an application running on another platform. ObjectStore automatically converts data if necessary so that data is in the correct format for your application. There is, however, an exception to this rule. Pointers to Members
On some platforms, you cannot use pointers to members in persistent classes. Base Class Initialization Order
Occasionally, you might receive neutralization instructions from ossg that involve the reordering of base classes. Following these instructions might disturb dependencies in your source files. If this occurs, you might need to modify your source code to accommodate changes in the base class initialization order as well as to accommodate neutralization. Parameterized Classes
The schema generator instructs you to neutralize class instantiations rather than the template class itself. This is because you can create a template specialization with different parameters that produces a different layout. This can present a problem. For example:
template <class T> class Y { public: char a; T b; }; Y<char> y_char; Y<double> y_double;The Y<char> template requires no additional padding to be neutral. However, the Y<double> template does require padding. To define the schema as neutral, you can follow the neutralizer instructions and define a template specialization for Y<double>.
/* a simple template class that holds a data item */ template<class T> class Data { public: Data(T& the_data) : data(the_data) {} T data; }; /* a specialization that knows to strdup string data */ class Data<char*> { public: Data(char* the_data) : data (the_data ? strdup(the_data) : 0) {} ~Data() { if (data) free(data); } char* data; };Here is the template specialization you would define for the example:
class Y<double> { public: char a; char_os_pad_1[7] double b; };You might find that the schema generator instructs you to specialize each class instantiation in the same way. In this case, it is easier for you to change the template itself. Since the schema generator does not provide instructions for modifying class templates, it is up to you to decide when this is appropriate. For example:
Sizes for Data Types
A neutralized schema requires that a data type be the same size on all platforms. When the types involved are classes, the schema generator can determine how to achieve the same size. But when the types involved are primitive types, the schema generator cannot provide instructions for padding to achieve the same size. In this case, ossg displays messages similar to the ones following. You might receive multiple versions of the second message.
<err-0013-0006>The following neutralization problems occurred during the compilation of file m.cc: failures for class E: <err-0013-0011>Components of the class have differing sizes: Data member eIn general, you must do one of the following:
If you carefully followed the neutralization instructions and you still receive the Neutralization failure message, it might mean that your schema includes such a class. In this situation, contact Object Design Technical Support for assistance in neutralizing your schema.
An example of when this might occur is when you are using virtual base classes that contain doubles. Even with a single compiler (cfront is the most likely one), there might be cases where the schema generator cannot adequately align the virtual base classes for all platforms.
Neutralizing the Schema
Follow these instructions to generate a neutral application schema.
When there are layout discrepancies, the schema generator determines the changes needed to produce a neutral layout, and provides instructions for modifying your source files.
To invoke ossg, use the same format you use to generate an application, library, or compilation schema. The only difference is the addition of neutralizer options. The following format shows the addition of neutralization options when generating an application schema. You can also add neutralization options when you generate a library or compilation schema. For an explanation of the ossg command line, see Generating an Application or Component Schema. (Portions of the command line are on different lines only for clarity.)
ossg [ compilation_options] neutralizer_options [ other_schema_generator_options] {-assf app_schema_source_file | -asof app_schema_object_file} -asdb app_schema_database schema_source_file[ lib_schema.ldb ... ]
Specifying the -arch set n option creates internal information needed by the relocation subsystem. This information ensures access to the correct virtual function tables.
If you remove the -arch set n option, you might add data that is not properly aligned for a particular platform. The schema generator normally selects the most restrictive alignment. Without the -arch set n option, the schema generator cannot determine that the alignment must be larger on certain platforms.
Be sure to mark all required data types in the schema source file. When you fail to mark a required type, the schema generator cannot detect incompatibilities.
The schema generator might require neutralization to prevent straddling pointers (pointers that span pages). This might be necessary
ossg -arch set1 -padm -assf proj_schema.cc \ -asdb progschema.adb \ proj_schema_source.cc $(OS_ROOTDIR)/lib/liboscol.ldb \ $(OS_ROOTDIR)/lib/libosqry.ldbThe schema will be neutralized for use on platforms belonging to set1. Maximal padding will be done. Since this is not being invoked on a Windows platform, the schema generator produces an application schema source file (prog_schema.cc) that you must compile. The application schema will include the type information from the two library schemas specified.
#include <ostore/ostore.hh> #include <ostore/manschem.hh> class A { public: virtual void fun1(); double d; A(); }; OS_MARK_SCHEMA_TYPE(A);First, try running the schema generator and specifying -arch set1 for schema neutralization. These examples assume that you are running ossg on a UNIX platform. To try these examples on a Windows NT platform, you would specify -asof instead of -assf. Also, on Windows and OS/2 platforms, the specification of the path for ObjectStore header files would be -I%OS_ROOTDIR%\include instead of the way it is in the examples.
ossg -assf hetero.cc -asdb hetero.adb -arch set1 \ -I$OS_ROOTDIR/include hetero.cc
<err-0013-0002>The schema must be neutralized in order to operate heterogeneously with the architectures specified: The following schema modifications must occur: class A : public os_virtual_behavior /* New */ { public: char _os_pad_0[4]; /* New */ double d; };In the output, the schema generator does not display the member functions. It displays only the data members and nested types in the class definitions.
Also, the /* New */ comment in the output flags the changes you need to make. You must edit the schema source file to have this content:
#include <ostore/ostore.hh> #include <ostore/manschem.hh> class A : public os_virtual_behavior { public: virtual void fun1(); double d; char _os_pad_0[4]; A(); }; OS_MARK_SCHEMA_TYPE(A);Now the previous ossg command line generates the schema with no error messages.
ossg -assf hetero.assf -asdb hetero.adb -noreorg -arch set1 \ -I$OS_ROOTDIR/include hetero.cc
<err-0013-0002>The schema must be neutralized in order to operate heterogeneously with the architectures specified: The following schema modifications must occur: class A { public: os_pad_vftbl_start /* New */ char _os_pad_0[4]; /* New */ double d; char _os_pad_1[4]; /* New */ os_pad_vftbl_end /* New */ };Working from this output, edit the original class description as follows:
class A { public: virtual void fun1(); os_pad_vftbl_start char _os_pad_0[4]; double d; char _os_pad_1[4]; os_pad_vftbl_end A(); };Next, modify the original ossg command line by adding the -show_difference option. The only effect that this has is on the way that the changes are presented:
ossg -assf hetero.assf -asdb hetero.adb -arch set1 -show_ difference\ -I$OS_ROOTDIR/include hetero.cc
<err-0013-0002>The schema must be neutralized in order to operate heterogeneously with the architectures specified: The following schema modifications must occur: Changes for class A: Add os_virtual_behavior as the first base class Add a padding member as the first member: char _os_pad_0[4];As you can see, the output in this case is simpler. For complex classes, the difference mode of display might be more easily understood.
For most classes, the default (-show_whole) display behavior is probably simplest.
#include <ostore/ostore.hh> #include <ostore/manschem.hh> class A { public: virtual void fun1(int); A(); }; class B { public: virtual void fun2(char); B(); }; class C { public: virtual void fun3(void*); C(); }; class D : public virtual A, public virtual B, public C { public: D(); virtual void fun1(int); }; OS_MARK_SCHEMA_TYPE(D);In this case, neutralize with the set2 architecture group because heterogeneity of classes with virtual bases between cfront and non-cfront-type platforms is not supported.
ossg -assf hetero.assf -asdb hetero2.adb -arch set2 \ -I$OS_ROOTDIR/include hetero2.cc
<err-0013-0002>The schema must be neutralized in order to operate heterogeneously with the architectures specified: The following schema modifications must occur: class/* file: m.cc line: 19 */ class D : public os_vb_fbsc<0,A> /* New */, public C, public os_vb_fbs<0,B> /* New */ { };
The particular template that the schema generator chooses for a given virtual base depends on the characteristics of the virtual base and the derived class.
all: my_exec my_exec: main.o os_schema.o foo.o bar.o CC -o my_exec main.o os_schema.o foo.o bar.o -los -loscol $(OS_POSTLINK) my_exec os_schema.cc: schema_source.o # os_schema.cc must depend on all headers that # schema_source.cc depends on. # You must also set up default rules so that schema_source.cc # compiles to schema_source.o. ossg -arch set2 -showd -mrscp -asdb my_exec.adb \ -assf os_schema.cc $(CPPFLAGS) schema_source.cc \ $(OS_ROOTDIR)/lib/os_col.ldb
If you are neutralizing for any architecture set except set3 (which does not include OS/2), the schema generator assumes that the schema is to be used on OS/2. Consequently, unless you specify otherwise, the schema generator expects OS/2 to use one byte for small-valued enums. This causes a neutralization error.
Regardless of whether or not you intend to use the schema on OS/2, you must do one of the following:
enum embedd_enum { enum_val1, enum_val2, enum_val3, enum_val4 = 100000 };
In the options file, you maintain a list of any compiler options and pragma statements that alter default object layout required on all platforms in the application's heterogeneity set. The schema generator uses the compiler option file when determining what changes are necessary for schema neutralization. You tell ossg what schema options file to use by the -schema_options options_file command-line argument.
See Compiler Option Files for Architecture Sets for information about the contents of basic compiler option files for specific platform architectures. These describe what you should use as an absolute minimum for each architecture set.
If there are compiler options that you use on the current platform, specify them on the ossg command line as well as in the schema options file.
Compiler Option File Format
The compiler options file has the following structure:
{ compiler_spec | architecture_spec } [ ( class_list) ]
option
The compiler_spec variable indicates the compiler with which you are using the specified option.The architecture_spec indicates both the compiler and the platform that you are using. The possible values are in the following table.
The class_list variable lists one or more classes that the specified compiler option or pragma operates on. Classes in the list can be all application classes included in the schema. If you do not specify a class, the option applies to all possible classes.
Enclose the class list in parentheses and insert a space between two class names.
The option variable can be a compiler switch or a pragma statement.
Compiler switches
When the option variable is a compiler switch, it has one of the following forms:
switch compiler_switch switch compiler_switch compiler_switch_value switch compiler_switch '=' compiler_switch_valueThe compiler switches you can specify appear in the following table. See your compiler documentation for an explanation of each switch. These switches apply to an entire compilation rather than to a specific class.
pragma directive directive_valueThe pragma statements you can specify appear in the following table. See your compiler documentation for an explanation of these pragma statements.
Overriding Options Within the Compiler Option File
You can specify compiler options and pragmas at various levels. Specifications for a specific platform or compiler can override a specification that applies to all platforms or a set of platforms. Specifications for specific classes can override a specification for all classes. The order of the options in the compiler option file is not significant. For example:
intel_os2_visualage switch /Sp intel_os2_visualage (classA classB classC) switch /Sp2For all classes, ossg assumes that the compiler uses the /Sp switch. Except for classA, classB, and classC, ossg assumes the /Sp2 switch.
visualc++ switch /Zpn intel_os2_visualage switch /Sp4 intel_win32_msoft pragma pointers_to_members best_case visualc++ (ClassX) pragma pack (1) rs6000_cset pragma options align=full
class A { public: enum { X,Y,Z} id; };The platforms you intend to use are OS/2, Windows NT, and Solaris 2. This class will not be neutral unless you specify the /Su4 option on OS/2. (This option forces enums to be of size int.) You need a schema option file that contains the line
intel_os2_visualage option /Su4In this example, the name of the schema option file is schm.opt. When you generate the schema on OS/2, specify the /Su4 option. When you run ossg on the other platforms, specify schm.opt. Specifying the schema option file indicates to the schema generator exactly how objects are laid out on all platforms.
Compiler option file
When you use one of these compiler options, remember to include it in the compiler option file. In fact, if you specify -arch set1 for neutralization but you do not intend to use OS/2, you still need to specify compiler options that would be needed on OS/2. Compiler Option Files for Architecture Sets
This section provides basic compiler option files that are a minimum starting point for each of the architecture sets. Note that file contents are listed for set1 through set6. In the event that you are using any set beyond set6 (set7 through set11), be aware that these sets are based on the first six. See ossg Neutralization Options to clarify the relationship between the sets.
Description of Schema Generator Instructions
When run with neutralization options, the schema generator instructs you to insert ObjectStore padding macros and make other changes in your source files. The neutralization instructions are explicit. Be sure to use the exact macro name the schema generator provides. Base Class Padding Macros
On platforms where the base class produces no padding, the schema generator cannot recognize that the padding macro exists. However, the schema generator can determine that, if the macro were present, the schema would be neutral. This allows the schema generator to both
Dynamically Defined Padding Macros
The schema generator does some dynamic naming of macros when inheritance precludes reusing a macro name. Dynamically named macros all begin with _os_pad_. Member Padding Macros
Each member padding macro does one of the following:
Virtual Base Templates
Class layout varies so greatly among compilers that in many cases there is no way to achieve a compatible layout by padding alone. Often, complex inheritance paths that differ from platform to platform are needed.
class A : public virtual B {}The schema generator might instruct you to convert this to something like the line following. This varies depending on which platforms are involved.
class A : public os_vb_fbs<0,B> {}Sometimes, instead of using a particular virtual base class, the schema generator instructs you to use a specific class whose name starts with os_vb_. This class takes two arguments. The first is an int, and you should insert the exact int that the schema generator provides. The second is the name of the virtual base class that you are replacing. Here are the class names:
An important effect of this technique is that class B must have a public or protected default constructor. Since it is the responsibility of the most derived class to actually invoke the correct constructor, it should not be difficult to provide a public or protected default constructor.
The virtual base introduction templates have the prefix os_vb_. The schema generator flattens these template instantiations so that your class definitions are retained and the classes have compatible schema representations.
One way to try to determine any effect on database size would be to neutralize the schema and then run the osexschm utility on the preneutralized schema and postneutralized schema. Compare class sizes weighted by their relative frequency of occurrence in the database. You can also make a test run of the neutralized application and compare the database size to an equivalent preneutralized database.
When you use the schema generator to neutralize for a group of platforms, the schema generator takes into account all platforms you want to use and the endian type for each platform. When the schema generator does this, it helps determine how to lay out objects in a way that can be used by all machines involved.
The following table shows the endian type for ObjectStore platforms. In a big-endian type, the high-order bit is first.
Big-Endians | Little-Endians |
---|---|
HP | DEC AXP |
RS/6000 | Intel |
SGI | |
Sun SPARC |
Updated: 03/26/98 20:00:39