MqContextC - setup and manage a routing-link … More...
MqContextC - setup and manage a routing-link …
A routing-link is the connection of two context, the route-source and the route-target, with a unspecifiend number of hub-context in between using a specific service-token.
A single context is identified by the context-identifier as returned by MqClassIdentGet.
A routing-link can be created using Service-Level-Routing or Package-Level-Routing.
The difference between Service-Level-Routing and Package-Level-Routing is the public versa private behaviour.
Summary:
ctx.RouteCreate(MK_STRN route, MK_STRN service, MK_BOOL overwrite = false)
using a route-connection-string and a service-token. The TCP/IP model define the following layers (from: https://www.geeksforgeeks.org/tcp-ip-model/) :
The libmqmsgque layer model is an extension to the TCP/IP layer model.
protocoll_mq.h
→ this is the "syntax" of the protocol. This layer provide the MqContextC-ServiceApi ontop of the Application Layer.
The master-slave-link is used to create a mesh of nodes defined by different parent-context. The master control the slave.
The master-slave-link is used to perform the following tasks:
In difference to the client-server-link the master-slave-link connect two independent parent-context in the same process or thread (e.g. node). This leads to the restriction that only the master-context can be a server-context because only one server-context per node is possible.
node-0 | node-1/2 | node-3/4/5 =================================================================== | <- client/server link -> | <- client/server link -> | | <-- master/slave link --> | |- client1-0 -|- server3 ... |- server1 -| | |- client1-1 -|- server4 ... client0-0 -| |- server2 -|- client1-2 -|- server5 ...
Definition of the "master-context"
Definition of the "slave-context"
0
.Definition of the "worker-context"
0
./etc/services
0
slave-id | value | definition |
---|---|---|
libmqmsgque::MQ_SLAVE_MAX | 1024 | internal: the maximum slave-id … . |
libmqmsgque::MQ_SLAVE_USER | 10 | internal: start of user-defined-slave-id . |
libmqmsgque::MQ_SLAVE_LOOPBACK | 0 | internal: the loopback-slave-id, (call my own services) . |
libmqmsgque::MQ_SLAVE_FILTER | 1 | internal: the filter-slave-id, (on a master get the filter-slave) . |
libmqmsgque::MQ_SLAVE_MASTER | 1 | internal: the master-slave-id, (on a slave get the master) . |
libmqmsgque::MQ_SLAVE_OTHER | 1 | internal: on the master-ctx get the slave-ctx and on the slave-ctx get the master-ctx . |
range | definition |
---|---|
0 <= slave-id < libmqmsgque::MQ_SLAVE_MAX | range of valid slave-id's |
0 <= slave-id < libmqmsgque::MQ_SLAVE_USER | internale usage |
libmqmsgque::MQ_SLAVE_USER <= slave-id < libmqmsgque::MQ_SLAVE_MAX | external usage |
Definition of the "LOOPBACK" (0) slave
client | server | =========================================== | <--- client/server ---> | <-- loop --> | | <------ master/slave -----> | client -- | -- server -- | -- client -- # == == # server -- | -- client -- #
slave-id = 0
. MyLoopServer.cc
→ create a new loop-server #include "LibMqMsgque_cc.hh" using namespace ccmqmsgque; // package-item class MyLoopServer : public MqContextC, public IServerSetup { friend class MqFactoryCT<MyLoopServer>; // set the "mydata" attribute to the master-context MK_STRN mydata = "Hello World"; // define the factory constructor MyLoopServer(MK_TYP const typ, MqContextC* tmpl=NULL) : MqContextC(typ, tmpl) {}; private: // service to serve all EXTERNAL requests for token "HLWO" void HLWO_srv () { // get the "loopback" context auto loop = SlaveGet(MQ_SLAVE_LOOPBACK); // call the LOOP service on the SAME server loop->Send("W", "LOOP"); // answer HLWO with string-return from LOOP Send("R", "C", loop->ReadSTR()); } // service to serve all INTERNAL requests for token "LOOP" void LOOP_srv () { // get the "master" context auto master = static_cast<MyLoopServer*>(SlaveGetMaster()); // answer LOOP with data from MASTER->mydata attribute Send("R", "C", master->mydata); } // define a service as link between the token "HLWO" and the callback "MyFirstService" void ServerSetup() { // EXTERNAL: link the "HLWO" service with "HLWO_srv" ServiceCreate("HLWO", MqServiceICB(&MyLoopServer::HLWO_srv)); // INTERNAL: link the "LOOP" service with "LOOP_srv" SlaveGet(MQ_SLAVE_LOOPBACK)->ServiceCreate("LOOP", MqServiceICB(&MyLoopServer::LOOP_srv)); } }; // package-main int MK_CDECL main(int argc, MK_STRN argv[]) { MqMsgque::Setup(); // create "MyLoopServer" factory… and the instance auto srv = MqFactoryCT<MyLoopServer>::Add("MyLoopServer")->New(); try { srv->LinkCreate( MkBufferListC {argc, argv} ); srv->ProcessEvent (MQ_WAIT_FOREVER); } catch (const std::exception& e) { srv->ErrorCatch(e); } srv->Exit(); }
Performance analyse
Nhi1Exec perfclient.c --parent --wrk ? @ perfserver.c
Nhi1Exec -r=uds perfserver.c --spawn|fork|thread
Nhi1Exec -r=uds perfclient.c --parent --wrk ?
perfclient worker perfserver ========== ====== ========== | |- loop --wrk x |- MqSlaveWorker(...) -> worker[1] |- MqSend(worker[1],"E","STR0..") -> PerfWorker_I160(...) |- loop endless |- MqContextCreate(...) |- MqLinkCreate(...) <-> MqContextCreate(...) |- MqContextDelete(...) <-> MqContextDelete(...) |- sleep x sec |- loop --wrk x |- MqSend(worker[1],"C"..,"END0") -> PerfWorker_END0(...) | |- stop loop |- "callback" - add number to all <- |- return #context
setup | –wrk | # worker-context | performance | info |
---|---|---|---|---|
pipe | 1 | 2500 | 1000 | the pipe start a new worker-context with spawn |
spawn | 1 | 2500 | <1000 | same as pipe but use network-protocoll |
fork | 1 | 3800 | 4000 | the fork is faster than spawn |
thread | 1 | 16500 | 9000 | the thread is faster than fork |
pipe | 4 | 8000 | 4500 | the worker scale linear up to number of processors |
spawn | 4 | 7600 | <4500 | - |
fork | 4 | 23200 | 11500 | - |
thread | 4 | 55500 | 27500 | - |
pipe | 8 | 10000 | 5500 | the additional scaling up to the max hyper-threading does not really help |
spawn | 8 | 9100 | <5500 | - |
fork | 8 | 23200 | 11500 | - |
thread | 8 | 55500 | 27500 | - |
A client-server connection is defined with the route-connection-string as a composition of "identifier" and is build like a UNIX directory tree with the initial client as root.
Example: GUI/Data Frontend
With --ident-from prefix|factory the identifier is defined as prefix-identifier or factory-identifer.
A route-connection-string is the path between TWO locations in the tree using the UNIX syntax:
short | syntax | direction |
---|---|---|
dot | . | current-context |
double-dot | .. | previous-context |
slash | / | root-context (the client) |
"string" | xxx | next-context with name xxx |
path between "DB" and "header"
relative: ctx.RouteCreate("../GUI/header",service)
absolute: ctx.RouteCreate("/frontend/GUI/header",service)
path between "footer" and "DB"
relative: ctx.RouteCreate("../../DB",service)
absolute: ctx.RouteCreate("/frontend/DB",service)
path between "frontend" and "footer"
relative: ctx.RouteCreate("GUI/footer",service)
absolute: ctx.RouteCreate("/frontend/GUI/footer",service)
The LibMqMsgque-Service-Layer-Routing create proxy-services (MqServiceProxyRoundRobin ...) between frontend and footer. (example c++)
The MqRouteCreate will take the following action:
Attention:
overwrite=true
to guarantee that a route is available....
A routing-link is the connection of two context, the route-source and the route-target, with a unspecifiend number of hub-context in between using a specific service-token.
A single context is identified by the context-identifier as returned by MqClassIdentGet.
A routing-link can be created using Service-Level-Routing or Package-Level-Routing.
The difference between Service-Level-Routing and Package-Level-Routing is the public versa private behaviour.
Summary:
ctx.RouteCreate(MK_STRN route, MK_STRN service, MK_BOOL overwrite = false)
using a route-connection-string and a service-token. The TCP/IP model define the following layers (from: https://www.geeksforgeeks.org/tcp-ip-model/) :
The libmqmsgque layer model is an extension to the TCP/IP layer model.
protocoll_mq.h
→ this is the "syntax" of the protocol. This layer provide the MqContextC-ServiceApi ontop of the Application Layer.
The master-slave-link is used to create a mesh of nodes defined by different parent-context. The master control the slave.
The master-slave-link is used to perform the following tasks:
In difference to the client-server-link the master-slave-link connect two independent parent-context in the same process or thread (e.g. node). This leads to the restriction that only the master-context can be a server-context because only one server-context per node is possible.
node-0 | node-1/2 | node-3/4/5 =================================================================== | <- client/server link -> | <- client/server link -> | | <-- master/slave link --> | |- client1-0 -|- server3 ... |- server1 -| | |- client1-1 -|- server4 ... client0-0 -| |- server2 -|- client1-2 -|- server5 ...
Definition of the "master-context"
Definition of the "slave-context"
0
.Definition of the "worker-context"
0
./etc/services
0
slave-id | value | definition |
---|---|---|
libmqmsgque::MQ_SLAVE_MAX | 1024 | internal: the maximum slave-id … . |
libmqmsgque::MQ_SLAVE_USER | 10 | internal: start of user-defined-slave-id . |
libmqmsgque::MQ_SLAVE_LOOPBACK | 0 | internal: the loopback-slave-id, (call my own services) . |
libmqmsgque::MQ_SLAVE_FILTER | 1 | internal: the filter-slave-id, (on a master get the filter-slave) . |
libmqmsgque::MQ_SLAVE_MASTER | 1 | internal: the master-slave-id, (on a slave get the master) . |
libmqmsgque::MQ_SLAVE_OTHER | 1 | internal: on the master-ctx get the slave-ctx and on the slave-ctx get the master-ctx . |
range | definition |
---|---|
0 <= slave-id < libmqmsgque::MQ_SLAVE_MAX | range of valid slave-id's |
0 <= slave-id < libmqmsgque::MQ_SLAVE_USER | internale usage |
libmqmsgque::MQ_SLAVE_USER <= slave-id < libmqmsgque::MQ_SLAVE_MAX | external usage |
Definition of the "LOOPBACK" (0) slave
client | server | =========================================== | <--- client/server ---> | <-- loop --> | | <------ master/slave -----> | client -- | -- server -- | -- client -- # == == # server -- | -- client -- #
slave-id = 0
. MyLoopServer.cc
→ create a new loop-server #include "LibMqMsgque_cc.hh" using namespace ccmqmsgque; // package-item class MyLoopServer : public MqContextC, public IServerSetup { friend class MqFactoryCT<MyLoopServer>; // set the "mydata" attribute to the master-context MK_STRN mydata = "Hello World"; // define the factory constructor MyLoopServer(MK_TYP const typ, MqContextC* tmpl=NULL) : MqContextC(typ, tmpl) {}; private: // service to serve all EXTERNAL requests for token "HLWO" void HLWO_srv () { // get the "loopback" context auto loop = SlaveGet(MQ_SLAVE_LOOPBACK); // call the LOOP service on the SAME server loop->Send("W", "LOOP"); // answer HLWO with string-return from LOOP Send("R", "C", loop->ReadSTR()); } // service to serve all INTERNAL requests for token "LOOP" void LOOP_srv () { // get the "master" context auto master = static_cast<MyLoopServer*>(SlaveGetMaster()); // answer LOOP with data from MASTER->mydata attribute Send("R", "C", master->mydata); } // define a service as link between the token "HLWO" and the callback "MyFirstService" void ServerSetup() { // EXTERNAL: link the "HLWO" service with "HLWO_srv" ServiceCreate("HLWO", MqServiceICB(&MyLoopServer::HLWO_srv)); // INTERNAL: link the "LOOP" service with "LOOP_srv" SlaveGet(MQ_SLAVE_LOOPBACK)->ServiceCreate("LOOP", MqServiceICB(&MyLoopServer::LOOP_srv)); } }; // package-main int MK_CDECL main(int argc, MK_STRN argv[]) { MqMsgque::Setup(); // create "MyLoopServer" factory… and the instance auto srv = MqFactoryCT<MyLoopServer>::Add("MyLoopServer")->New(); try { srv->LinkCreate( MkBufferListC {argc, argv} ); srv->ProcessEvent (MQ_WAIT_FOREVER); } catch (const std::exception& e) { srv->ErrorCatch(e); } srv->Exit(); }
Performance analyse
Nhi1Exec perfclient.c --parent --wrk ? @ perfserver.c
Nhi1Exec -r=uds perfserver.c --spawn|fork|thread
Nhi1Exec -r=uds perfclient.c --parent --wrk ?
perfclient worker perfserver ========== ====== ========== | |- loop --wrk x |- MqSlaveWorker(...) -> worker[1] |- MqSend(worker[1],"E","STR0..") -> PerfWorker_I160(...) |- loop endless |- MqContextCreate(...) |- MqLinkCreate(...) <-> MqContextCreate(...) |- MqContextDelete(...) <-> MqContextDelete(...) |- sleep x sec |- loop --wrk x |- MqSend(worker[1],"C"..,"END0") -> PerfWorker_END0(...) | |- stop loop |- "callback" - add number to all <- |- return #context
setup | –wrk | # worker-context | performance | info |
---|---|---|---|---|
pipe | 1 | 2500 | 1000 | the pipe start a new worker-context with spawn |
spawn | 1 | 2500 | <1000 | same as pipe but use network-protocoll |
fork | 1 | 3800 | 4000 | the fork is faster than spawn |
thread | 1 | 16500 | 9000 | the thread is faster than fork |
pipe | 4 | 8000 | 4500 | the worker scale linear up to number of processors |
spawn | 4 | 7600 | <4500 | - |
fork | 4 | 23200 | 11500 | - |
thread | 4 | 55500 | 27500 | - |
pipe | 8 | 10000 | 5500 | the additional scaling up to the max hyper-threading does not really help |
spawn | 8 | 9100 | <5500 | - |
fork | 8 | 23200 | 11500 | - |
thread | 8 | 55500 | 27500 | - |
A client-server connection is defined with the route-connection-string as a composition of "identifier" and is build like a UNIX directory tree with the initial client as root.
Example: GUI/Data Frontend
With --ident-from prefix|factory the identifier is defined as prefix-identifier or factory-identifer.
A route-connection-string is the path between TWO locations in the tree using the UNIX syntax:
short | syntax | direction |
---|---|---|
dot | . | current-context |
double-dot | .. | previous-context |
slash | / | root-context (the client) |
"string" | xxx | next-context with name xxx |
path between "DB" and "header"
relative: ctx.RouteCreate("../GUI/header",service)
absolute: ctx.RouteCreate("/frontend/GUI/header",service)
path between "footer" and "DB"
relative: ctx.RouteCreate("../../DB",service)
absolute: ctx.RouteCreate("/frontend/DB",service)
path between "frontend" and "footer"
relative: ctx.RouteCreate("GUI/footer",service)
absolute: ctx.RouteCreate("/frontend/GUI/footer",service)
The LibMqMsgque-Service-Layer-Routing create proxy-services (MqServiceProxyRoundRobin ...) between frontend and footer. (example c++)
The MqRouteCreate will take the following action:
Attention:
overwrite=true
to guarantee that a route is available....
|
inline |
C++:
→ C-API ctx.RouteCreate(MK_STRN route, MK_STRN service, MK_BOOL overwrite = false)
create/delete a routing-link between context an a service using route
Definition at line 1506 of file MqContextC_inline_cc.hh.
|
inline |
C++:
→ C-API ctx.RouteCreate(MK_STRN route, MK_STRN service, MK_BOOL overwrite = false)
create/delete a routing-link between context an a service using route
Definition at line 1498 of file MqContextC_inline_cc.hh.
|
inline |
C++:
→ C-API ctx.RouteDelete(MK_STRN route, MK_STRN service, MK_BOOL overwrite = false)
delete a routing-link created with MqRouteCreate
Definition at line 1524 of file MqContextC_inline_cc.hh.
|
inline |
C++:
→ C-API ctx.RouteDelete(MK_STRN route, MK_STRN service, MK_BOOL overwrite = false)
delete a routing-link created with MqRouteCreate
Definition at line 1516 of file MqContextC_inline_cc.hh.
|
inline |
C++:
→ C-API MK_STRN ctx.RouteGetPath()
return the absolut route-connection-string up to the current ctx …
Definition at line 1613 of file MqContextC_inline_cc.hh.
|
inline |
C++:
→ C-API MkBufferListC* ctx.RouteGetTree()
create an overview about all available routing-target and services …
Definition at line 1486 of file MqContextC_inline_cc.hh.
|
inline |
C++:
→ C-API MqContextC_A ctx.RouteResolve(MK_STRN ident, MK_NUM retnum = -1)
return a list of all context belonging to ident …
Definition at line 1553 of file MqContextC_inline_cc.hh.
|
inline |
C++:
→ C-API MqContextC_A ctx.RouteResolve(MK_STRN ident, MK_NUM retnum = -1)
return a list of all context belonging to ident …
Definition at line 1534 of file MqContextC_inline_cc.hh.
|
inline |
C++:
→ C-API ctx.RouteTraverse(MK_STRN service, MkBufferListC* args = NULL)
traverse a tree down and call service if available.
Definition at line 1601 of file MqContextC_inline_cc.hh.
|
inline |
C++:
→ C-API ctx.RouteTraverse(MK_STRN service, MkBufferListC* args = NULL)
traverse a tree down and call service if available.
Definition at line 1591 of file MqContextC_inline_cc.hh.
|
inline |
C++:
→ C-API ctx.RouteTraverse(MK_STRN service, MkBufferListC* args = NULL)
traverse a tree down and call service if available.
Definition at line 1582 of file MqContextC_inline_cc.hh.
|
inline |
C++:
→ C-API ctx.RouteTraverse(MK_STRN service, MkBufferListC* args = NULL)
traverse a tree down and call service if available.
Definition at line 1573 of file MqContextC_inline_cc.hh.