Partially fixed a bug in the test suite that led to test runs randomly failing.
[invirt/third/libt4.git] / handle.cc
index a233d5b..d32c895 100644 (file)
--- a/handle.cc
+++ b/handle.cc
 #include "handle.h"
-#include <stdio.h>
-#include "tprintf.h"
 
-handle_mgr mgr;
+class hinfo {
+public:
+    rpcc *cl = nullptr;
+    int refcnt = 0;
+    bool del = false;
+    string m;
+    mutex client_mutex;
+    hinfo(const string & m_) : m(m_) {}
+};
 
-handle::handle(std::string m) 
-{
-  h = mgr.get_handle(m);
-}
+class handle_mgr {
+    private:
+        mutex mgr_mutex;
+        map<string, hinfo *> hmap;
+        void delete_handle(const string & m, lock & handle_mutex_lock);
+    public:
+        hinfo *acquire_handle(string m);
+        void release_handle(hinfo *h);
+        void delete_handle(const string & m);
+};
+
+static handle_mgr mgr;
+
+handle::handle(const string & m) : h(mgr.acquire_handle(m)) {}
 
-rpcc *
-handle::safebind()
-{
-  if (!h)
-    return NULL;
-  ScopedLock ml(&h->cl_mutex);
-  if (h->del)
-    return NULL;
-  if (h->cl)
+rpcc * handle::safebind() {
+    if (!h)
+        return nullptr;
+    lock ml(h->client_mutex);
+    if (h->del)
+        return nullptr;
+    if (h->cl)
+        return h->cl;
+    rpcc *cl = new rpcc(h->m);
+    LOG("handler_mgr::acquire_handle trying to bind..." << h->m);
+    // 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.
+    int ret = cl->bind(rpcc::to(1000));
+    if (ret < 0) {
+        LOG("handle_mgr::acquire_handle bind failure! " << h->m << " " << ret);
+        delete cl;
+        h->del = true;
+    } else {
+        LOG("handle_mgr::acquire_handle bind succeeded " << h->m);
+        h->cl = 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;
-  // Starting with lab 6, our 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.
-  // 
-  // Note: with RPC_LOSSY=5, your lab would failed to pass the tests of
-  // lab 6 and lab 7 because the rpc layer may delay your RPC request, 
-  // and cause a time out failure. Please make sure RPC_LOSSY is set to 0.
-  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);
+handle::~handle() {
+    if (h) mgr.release_handle(h);
 }
 
-handle_mgr::handle_mgr()
-{
-  VERIFY (pthread_mutex_init(&handle_mutex, NULL) == 0);
+hinfo * handle_mgr::acquire_handle(string m) {
+    lock ml(mgr_mutex);
+    hinfo *h = nullptr;
+    if (hmap.find(m) == hmap.end()) {
+        h = new hinfo(m);
+        hmap[m] = h;
+        h->refcnt++;
+    } else if (!hmap[m]->del) {
+        h = hmap[m];
+        h->refcnt++;
+    }
+    return h;
 }
 
-struct hinfo *
-handle_mgr::get_handle(std::string m)
-{
-  ScopedLock 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;
-    pthread_mutex_init(&h->cl_mutex, NULL);
-    hmap[m] = h;
-  } else if (!hmap[m]->del) {
-    h = hmap[m];
-    h->refcnt ++;
-  }
-  return h;
+void handle_mgr::release_handle(hinfo *h) {
+    lock ml(mgr_mutex);
+    if (--h->refcnt == 0 && h->del)
+        delete_handle(h->m, ml);
 }
 
-void 
-handle_mgr::done_handle(struct hinfo *h)
-{
-  ScopedLock ml(&handle_mutex);
-  h->refcnt--;
-  if (h->refcnt == 0 && h->del)
-    delete_handle_wo(h->m);
+void handle_mgr::delete_handle(const string & m) {
+    lock ml(mgr_mutex);
+    delete_handle(m, ml);
 }
 
-void
-handle_mgr::delete_handle(std::string m)
-{
-  ScopedLock ml(&handle_mutex);
-  delete_handle_wo(m);
+void handle_mgr::delete_handle(const string & m, lock &) {
+    if (hmap.find(m) == hmap.end()) {
+        LOG("handle_mgr::delete_handle: cl " << m << " isn't in cl list");
+        return;
+    }
+    LOG("handle_mgr::delete_handle: cl " << m << " refcnt " << hmap[m]->refcnt);
+    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;
 }
 
-// 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;
-      }
-      pthread_mutex_destroy(&h->cl_mutex);
-      hmap.erase(m);
-      delete h;
-    } else {
-      h->del = true;
-    }
-  }
+void invalidate_handle(const string & m) {
+    mgr.delete_handle(m);
 }