Document revision date: 19 July 1999 | |
Previous | Contents | Index |
The design approach writes the log record in a main loop that hibernates when it has no work to do. The loop uses ASTs to read keystrokes from the terminal, write to the pseudoterminal, and write data to the terminal. When a block of characters is written to the terminal, that block is placed into a queue of blocks to be written to the log file, and a wake request is issued. Logging is stopped if you log out of the subprocess, if you enter the stop logging character Ctrl\, or if a severe error occurs during data processing. When any of these events occur, all outstanding log records are written before the program exits.
One major design consideration is how flow control should be handled---either by attempting to enforce flow control, or by letting the terminal and terminal driver handle it. In this example, the terminal and terminal driver handle flow control; the driver sends XON, XOFF, or BELL characters to the terminal as necessary.
One of the six I/O buffers is permanently reserved as the terminal read buffer. This buffer is passed directly to the terminal read $QIO. This eliminates having to move data that is read from the terminal into the read buffer. The other five buffers are placed in a queue and are allocated and deallocated as needed. This pool of buffers reserves the first two longwords to be used as queue headers and traditional IOSBs. The third longword and the I/O status longwords are used by the pseudoterminal driver.
Example 6-1 Sample Pseudocode for Pseudoterminal Driver Program |
---|
/* ** Main Routine ** ** Function: Intitializes the environment and then hibernates, waiting ** to be awakened. When awakened, the program checks to see whether it ** is exiting, or whether more log data is available. If more data is ** available, the data is appended to the current log record and checked ** to see whether a log record should be written. A log record is written ** either when maxbuf characters are in the log buffer, ** or when it finds a <CR><LF> character pair. The algorithm ** allows an unlimited number of <NULL> fill characters to occur ** between the <CR> and the <LF>. If the program is ** exiting, it closes the log file, deletes the pseudoterminal, resets the ** terminal, and exits. */ Initialize environments (This includes creating pseudoterminal, the log file and starting up the subprocess.) If (Initialization OK) Then Do while (I/O buffer to log) Data size = number of bytes in I/O buff For all data in I/O buffer If (cr_seen) Then If (current char == <LF>) Then write current log buffer reset cr_seen point to start of log buffer Else if (current char != <NULL>) Then insert <CR> and current char into log buffer move log buffer ptr over 2 characters reset cr_seen Endif Else if (current character != <CR>) Then insert character into log buffer move log buffer ptr over 1 character Else set cr_seen Endif If (log buffer ptr >= IOC$GW_MAX-48) Then write log buffer reset log buffer pointer reset cr_seen Endif Endloop Free I/O buffer call free_io_buffers Endwhile If (not exiting) Then Wait for more to do call SYS$HIBER Endif Until ((exiting) and (no I/O buffers to log)) close log file If ((close failed) and (exit reason is SS$_NORMAL)) Then set exit to status to failure reason Endif If (subprocess still running) Then call SYS$FORCEX to run down the subprocess Endif call PTD$CANCEL to flush all pending pseudoterminal read requests call SYS$CANCEL to flush all terminal requests call PTD$DELETE to delete the pseudoterminal If ((delete failed) and (exit reason is SS$_NORMAL)) Then set exit to status to failure reason Endif reset terminal to startup condition using SYS$QIOW If ((terminal reset failed) and (exit reason is SS$_NORMAL)) Then exit to status to failure reason Endif Endif call LIB$SIGNAL and report exit reason Exit /* ** ** Initialization Code ** ** Function: This routine sets the terminal characteristics, creates the ** pseudoterminal, starts up the subprocess, and opens the log file. If ** any of these steps fail, the program undoes any steps already done and ** returns to the main routine. ** */ read the maximum buffer size from IOC$GW_MAXBUF Assign a channel to SYS$INPUT If (assign ok) Then Read the terminal characteristics from the terminal If (read of terminal characteristics ok) Then Open log file with maximum record size of IOC$GW_MAXBUF If (open ok) Then Create the pseudoterminal with characteristics of terminal If (create ok) then Place 4 of the buffers on the queue of free I/O buffers Copy terminal characteristics and modify them to NOECHO and PASTHRU Set the terminal characteristics use modified value If (set ok) Then Get device name of pseudoterminal use SYS$GETDVI If (get ok) Then Create subprocess If (create ok) Then Enable XON, XOFF, BELL, SET_LINE event notification ASTs If (AST setup OK) Then Call PTD$READ to start reading from the pseudoterminal ASTADR = ft_read_ast ASTPRM = buffer address READBUF = I/O buffer + 8 READBUF_LEN = 500 If (read ok) Then Call SYS$QIO and read a single character from the keyboard ASTADR = kbd_read_ast If (read failed) Then Call PTD$CANCEL to flush queued pseudoterminal read Call PTD$DELETE to delete pseudoterminal Reset terminal to original state Close log file and delete it Endif Else Call PTD$DELETE to delete pseudoterminal Reset terminal to original state Close log file and delete it Endif Else Call PTD$DELETE to delete pseudoterminal Reset terminal to original state Close log file and delete it Endif Else Call PTD$DELETE to delete pseudoterminal Reset terminal to original state Close log file and delete it Endif Else Call PTD$DELETE to delete pseudoterminal Reset terminal to original state Close log file and delete it Endif Else Call PTD$DELETE to delete pseudoterminal Close log file and delete it Endif Else Close log file and delete it Endif Endif Endif Endif /* ** kbd_read_ast ** ** Function: This routine is called every time data is read from the terminal. ** If the program is exiting, then the routine exits without restarting the ** read. The character read is checked to see if the terminate processing ** character Ctrl\ was entered. If the terminate processing character was ** entered, the exiting state is set and a SYS$WAKE is issued to start the ** main routine. Now an attempt is made to obtain an I/O buffer in which ** to store echoed output. If an I/O buffer is unavailable, a simple ** PTD$WRITE is issued; a PTD$WRITE with echo is issued if a buffer is ** available. If the write completes successfully, another read is issued ** to the keyboard. ** */ If (not exiting) Then If (read ok) Then Search input data for Ctrl\ Allocate a read buffer call allocate_io_buffer If (got a buffer) Then Call PTD$WRITE to write characters to pseudoterminal ASTADR = ft_echo_ast ASTPRM = allocated I/O buffer WRTBUF = read I/O buffer WRTBUF_LEN = number of characters read ECHOBUF = allocated I/O buffer ECHOBUF_LEN = 500 Else Call PTD$WRITE to write characters to pseudoterminal WRTBUF = read I/O buffer WRTBUF_LEN = number of characters read Endif If (write setup ok) If ((write status is ok) or (write status is SS$_DATALOST)) Issue another single character read to terminal with ASTADR = kbd_read_ast, with data going to read I/O buffer If (read setup failed) Then Set exit flag Set exiting reason to SS$_NORMAL Endif Else Set exit flag Set exiting reason to SS$_NORMAL Endif Else Set exit flag Set exiting reason to SS$_NORMAL Endif Else Set exit flag Set exiting reason to read failure status Endif If (exiting) Then Wake the mainline call SYS$WAKE Endif Endif /* ** terminal_output_ast ** ** Function: This routine is called every time an I/O buffer is written ** to the terminal. If the terminal write request completes successfully, ** it inserts the I/O buffer into the queue of I/O buffers to be logged. ** If the I/O buffer is the only entry on the queue, it issues a SYS$WAKE ** to start the main routine. To prevent spurious wake requests, ** SYS$WAKE is not issued if multiple entries are already on ** the queue. If a terminal write error occurs, the routine sets the ** exit flag and wakes the main routine. ** */ If (terminal write completed ok) Then insert I/O buffer onto logging queue If (this is only entry on queue) Then wake the mainline call SYS$WAKE Endif Else set exit flag set exiting reason to terminal write error reason wake the mainline call SYS$WAKE Endif /* ** ** ft_read_ast ** ** Function: This routine is called when a pseudoterminal read request ** completes. It writes the buffer to the terminal and attempts to start ** another read from the pseudoterminal. If the program is not exiting, ** this routine writes the buffer to the terminal and does not start another ** pseudoterminal read. ** */ If (not exiting) If (Pseudoterminal read ok) Then write buffer to the terminal ASTADR = terminal_output_ast If (write setup ok) Then Allocate another read buffer call allocate_io_buffer If (got a buffer) Then Call PTD$READ to restart reads from the pseudoterminal. ASTADR = ft_read_ast ASTPRM = buffer address READBUF = I/O buffer + 8 READBUF_LEN = 500 If (read setup failed) Then Set exit flag Set exiting reason to read failure reason Wake the mainline call SYS$WAKE Endif Else Set read stopped flag Endif Else Set exit flag Set exiting reason to terminal write failure reason Wake the mainline call SYS$WAKE Endif Else Set exit flag Set exiting reason to terminal read failure reason Wake the mainline call SYS$WAKE Endif Endif /* ** ** ft_echo_ast ** ** Function: This routine is called if a write to the pseudoterminal used ** an ECHO buffer. If any data was echoed, the output is written to the ** terminal. If no data was echoed, the I/O buffer is freed so it can be ** used later. If the program is exiting, this routine exits. ** */ If (not exiting) Then If (ECHO buffer has data) Then Write the buffer to the terminal with ASTADR = terminal_output_ast If (error setting up write) Then Set exit flag Set exiting reason to write failure reason Wake mainline call SYS$WAKE Endif Else Free I/O buffer call free_io_buffers Endif Endif /* ** free_io_buffers ** ** Function: This routine places a free I/O buffer on the queue of available ** I/O buffers. It also restarts any stopped read operations from the ** pseudoterminals. This routine disables AST delivery while it is running ** in order to synchronize reading and resetting the read stopped flag. ** */ If (not exiting) Then Disable AST deliver using SYS$SETAST If (Pseudoterminal reads not stopped) Then Insert I/O buffer on the interlocked queue of free I/O buffers Else Call PTD$READ to restart reads from the pseudoterminal. ASTADR = ft_read_ast ASTPRM = buffer address READBUF = I/O buffer + 8 READBUF_LEN = 500 If (no error starting read) Then Clear read stopped flag Else Set exit flag Set exit reason to read setup reason Endif Endif Enable AST delivery using SYS$SETAST Endif /* ** ** allocate_io_buffer ** ** Function: This routine obtains a free I/O buffer from the queue of ** available I/O buffers. If the program is exiting, this routine ** returns an SS$_FORCEDEXIT error. ** */ If (not exiting) Then remove a I/O buffer from the interlocked queue of I/O buffers If (queue empty) Then exit with reason LIB$_QUEWASEMP else exit with reason SS$_FORCEDEXIT Endif /* ** subprocess_exit ** ** Function: This routine is called when the subprocess has completed ** and exited. This routine checks whether the program is already exiting. ** If not, then the routine indicates that the program is exiting and wakes ** up the main program. ** */ If (not exiting) Then indicate subprocess no longer running set exit status to SS$_NORMAL indicate exiting call SYS$WAKE to start up main loop Endif /* ** xon_ast ** ** Function: This routine is called for the pseudoterminal driver to signal ** that it is ready to accept keyboard input. The routine attempts to send ** an XON character to the terminal by sending XON DC1 using SYS$QIO. ** If the attempt fails, it is not retried. ** */ If (not exiting) Then call SYS$QIO to send a <DC1> character to the terminal Endif /* ** bell_ast ** ** Function: This routine is called when the pseudoterminal driver wants ** to warn the user to stop sending keyboard data. The routine attempts ** to ring the terminal bell by sending the BELL character to the terminal ** using SYS$QIO. If the attempt fails, it is not retried. ** */ If (not exiting) Then call SYS$QIO to send a <BELL> character to the terminal Endif /* ** xoff_ast ** ** Function: This routine is called when the pseudoterminal driver wants to ** signal that it will stop accepting keyboard input. The routine attempts ** to send an XOFF character to the terminal by sending XOFF DC3 to the ** terminal using SYS$QIO. If the attempt fails, it is not retried. ** */ If (not exiting) Then call SYS$QIO to send a <DC3> character to the terminal Endif /* ** set_line_ast ** ** Function: This routine is called when the pseudoterminal device ** characteristics change. The routine reads the current pseudoterminal ** characteristics, changes the characteristics to set PASTHRU and NOECHO, ** and applies the characteristics to the input terminal. If the attempt ** to alter the terminal characteristics fails, it is not retried. ** */ If (not exiting) Then call SYS$QIOW to read the pseudoterminals characteristics If (not error) Then Set the alter the just read characteristics to have PASTHRU and NOECHO attributes call SYS$QIO to set the terminal characteristics. Endif Endif |
This chapter provides an overview of Volume Shadowing for OpenVMS and
describes the use of the shadow-set virtual unit driver (SHDRIVER).
7.1 Introduction
Volume Shadowing for OpenVMS ensures that data is available for applications and end users by duplicating data on multiple disks. Because the same data is recorded on multiple disk volumes, if one disk fails, the remaining disk or disks can continue to service I/O requests. This ability to shadow disk volumes is sometimes referred to as disk mirroring.
Volume shadowing supports the clusterwide shadowing of DIGITAL SCSI and DSA storage systems. Volume shadowing also supports shadowing of all mass storage control protocol (MSCP) served DSA disks and DIGITAL SCSI disks. For more information about Volume Shadowing supported devices, refer to the Volume Shadowing for OpenVMS Software Product Description.
You can mount one, two or three compatible disk volumes, including the system disk, to form a shadow set. Each disk in the shadow set is known as a shadow set member. Volume Shadowing for OpenVMS logically binds the shadow set devices together and represents them as a single virtual device called a virtual unit. This means that multiple members of the shadow set, represented by the virtual unit, appear to applications and users as a single, highly available disk.
Volume Shadowing features include:
Applications and users read and write data to and from a shadow set using the same commands and program language syntax and semantics that are used for nonshadowed I/O operations. Volume shadowed sets are managed and monitored using the same commands and utilities that are used for nonshadowed disks. The only difference is that access is through the virtual unit, not to individual devices.
SHDRIVER, the driver that controls the virtual unit functions, is described in Section 7.3.
For more detailed information on Volume Shadowing for OpenVMS, see the
Volume Shadowing for OpenVMS manual.
7.2 Configurations
Volume Shadowing for OpenVMS does not depend on specific hardware in
order to operate. All shadowing functions can be performed on VAX and
Alpha systems running the OpenVMS operating system. Shadow set members
must have the same physical geometry (that is, the same number of
identical logical blocks [LBNs]) and members can be located anywhere in
a VAXcluster system.
7.2.1 Supported Hardware
Volume Shadowing for OpenVMS does not depend on specific hardware to operate. All shadowing functions can be performed on any type of VAX or Alpha system using the OpenVMS operating system. Volume shadowing requires a minimum of one VAX computer, one mass storage controller, and DSA (DIGITIAL Storage Architecture) or Small Computer System Interface (SCSI) disk drives.
See the most recent Volume Shadowing for OpenVMS Software Product
Descriptions (SPD 27.29.xx) for additional information
about hardware requirements.
7.2.2 Compatible Disk Drives and Volumes
Volume shadowing requires compatibility among the physical units (disk drives and volumes) that form a shadow set. For example:
This section describes the major virtual unit functions supported by SHDRIVER. In addition to the virtual unit functions described in this section, SHDRIVER supports all OpenVMS disk functions. SHDRIVER receives QIO operations from application programs and is a client of the disk class drivers DUDRIVER. Applications access the shadow set as they would access a standard OpenVMS disk.
Table 7-1 summarizes the major SHDRIVER functions.
The MOUNTSHAD, ADDSHADMBR, COPYSHAD, and REMSHADMBR functions are reserved for Compaq internal use. Use of these functions by customer or third-party provided software may cause unpredictable results including system crashes and data corruption. |
Function | Description |
---|---|
MOUNTSHAD | Creates a virtual unit |
ADDSHAD | Evaluates a physical member and adds members |
COPYSHAD | Triggers and controls copy operations |
REMSHAD | Removes a physical member |
AVAILABLE | Virtual unit dissolution |
SENSECHAR | Verifies shadow set status |
READ | Directs I/O to a physical member |
WRITE | Propagates a write operation to all physical members |
With minor changes, the read and write functions for SHDRIVER operate the same as for the disk class driver (see Sections 2.4.1 and 2.4.2).
During an SHDRIVER read operation, the host directs the read to the member volume with the shortest path.
During a write operation, SHDRIVER directs the write to each member volume. The write operations for each member volume usually proceed in parallel; the virtual unit write operation terminates when all writes have completed. The write function for SHDRIVER takes the IO$M_VUEX_FC function modifier; this modifier should not be used by application programs.
The read and write SHDRIVER functions, as well as all user functions, are issued by user programs. All other SHDRIVER functions are invoked by MOUNT and DISMOUNT commands, or the $MOUNT and $DISMOUNT system services.
Remember that volume shadowing provides data availability by protecting against hardware problems or communication path problems that might cause a disk volume to be a single point of failure. If a write request is made to a shadow set, but the system fails before a completion status is returned from all of the shadow set members, it is possible that:
When the system recovers, volume shadowing performs a merge or copy operation to ensure that the corresponding blocks on each shadow set member contain the same data (right or wrong). Therefore, the goal here is not one of data correctness but of data availability. Volume shadowing is designed to make the data on all disks identical, then, if necessary, incorrect data can be reconciled either by the user reentering the data or by an application automatically employing database or journaling techniques.
For example, when used with volume shadowing, OpenVMS RMS journaling allows you to develop applications that can automatically recover from failures such as:
See the Volume Shadowing for OpenVMS manual for more information about shadowing merge and copy operations.
Previous | Next | Contents | Index |
privacy and legal statement | ||
6136PRO_026.HTML |