Basic information about the context usage …
MqContextC - the class known as ctx or context is the application-handle of the application-server and also the main data-handle …
The context is the package-item with the required features and created by the implementation-layer-programmer. The context can be a client or a server.
The client-context-creation is triggerd by the software-workflow on demand. The client is calling the MqLinkCreate to create a connection to the server using the connection-arguments to specify the target.
The life-cycle of a client is:
ContextCreate | create and initialize the MqContextC ... |
LinkCreate | make ctx to a parent-context and setup a new client-server-link … |
SendTT | MqContextC - append a native PRIMITIVE TYPE value to the send-data-package … |
ReadTT | read a PRIMITIVE TYPE from the read-data-package … |
LinkDelete | close the client-server-link … |
ContextDelete | Destructor - delete a MqContextC instance … |
Exit | delete the context and exit the current process or thread … |
The server-context-creation is always triggerd by the MqLinkCreate command of the client. The server is usually using a factory-constructor to call the MqContextCreate and finally to call the MqContextDelete.
The server-context is fully under control of the client.
The life-cycle of a server is:
SETUP | define a class and add the setup/cleanup code |
IServerSetup | define the server-setup-interface (callback) used on startup … |
ServiceCreate | create a link between a service-token and a service-callback … |
IServerCleanup | define the server-cleanup-interface (callback) used on cleanup … |
ServiceDelete | delete a service. … |
STARTUP | define the factory and start the listener |
FactoryAdd | add a new MqFactoryC identified by factory-identifier and defined by factory-constructor … |
FactoryNew | create a new MqContextC from a MqFactoryC … |
LinkCreate | make ctx to a parent-context and setup a new client-server-link … |
ProcessEvent | enter the event-loop and wait for an incoming service-request. … |
WORK | process the service-calls and exit on end |
ReadTT | read a PRIMITIVE TYPE from the read-data-package … |
SendTT | MqContextC - append a native PRIMITIVE TYPE value to the send-data-package … |
Exit | delete the context and exit the current process or thread … |
command | alias |
---|---|
[constructor,static] MqContextC MqContextC.Create(?MqContextC tmpl = null?) | pymkmsgque.MqContextC(?tmpl:MqContextC=None?) |
[destructor] ctx.Delete() | ctx = None |
MqContextC - setup and manage a client-server-link …
The client-server-link connect two context, a client-parent-context and a server-parent-context. The link can be local (connect two context on the same host) or can be remote (connect two context on different hosts). On-Top the parent-context multiple child-context are allowed.
!on remote host! !on local host! server1---------x x----------server2 | | | | | child-context-1 child-context-2 | | | | | server parent-context-1-----x x-----parent-context-2 | | (MqConfigS::server) (example: MqConfigS::server --fork --uds … --file …) | | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | | (--tcp) (--pipe, --uds, --tcp) | | parent-context-1-----x x-----parent-context-2 | | | | client | child-context-1 child-context-2 | | | | | x------------x--------client-------x-------------x !on local host!
Definition of a "client-context"
Definition of a "server-context"
Definition of a "parent-context"
Definition of a "child-context"
MqContextC - create and manage a slave context …
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 |
---|---|---|
MQ_SLAVE_MAX | 1024 | internal: the maximum slave-id … . |
MQ_SLAVE_USER | 10 | internal: start of user-defined-slave-id . |
MQ_SLAVE_LOOPBACK | 0 | internal: the loopback-slave-id, (call my own services) . |
MQ_SLAVE_FILTER | 1 | internal: the filter-slave-id, (on a master get the filter-slave) . |
MQ_SLAVE_MASTER | 1 | internal: the master-slave-id, (on a slave get the master) . |
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 < MQ_SLAVE_MAX | range of valid slave-id's |
0 <= slave-id < MQ_SLAVE_USER | internale usage |
MQ_SLAVE_USER <= slave-id < 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.java
→ create a new loop-server package example; import jvmsgque.mqmsgque.*; import jvmsgque.mkkernel.*; // package-item final class MyLoopServer extends MqContextC implements IServerSetup { // set the "mydata" attribute to the master-context String mydata = "Hello World"; // Factory Constructor public MyLoopServer(MqContextC tmpl) { super(tmpl); } // service to serve all EXTERNAL requests for token "HLWO" class HLWO_srv implements MqServiceIF { public void Callback(MqContextC ctx) { // get the "loopback" context MqContextC loop = SlaveGet(MqSlaveE.LOOPBACK.get()); // 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" class LOOP_srv implements MqServiceIF { public void Callback(MqContextC ctx) { // get the "master" context MyLoopServer master = ((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 class "MyFirstService" public void ServerSetup() { // EXTERNAL: link the "HLWO" service with the "HLWO_srv" ServiceCreate("HLWO", new HLWO_srv()); // INTERNAL: link the "LOOP" service with "LOOP_srv" SlaveGet(MqSlaveE.LOOPBACK.get()).ServiceCreate("LOOP", new LOOP_srv()); } // ------------------------------------------------------------- // package-main public static void main(String[] argv) { // create the "MyLoopServer" factory… and the instance MqContextC srv = MqFactoryC.Add(MyLoopServer.class).New(); try { srv.LinkCreate(argv); srv.ProcessEvent(MqWaitOnEventE.FOREVER); } catch (Throwable 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 | - |