Burst loss is an Ultra Messaging concept that deals with large amount of message fragments that have been detected as loss on a given transport. Typically in a UM application, when a single message fragment is detected loss and not recovered within the configured transport timeout window, that message fragment is declared unrecoverable loss. In the event of a very large fragment gap, the loss could be declared unrecoverable much sooner if the size of the gap exceeds the threshold configured by the receiver attribute delivery_control_maximum_burst_loss - default is 512 message fragments.
The key thing about burst loss is that the size of the burst is not necessarily equal to that of the configured threshold, in fact the burst is very likely much larger than the threshold. The threshold acts more as a maximum threshold in which the receiver is willing to accept before giving up. The event itself does not provide the size of the burst though, it is the applications responsibility to capture that data if it is necessary, and that is the purpose of this sample application, to demonstrate how to calculate the size of the burst.
Calculating the size of the burst is quite easy. The burst event callback does provide a sequence number which is the high sequence number of the burst. If the application simply tracks the previously consumed sequence number, it can subtract that from the sequence number in the burst event to know exactly how many message fragments are included in the burst. To successfully track the last sequence number, the application will simply need to record the last sequence number received in the message callback, unrecoverable loss callback, and the burst callback itself, as these are the only three callbacks that will advance the sequence number.
Note: As always, sequence numbers are assigned to message fragments, which may or may not be equal to one whole application message. If an application level message exceeds the configurable UM datagram size, than a single message may take up multiple message fragments, which would span over multiple sequence numbers.
There is one program source file:
Standard context and receiver creation, with a minimal amount of options set:
00018 /* Initialize and create receiver and receiver callback */ 00019 ReceiverCallback myReceiverCallback = new ReceiverCallback(); 00020 00021 ctx = new LBMContext(); 00022 rcv_attr = new LBMReceiverAttributes(); 00023 00024 rtopic = new LBMTopic(ctx, "test.topic", rcv_attr); 00025 rcv = new LBMReceiver(ctx, rtopic, myReceiverCallback, null);
Here in the message callback, the sample application focuses on thress particular events:
First the message callback. This is where the application would typically process the data inside a message, or maybe retain the message to be processed later on a spearate thread. In either case, the last sequence number should be updated here:
00039 case LBM.MSG_DATA: 00040 lastSqn = msg.sequenceNumber(); 00041 break;
Next is the unrecoverable loss event, which indicates that a single message fragment has become unrecoverable. The sequence number provided in this event is the message fragment that is unrecoverable, so it should set the last sequence number variable here as well:
00042 case LBM.MSG_UNRECOVERABLE_LOSS: 00043 lastSqn = msg.sequenceNumber(); 00044 break;
Finally the burst event callback. Here we can calculate the size of the burst my subtracting the last sequence number from the sequence number provided in the callback itself. Once the burst size has been calculated, update the last sequence number as well, because the very next could be another burst loss event, and the application will want to calculate the size of that burst as well:
00045 case LBM.MSG_UNRECOVERABLE_LOSS_BURST: 00046 long burst = lastSqn - msg.sequenceNumber(); 00047 System.out.println("WARNING: Burst loss of " + burst + " messages!"); 00048 lastSqn = msg.sequenceNumber(); 00049 break;