You need to design a highly scalable solution. By definition this means that you use the same resources in a number of different environments—thus improving your efficiency.
You need to prevent multiple users updating the same account record at the same time.
Single-user resources, which can be used by only one user at a time, such as file records being updated, scratchpad areas, and so on
Let’s examine these individually and develop some guidelines for designing and programming CICS applications from them. Remember, there’s bound to be conflict from time to time when trying to conserve one resource at the cost of another. The appropriate compromises vary from one program to the next.
You can use different techniques for locking (allowing single use of) specific types of resources. These are described in the following paragraphs:
In an online system, storage needs constantly change. Most exist only for the duration of a transaction, and so, in assessing storage needs you have to consider not only how much is used, but for how long. The trade-off between space and time requires the following storage consumers to be considered:
The internal CICS data areas associated with any transaction being processed. You should therefore minimize the duration of the transaction.
The program or programs being executed to accomplish the transaction. Don’t worry about the size of programs, because they are shared by all transactions and there is only one copy in the system at a time. It is much more important to structure the code well for ease of maintenance.
In general, you need to conserve processor time. Calls for CICS or operating system services take much longer, relatively speaking, than straight application code. Avoiding unnecessary commands reduces processor time much more than fine tuning your code.
It is undesirable to do long calculations in an online program, because you may be sharing the process with thousands of other users. If such calculations are necessary, you need to use an application design approach that is beyond the scope of this book.
It is undesirable to do complex database queries in an online program. If such queries are needed, special design approaches are needed; these are beyond the scope of this book.
There are two main principles governing community bandwidth:
Send only the necessary data.
Send in a single message as much as is likely to be needed.
Resources that can only be used sequentially by one user at a time are something that we do not want multiple transactions accessing concurrently. A file record destined for update is a perfect example of this type of resource. CICS provides a user-locking mechanism (called EXEC CICS ENQUEUE/DEQUEUE) for transactions to prevent concurrent use and CICS uses the mechanism internally to obtain a lock prior to using the resource and free it automatically at the end of the task or at a user syncpoint. While one transaction owns the lock, other transactions that wish to use this resource have to wait. Therefore, minimize the duration of transactions that require exclusive use of resources because everyone else who wants to update that resource is held in a queue until the lock is released.
CICS applications do not typically need to obtain locks explicitly, because CICS file and database operations use locks automatically to implement the Isolation property of ACID transactions. CICS locks can be held only for the duration of a single task. If a lock needs to be held for longer than this, other approaches are needed. This is discussed in more detail in the next section.
When a user works on an account, she will bring the account details onto the screen, work with the information, optionally save changes to the database and cease working with the customer account.
There is a potential problem if two users try to do this on the same account at the same time. Both users could be making changes based on the same old copy of the record. Changes made by the first user to complete his work go into the file, but then changes from the second user will overwrite the first user’s updates. You must ensure that, when one user starts to work with a customer account record, subsequent users are prevented from doing so. As discussed in Transactions in Chapter 2, ACID transactions should not wait for user input. Thus, you can’t use the Isolation property of ACID transactions to prevent multiple users working on the same account.
Our solution is to introduce an application-level locking scheme that locks out other users between the initial display of the account details on the screen and ceasing to work with the customer record. Note that you can still exploit the capabilities of ACID transactions during the step that saves the changes.
Use of an application locking scheme is better than using ACID transactions from the perspective of users, too. If you used a long-running ACID transaction to protect against double updating, the second user would be locked out waiting for the first user to complete his work. With an application lock, you can tell the second user to try again later, and you can even pass information as to who owns the lock so that the second user (who may have the actual customer waiting on the telephone) can discuss the problem with the first. Let’s look at one way this locking mechanism could work.
Suppose that as soon as a user asked to update an account number, you make a note in a scratchpad area. (CICS provides scratchpad facilities for keeping track of things between transactions.) You can leave the number there until the update is entirely completed and then erase it. In our example, this means that if you write a scratchpad record in a subsequent transaction, it erases the earlier one. Before starting any update request, you can check to see if the account number is in use. If it is, you can tell the user this and ask him or her to resubmit the request later. Furthermore, you can let the user display the record even if it is in use.
This isn’t quite all, however. Because CICS ensures that transactions are either executed completely or not at all, you have to make sure that all your protected resources get updated in what CICS regards as a single transaction to ensure the consistency of your data. In the conversational case, (see Table 10-1) the program performs all the steps in one transaction. On the other hand locks are held over two terminal output/input operations so the scalability of the system might be adversely affected by a user going to lunch in the middle of a transaction. In the pseudo-conversational case (see Table 4-2), the files are all updated in the third transaction (this is the preferred solution), but the scratchpad is updated in two different transactions (not so good). The real benefit of this design is that no locks are held while waiting for user’s terminal input, so step 2 has disappeared between 1 and 3 and step 6 between 5 and 7.
Table 4-2. Example of Pseudo-Conversational Transactions
Display menu screen
Receive menu screen (which is presumed to contain a correct modify request)
Display the record in formatted form
Receive the changes
Update the account file accordingly
Re-display the menu screen
If the second transaction is completed successfully, but something happens to the third, the scratchpad record is written but not erased. Our data files would be consistent, which is the main concern, but you’d be unable to update the record involved until you could somehow reset the scratchpad.
You can get around this by designing a slightly more sophisticated scratchpad mechanism, for instance, by putting a limit on the time for which a transaction can own an account number. Then an error in the third transaction or thoughtless behavior by a user (going to lunch in the middle of a modification) will not cause an account record to become unusable for more than a short period of time. But all this involves extra coding and complications—is it worth it?
Absolutely. You can program your own mechanism for avoiding concurrent updates. Double updating is one of those problems you can tackle in a variety of ways. We chose a scratchpad. A drawback of a scratchpad, however, is that all future (and, as yet, unknown) transactions that update the account file have to refer to this scratchpad. However you can control this by the design you have chosen to separate the presentation logic from the business logic. Since all updating automatically manages the locking, this should be less of a problem than it may appear at first.
Ensures that the system continues without damage by cleaning up:
Ensures that the end user, or the calling program or component, knows what’s happened by means of an on-screen message or return code, or occasionally an abnormal end (abend).
Ensures that CICS administrators know what’s going on.
Ensures that you, the developer, can find out why the error happened by writing debugging information to a log file or providing a dump.
The errors that can occur in a CICS transaction can be divided into five categories. For each category, you need to consider which of the error-handling actions are required.
|Conditions that aren’t normal from the CICS point of view but are anticipated in the program|
For example, when you try to read a record and get a “not found” response.
Actions needed: 2. (If a record is not found the user should be told.)
|Conditions caused by user errors and input data errors|
An error of this kind in the sample application would occur if a user tried to add an account number that already existed.
Errors in this category should also be handled by explicit logic in your program. Ideally, no errors of this type should be allowed to stop the program, or do anything else to upset the user.
Actions needed: 2.
|Conditions caused by omissions or errors in the application code|
These may result in the immediate failure of the transaction (abend) or simply in a condition that you believed “could not happen” according to your program logic. In the sample application, an attempt to add two identical records to the account file would represent this kind of error. You wouldn’t expect it, because you’ve already tested in the frontend transaction that no record with the same key is in the file. One of the main goals of the debugging process should be to get rid of this type of error.
Actions needed: 1, 2, 3, 4.
|Errors caused by mismatches between applications and CICS resource definitions, generation parameters and Job Control Language (JCL)|
An example is when CICS responds “no such file exists” to your read or write request. When you are first debugging an application, these problems are almost invariably your fault. Perhaps the definition of the file was not installed into the CICS system you are using to test or you spelled a name differently in the program than that used in the definition.
These conditions sometimes occur after the system has been put into production use as well. In this stage, they are usually the result of changes to a CICS resource definition, or a failure to install a resource definition, or JCL, more often than not related to some other application.
This category needs the same treatment as errors in a program that you are debugging. Once the program is in actual use, however, something more is needed when one of these conditions arises. You must give users an intelligible message that they or their supervisors can relay to the operations staff, to help in identifying and correcting the problem. For example, if an administrator has disabled a file for some reason and forgotten to re-enable it, you want a message to the operations staff that says that the problem is caused by a disabled file (and which file, of course). Moreover, you should program for these eventualities from the start, as this part of the program will need debugging just as well as the rest.
Actions needed: 1, 2, 3.
|Errors related to hardware or other system conditions beyond the control of an application program|
The classic example of this is an “I/O error” while accessing a file. As far as the application programs are concerned, this category needs the same treatment as the one above. Systems or operations personnel still have to analyze the problem and fix it. The only differences are that they probably didn’t cause it directly, and it may take much more effort to put right.