Real-time systems use communication protocols to send and receive critical information, both among internal processors, and with external actors in the environment. Within the same system, different messages may have different levels of criticality and so may have different requirements for the reliability of message transfer. Further, different media have different reliability, as do different environments. The transaction is used when communication reliability is required over unreliable media or when extraordinary reliability is required. For example, suppose the system needs three distinct levels of communications reliability:
9.5.1 AbstractThe transaction pattern is particularly suited to real-time systems that use a general communication protocol with a rich grammar when different levels of reliability of message transfer are required. It allows the application designers flexibility in their choice of communications method so that they may optimize for speed or reliability. 9.5.2 ProblemThe basic problem addressed by this pattern is to support three levels of reliability in the transmission of messages over unreliable communications media. 9.5.3 Pattern StructureFigure 9-6 shows the structure of the reliable transaction pattern. Ultimately, the sender wants to send a message to the receiver these are object roles played by instances of the class CommunicatingObject. This is mediated by CommStack, which represents a protocol stack. Notice that in the usual case, there are two instances of CommStack for any given message, one is mediating the sending of the message and the other is mediating the reception of the message. The sender and receiver roles are usually connected to different instances of the CommStack class. Each CommStack may, at any time, be sending and receiving dozens or hundreds of messages. Each message may, if at the appropriate level of reliability, be associated with a SendTransaction instance (for ALO and EO protocols) and a ReceiveTransaction instance (for EO protocol). Figure 9-6. Transaction PatternThe important classes in the pattern are the SendTransaction and the ReceiveTransaction instances, as they actually mediate the reliable delivery of the messages. Their statecharts are shown in Figure 9-7. Figure 9-7a. Sender Transaction StatechartFigure 9-7b. Receiver Transaction StatechartThe AMO semantics are the simplest to implement because no transaction objects are required. The reliability of the communications medium and protocol are sufficiently high, and the consequences of a lost message are sufficiently low, so that no extra measures are needed. Transferring messages using AMO semantics is fast and requires the fewest computation resources. ALO semantics require that the sending CommStack maintain a transaction object until an explicit acknowledgment is received back from the receiver. If an acknowledgment is received, the transaction object is destroyed. If no acknowledgment is received within the retry period, then the SendTransaction automatically retransmits the message to the receiving CommStack. If the SendTransaction fails to successfully get the message to the receiver (i.e., the MaxRetries count is exceeded), the message originator is notified so that corrective measures can be initiated. The sending CommunicatingObject cannot distinguish between a loss of the message and a loss of the acknowledgement, so the Receiver object may receive the message more than once. This is normally not a problem for operations like set() when setting an absolute value, but it becomes problematic when the operation is something like increment(). ALO semantics are incompatible with incremental operations. EO semantics require transaction objects on both sides. The objects on the sending side function exactly as they do to support ALO semantics. What is different is that the receiving CommStack object must now create a ReceiveTransaction. When the receiving CommStack receives a message with an EO transaction type, it creates a ReceiveTransaction object and sets its timeToLive and msgID attributes. The timeToLive attribute is used for a timeout; once this timeout occurs, the ReceiveTransaction object is destroyed. If a duplicate message is received before that occurs, the receiving CommStack sends an evReceive event to the ReceiveTransaction, causing it to reenter the waiting state, restarting its timeout period from zero. 9.5.4 Collaboration RolesThe following objects participate in this pattern.
9.5.5 ConsequencesThe reliable transaction pattern simplifies the delivery of messages with three distinct levels of reliability: AMO, ALO, and EO. This is particularly true when many messages may be in transit at any given time, such as when peer-to-peer communications are occurring across a multimastered bus. In a master-slave communications environment, in which a master is in charge of initiating and managing all communications, this pattern is overly complex. The pattern as it is can handle any number of simultaneously active messages. 9.5.6 Implementation StrategiesThe implementation of these classes is straightforward. The CommStack is highly protocol specific, of course, but the SendTransaction and ReceiveTransaction objects have simple statecharts. 9.5.7 Sample ModelFigure 9-8a shows the structure of a simple example. In a medical device, the AnesthesiaControl is remote from the Vaporizer. It needs to send an Increment Dose command to the Vaporizer. Because an "increment" style command is one that should be sent with EO semantics, it creates the message with the transactionType attribute set to EO. It adds the source objectID (99) and the target object (54) as needed by the message. Since the CommunicatingObjects don't have anything to do with the actual message transmission, it leaves the msgID attribute of the Message blank for the CommStack to fill in. Because the EO semantics demand both a SendTransaction and a ReceiveTransaction, those are part of the class diagram. Figure 9-8a. Reliable Transaction Example StructureFigure 9-8b shows a scenario for sending the Increment Dose message. In this scenario, the returning ACK is lost (indicated by the X) so the sending transaction, not knowing whether the original message or the responding ACK was lost, must retransmit after its timeout. The receiving side, meanwhile, has received the message and forwarded it on to the Vaporizer. It has also created a ReceiveTransaction, which waits and receives (and discards) the second command, before eventually timing out and being destroyed. Figure 9-8b. Reliable Transaction Example Scenario |