WRT binary marshal, we need a high performance, efficient, RPC (remote procedure call) mechanism. Options are: 1. Current RMD 2. Google protobufs: https://code.google.com/p/protobuf/ 3. A new RPC mechanism defined by Yang files. The user would define separate Yang files for RPC calls -- that is different than the configuration file. However, the RPC Yang file might include the configuration one if a RPC call requires a parameter that is also a config object.
Pros/Cons:
1. Current RMD Pros: exists
Cons: XML definition language is not convenient for editing. XML definition language is OpenClovis-specific Code is complex for a simple thing, hard to debug. Could be higher performance C-only
2. Protobufs: Pros: exists in common use -- defacto standard
Cons: in common use -- OpenClovis adds no value possibly least efficient of the 3 (uses pedantic >> and << for serialization) Not integrated with TIPC or IOC
3. Yang Pros: Uses standard file format Integrates well with SAFplus7 because we already use Yang for configuration We have experience with Yang file format We could make an extremely efficient data format.
Cons: we must create it
Given these options, I think we should do some basic investigation into #2 and #3.
For #2, we need to see how efficient it is, and how hard to add IOC/TIPC underneath.
For #3, that means creating a binary marshal format and a special y2cpp that generates RPC optimized code and data. For example, the classes would not be "Managed" -- that is:
->
Also I would like the code generator to be capable of generating an in-place implementation. That is:
Classically could generate:
1 class GroupType
2 {
3 int something;
4 int somethingElse;
5 }
6
7 operator >> (Buffer& msg, GroupType& g) { ... } // Generate binary marshal
8
9 void getDataServer(Buffer* msg, Buffer* ret)
10 {
11 int rc;
12 GroupType g;
13 *msg >> g; // Marshal and Demarshal functions are generated for each object
14 rc = getData(&g);
15 *ret << rc;
16 }
In-place:
1 void getDataServer(Buffer* msg, Buffer* ret, int swapNeeded)
2 {
3 GroupType *g = (GroupType*) (msg+GroupTypeOffset);
4 if (swapNeeded)
5 {
6 // Do an "in-place" endian swap. These are inlined functions for efficiency.
7 swap(g->something);
8 swap(g->somethingElse);
9 }
10 *(ret+RetOffset) = getData(g);
11 }
For complex structures, the in-place mechanism is extremely efficient because it:
- does no malloc/free
- does not call a large number of nested subfunctions that demarshal each individual thing -- function calls are actually expensive when you think about doing 50 of them just for a single RPC.
- does not copy, which both increases cache utilization and reduces expensive memory access.