#include "handle.h"
-#include <stdio.h>
-#include "tprintf.h"
-#include "lock.h"
-handle_mgr mgr;
+class hinfo {
+public:
+ unique_ptr<rpcc> client;
+ bool valid = true;
+ string destination;
+ mutex client_mutex;
+ hinfo(const string & destination_) : destination(destination_) {}
+};
-handle::handle(std::string m)
-{
- h = mgr.get_handle(m);
-}
-
-rpcc *
-handle::safebind()
-{
- if (!h)
- return NULL;
- lock ml(h->cl_mutex);
- if (h->del)
- return NULL;
- if (h->cl)
- return h->cl;
- sockaddr_in dstsock;
- make_sockaddr(h->m.c_str(), &dstsock);
- rpcc *cl = new rpcc(dstsock);
- tprintf("handler_mgr::get_handle trying to bind...%s\n", h->m.c_str());
- int ret;
- // The test script assumes that the failure can be detected by paxos and
- // rsm layer within few seconds. We have to set the timeout with a small
- // value to support the assumption.
- //
- // With RPC_LOSSY=5, tests may fail due to delays and time outs.
- ret = cl->bind(rpcc::to(1000));
- if (ret < 0) {
- tprintf("handle_mgr::get_handle bind failure! %s %d\n", h->m.c_str(), ret);
- delete cl;
- h->del = true;
- } else {
- tprintf("handle_mgr::get_handle bind succeeded %s\n", h->m.c_str());
- h->cl = cl;
- }
- return h->cl;
-}
-
-handle::~handle()
-{
- if (h) mgr.done_handle(h);
-}
+static mutex mgr_mutex;
+static map<string, shared_ptr<hinfo>> hmap;
-handle_mgr::handle_mgr()
-{
+handle::handle(const string & destination) : destination_(destination) {
+ lock ml(mgr_mutex);
+ h = hmap[destination];
+ if (!h || !h->valid)
+ h = (hmap[destination] = make_shared<hinfo>(destination));
}
-struct hinfo *
-handle_mgr::get_handle(std::string m)
-{
- lock ml(handle_mutex);
- struct hinfo *h = 0;
- if (hmap.find(m) == hmap.end()) {
- h = new hinfo;
- h->cl = NULL;
- h->del = false;
- h->refcnt = 1;
- h->m = m;
- hmap[m] = h;
- } else if (!hmap[m]->del) {
- h = hmap[m];
- h->refcnt ++;
+rpcc * handle::safebind() {
+ if (!h)
+ return nullptr;
+ lock cl(h->client_mutex);
+ if (!h->valid)
+ return nullptr;
+ if (!h->client) {
+ unique_ptr<rpcc> client(new rpcc(h->destination));
+ LOG("bind(\"" << h->destination << "\")");
+ int ret = client->bind(milliseconds(1000));
+ if (ret < 0) {
+ LOG("bind failure! " << h->destination << " " << ret);
+ h->valid = false;
+ } else {
+ LOG("bind succeeded " << h->destination);
+ h->client = move(client);
+ }
}
- return h;
-}
-
-void
-handle_mgr::done_handle(struct hinfo *h)
-{
- lock ml(handle_mutex);
- h->refcnt--;
- if (h->refcnt == 0 && h->del)
- delete_handle_wo(h->m);
+ return h->client.get();
}
-void
-handle_mgr::delete_handle(std::string m)
-{
- lock ml(handle_mutex);
- delete_handle_wo(m);
-}
-
-// Must be called with handle_mutex locked.
-void
-handle_mgr::delete_handle_wo(std::string m)
-{
- if (hmap.find(m) == hmap.end()) {
- tprintf("handle_mgr::delete_handle_wo: cl %s isn't in cl list\n", m.c_str());
- } else {
- tprintf("handle_mgr::delete_handle_wo: cl %s refcnt %d\n", m.c_str(),
- hmap[m]->refcnt);
- struct hinfo *h = hmap[m];
- if (h->refcnt == 0) {
- if (h->cl) {
- h->cl->cancel();
- delete h->cl;
- }
- hmap.erase(m);
- delete h;
- } else {
- h->del = true;
- }
+void handle::invalidate() {
+ h.reset();
+ lock ml(mgr_mutex);
+ if (hmap.find(destination_) != hmap.end()) {
+ hmap[destination_]->valid = false;
+ LOG_NONMEMBER("cl " << destination_ << " refcnt " << hmap[destination_].use_count());
+ hmap.erase(destination_);
}
}