[SAGA-RG] Message API Evolution

Andre Merzky andre at merzky.net
Mon May 10 13:03:50 CDT 2010


Dear Group,

the Messaging API originally evolved around a single endpoint class,
whose behaviour was, together with the endpoint's URL, determined by
a number of properties, all specified on creation time.  In order to
satisfy the relatively wide range of use cases, the number of
properties was rather large, and included

  - communication topology
  - message reliability
  - message delivery atomicity
  - message correctness/completeness
  - message ordering

(All properties can be left unspecified, and the URL schema can
pinpoint a specific protocol and transport medium to be used.)

Additionally, the API proposal contained a message class, which is
derived from saga::buffer, and allows to add application level
structure to that SAGA buffer.  That message class also provides
some means of inspection (message origin and id, and generic user
level attributes MAY be available on the message instances).

There was some feedback (at OGF and on this list) that this API, and
in particular the endpoint class, may be cumbersome to use (too many
degrees of freedom), and that the ability to specify incompatible
endpoint properties (e.g. 'Unreliable & ExactlyOnce') was confusing.

There are, however, not many obvious ways how to remedy those points
without blowing the API out of proportion, or loosing coverage for
specific use cases.  The examples attached to this mail illustrate
the different possible approaches:  they contain the respective API
prototypes, and a short code example, which creates a visualization
pipeline segment (communicating a geometry between mapper and
renderer).

