NORM Rules

This file contains descriptions of rules used in the NRL
NORM implementation for various aspects of protocol
operation.  These rules are related to the nature of the
NORM protocol and how this particular implementation
maintains protocol state.

Norm Receive Object Status Rules
====================================

When a message for a transport object is received from a
remote NORM server node, the "status" (based on the object's
transport identifier - NormObjectId)of the object is
determined so that appropriate actions may be taken by the
receiver.  The possible status types include:

INVALID - the NormObjectId is out-of-range with respect
          to the current state for the sender.  Out-of-
          range is defined as an objectId which is
          excessively ordinally less than the range of
          currently pending objects (or last object
          successfully complete if none are pending)
          Note that if the object is the _first_ object
          received for the sender, it is always considered
          "valid", thus establishing an initial 
          synchronization point for the sender (sync_id):
          
          sender->Synchronized AND
          
          objectId < sync_id OR 
          objectId > first_pending + bufferRange
          (first_pending = sender->IsPending ? 
            first_pending : next_pending)
          
NEW     - The objectId is greater than the range of 
          currently pending objects (but not too
          much greater) and acceptable for reception.
          Note that is the object is the _first_
          received from the sender, this status
          always results:
          
            !sender->Synchronized OR
            
            objectId >= next_pending AND
            object_id - first_pending < bufferRange
            (first_pending = sender->IsPending ? 
            first_pending : next_pending)
            
PENDING - The objectId corresponds to an object _within_
          the range of currently pending objects for
          the sender and has is marked as still pending:
          
          sender->Synchronized AND
          sender->IsPending() AND
          first_pending <= objectId < next_pending AND
             sender->IsPending(objectId)
          
COMPLETE - The objectId is within range of objects which
           have been detected and is not marked as pending:
           
           sender->Synchronized AND
           sync_id <= objectId < next_pending  AND
           !sender->IsPending(objectId)
           
Note since the sequence of objectId's received from a sender
is circular, the "sync_id" will eventually need to be
updated as the sequence of objects progresses.  Also note
that the "sync_id" might be adjusted depending upon the
receiver synchronisation policy.  For example, if the
synchronization policy is strict, the "sync_id" will be
fixed to no less than the first object the receiver accepts
for reception (according to policies)  But for a looser
policy the receiver might permit the sync_id to be
decremented to  fit within the current "bufferRange".  An
even looser policy would be to allow the receiver's buffer
range to grow as needed.  However, for some applications,
the sender has a finite range of objects for which it
will maintain repair state.

The "bufferRange" is the range (sequential count) of objects
for which the receiver is maintaining state.  That range may
be application specific and senders/receivers are anticipated
to use relatively compatible buffer ranges/sizes based on
application needs.

SENDER/RECEIVER RESOURCE MANAGEMENT

The NORM implementation restricts the server (sender) to a
user-defined,  fixed amount of buffer space (memory) for storing
calculated parity segments and repair state (i.e. which
blocks/segments are pending transmission, and any pending repairs). 
The client (receiver) is similarly limited, but on  a "per-sender"
basis (i.e. the client allocates a fixed pool of buffer space per
sender).  However, the code is designed  to successfully work even
when the buffer limits are exceeded.  It does this via resource
management (i.e. stealing less critical buffer resources to cache
transmit or receive repair  state).  The buffer space consists of a
pool of NormBlock objects (keeps send/receive state on FEC coding
blocks) and a pool of segments (vectors for buffering NORM data or
parity payloads).  The server (sender) keeps pools on a "per-session"
basis and the client (receiver) keeps pools on a "per-server" basis. 
The policies for managing these pools are as follows:

NORM Server (sender) resource management.

When the NORM server is transmitting ordinally new objects/ blocks (or
is required to store repair state for previously transmitted blocks
when receiving a NACK) and its block or segment pools are empty, it
will attempt to "steal" block and/or segment resources from
non-pending blocks (oldest first) of objects in its "holding queue". 
The  presumption is that requests for repair of oldest objects/blocks
is less likely since clients (receivers) request repair of oldest
objects first and older objects/blocks in the queue are more likely to
have already been successfully received by all of the clients.  This
results in most efficient use of CPU time on the sender side when
BANDWIDTH*DELAY*LOSS product of the network topology falls well within
the buffer space limits defined for the server.  NORM will still
operate successfully at extremes of bandwidth*delay*loss, but a cost
of additional CPU demand for recalculating parity repair segments. 
When there are no "non-pending" blocks to steal, repairs may be
ignored, or tranmission paused, until the repair process, and
subsequent transmissions, cause blocks to be marked as non-pending (no
pending segment transmissions or  repairs).

Also note the oldest object is removed from the "holding queue" when
the count of objects in the holding queue exceeds the "transmit
hold" buffer limits when a new object is queued for transmission by
the server (sender) application.  When these objects are removed, any
block or segment resources used by those objects are returned to the
respective server pools.  The "transmit hold" buffer limits will be
defined as the minimum of 1) total size of objects  in the queue
exceeding a "maxSize" parameter, or 2) total count of objects in the
queue exceeding a "maxCount" parameter.  The "maxSize" limit is
overridden if a "minCount" value of greater than one is defined.  The
"transmit hold" buffer limits define how far back the NORM server is
willing/able to go to provide repair information previous to its
current oridinal transmission point.

NORM Client (receiver) resource management.

The client portion of NORM similarly has pre-determined limits on the
quantity of buffering resources (memory) it will use on a per-server
basis.  Again, NORM will still successfully operate when the
bandwidth*delay*loss product of the network topology exceed these
expected/allocated buffer limits.  The cost, when this occurs, is a
decrease in the repair _efficiency_ of the NORM protocol.  When the
client (receiver) becomes buffer limited, it attempts to "steal"
buffer/segment resources from ordinally _newer_  objects/blocks for
which it has accumulated state (Thus giving priority to the repair of
ordinally oldest objects/blocks).  When the bandwidth*delay*loss
product of the network topology causes this to occur, the result is
less efficient repair since the client will either "forget" about some
segments it has already succesfully received (when newer blocks are
"stolen") or ignore received segments for the most ordinally recent
blocks in favor of holding state for older objects/blocks.  

In summary, the NORM protocol will operate most efficiently when there
is ample buffer space, but will still successfully converge when
bandwidth*delay*loss of the network reaches extremes.  The amount of
memory used by NORM can be controlled by the application.


