Previous | Contents | Index |
The examples in this section show a BASIC initialization procedure that opens an Employee file and a History file.
The procedure PERS_UPD_SERVER_INIT_PROC first includes some common definitions used by the Personnel application and the record layouts for the Employee and History files:
%INCLUDE "pers_files:pers_common_defns" %INCLUDE %FROM %CDD "pers_cdd.employee_record" %INCLUDE %FROM %CDD "pers_cdd.history_record" |
The PERS_COMMON_DEFNS.BAS file includes definitions for the channel numbers used for the Employee and History files, together with frequently used BASIC errors, error message symbols, system services, and ACMS, OpenVMS, and RMS errors:
!+ ! Common definitions for the PERSONNEL application. !- !+ ! Channel numbers. !- DECLARE LONG CONSTANT emp_file = 1% DECLARE LONG CONSTANT hist_file = 2% !+ ! Frequently used BASIC error codes. !- DECLARE LONG CONSTANT basicerr_wait_exhausted = 15% DECLARE LONG CONSTANT basicerr_duplicate_key = 134% DECLARE LONG CONSTANT basicerr_record_locked = 154% DECLARE LONG CONSTANT basicerr_record_not_found = 155% DECLARE LONG CONSTANT basicerr_deadlock = 193% !+ ! Personnel application messages !- EXTERNAL LONG CONSTANT persmsg_success EXTERNAL LONG CONSTANT persmsg_empexists EXTERNAL LONG CONSTANT persmsg_empnotfound EXTERNAL LONG CONSTANT persmsg_emplocked EXTERNAL LONG CONSTANT persmsg_empchanged EXTERNAL LONG CONSTANT persmsg_empdeleted !+ ! Frequently used system services !- EXTERNAL LONG FUNCTION SYS$GETTIM !+ ! ACMS, OpenVMS system and RMS status codes !- EXTERNAL LONG CONSTANT ACMS$_TRANSTIMEDOUT EXTERNAL LONG CONSTANT RMS$_NRU EXTERNAL LONG CONSTANT RMS$_DDTM_ERR |
The initialization procedure then specifies the MAP statements for the Employee and History files:
MAP ( emp_map ) employee_record emp_rec MAP ( hist_map ) history_record hist_rec |
Next, using an error handler, the procedure initializes the return status to success and opens the Employee and History files. If both files are opened successfully, the procedure returns the success status, indicating that the server process is now ready for use. If an error occurs, the error handler sets the return status to the RMS error status, indicating that the initialization processing failed. The EXIT HANDLER statement causes BASIC to resignal the error, which ACMS then writes to the ACMS audit trail log. Note that the built-in RMSSTATUS function can be used only after BASIC has successfully opened a file.
WHEN ERROR IN pers_upd_server_init_proc = persmsg_success OPEN "emp_file:employee.dat" & FOR INPUT AS FILE # emp_file, & ORGANIZATION INDEXED FIXED, & ALLOW MODIFY, & ACCESS MODIFY, & UNLOCK EXPLICIT, & MAP emp_map, & PRIMARY KEY emp_rec::emp_badge_number OPEN "hist_file:history.dat" & FOR INPUT AS FILE # hist_file, & ORGANIZATION INDEXED FIXED, & ALLOW MODIFY, & ACCESS MODIFY, & UNLOCK EXPLICIT, & MAP hist_map, & PRIMARY KEY hist_rec::hist_badge_number USE pers_upd_server_init_proc = VMSSTATUS EXIT HANDLER END WHEN |
The procedures that run in PERS_UPD_SERVER use explicit lock control to handle record locks to ensure the consistency of the Employee and History files. For this reason, the OPEN statement contains an UNLOCK EXPLICIT clause. Any record accessed by any procedure in the task group remains locked until it is explicitly unlocked with an UNLOCK or FREE statement.
Example 2-6 contains a complete BASIC initialization procedure.
Example 2-6 BASIC Initialization Procedure for RMS Server |
---|
FUNCTION LONG pers_upd_server_init_proc %INCLUDE "pers_files:pers_common_defns" %INCLUDE %FROM %CDD "pers_cdd.employee_record" %INCLUDE %FROM %CDD "pers_cdd.history_record" MAP ( emp_map ) employee_record emp_rec MAP ( hist_map ) history_record hist_rec WHEN ERROR IN pers_upd_server_init_proc = persmsg_success OPEN "emp_file:employee.dat" & FOR INPUT AS FILE # emp_file, & ORGANIZATION INDEXED FIXED, & ALLOW MODIFY, & ACCESS MODIFY, & UNLOCK EXPLICIT, & MAP emp_map, & PRIMARY KEY emp_rec::emp_badge_number OPEN "hist_file:history.dat" & FOR INPUT AS FILE # hist_file, & ORGANIZATION INDEXED FIXED, & ALLOW MODIFY, & ACCESS MODIFY, & UNLOCK EXPLICIT, & MAP hist_map, & PRIMARY KEY hist_rec::hist_badge_number USE pers_upd_server_init_proc = VMSSTATUS EXIT HANDLER END WHEN END FUNCTION |
Termination procedures perform application-specific cleanup work for a server process. Note that Rdb, DBMS, and RMS automatically release databases and close files when a process runs down.
The use of a termination procedure for a server is optional. If you do specify a termination procedure for a server, ACMS calls the termination procedure whenever a server process runs down. The only exception is when a server process is forced to run down as the result of a task cancellation; in that case, by default, ACMS does not call the termination procedure. However, by using the ALWAYS EXECUTE TERMINATION PROCEDURE ON CANCEL clause when you define the server in the task group definition, you can force ACMS to call the termination procedure when a server is run down due to a task cancellation. If you do not specify a termination procedure, ACMS runs down the server process without performing any application-specific termination processing.
ACMS runs down server processes when an application is stopped and when more processes than the minimum defined for the server have been started and the extra processes are not needed to handle users' demands. As with initialization procedures, have termination procedures do work specific to the server process rather than task-related work. Termination procedures do the same kind of work for server processes that use Rdb and DBMS databases and RMS files.
Follow these guidelines when writing a termination procedure for files and databases:
The following sections contain examples of termination procedures. They
describe how to write code for Rdb and DBMS databases, and for RMS
files.
2.2.1 Termination Procedures for Rdb Databases Using SQL
You do not need to write a termination procedure for a server that uses an Rdb database. When a server process stops, Rdb automatically releases the database used by the process, rolling back a database transaction if one is still active.
If you decide that you need a termination procedure to perform application-specific processing when the server stops, you must be careful. If you explicitly include a FINISH statement in a server termination procedure, Rdb commits an outstanding database transaction. However, typically you do not want to commit an outstanding transaction in a termination procedure. For example, you normally want to roll back an existing database transaction if:
In general, if there is a chance that your termination procedure will be called when there is an outstanding database transaction and you are going to use the FINISH verb, include a ROLLBACK verb before the FINISH verb.
Because a transaction is not usually active when the termination procedure runs, the termination procedure should ignore any error from the ROLLBACK verb. Any error returned by the FINISH verb is used as the return status of the termination procedure.
Example 2-7 shows a sample termination procedure for a fictional database.
Example 2-7 SQL Termination Procedure |
---|
IDENTIFICATION DIVISION. ************************************************************** PROGRAM-ID. PERS-TERM-PROC. ************************************************************** * F U N C T I O N A L D E S C R I P T I O N * * * * This procedure is used to close the PERSONNEL database. * * * ************************************************************** ENVIRONMENT DIVISION. CONFIGURATION SECTION. ************************************************************** DATA DIVISION. ************************************************************** WORKING-STORAGE SECTION. * * return status * 01 RET-STAT PIC S9(9) COMP. * * Define the SQL return status * 01 SQLCODE PIC S9(9) COMP. * EXEC SQL DECLARE EXTERNAL SCHEMA FILENAME personnel_database:employees END-EXEC. ************************************************************** PROCEDURE DIVISION GIVING RET-STAT. ************************************************************** MAIN SECTION. 000-CLOSE_DB. SET RET-STAT TO SUCCESS. * * <<<<Insert application-specific cleanup here>>>> * EXEC SQL ROLLBACK END-EXEC. EXEC SQL FINISH END-EXEC. IF SQLCODE < ZERO THEN MOVE RDB$LU_STATUS TO RET-STAT CALL "SQL$SIGNAL" END-IF. 100-EXIT-PROGRAM. EXIT PROGRAM. |
For more information about SQL, refer to the SQL documentation.
2.2.2 Termination Procedures for Rdb Databases Using RDO
You do not need to write a termination procedure for a server that uses an Rdb database. When a server process stops, Rdb automatically releases the database used by the process, rolling back a database transaction if one is still active.
If you decide that you need a termination procedure to perform application-specific processing when the server stops, you must be careful. If you explicitly include a FINISH statement in a server termination procedure, Rdb commits an outstanding database transaction. However, typically you do not want to commit an outstanding transaction in a termination procedure. For example, you normally want to roll back an existing database transaction if:
In general, if there is a chance that your termination procedure will be called when there is an outstanding database transaction, and you are going to use the FINISH verb, include a ROLLBACK verb before the FINISH verb.
Because a transaction is usually not active when the termination procedure runs, any error from the ROLLBACK verb is ignored. Any error returned by the FINISH verb is used as the return status of the termination procedure. For example:
! ! <<<<Insert application-specific cleanup here>>>> ! &RDB& ROLLBACK &RDB& ON ERROR personnel_term_proc = persmsg_success &RDB& END_ERROR &RDB& FINISH &RDB& ON ERROR personnel_term_proc = RDB$LU_STATUS &RDB& END_ERROR |
You do not need to write a termination procedure for a server that uses a DBMS database. When a server process stops, DBMS automatically unbinds the database used by the process, rolling back a database transaction if one is still active. This section illustrates how to unbind from a DBMS database using the DBMS UNBIND embedded DML statement. Note that there is no UNBIND statement in the COBOL language.
The following example illustrates a termination procedure for a DBMS database written in BASIC:
FUNCTION LONG pers_upd_server_term_proc %INCLUDE "pers_files:pers_common_defns" ! ! <<<<Insert application-specific cleanup here>>>> ! # INVOKE DEFAULT_SUBSCHEMA - WITHIN PERS_CDD.PERSONNEL_SCHEMA - FOR PERS_DB:PERSONNEL - ( RECORDS ) # ROLLBACK ( TRAP ERROR ) # UNBIND pers_upd_server_term_proc = persmsg_success END FUNCTION |
If a database transaction is active when a step procedure explicitly
unbinds from a database, DBMS returns an error. Therefore, use the
ROLLBACK statement to roll back an outstanding transaction. Because
there is not usually a transaction active when a termination procedure
is executed, ignore any error returned by the ROLLBACK statement.
Finally, use the UNBIND statement to unbind from the database.
2.2.4 Termination Procedures for RMS Files
You do not need to write a termination procedure for a server that uses
RMS files. When a server process stops, RMS automatically closes any
files that the process has opened. A termination procedure for an RMS
server simply closes each open file used by the server, returning a
failure status if an error is detected.
2.2.4.1 Using COBOL
The termination procedure in Example 2-8 closes the Employee and History files. Any error is signaled and returned as the procedure's return status.
Example 2-8 COBOL Termination Procedure for RMS Files |
---|
IDENTIFICATION DIVISION. PROGRAM-ID. pers_upd_server_term_proc. ENVIRONMENT DIVISION. INPUT-OUTPUT SECTION. FILE-CONTROL. SELECT emp_file ORGANIZATION INDEXED ACCESS RANDOM ASSIGN TO "emp_file:employee.dat". SELECT hist_file ORGANIZATION INDEXED ACCESS RANDOM ASSIGN TO "hist_file:history.dat". I-O-CONTROL. APPLY LOCK-HOLDING ON emp_file, hist_file. DATA DIVISION. FILE SECTION. FD emp_file EXTERNAL DATA RECORD IS employee_record RECORD KEY emp_badge_number OF employee_record. COPY "pers_cdd.employee_record" FROM DICTIONARY. FD hist_file EXTERNAL DATA RECORD IS history_record RECORD KEY hist_badge_number OF history_record. COPY "pers_cdd.history_record" FROM DICTIONARY. WORKING-STORAGE SECTION. 01 status_result PIC S9(5) COMP. PROCEDURE DIVISION GIVING status_result. DECLARATIVES. employee_file SECTION. USE AFTER STANDARD ERROR PROCEDURE ON emp_file. employee_file_handler. CALL "LIB$SIGNAL" USING BY VALUE RMS-STS OF emp_file, BY VALUE RMS-STV OF emp_file. MOVE RMS-STS OF emp_file TO status_result. history_file SECTION. USE AFTER STANDARD ERROR PROCEDURE ON hist_file. history_file_handler. CALL "LIB$SIGNAL" USING BY VALUE RMS-STS OF hist_file, BY VALUE RMS-STV OF hist_file. MOVE RMS-STS OF hist_file TO status_result. END DECLARATIVES. MAIN SECTION. 000-start. SET status_result TO SUCCESS. * * <<<<Insert application-specific cleanup here>>>> * CLOSE emp_file. CLOSE hist_file. 999-end. EXIT PROGRAM. |
The termination procedure in Example 2-9 closes the Employee and History files. Any error is signaled and returned as the procedure's return status.
Example 2-9 BASIC Termination Procedure for RMS Files |
---|
FUNCTION LONG pers_upd_server_term_proc %INCLUDE "pers_files:pers_common_defns" ! ! <<<<Insert application-specific cleanup here>>>> ! WHEN ERROR IN pers_upd_server_term_proc = persmsg_success CLOSE # emp_file CLOSE # hist_file USE pers_upd_server_term_proc = VMSSTATUS EXIT HANDLER END WHEN END FUNCTION |
One way to achieve high system performance is to avoid stopping and restarting servers. In addition to the overhead of OpenVMS process creation, starting a server also involves running the server initialization procedure that binds to databases and opens files. Perform these operations as infrequently as possible.
On the other hand, if your server is interrupted and left in an unpredictable state as a result of a task cancellation, it is best to run down the server process and start a new one.
In order to balance these two needs, ACMS allows you to control whether a server process is run down when the execution of a server procedure is interrupted due to a task cancel. ACMS provides the following three options:
In most cases, the recommended option is to run down down on cancel only if the cancel caused a server procedure to be interrupted. This option balances the need for good performance with the need to run down servers that are in an unpredictable state.
You can specify the rundown option for your servers in the following ways:
RUNDOWN ON CANCEL IF INTERRUPTED
RUNDOWN ON CANCEL
NO RUNDOWN ON CANCEL
Table 2-1 shows whether or not ACMS runs down a server during a cancel operation. The table assumes that a task has context in the server at the time the cancellation occurs. In cancel processing, ACMS never runs down a server if the task does not have context in any servers when the cancellation occurs.
Rundown Characteristic | RUNDOWN ON CANCEL | RUNDOWN ON CANCEL IF INTERRUPTED | NO RUNDOWN ON CANCEL | |||
---|---|---|---|---|---|---|
Server executing during cancel? | No | Yes | No | Yes | No | Yes |
ACMS$RAISE_..._EXCEPTION | N/A 1 | Run down | N/A 1 | Not run down | N/A 1 | Not run down |
ACMSAD$REQ_CANCEL | N/A 1 | Run down | N/A 1 | Run down | N/A 1 | Not run down |
Retain context and cancel task in action step | Run down | N/A 1 | Not run down | N/A 1 | Not run down | N/A 1 |
Fatal error generated in procedure code | N/A 1 | Run down | N/A 1 | Run down | N/A 1 | Run down |
Channel open to device error created from procedure | N/A 1 | Run down | N/A 1 | Run down | N/A 1 | Run down |
All other cancels | Run down | Run down | Not run down | Run down | Not run down | Not run down |
Previous | Next | Contents | Index |