The following example use cases shows how to use mBrane API.

Object Overview

Nodes

One mBrane Node object is instantiated on each computer participating in the application cluster. A Node is meant to run as a Daemon and should automatically restart when terminated abnormally. Modules connected to a Node should handle a Node restart without any impact on the user code. The maximum downtime of a Node should be less than N milliseconds. Nodes can either auto-discover each other or a new node can be specifically told about an existing network node. A node can join a network, leave a network, restart and terminate.

Modules

Modules run separately from the local Node and communicates directly to the Node using shared memory. If a node is not running, the module will wait for N milliseconds for a Node to be instantiated, before exiting with an error. Once a Module is connected to the Node it will register itself on the network with name and properties. If the local Node is restarted the module will re-register automatically.

Once a module has registered it can submit its subscription, if needed. A subscription may already exist for the module, and this is overwritten each time the module submits a new one. At startup and after each subscription the module will read and cache its own current subscription from the network. If another module changes the subscription the new subscription will be received as a notification and cached locally. If the local Node is restarted the module will re-submit the last cached subscription.

Messages

A Message is a placeholder for data and will be instantiated by the sending Module. The Module will fill in the fields in the Message and post it. The Node will determine who has subscribed for this Message and forward a copy of the Message either to both locally connected receivers and receivers connected to other Nodes in the system. If possible, the original Message object will be reused for one of the local receivers to avoid unnecessary memory allocation.

Stream Messages

Messages posted to Streams are identical in nature to the non-streaming Messages, except for the fact that they contain a 32-bit unsigned integer sequence number.

Signals

A signal is used for notification of events, such as Module Created, Subscription changed, etc. Users can also define their own application specific signal types. A Module can subscribe to signal notifications if they are interested in one or more signal events.

Nodes

Initialise

No information needs to be provided to the Node object at initialisation time:

MBNode* node = new MBNode(); (called by mBrane::main())

Join a Network

There are two ways that a Node can join a network:

* Automatic - using UDP to discover other Nodes on the network

bool res = node→joinNetwork();

* Manually - provide an address and optionally a port of one other node in the network

bool res = node→joinNetwork(“server.com”);

bool res = node→joinNetwork(“server.com”, 12445);

Leave a Network

bool res = node→leaveNetwork();

Restart

bool res = node→leaveNetwork();

if (!res) error;

delete(node);

node = new MBNode();

bool res = node→joinNetwork();

Terminate

bool res = node→leaveNetwork();

if (!res) error;

delete(node);

Test and Performance

Once the Node Network has been established, any node can act as the Test Master Node:

* Unit Test - automatically uses all available nodes in network

mBrane::TestResult *result=mBrane::Test::AParticularUnitTest::new(mBrane::Node::Get())→run();

in addition we'll have to test the node functions with respect to module execution (ex: order of delivery, prioritization, etc): this calls for building test modules and run them in coordination with unit tests

* Performance Test - automatically uses all available nodes in network

mBrane::TestResult *result=mBrane::Test::AParticularPerformanceTest::new(mBrane::Node::Get())→run();

for intrinsic capabilities (networking, RAM allocation, latencies, etc). In addition, for extrinsic capabilities (performance under application load) we could use entities to build organizations of test modules to stress the system in various situations

Generally speaking, testing / profiling shall combine unit tests / profiles and system-wide stress configurations. In other words, unit testing / profiling must describe the capacity of the system to bear load / complexity (like messaging patterns).

For more information about testing, see testing_and_performance.

Modules

Management

Initialise

Since the Node should already be running on the local computer a module can be initialised using

MBModule* module = new MBModule(“MyName”); mBrane::Module *m=new CommonLib::C();m→init(parameters);

since modules are class instances, where C is the module class, loaded in the CommonLib, and parameters come from the relevant psyspec file

Register on Network

If the user wants to wait forever for the Node to be ready or be started:

bool res = module→register();

If the user wants to wait for N milliseconds for the Node to be ready or be started and after this give up:

bool res = module→register(N);

