stasher::client
->subscribeserverstatus
(): server status reports#include <iostream> #include <stasher/client.H> #include <stasher/serverstatuscallback.H> #include <x/fmtsize.H> #include <string> class mycallbackObj : public stasher::serverstatuscallbackObj { public: mycallbackObj() {} ~mycallbackObj() {} void serverinfo(const stasher::userhelo &serverinfo) override { std::cout << "Connected to " << serverinfo.nodename << " (cluster " << serverinfo.clustername << ")" << std::endl; std::cout << "Maximum " << serverinfo.limits.maxobjects << " objects, " << x::fmtsize(serverinfo.limits.maxobjectsize) << " aggregate object size, per transaction." << std::endl << "Maximum " << serverinfo.limits.maxsubs << " concurrent subscriptions." << std::endl; } void state(const stasher::clusterstate &state) override { std::cout << "Current master: " << state.master << std::endl; for (auto &node:state.nodes) { std::cout << " Peer: " << node << std::endl; } std::cout << "Quorum: full=" << x::tostring(state.full) << ", majority=" << x::tostring(state.majority) << std::endl; } }; void serverstatussubscriber() { stasher::client client=stasher::client::base::connect(); std::cout << "Subscribing to server status, press ENTER to stop" << std::endl; auto subscriber=x::ref<mycallbackObj>::create(); stasher::subscribeserverstatusresults results= client->subscribeserverstatus(subscriber); std::cout << "Subscription status: " << x::tostring(results->status) << std::endl; x::ref<x::obj> mcguffin=results->mcguffin; x::ref<x::obj> cancel_mcguffin=results->cancel_mcguffin; std::string dummy; std::getline(std::cin, dummy); } int main() { try { serverstatussubscriber(); } catch (const x::exception &e) { std::cerr << e << std::endl; exit(1); } return 0; }
This is a subscription to a notification mechanism of the server's status.
The parameter to
()
is an stasher::client
->subscribeserverstatusx::ref
to a subclass of
stasher::client::base::subscriberObj
that implements the two methods shown in this example.
The serverinfo
() callback gets invoked once,
shortly after subscribeserverstatus
() returns
(or just before it, dependencies on how fast the thread hamster runs).
It reports the object repository server's name, and the resource limits
for the connection.
The state
() callback gets invoked shortly after
serverinfo
() returns, and any time thereafter
when its reported information changes. The state
()
callback reports which node is the master
controller, and all the connected peer nodes; as well as the
quorum status.
()
returns a stasher::client
->subscribeserverstatusstasher::subscribeserverstatusresults
, which is an
x::ref
to a reference-counted object with
the following members:
status
The subscription status status,
with stasher::req_processed_stat
indicating that
the server status subscription is succesfully established.
mcguffin
A mcguffin representing the subscription. There is no formal unsubscribe(), rather than subscription remains open as long as the mcguffin exists. Stopping the subscription involves simply letting the mcguffin go out of scope and get destroyed.
While a subscription remains open, the client object holds a strong reference on the server status subscriber callback. When the mcguffin goes out of scope and gets destroyed, if the client connection thread is in the middle of invoking the one of its callbacks, or is busy with something else at the moment, there may be a slight delay before the subscription gets wrapped up, and the connection thread releases its reference on the subscriber callback object; and it's remotely possible that one of the callbacks can get invoked at the same time, or just after, the mcguffin goes out of scope and gets destroyed.
cancel_mcguffin
The flip side of the coin. This is a mcguffin that's owned by the client connection thread. When the subscription gets closed, for any reason, the client connection thread releases its reference on the mcguffin.
It's possible that the server status subscription can get closed even before its mcguffin goes out of scope and gets destroyed, and the cancellation mcguffin provides the means for detecting this situation. The normal sequence of events when the subscription gets closed goes like this;
The application destroys the mcguffin.
The client connection thread stops the subscription.
The client connection thread releases its reference on the cancellation mcguffin and the subscriber callback object.
The last step also happens spontaneously in the event that the
client connection thread's connection to the server breaks for any reason. The
subscription does not get reopened automatically, when a new
client connection thread reconnects to the stasher server. Attaching a destructor
callback to the cancellation mcguffin (and releasing the reference
on the cancellation mcguffin, and the
stasher::subscribeserverstatusresults
object)
provides the means for detecting and handling this situation.
The cancellation mcguffin's destructor callbacks also gets invoked when the subscription gets closed in the regular way, by destroying the subscription mcguffin.
Example:
$ ./subscribeserverstatus
Subscribing to server status, press ENTER to stop
Connected to octopus.objrepo.example.com (cluster objrepo.example.com)
Maximum 10 objects, 32 Mb aggregate object size, per transaction.
Maximum 10 concurrent subscriptions.
Current master: octopus.objrepo.example.com
Peer: monster.objrepo.example.com
Subscription status: Transaction/request processed
Quorum: full=true, majority=true
Current master: octopus.objrepo.example.com
Peer: monster.objrepo.example.com
Quorum: full=false, majority=false
Current master: monster.objrepo.example.com
Peer: monster.objrepo.example.com
Quorum: full=false, majority=false
Current master: monster.objrepo.example.com
Peer: monster.objrepo.example.com
Quorum: full=true, majority=true
The limitations on callback methods described later, in the section called “What asynchronous C++ API methods can and cannot do”, apply to these callbacks too.