We are mentoring a google-summer-of-code student at LSU at the
moment (Hi Christos!), and his task is to provide a prototype
implementation of the message API.  I would thus propose to have a
quick vote on one of the proposals below, to allow Christos to go
forward with the resulting option (remember: "rough consensus &
running code").  Once we have running code and a matching proposed
recommendation, we have two years time to gather experiences with
that, and should be prepared to switch to any of the other options
on the final recommendation, if needed.

So, please provide feedback to the following options, or provide
alternative options.  FWIW, I also attach the current (generic) API
proposal again.  Both the proposal and the code examples can be
found in svn, at

  https://svn.cct.lsu.edu/repos/saga-ogf/trunk/documents/saga-package-messagebus

Thanks, and best regards, Andre.


  (A) generic.cpp
   
    The orginal API proposal, which described a single endpoint
    class with multiple properties.


  (B) specific.cpp

    Specifying individual endpoint types for specific use case
    classes makes those endpoints simpler (most properties are
    preset), but also makes use case coverage difficult (one cannot
    sensibly cover the complete property-space with individual
    classes).


  (C) topology.cpp

    Specific individual endpoint classes for the different
    communication topologies also blow the API, to some extent, but
    also reduce the number of explicit endpoint properties (from 5
    to 4).  One could also consider to have different property
    presets per topology class (like 'Unrealiable, Unordered' for
    'PeerToPeer' endpoints, and 'Reliable, Ordered' for
    'PointToPoint' endpoints), but that may be confusing to the
    unaware end user.


  (D) mixed.cpp

    Another possible approach is to mix elements from the approaches
    above: the API could include a generic_endpoint class, but also
    topology specific endpoints, and/or use case class specific
    endpoints.  That may address all levels of end users, but would
    also convolute the API significantly.


-- 
Nothing is ever easy.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: saga_messages.pdf
Type: application/pdf
Size: 241512 bytes
Desc: not available
Url : http://www.ogf.org/pipermail/saga-rg/attachments/20100510/6f2fcbf9/attachment-0001.pdf 
-------------- next part --------------

namespace saga
{
  namespace messaging
  {
    enum state
    {
      Unknown = 0,
      New     = 1,
      Open    = 2, 
      Closed  = 3,
      Dropped = 4
    };

    enum topology
    {
      Any              = 0,
      PointToPoint     = 1,
      Multicast        = 2, 
      PublishSubscribe = 3,
      PeerToPeer       = 4
    };

    enum reliability
    {
      Any              = 0,
      Unreliable       = 1,
      Consistent       = 2,
      SemiReliable     = 2,
      Reliable         = 3
    };

    enum atomicity
    {
      Any              = 0,
      AtMostOnce       = 1, 
      AtLeastOnce      = 2, 
      ExactlyOnce      = 3
    };

    enum correctness
    {
      Any              = 0,
      Verified         = 1, 
      Unverified       = 2,
      Signed           = 3,
      Encrypted        = 4
    };

    enum ordering
    {
      Any              = 0,
      Unordered        = 1,
      Ordered          = 2,
      GloballyOrdered  = 3
    };

    class message : public saga::buffer
    {
      public:
        message (void);
        message (int            size);
        message (void         * data);
        message (saga::buffer   buf, 
                 int            size = -1);
       ~message (void);

       std::string get_sender (void);
       std::string get_id     (void);
    };


    class endpoint;
    class endpoint : public saga::object
                   , public saga::async
                   , public saga::monitorable
    {
      public:
        endpoint (void);
        endpoint (saga::object & obj); 
        endpoint (saga::url   url, 
                  topology    t, 
                  reliability r, 
                  atomicity   a, 
                  correctness c,
                  ordering    o); 
       ~endpoint (void);

       // inspection
       saga::url get_url       (void);
       std::list <saga::url>
                 get_receivers (void);

       // management methods
       void      serve         (int       n_clients = -1);
       endpoint  serve_once    (float     timout    = -1.0);
       void      connect       (float     timout    = -1.0);
       void      disconnect    (void);

       // I/O methods
       void      send          (message   m,
                                saga::url client    = "",
                                float     timout    = -1.0);

       int       test          (saga::url client    = "",
                                float     timout    = -1.0);
       
       message   receive       (saga::url client    = "",
                                float     timout    = -1.0) 
    };
  }
}



//////////////////////////////////////////////////////////////////////
//
// application example
//

class geometry
{
  // ...
};

class geometry_message : public saga::messaging::message
{
  // define how the message is serialized into and deserialized from a message
  // buffer
};

void mapper_to_renderer (geometry geom)
{
  // The generic endpoint class has all properties defaulting to 
  // 'Any', so we need to specify the properties (unless we are 
  // happy with Any, which we aren't in this use case).

  saga::messaging::endpoint ep ("geom://remote.host.net:1234/renderer/", 
                                saga::messaging::PublishSubscriber, // Topology
                                saga::messaging::Reliable,          // Reliability
                                saga::messaging::AtMostOnce,        // Atomicity
                                saga::messaging::Verified,          // Correctness
                                saga::messaging::Unordered          // Ordering
                               );
  geometry_message gm (geom);
  ep.send (gm);
}

-------------- next part --------------


namespace saga
{
  namespace messaging
  {
    enum state
    {
      Unknown = 0,
      New     = 1,
      Open    = 2, 
      Closed  = 3,
      Dropped = 4
    };

    enum topology
    {
      Any              = 0,
      PointToPoint     = 1,
      Multicast        = 2, 
      PublishSubscribe = 3,
      PeerToPeer       = 4
    };

    enum reliability
    {
      Any              = 0,
      Unreliable       = 1,
      Consistent       = 2,
      SemiReliable     = 2,
      Reliable         = 3
    };

    enum atomicity
    {
      Any              = 0,
      AtMostOnce       = 1, 
      AtLeastOnce      = 2, 
      ExactlyOnce      = 3
    };

    enum correctness
    {
      Any              = 0,
      Verified         = 1, 
      Unverified       = 2,
      Signed           = 3,
      Encrypted        = 4
    };

    enum ordering
    {
      Any              = 0,
      Unordered        = 1,
      Ordered          = 2,
      GloballyOrdered  = 3
    };

    class message : public saga::buffer
    {
      public:
        message (void);
        message (int            size);
        message (void         * data);
        message (saga::buffer   buf, 
                 int            size = -1);
       ~message (void);

       std::string get_sender (void);
       std::string get_id     (void);
    };


    class endpoint;
    class endpoint : public saga::object
                   , public saga::async
                   , public saga::monitorable
    {
      public:
        endpoint (void);
        endpoint (saga::object & obj); 
        endpoint (saga::url   url, 
                  topology    t, 
                  reliability r, 
                  atomicity   a, 
                  correctness c,
                  ordering    o); 
       ~endpoint (void);

       // inspection
       saga::url get_url       (void);
       std::list <saga::url>
                 get_receivers (void);

       // management methods
       void      serve         (int       n_clients = -1);
       endpoint  serve_once    (float     timout    = -1.0);
       void      connect       (float     timout    = -1.0);
       void      disconnect    (void);

       // I/O methods
       void      send          (message   m,
                                saga::url client    = "",
                                float     timout    = -1.0);

       int       test          (saga::url client    = "",
                                float     timout    = -1.0);
       
       message   receive       (saga::url client    = "",
                                float     timout    = -1.0) 
    };


    class reliable_pubsub_endpoint ...
    class unreliable_pubsub_endpoint ...
    class reliable_atomic_point2point_endpoint ...
    class reliable_atomic_point2point_endpoint ...
    class unreliable_point2point_endpoint ...
    ...

    class point2point_endpoint ...
    class peer2peer_endpoint ...
    class multicast_endpoint ...
  }
}



//////////////////////////////////////////////////////////////////////
//
// application example
//

class geometry
{
  // ...
};

class geometry_message : public saga::messaging::message
{
  // define how the message is serialized into and deserialized from a message
  // buffer
};

void mapper_to_renderer (geometry geom)
{
  // there is no specific endpoing class which exactly
  // poinpoints all ep properties, so we use the more generic 
  // pubsub endpoint (which has the correct topology), and 
  // specify the other properties (Atomicity is here the 
  // non-default 'AtMostOnce').

  saga::messaging::pubsub_endpoint ep ("geom://remote.host.net:1234/renderer/",
                                       saga::messaging::Reliable,          // Reliability
                                       saga::messaging::AtMostOnce,        // Atomicity
                                       saga::messaging::Verified,          // Correctness
                                       saga::messaging::Unordered          // Ordering
                                      );

  geometry_message gm (geom);

  ep.send (gm);
}

-------------- next part --------------

namespace saga
{
  namespace messaging
  {
    enum state
    {
      Unknown = 0,
      New     = 1,
      Open    = 2, 
      Closed  = 3,
      Dropped = 4
    };

    class message : public saga::buffer
    {
      public:
        message (void);
        message (int            size);
        message (void         * data);
        message (saga::buffer   buf, 
                 int            size = -1);
       ~message (void);

       std::string get_sender (void);
       std::string get_id     (void);
    };


    class reliable_pubsub_endpoint : public saga::object
                                   , public saga::async
                                   , public saga::monitorable
    {
      // default properties for the reliable pubsub endpoint are:
      //   Topology    : PublishSubscriber
      //   Reliability : Reliable,        
      //   Atomicity   : ExactlyOnce,      
      //   Correctness : Verified,        
      //   Ordering    : Unordered        
      public:
        reliable_pubsub_endpoint (void);
        reliable_pubsub_endpoint (saga::object & obj); 
       ~reliable_pubsub_endpoint (void);

       // inspection
       saga::url get_url       (void);
       std::list <saga::url>
                 get_receivers (void);

       // management methods
       void      serve         (int       n_clients = -1);
       reliable_pubsub_endpoint  serve_once    (float     timout    = -1.0);
       void      connect       (float     timout    = -1.0);
       void      disconnect    (void);

       // I/O methods
       void      send          (message   m,
                                saga::url client    = "",
                                float     timout    = -1.0);

       int       test          (saga::url client    = "",
                                float     timout    = -1.0);
       
       message   receive       (saga::url client    = "",
                                float     timout    = -1.0) 
    };

    class unreliable_pubsub_endpoint ...
    class reliable_atomic_point2point_endpoint ...
    class reliable_atomic_point2point_endpoint ...
    class unreliable_point2point_endpoint ...
    ...
  }
}



//////////////////////////////////////////////////////////////////////
//
// application example
//

class geometry
{
  // ...
};

class geometry_message : public saga::messaging::message
{
  // define how the message is serialized into and deserialized from a message
  // buffer
};

void mapper_to_renderer (geometry geom)
{
  // Our set of specific endpoints does not offer any endpoint with the exact
  // properties we want, so we uses the closest match, which is the reliable
  // pubsub endpoint, which has Atomicity set to ExactlyOnce, instead of the
  // AtMostOnce we actually want.
  
  saga::messaging::reliable_pubsub_endpoint ep ("geom://remote.host.net:1234/renderer/");

  geometry_message gm (geom);
  
  ep.send (gm);
}

-------------- next part --------------


namespace saga
{
  namespace messaging
  {
    enum state
    {
      Unknown = 0,
      New     = 1,
      Open    = 2, 
      Closed  = 3,
      Dropped = 4
    };

    enum reliability
    {
      Any              = 0,
      Unreliable       = 1,
      Consistent       = 2,
      SemiReliable     = 2,
      Reliable         = 3
    };

    enum atomicity
    {
      Any              = 0,
      AtMostOnce       = 1, 
      AtLeastOnce      = 2, 
      ExactlyOnce      = 3
    };

    enum correctness
    {
      Any              = 0,
      Verified         = 1, 
      Unverified       = 2,
      Signed           = 3,
      Encrypted        = 4
    };

    enum ordering
    {
      Any              = 0,
      Unordered        = 1,
      Ordered          = 2,
      GloballyOrdered  = 3
    };

    class message : public saga::buffer
    {
      public:
        message (void);
        message (int            size);
        message (void         * data);
        message (saga::buffer   buf, 
                 int            size = -1);
       ~message (void);

       std::string get_sender (void);
       std::string get_id     (void);
    };


    class pubsub_endpoint : public saga::object
                          , public saga::async
                          , public saga::monitorable
    {
      // default properties for the pubsub endpoint are:
      //   Topology    : PublishSubscriber
      //   Reliability : Reliable,        
      //   Atomicity   : ExactlyOnce,      
      //   Correctness : Verified,        
      //   Ordering    : Unordered          
      public:
        pub_sub_endpoint (void);
        pub_sub_endpoint (saga::object & obj); 
        pub_sub_endpoint (saga::url   url, 
                          reliability r, 
                          atomicity   a, 
                          correctness c,
                          ordering    o); 
       ~pub_sub_endpoint (void);

       // inspection
       saga::url get_url       (void);
       std::list <saga::url>
                 get_receivers (void);

       // management methods
       void      serve         (int       n_clients = -1);
       endpoint  serve_once    (float     timout    = -1.0);
       void      connect       (float     timout    = -1.0);
       void      disconnect    (void);

       // I/O methods
       void      send          (message   m,
                                saga::url client    = "",
                                float     timout    = -1.0);

       int       test          (saga::url client    = "",
                                float     timout    = -1.0);
       
       message   receive       (saga::url client    = "",
                                float     timout    = -1.0) 
    };

    class point2point_endpoint ...
    class peer2peer_endpoint ...
    class multicast_endpoint ...
  }
}



//////////////////////////////////////////////////////////////////////
//
// application example
//

class geometry
{
  // ...
};

class geometry_message : public saga::messaging::message
{
  // define how the message is serialized into and deserialized from a message
  // buffer
};

void mapper_to_renderer (geometry geom)
{
  // our topology specific endpoint needs slightly different default 
  // property settings, so we specify them (Atomicity is here the 
  // non-default 'AtMostOnce').

  saga::messaging::pubsub_endpoint ep ("geom://remote.host.net:1234/renderer/", 
                                       saga::messaging::Reliable,          // Reliability
                                       saga::messaging::AtMostOnce,        // Atomicity
                                       saga::messaging::Verified,          // Correctness
                                       saga::messaging::Unordered          // Ordering
                                      );
  geometry_message gm (geom);
  ep.send (gm);
}



More information about the saga-rg mailing list