[E: I'd prefer a node to broadcast a “ready” signal upon which modules could react, registration being enacted in at module instantiation time by the node. NB: a module is executed by a holding thread controlled by the node. If the node is down or not ready no thread is running and the module cannot be executed.] [T: How would that look, then?]

To query the local Node, again with a timeout:

Node *n=mBrane::Node::Get(); …; n→register(this);…; mBrane::Node::Descriptor *d=n→getDescriptor();

This could be done by invoking a callback when the node state changes instead of queries. The goal is to inverse the control flow, as needed by the many-modules-scheduled-and-executed-by-one-thread arrangement.

As part of the registration the current subscription will be downloaded to the module, if the network knows of a subscription already, either because

* the module was connected and got or chose to be disconnected * another module entered a subscription for the module

This can be seen using

int count = module→getSubscriptionCount();

MBSubscription* sub = module→getSubscription(id);

[E: we should also introduce subscription sets. Apparently the subscriptions you describe here stand for the subscription to one message class|content id. It would be useful for a module to be able to compare different sets coming from different states (previous subscriptions, subscriptions made by other modules, etc. Then only one set has to be published.] [T: I like that! How would that look…?]

Subscribe

A subscription can be registered using subscription objects.

MBSubscription* sub = new MBSubscription();

sub→subscribeType(“Type”); [E: what is type? why parameters are still a strings?]

sub→subscribeFrom(“Module”);

sub→subscribeTo(“Module”);

sub→subscribeAfter(timeout);

sub→subscribeContent(“StringMatch”);

[E: what does it mean?]

[T: This was for the option of local filtering by content, ie. messages containing “*mystring*” - is that possible or doable?]

int id = module→addSubscription(sub);

int count = module→getSubscriptionCount();

MBSubscription* sub = module→getSubscription(id);

bool res = module→removeSubscription(id);

bool res = module→publishSubscriptions();

Resubscribe

bool res = module→publishSubscriptions();

Unsubscribe

bool res = module→removeAllSubscriptions();

bool res = module→publishSubscriptions();

Unregister from Network

If the user wants to disconnect from the network

mBrane::Node::Get()→unregister(this);

This will inactivate, but not delete the current subscriptions. These will be reactivated if the module connects again.

Terminate

delete(module); when the crank returns a termination value

mBrane::Node::Get()→terminate(this); when the termination decision is made from a user-defined thread spawn from the module

Messaging

Post Message

When a module is registered on the network it can post messages:

MBMessage* message mBrane::Node::get()→message(new CommonLib::C(args));

bool res = message→setTo(“Module”);

bool res = message→setType(“Type”); [T: Do we need this?]

bool res = message→setCC(“Module”); [T: Do we support this?]

bool res = message→setContent(char*, len);

bool res = mBrane::Node::get()→post(message);

Receive Message

Two modes:

* Callback Crank

namespace CommonLib{

int MyModuleClass::MyCrank(Module *mod,Message *msg){

return ( (MyModuleClass *) mod)→myCrank(msg);

}

int MyModuleClass::myCrank(Message *msg){

(user code)

return 0;

}

}

Where the address of MyCrank is stored in a static array in MyModuleClass, indexed by the crank ID.
All of these are built and initialized at CommonLib compilation / loading time, from the module class declaration and definition.
In particular the code for MyCrank is generated, by macros / template instantiation; same for static data like class and crank IDs.
NB: with the inverted control flow, modules are always running in continuous mode.

* Continuous Crank

int MyCrankFunction(MBModule* module) {

if (module == NULL) return -1;

MBMessage* message;

int timeout = 100;

while (some condition) {

message = waitForTriggerMessage(timeout);

if (message != NULL) {…}

}

return 0;

}

Alternative getTriggerMessage calls:

Get the Nth trigger message instead of the first:

MBMessage* message = getTriggerMessage(N);

If N not provided, default value is 0;

Wait for N milliseconds for a new trigger message to appear:

MBMessage* message = waitForTriggerMessage(N);

If a trigger message is already there, this acts like getTriggerMessage();

Post to Stream

mBrane Streams do not have any storage and basically work very much like normal messaging. If the module has subscribed to a stream called S it will be triggered by stream messages just like normal messages, probably just at a higher frequency, so the code should expect this and act accordingly to prevent exponential queuing.

Receive from Stream

If a module is subscribed to a stream S it can post to it by posting messages of type S: [E: I don't understand “posting to a stream”.] [T: Output data to the stream S]

MBMessage* message = new MBMessage();

bool res = message→setType(“S”);

bool res = message→setContent(char*, len);

bool res = module→post(message);

Signalling

Post Signal

When a module is registered on the network it can post custom signals:

MBSignal* signal = mBrane::Node::Get()→signal(new CommonLib::C(args));

bool res = signal→setType(“Z”);

bool res = module→post(signal);

where C is the message class. NB: nothing differentiates a message from a signal. Only its handling by a node is different.

Subscribe to and receive Signals

mBrane Signals work very much like normal messaging. If the module has subscribed to a signal called Z it will be triggered by Signal Messages just like normal messages. A Signal Message is merely a Message with type “Signal:Z” [E: again I suggest using classes instead of strings] [T: Agreed]

MBSubscription* sub = new MBSubscription();

sub→subscribeType(“Signal:Z”);

int id = module→addSubscription(sub);

Advanced

Suspend

Resume

Reset

Migrate to new Node

 
projects/mbrane/use_cases.txt · Last modified: 2008/04/02 08:47 by thorlist
 
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki