We were recently asked to help a customer diagnose a runtime problem with their Gen application. They have a server p-step (server1) that calls an action block which in turn performs a USE of a p-step in another server load module (server2).
pstep1 --> ab --> pstep2
This worked fine until one day they re-generated the server manager for server1 and when the action block attempted the use of server2, there was a runtime failure.
The reason was because at some point they had converted the action block in this model to a 'stub' (it is developed in a different model). A p-step USE is implemented in the generated code by a runtime function call that references the called server details which resides in a table that is generated into the server manager. The Gen server manager generator needs to know about all of the servers that are called by the p-steps and subordinate action blocks. If some of these subordinate action blocks are 'stubs', then the generators will not detect that the action block calls a server and that server will not be added to the table.
However the code is still generated and the load module build will succeed. The code will also run until the point when the p-step use is invoked, at which point a runtime error will result.
This can be difficult to detect, and so we will develop a new VerifIEr check to detect these conditions.
This is an occasional blog about IET's use of CA Gen for internal development as well as thoughts, tips and techniques on using CA Gen for application development. It is aimed at the CA Gen development professional, so please excuse the jargon and assumed level of knowledge about CA Gen. Reference will also be made to our products to put the development into context, so if you are not familiar with these, please visit the IET web site by clicking on the company logo.
Friday, 26 October 2012
Thursday, 7 June 2012
Checking Data Integrity
In supporting our customers, we occasionally come across problems with data integrity in the GuardIEn database, specifically rows with orphan foreign keys.
An orphan foreign key is a foreign key value (for a simple or compound key) where the parent row does not exist.
For example, in the case of table PARENT has many CHILD, the key of PARENT exists as a foreign key in the CHILD table. If the CHILD FK_PARENT_CODE has a value where the PARENT row does not exist with the same code, then the CHILD foreign key is an orphan.
This situation can arise from errors in the RI trigger runtime routines, use of SQL to delete the parent rows without deleting / nullifying the child rows, incorrectly generated RI triggers or incorrectly implemented DBMS RI rules. In the case of GuardIEn, the most common causes are use of SQL to (incorrectly) load rows or delete rows, and on some platforms, issues with the RI trigger runtimes.
To help identify and fix these integrity issues, we have added a new genIE function that generates the SQL to firstly identify orphan rows and then to perform a cleanup.
We will be distributing the SQL to GuardIEn users so that they can check the integrity of the database, and the new function will be available in 8.1.4 so that customers can generate the SQL to check their own application databases.
An orphan foreign key is a foreign key value (for a simple or compound key) where the parent row does not exist.
For example, in the case of table PARENT has many CHILD, the key of PARENT exists as a foreign key in the CHILD table. If the CHILD FK_PARENT_CODE has a value where the PARENT row does not exist with the same code, then the CHILD foreign key is an orphan.
This situation can arise from errors in the RI trigger runtime routines, use of SQL to delete the parent rows without deleting / nullifying the child rows, incorrectly generated RI triggers or incorrectly implemented DBMS RI rules. In the case of GuardIEn, the most common causes are use of SQL to (incorrectly) load rows or delete rows, and on some platforms, issues with the RI trigger runtimes.
To help identify and fix these integrity issues, we have added a new genIE function that generates the SQL to firstly identify orphan rows and then to perform a cleanup.
We will be distributing the SQL to GuardIEn users so that they can check the integrity of the database, and the new function will be available in 8.1.4 so that customers can generate the SQL to check their own application databases.
Friday, 2 March 2012
Use of IN clause
Gen 8.0 introduces IN and BETWEEN clauses for READ and READ EACH statements.
Whilst there may no longer be any performance benefit in converting to this syntax, an IN clause can make a complex READ statement more readable (no pun intended).
Consider the example below:
This can be re-written using IN clauses:
Even better, the improved READ EACH statement above was automatically converted by using a VerifIEr check that detects READ statements that could use an IN clauses and then invokes the integrated genIE fix to convert the READ statement.
Whilst there may no longer be any performance benefit in converting to this syntax, an IN clause can make a complex READ statement more readable (no pun intended).
Consider the example below:
This can be re-written using IN clauses:
Even better, the improved READ EACH statement above was automatically converted by using a VerifIEr check that detects READ statements that could use an IN clauses and then invokes the integrated genIE fix to convert the READ statement.
Monday, 20 February 2012
CSE and Separate Database Machines
Over the years a number of CSE sites have tried to place the CSE database and software on separate physical servers. Technically there is no issue with making this function correctly, but what we have seen is that the additional network traffic required slows down the overall performance and response times of the software considerably, the point where it outweighs the benefits of spreading the CPU load. This is especially noticeable for servers that have huge amounts of memory, where large portions of the database are available in cache, and therefore the network response becomes a larger percentage of the overall transaction since disk i/o is less of a bottleneck.
Where customers have utilised this approach, it has been necessary to implement complex and expensive dedicated network pipes between the servers, and frankly is not worth it just to spread the load, where actually a single powerful server is perfectly capable of serving the needs of the entire Gen development team.
We therefore strongly recommend that the database and software reside on the same machine.
Where customers have utilised this approach, it has been necessary to implement complex and expensive dedicated network pipes between the servers, and frankly is not worth it just to spread the load, where actually a single powerful server is perfectly capable of serving the needs of the entire Gen development team.
We therefore strongly recommend that the database and software reside on the same machine.
Friday, 17 February 2012
z/OS Operations Libraries and Dynamic Linking
Gen r8 introduced a new feature to package action blocks into z/OS Operations Libraries (z/LIB). These are DLLs that contain one or more action blocks and are similar in concept to the operations libraries that have been available in Gen for the Windows and UNIX environments for some time.
One difference between Windows/UNIX and z/OS relates to the use of the MVS Dynamic Linking property of an action block (or business system default). To be eligible for packaging into a z/LIB, the action block must be marked as dynamic (not static or compatibility).
You should be careful when converting from purely dynamic action blocks to z/LIBs. If you only package the top level action blocks into the z/LIB, the lower level action blocks will be called dynamically from a separate load module if they remain dynamic and are not packaged into the z/LIB.
Consider the following example: AB1 calls AB2 and both are marked as dynamic, either as a business system default or explicitly.
If you create a z/LIB and only add AB1 into the z/LIB, since AB2 is private to AB1, then the z/LIB will only contain AB1 and AB2 remains an 'old style' dynamic action block with its own load module and the call from AB1 to AB2 is dynamic.
If AB2 is private, it should either be changed to static so that it is only statically linked into the z/LIB, or added to the scope of z/LIB so that it is also linked into the z/LIB.
One difference between Windows/UNIX and z/OS relates to the use of the MVS Dynamic Linking property of an action block (or business system default). To be eligible for packaging into a z/LIB, the action block must be marked as dynamic (not static or compatibility).
You should be careful when converting from purely dynamic action blocks to z/LIBs. If you only package the top level action blocks into the z/LIB, the lower level action blocks will be called dynamically from a separate load module if they remain dynamic and are not packaged into the z/LIB.
Consider the following example: AB1 calls AB2 and both are marked as dynamic, either as a business system default or explicitly.
If you create a z/LIB and only add AB1 into the z/LIB, since AB2 is private to AB1, then the z/LIB will only contain AB1 and AB2 remains an 'old style' dynamic action block with its own load module and the call from AB1 to AB2 is dynamic.
If AB2 is private, it should either be changed to static so that it is only statically linked into the z/LIB, or added to the scope of z/LIB so that it is also linked into the z/LIB.
Tuesday, 24 January 2012
Static Code Analysis
Of the 150 checks currently available in VerifIEr, a good many are aimed at detecting errors in code. If you can find an error in the code prior to code generation, it is much easier and quicker to fix, and fixes an error that might not get detected during testing.
Until recently my favourite check was one that detects views that are used but not populated, since this usually indicates an error.
My new favourite is our latest check, which looks for ambiguous OR clauses in an expression. For example, the following code is ambiguous: IF x=1 OR x=2 AND y=3 and should be written as IF (x=1 OR x=2) AND y=3.
We ran this check on our current code base and a few clauses were highlighted. As an example of how difficult it can be to spot these errors, can anyone see the error in this READ statement? We didn't, but the check did!
Until recently my favourite check was one that detects views that are used but not populated, since this usually indicates an error.
My new favourite is our latest check, which looks for ambiguous OR clauses in an expression. For example, the following code is ambiguous: IF x=1 OR x=2 AND y=3 and should be written as IF (x=1 OR x=2) AND y=3.
We ran this check on our current code base and a few clauses were highlighted. As an example of how difficult it can be to spot these errors, can anyone see the error in this READ statement? We didn't, but the check did!
Thursday, 5 January 2012
Unadopting action blocks
A customer recently contacted us with an issue related to having two action blocks (in different models) that had the same ancestry but were otherwise different, i.e. different names, logic, source code member name, etc. Because they had the same ancestry, GuardIEn was managing them as the same deliverable, but they needed to be managed separately.
The solution was to give the second copy of the action block different ancestry, but how, since there isn't an unadopt function on the CSE.
The workaround was as follows:
The solution was to give the second copy of the action block different ancestry, but how, since there isn't an unadopt function on the CSE.
The workaround was as follows:
- scope a subset containing the ABs that you want to unadopt
- download the subset
- generate a new (temp) model on the CSE from the subset so that the ABs in the new model have new ancestry
- selectively adopt just the business systems in the new model to the old model
- selectively adopt the ABs in the old model to the ABs in the new model so that the ancestry in the old model changes
- delete the new (temp) model
Subscribe to:
Posts (Atom)