Compaq ACMS for OpenVMS
Writing Server Procedures


Previous Contents Index

2.1.6.2 Using BASIC

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 

2.2 Writing Termination Procedures

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 

2.2.3 Termination Procedures for DBMS Databases

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. 

2.2.4.2 Using BASIC

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 

2.3 Server Process Rundown

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:

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.

Table 2-1 Server Rundown
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


1N/A = Not applicable.


Previous Next Contents Index