2.1 Program fetch parameter CXUOSR.EXE (unload)
2.2 Fetch parameter for CXCOSR.EXE (generating checksum)
2.3 Program fetch parameter CXLOSR.EXE (load)
3. Clustering
When unloading the database, it gets written in the ASCII format (DATABASE.DMP, FREEOBJ1.DMP, ...) in sequential files. ASCII is technically also readable for people. The files contain all information about database objects that are required to rebuild these objects in a new database with the same data and to reconstruct all relations between the objects. Doing this, object division into sub-databases, segments and clusters can be modified, which is usually the reason for such operations.
Unload - Load can be used instead of the schema evolution
which is provided by ObjectStore (database migration to a new schema - modified class
definitions). Unloading, the following information will get lost:
Logically deleted objects will persist, as long as they are referenced
directly or indirectly by an active object.
The total procedure - including checksum creation to assure logical integrity - involves four sub-steps:

Information: The newly built database can only be unloaded instead of the unloaded "old" database, if the total checksums in CHECKSUM.OLD and CHECKSUM.NEW are identical

All flags can start with / or -. Capital letters and lower-case letters are equal. A parameter coming after a flag can follow directly or be separated via blanks; e.g.:
cxuosr /iTS.INI /h5000000
or
cxuosr –I ts.ini /H 5000000
If successfully, the programs provide the return code 0.
| Parameter | Meaning | Default Option |
|---|---|---|
| /I fileName | initialization file | CLASSIX.INI |
| /W fileName | hash table | TMPFILE.DMP |
| /D workDir | work directory, holding all other files | actual directory |
| /Hn | estimated number of objects n in the database | 47977 |
| /F | keep hash table in storage (fast mode) | hash table as file |
| /EparamFile | hash table on external DCOM servers | hash table as file |
| /1 | only phase 1 | phase 1 and 2 |
| /2 | only phase 2 | phase 1 and 2 |
| /3 | phase 3 | |
| /Cn | clustering pattern | 0xff or environment variable CX_CLUSTERING |
| /Mn | calculates hash table storage size for n objects. With this, it is possible to estimate, whether a large database can be unloaded with -F or -E. |
The two phases
are executed automatically one after the other, if neither /1 nor/2 has been indicated. While unloading, it is specified how the objects are clustered in the new database. Phase 3 collects information about the object order in the root entry point collections.
Phase 1 is restart-capable. Condition: hash table is maintained storage resident
(parameter /E or /F).
If a class had been unloaded completely after the predetermined time had run
out, the hash table is saved as file 'filename.nnn', with nnn = { 001, 002, ...
}and the unload file is labeled (Checkpoint).
From here, it is possible to continue: Parameter /R. The
generated unload data parts have to be joined in the end, eliminating redundant
information - call with parameter /P. The following overview shows all other
flags that are relevant for restart-capability:
| Parameter | Meaning | Default Option |
|---|---|---|
| -Vn | time window (n in seconds) for restart | -V7200 (2 hours) |
| -RclassName,k | restart after class 'className', k = { 1, 2, ... } is the consecutive number of the restart attempt | |
| -Pfile1{restartInfo1},file2{restartInfo2},...,filen,outFile | copy files together after n-1 times restart, eliminate redundant data |
The file name of the saved hash files (complete path) has to be indicated as 'restartInfo' (see Example).
| Parameter | Meaning | Default Option |
|---|---|---|
| /I fileName | initialization file | CLASSIX.INI |
| /W fileName | hash table (CXUOSR.exe) | TMPFILE.dmp |
| /G fileName | hash table (CXLOSR.exe) | GATEWAY.dmp |
| /D workDir | work directory, holding all other files | current directory |
| /1 | generate "old database" checksum | none |
| /2 | generate "new database" checksum | none |
| /U fileName | CXUOSR.EXE hash table (only for /1) | TMPFILE.DMP |
| /F | hold hash table in memory (fast mode) | as file |
| /EparamFile | hash table on DCOM servers | as file |
For each single object, /1 makes the checksums get written into the file OBJECTS.OLD.
If CXCOSR.EXE runs for the new database via /2, the file OBJECTS.NEW forms, which holds
all objects including checksums. Characteristic for checksum differences is,
that it is possible to view the relevant objects
via InstantView®
in the new database, as well as in the old one. E.g. with the object inspector – InstantView®
source: CHECKSUM.CXP. The CX_DB_UTILITY
object provides further functions for object analysis in the old and new
database.
The program CXCOSR.EXE provides another function, which doesn't directly belong to database loading and -unloading: the construction of an Object Cross-Reference – a help database, which can define from which other objects an object gets referenced.
| Parameter | Meaning | Default option |
|---|---|---|
| /I fileName | initialization file | CLASSIX.INI |
| /G fileName | hash file (gateway old to new database) | GATEWAY.dmp |
| /D workDir | work directory, holding all other files | current directory |
| /H nObjekte | estimated number of objects in the database | 47977 |
| /F | keep hash table in memory (fast mode) | as file |
| /EparamFile | hash table on DCOM servers | as file |
| /N | Do not insert objects into root EP collections yet, while loading (phase 1). Phase 3 is necessary. | insert objects directly into REP-Colls, do NOT use phase 3 |
| /1 | only phase 1 (load, generate objects) | Phase 1 und 2 |
| /2 | only phase 2 (reconstruct relations) | Phase 1 und 2 |
| /3 | phase 3 (insert object in REP collections) | |
| /U | add to existing database | database gets generated |
| /batch | in phase 1: generate new database(s) (and delete database(s) with the same name without interactive confirmation | interactive query (has to be answered with 'YES') |
| /Mn | calculates hash table storage size for n objects; this makes it possible to generate, whether a large database can be loaded with -F. |
Usually (neither /1 nor /2 indicated), both phases are automatically executed
one after the other. CXLOSR.EXE generates a protocol in the LOAD.LOG file.
The hash table (GATEWAY.DMP) forms the bridge between old
and new database: The according object location in the new database is known for
each object Location in
the old database. The table can be kept resident in the memory while loading:
local (flag/F) or get distributed across external servers (flag
/E). A "distributed gateway file" can be pooled in
one file.
cxuosr -Its.ini
if ERRORLEVEL 1 goto ABEND
cxuosr -3 -Its.ini
if ERRORLEVEL 1 goto ABEND
cxcosr -1 -its.ini
if ERRORLEVEL 1 goto ABEND
cxlosr -its.ini -batch
if ERRORLEVEL 1 goto ABEND
cxlosr -its.ini -3
if ERRORLEVEL 1 goto ABEND
cxcosr -2 -its.ini
echo "Database sucessfully reloaded"
pause
exit
:ABEND
echo "Reload failed"
The ObjectStore data transfer between the database server and the client is page-oriented. Therefore the database object order has great influence on the application performance.
Object clustering can be controlled for
The clustering can be activated/deactivated step by step in both cases.
For the clustering, an object is either a master- or a slave object:
A master object gets saved in a database segment, that has been determined for its class; a cluster might be created for the master object. Segment information and information about the cluster are described in the database layout (file CLASSIX.ODB).
After deactivating the clustering completely, there are only master objects - this is the default option in ClassiX®.
The slave object position in a database determines another database object,
which it gets connected to. Generating such an object with
CreatePersObject, CopyPersObject needs to be delayed until a
relation to an already existing database gets built. Therefore, the named InstantView®
commands generate a (transient) CX_LAZY_CREATOR object class.
The unload/load procedure is explained below.
First, this requires to determine the rules to define, whether an object is master or not.
The clustering rules have been split up into categories. Assigning a bit to each category, creates a pattern, which lets the categories get switched on and off independently.
This pattern is set with the environment variable CX_CLUSTERING; default option is CX_CLUSTERING=0.
The following table shows the categories and the according rules; column 1 lists the bit and column 2 the according name.
Column 3 indicates which class can be a slave object. While the class is the only necessary criterion for basic objects (e.g. the basic classes CX_DATE, CX_VALUE ...), there are more conditions for more complex objects:
The rules above should not only control the clustering, which has been generated
via delayed object creation (CreateOersObject -> CX_LAZY_CREATOR). Moreover,
it should also be active when unloading/loading a database.
New database object order is already determined when unloading:
Unloading a master object o, all objects or that are directly accessible from here via relations (Pointer/Collections) are checked for the rules above. Here, the objects o take over the master role. If there are slave object among the objects or, they are unloaded next and marked in the unload file as objects belonging to o.
When unloading the slave objects, the same happens - or takes over the master role and all accessible objects are tested, whether they can be "clustered" by or. These indirectly accessed objects also go into the cluster belonging to the object o. When loading the database, object o defines, how to save all its dependent objects.
A just unloaded object o "asks" all its referenced objects, whether they can be "clustered" by o.
According to this, it is important, in which order the objects are unloaded.
When unloading, the priority numbers (0 to 5) are assigned to the classes. In phase 1, all objects are unloaded out of the root entry point collections, whereas classes with priority numbers come first:
| Priority number | |
|---|---|
| 0 | CX_ATOM_TABEL, CX_UNIT_PARAMETER |
| 1 | CX_MULTIPLE_COM_OBJECT |
| 2 | REP_pattern in CLASSIX.ODB > 0 and 0, 1, 4 or 5 doesn't apply |
| 3 | REP_pattern in CLASSIX.ODB > 0 and 0, 1, 4 or 5 doesn't apply |
| 4 | CX_DESCRIPTIVE_REF, CX_OVERWRITING_REF |
| 5 | CreatePersObject would generate CX_LAZY_CREATOR |
Within one category, classes are unloaded according to order shown in the
class description in CLASSIX.ODB, meaning
the class statement order in
CLASSIX.ODB influences the clustering.
The database needs have only one corrupt object to make the unload procedure get cancelled with a bug.
Program CXAOSR.EXE can find such errors in an analysis run and write them into a report file:
| Parameter | Meaning | Default option |
|---|---|---|
| /I fileName | initialization file | CLASSIX.INI |
| /D workDir | work directory, holding all other files | current directory |
| /A | entire database analysis | none |
| /AsegmentName | analysis only for the indicated segment | none |
| /AsegX-segY | analysis from segment segX to segY | none |
| /AsegX- | analysis from segment segX to end | none |
| /A-segY | analysis (from start) to segment segY (incl.) | |
| /An%-m% bzw. /An%- oder /A-%m | just like above, segment segX, segY, selecting percentage
of database size: segX equals n % of the database size, segY equals m%; condition n < m |
none |
| /R | analysis of all REP collections | none |
| /R repName | analysis of the REP collection with the indicated name | |
| /P iptFile1,iptFile2,...,iptFilen,outFile,xRefFile[,W] | post-processing analyze files, errors are only adopted, when they refer to corrupt objects, file to control partial x-reference gets created, 'W'= copies 'WRAPPER' into this file | /Panalyze.lst,analyze2.lst,xObjects.lst |
Example: Analysis runs for a large database spread across three PCs: cxaosr /A-33%, cxaosr /A34%-66%, cxaosr /A67%-
Information: Don't forget parameter syntax in a batch file: double percentage character: e.g.: specify cxaosr /A34%%-66%%!
Analyzing (with Flag /A...), the virtual function SanityCheck() gets called for every object. A return code > 0 signalizes an error:
| 1 | slot: pointer to data = ZERO (or dynamic_cast<CX_CLASS *> fails) |
| 2 | slot: pointer corrupt (mapping into real memory fails) |
| 3 | slot – unknown data type (not in the dictionary) |
| 4 | error in frame: n < g |
| 5 | error in frame: n < 0 or g < 0 |
| 6 | error in frame: g > 0 but no allocated slot vector |
| 7 | DeleteSlot hasn't reset data pointer (to ZERO) ... harmless |
| 8 | slot name = 0 |
| 9 | dynamic slot (see. AssignSlot) - slot not in dictionary |
| 10 | dynamic slot (see. AssignSlot) - no reference for the defining expression |
| 13 | anonymous slot (see CX_OVERWRITING_REF) - no reference to the overwriting expression |
| 20 - 22 | CXB_MULTIPLE_STRING: conflict number - allocated strings |
| 24 | CXB_MULTIPLE_STRING: substring cannot be dereferenced |
| 30, 31 | CX_NUMERIC corrupt |
| 32 | Unit corrupt |
| 33 | value 94967254 !!! |
| 41 | CX_DESCRIPTIVE_REF and derived – pointer to
"wrapper" corrupt (dynamic_cast<CX_CLASS *> fails) |
| 42 | CX_DESCRIPTIVE_REF and derived – pointer to
"wrapper" corrupt (mapping into real memory fails) |
| 50 | CX_EXPANDABLE and derived - classID wrong |
| 71-73 | CX_SPAN_DATE |
| 80, 81 | CX_PERIODIC_DATE |
| 85, 86 | CX_DATETIME |
| 87-89 | CX_GLOBAL_DATETIME |
| 100-107 | CX_LOCALE ... |
| 391 | CX_FORMULA – expression conflicts with syntax |
| 400 | CX_CONDITIONED_BAG – CX_FCONDITIONs chain corrupt (dynamic_cast<CX_FCONDITION *> fails) |
| 401 | CX_CONDITIONED_BAG with "external" CX_FCONDITION (fCond->parent != this) |
| 402 | CX_CONDITIONED_BAG – CX_FCONDITIONs chain corrupt (mapping into real memory fails) |
| 501 | CX_COM_OBJECT without data (persistentDataStream == ZERO) |
| 511 | CX_MULTIPLE_COM_OBJECT contains at least one CX_COM_OBJECT without data |
SanityCheck calls itself also for DDI members, as
long as it is an object. In case of an error, original error code + 10000 gets returned.
Furthermore, relations to other objects are analyzed (function CheckReferences):
| Error | |
| 285 | active object referenced (logically) deleted object |
| 286 | (logically) deleted object references active object |
| 287 | reference corrupt (dynamic_cast<CX_CLASS *> fails) |
| 316 | reference corrupt (ObjectStore exception) |
| 317 | reference corrupt (undefined exception - caught with catch(...)) |
| 318 | ZERO pointer in collection |
| 319 | coll. corrupt (undefined error, caught with catch(...)) |
| 376 | coll. with cardinality c < 0 / c > 10 000 000 |
| 377 | coll. - endless iteration |
| 378 | coll. with cardinality by 1 too large |
| 379 | coll., cardinality too large |
| 380 | coll., cardinality too small |
| 207 | referenced object type conflicts DDI / slot dictionary (pointer) |
| 211 | referenced object type conflicts DDI / slot dictionary (collection) |
| 2001 | ObjectStore exception when calling the function SanityCheck() or CheckReferences() |
| 2002 | undefined exception when calling the function SanityCheck() or CheckReferences() |
CX_DB_UTILITY object functions support an effective error log analysis.
Sometimes it would be handy to know all referenced objects or for one object o, all objects that have a pointer to o or a collection with o as an element.
This information is kept in CX_XREF objects. Building a Cross-Reference means, that exactly one CX_XREF object gets generated for each object, which then points at all objects referencing the object that is represented by the CX_XREF object.
It makes sense, to keep the CX_XREF objects in a separate physical database - since they just represent a snapshot which will be outdated soon. CX_XREF objects refer to "normal" objects - but not the other way around. Therefore, the physical sub-database for the cross-reference can be deleted at any time, without an effect on the "actual" database.
An objects assignment to "its own" CX_XREF object is realized outside
of the database (in the gateway file).
The object manager function GetObjectsReferringTo()
provides a collection of all objects or referencing this object
o for an object o, which has been passed as a parameter.
No corresponding CX_XREF object gets generated for such an object o, which no other object or references to, unless it is required, that a CX_XREF object is generated via flag /O for every object to find single object in the database.
Describing a help database for the cross-reference:
| MetaInfo |
| Database(2, CX_XREFDB) Segment(xrefS, DB(2)) Class(CX_XREF, 51, xref) File(xref, xref, xref) Storage(xref, DB(2), xrefS, EP("xrefL0"(LIST)), CSeg(xrefS), Garbage(xrefG0, xrefS)) |
Working with the cross-reference, this description is added to the Initialization File (e.g. classix.ini).
Information:
Due to performance, the CX_XREF object REP Collection
should be of the type LIST.
A corresponding CX_XREF object is
generated for every
source database
object, which
is referenced by another one (which is the case for most objects).
For a larger number of objects, the integration into a SET will take longer. For large amounts of data, there
should be a limitation for the
Segment Splitting. CX_SLOT_XREF objects are
generated in the help database for dynamic database cross-reference. Meta
information for object- and slot cross-reference are shown in the following
example.
The object cross-reference gets built by generating the help object sub-database with
...
SET CX_XREFDB=myXReferenceDB.cxd
cxgosr –U –I modifiziertesIniFile.ini –batch
After, the cross-reference is built via CXXOSR.EXE:
| Parameter | Meaning | Default option |
|---|---|---|
| /X n | cross-reference, n estimated number of objects | n = 47977 |
| /X n,objectFile | cross-reference, n estimated number of objects, the objects indicated in the file are ignored (hide) | n = 47977 |
| /X objectFile | Partial Cross-Reference, only for objects specific in the file | |
| /S | generate cross-reference for dynamic data fields only | cross-reference for objects |
| /B | cross-reference for object and for dynamic data fields in a run | only cross-reference for objects |
| /O | help flag for collecting orphan objects, now an according CX_XREF object gets generated for every database object | CX_XREF objects are only generated for referenced objects |
| /I fileName | (modified) initialization file | CLASSIX.INI |
| /G fileName | hash file (gateway from old to new database) | objects.xrf |
| /F | keep hash table in memory (fast mode) | as file |
| /EparamFile | hash table on external DCOM servers | as file |
| /D workDir | work directory, holding all other files | current directory |
The functions GetObjectsReferringTo()
require gateway files.
Gateway files (parameter /E) spread across several
external DCOM servers and can therefore be pooled with program CXXOSR.EXE:
| Parameter | Meaning | Default option |
|---|---|---|
| /Cntotal,gatewayFile1,n1,gatewayFile2,n2,... | copies all sub-files to GATEWAY.CON |
The correct Teilgrößen specification (n1 + n2 + ... = ntotal)
is compared to the gatewayFilekspecifications.
Here you can view example batch files to generate the complete cross-reference.
Partial cross-reference:
The creation of an object cross-reference can be sped up, whenever it only
needs to be found out for a certain amount of objects { o1, o2,
... }, which objects or reference one of the
given objects { o1, o2, ... }. Parameter /X
indicates a file, which
The amount n is used to calculate the hash file prime number - a larger n
causes better performance. EXCLUDE requires the specified
objects not not to be tested as potential referents. This makes sense when
repairing corrupt objects in the database: the objective is to find out, which
objects refer to "corrupt" objects, while excluding these corrupt objects from
the test.
Example:
2000, EXCLUDE
<0|284|0|80f230|10000>, <0|284|0|80f350|10000>, <0|284|0|80f470|10000>, <0|284|0|80f590|10000>, <0|284|0|80f7e0|10000>, <0|284|0|80fa20|10000>, <0|284|0|80fb40|10000>, <0|284|0|80fc60|10000>, <0|284|0|80fd80|10000>, <0|284|0|810360|10000>, <0|284|0|8105bc|10000>, <0|284|0|8106ec|10000>, <0|284|0|810800|10000>, <0|284|0|810920|10000>, <0|284|0|810a40|10000>, <0|284|0|810b60|10000>, <0|284|0|810c80|10000>, <0|284|0|810da0|10000>, <0|284|0|810ec0|10000>, <0|284|0|81157c|10000>,
<0|284|0|811914|10000>, <0|284|0|811a84|10000>, <0|284|0|812040|10000>, <0|284|0|812268|10000>, <0|284|0|812320|10000>, <0|504|0|7d13cc|10000>
Comma as a separator between elements is optional. The number of objects per
line is also optional, as long as it is less than 512 characters.
Hide certain objects:
Even for a complete cross-reference, it is possible to exclude single objects.
This method was meant to help when dealing with a corrupt database. Display file
structure as shown above.
Database analysis and partial cross-reference form a tool to "repair" logically or physically corrupt/inconsistent objects in a database (Example procedure).
Information: An object can be replaced by another one via cross reference (function substitute, DB utility object).