Many shells (e.g. rc, bash) support the
following control flow structure:
case In a brief summary, in a Linda system,
distributed processes communicate thru shared associative "address
space" - tuple space which consist of tuples. Each tuple consists of
fields. Tuples are written
("out") to tuple space, read and taken ("in", "read") from tuple space.
Tuples are identified thru associative
lookup: two tuples match if all their corresponding fields match while
two fields match if they are of the same type and either of the same
value or one of them is wildcard.
Channel supports message passing and
name-matching based on regex pattern matching and Linda associative
lookup. Regex name-matching is implemented using Boost.Regex and the
code is relative straightforward. Please refer to
sample 9
for the usage of regex based name-matching. Here we focus on the
detailed
implemenation of names-matching
using Linda lookup. Please refer to
sample
10 for the usage of associative lookup based name-matching.
In Linda style associative name space, a message names/ids is "a
tuple" consisting of a set of fields. We use Boost.Tuple for
defining these ids and names. To support associative lookup, we define
field_trait template classes for each data type of the tuple fields.
Each field_trait class will define wildcard and match operation for its
data type. The following is a sample:
template <>
class
BOOST_CHANNEL_DECL field_trait<int> {
public:
typedef int field_type;
static int wildcard;
static bool wildcard_field(int f) {
if (f == wildcard)
return true;
return false;
}
static bool match(int f1, int f2) {
if (f1 == wildcard || f2 == wildcard)
return true;
return f1 == f2;
}
};
In assoc_id_trait.hpp, we define the field_trait template classes for
all the primitive data types. If user defined types (classes or
structs) are to be used as tuple field type, user code should provide
field_trait classes for these types.
We define the following template class as associative name space id:
template <typename Tuple_Type>
class tuple_id {
......
We need define copy constructor and
standard relational operators for tuple_id to work with std::map
container.
tuple_id(const tuple_id &id) : type_(id.type_),
tuple_(id.tuple_) {}
bool operator< (const tuple_id &id) const {......}
bool operator== (const tuple_id &id) const
{......}
bool operator!= (const tuple_id &id) const
{......}
......
Then we define serialize() method to
marshal/demarshal tuple_id using Boost.Serialization
template<class Archive>
void serialize(Archive & ar, const unsigned int
version) {......}
};
Next, we define id_trait class for
tuple_id:
template<typename Tuple_Type>
class BOOST_CHANNEL_DECL id_trait<tuple_id<Tuple_Type> > {
public:
we define some associated types.
typedef Tuple_Type tuple_type;
typedef tuple_id<tuple_type> id_type;
and define system internal messages
static id_type channel_conn_msg;
static id_type channel_disconn_msg;
static id_type init_subscription_info_msg;
static id_type connection_ready_msg;
static id_type subscription_info_msg;
static id_type unsubscription_info_msg;
static id_type publication_info_msg;
static id_type unpublication_info_msg;
Since internally Boost.Tuple is
represented as recursive cons list, the following match operation is
defined as recursive methods:
static bool match_tuple(const
boost::tuples::null_type&, const boost::tuples::null_type&)
{
return true;
}
template <typename H, typename T>
static bool match_tuple(const boost::tuples::cons<H,T> &t1,
const boost::tuples::cons<H,T> &t2)
{
if(!field_trait<H>::match(t1.get_head(),
t2.get_head()))
return false;
return match_tuple(t1.get_tail(), t2.get_tail());
}
static bool match(id_type id1, id_type id2)
{
if (id1.type_ != id2.type_)
return false;
if (id1.type_ == id_type::app_type) {
if (wildcard_tuple(id1.tuple_) &&
wildcard_tuple(id2.tuple_) && (id1.tuple_ != id2.tuple_))
return false;
if (id1.tuple_ == id2.tuple_)
return true;
return match_tuple(id1.tuple_, id2.tuple_);
}
return true;
}
Similarly, we define recursive methods to find if a tuple_id contains
wildcard:
static bool wildcard_tuple(const boost::tuples::null_type&)
{
return false;
}
template <typename H, typename T>
static bool wildcard_tuple(const boost::tuples::cons<H,T> &t1)
{
if(field_trait<H>::wildcard_field(t1.get_head()))
return true;
return wildcard_tuple(t1.get_tail());
}
static bool wildcard_name(const id_type &id) {
if (id.type_ != id_type::app_type)
return false;
return wildcard_tuple(id.tuple_);
}
Finally we define a method to display id content as string for
debugging purpose:
static std::string id_to_string(const id_type &id) {
std::ostringstream os;
os << "tuple_id : type[" << id.type_
<< "] tuple[" << id.tuple_ << "]";
return os.str();
}
};
Since the type of tuple (how many fields and what fields types) are
decided by application code of Channel and can be different for
different applications, the pre-defined system internal messages can
only be defined thru the following macro. Application code should
include this macro somewhere so that its system internal messages are
defined:
#define
DEFINE_ASSOC_SYS_IDS( tuple_type ) \
template
<> boost::channel::tuple_id<tuple_type>
boost::channel::id_trait<boost::channel::tuple_id<tuple_type>
>::channel_conn_msg(boost::channel::tuple_id<tuple_type>::channel_conn_type);
\
......