Unloading and Loading a ClassiX® database

1. Objective and Course of Action

2. Program Fetch

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)

2.4 Example – a batch file

3. Clustering

4. Database analysis

5. Object cross-reference

 

1. Objective and Course of Action

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:

load9.GIF (14767 Byte)
This is the procedure, if phase 3 of the unload- and load program is not used. The object order in the root entry point collections is determined via information in CLASSIX.INI. The explicit object pasting in phase 3 guarantees an absolutely identical object assignment to the root entry point collections (see Procedure).

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



2. Program Call

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.

 

2.1 Program Fetch Parameter CXUOSR.EXE (unload)

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).

2.2 Fetch parameter for CXCOSR.EXE (generating checksum)

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.

2.3 Program Fetch Parameter CXLOSR.EXE (loading)

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.

2.4 Example – a Batch 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"

 

 

3. Clustering

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:

 

Bit Category Classes Condition
1 BASIC CX_NUMERIC..., CX_VECTOR_AMOUNT..., CX_TERM..., CX_FORMULA, CX_FCONDITION, CX_NAMED_FCONDITION, CX_CONDITIONED_BAG

but not CX_NAMED_FORMULA

-
2 VALIDITY CX_VALIDITY... -
4 WRAPPER CX_DESCRIPTIVE_REF, CX_OVERWRITING_REF -
8 SLAVE_SEG all no own object segment
16 ZEROPATTERN CX_ATTRIBUTE_SET... REP_pattern = 0
32 ZEROPATTERN CX_PASSWORD..., CX_GENERAL_TERMS..., CX_CONDITION..., CX_ACCESS... REP_pattern = 0
64 TXN CX_TRANSACTION... REP_pattern = 0 &

(if ($ transaction ) transaction = master

else master is a CX_TRANSACTION)

    CX_ALLOCATION... REP_pattern = 0 &

if (card allocators > 0) master Î allocators

else true

128 MONITOR CX_ACCOUNT... if ($ owner) owner = master else true
    CX_DATA_CUBE... Dimension[0] = master

 


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.

 

4. Database Analysis

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:

Slots

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


Objects

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.

 

5. Object Cross-Reference

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).