DataDescriptor API
Describing the data
In order to allow GRAS to send data over the network (or simply to
dupplicate it in SG), you have to describe the structure of data attached
with each message. This mecanism is stolen from NWS message passing
interface.
For each message, you have to declare a structure representing the
data to send as payload with the message.
Sending (or receiving) simple structures
Let's imagin you want to declare a STORE_STATE
message, which will send some data to the memory server for inclusion in
the database. Here is the structure we want to send:
struct state {
char id[STATE_NAME_SIZE];
int rec_size;
int rec_count;
double seq_no;
double time_out;
};
And here is the structure description GRAS needs to be able to send
this over the network:
const static DataDescriptor stateDescriptor[] =
{SIMPLE_MEMBER(CHAR_TYPE, STATE_NAME_SIZE, offsetof(struct state, id)),
SIMPLE_MEMBER(INT_TYPE, 1, offsetof(struct state, rec_size)),
SIMPLE_MEMBER(INT_TYPE, 1, offsetof(struct state, rec_count)),
SIMPLE_MEMBER(DOUBLE_TYPE, 1, offsetof(struct state, seq_no)),
SIMPLE_MEMBER(DOUBLE_TYPE, 1, offsetof(struct state, time_out))};
Contrary to what one could think when you first see it, it's pretty
easy. A structure descriptor is a list of descriptions, describing each
field of the structure. For example, for the first field, you say that
the base type is CHAR_TYPE, that there is
STATE_NAME_SIZE element of this type and that it's
position in the structure is computed by offsetof(struct state,
id). This leads to two remarks:
it's impossible to send dynamic sized strings that way. It's a
known limitation, but I think we can live with it.
Yes, the offsetof(struct state, id)
construction is C ANSI and is portable.
Sending (or receiving) complex structure
How to send non-flat structures, do you ask? It's not harder. Let's
imagin you want to send the following structure:
typedef struct {
unsigned long address;
unsigned long port;
} CliqueMember;
typedef struct {
char name[MAX_CLIQUE_NAME_SIZE];
double whenGenerated;
double instance;
char skill[MAX_SKILL_SIZE];
char options[MAX_OPTIONS_SIZE];
double period;
double timeOut;
CliqueMember members[MAX_MEMBERS];
unsigned int count;
unsigned int leader;
} Clique;
As you can see, this structure contains an array of another user
defined structure. To be able to send struct Clique,
you have to describe each structures that way:
static const DataDescriptor cliqueMemberDescriptor[] =
{SIMPLE_MEMBER(UNSIGNED_LONG_TYPE, 1, offsetof(CliqueMember, address)),
SIMPLE_MEMBER(UNSIGNED_LONG_TYPE, 1, offsetof(CliqueMember, port))};
static const DataDescriptor cliqueDescriptor[] =
{SIMPLE_MEMBER(CHAR_TYPE, MAX_CLIQUE_NAME_SIZE, offsetof(Clique, name)),
SIMPLE_MEMBER(DOUBLE_TYPE, 1, offsetof(Clique, whenGenerated)),
SIMPLE_MEMBER(DOUBLE_TYPE, 1, offsetof(Clique, instance)),
SIMPLE_MEMBER(CHAR_TYPE, MAX_SKILL_SIZE, offsetof(Clique, skill)),
SIMPLE_MEMBER(CHAR_TYPE, MAX_OPTIONS_SIZE, offsetof(Clique, options)),
SIMPLE_MEMBER(DOUBLE_TYPE, 1, offsetof(Clique, period)),
SIMPLE_MEMBER(DOUBLE_TYPE, 1, offsetof(Clique, timeOut)),
{STRUCT_TYPE, MAX_MEMBERS, offsetof(Clique, members),
(DataDescriptor *)&cliqueMemberDescriptor, cliqueMemberDescriptorLength,
PAD_BYTES(CliqueMember, port, unsigned long, 1)},
SIMPLE_MEMBER(UNSIGNED_INT_TYPE, 1, offsetof(Clique, count)),
SIMPLE_MEMBER(UNSIGNED_INT_TYPE, 1, offsetof(Clique, leader))};
So, even if less natural, it is possible to send structures
containing structures with these tools.
You can see that it's not only impossible to send dynamic-sized
strings, it impossible to send dynamic-sized arrays. Here,
MAX_MEMBERS is the maximum of members a clique can
contain. In NWS, this value is defined to 100. I'm not
sure, but I think that all the 100 values are sent each time, even if
there is only 3 non-null members. Yes, that's
bad.
The DataDescriptor_t MUST be const. Malloc'ing them and
then casting them on argument passing IS NOT OK. This is because we get
the number of elements in the array with the sizeof(dd)/sizeof(dd[0]).
@CHAR_TYPE:
@DOUBLE_TYPE:
@FLOAT_TYPE:
@INT_TYPE:
@LONG_TYPE:
@SHORT_TYPE:
@UNSIGNED_INT_TYPE:
@UNSIGNED_LONG_TYPE:
@UNSIGNED_SHORT_TYPE:
@STRUCT_TYPE:
@type:
@repetitions:
@type:
@repetitions:
@offset:
@structType:
@lastMember:
@memberType:
@repetitions: