d048ead24b18074c98ab698fd70e9897b13fe6b1
[invirt/third/libt4.git] / handle.cc
1 #include "handle.h"
2 #include "threaded_log.h"
3 #include "lock.h"
4 #include <map>
5
6 using std::map;
7
8 class hinfo {
9 public:
10     rpcc *cl = nullptr;
11     int refcnt = 0;
12     bool del = false;
13     string m;
14     mutex client_mutex;
15     hinfo(const string & m_) : m(m_) {}
16 };
17
18 class handle_mgr {
19     private:
20         mutex mgr_mutex;
21         map<string, hinfo *> hmap;
22         void delete_handle(const string & m, lock & handle_mutex_lock);
23     public:
24         hinfo *acquire_handle(string m);
25         void release_handle(hinfo *h);
26         void delete_handle(const string & m);
27 };
28
29 static handle_mgr mgr;
30
31 handle::handle(const string & m) : h(mgr.acquire_handle(m)) {}
32
33 rpcc * handle::safebind() {
34     if (!h)
35         return nullptr;
36     lock ml(h->client_mutex);
37     if (h->del)
38         return nullptr;
39     if (h->cl)
40         return h->cl;
41     rpcc *cl = new rpcc(h->m);
42     LOG("handler_mgr::acquire_handle trying to bind..." << h->m);
43     // The test script assumes that the failure can be detected by paxos and
44     // rsm layer within few seconds. We have to set the timeout with a small
45     // value to support the assumption.
46     // 
47     // With RPC_LOSSY=5, tests may fail due to delays and time outs.
48     int ret = cl->bind(rpcc::to(1000));
49     if (ret < 0) {
50         LOG("handle_mgr::acquire_handle bind failure! " << h->m << " " << ret);
51         delete cl;
52         h->del = true;
53     } else {
54         LOG("handle_mgr::acquire_handle bind succeeded " << h->m);
55         h->cl = cl;
56     }
57     return h->cl;
58 }
59
60 handle::~handle() {
61     if (h) mgr.release_handle(h);
62 }
63
64 hinfo * handle_mgr::acquire_handle(string m) {
65     lock ml(mgr_mutex);
66     hinfo *h = nullptr;
67     if (hmap.find(m) == hmap.end()) {
68         h = new hinfo(m);
69         hmap[m] = h;
70     } else if (!hmap[m]->del) {
71         h = hmap[m];
72     }
73     h->refcnt++;
74     return h;
75 }
76
77 void handle_mgr::release_handle(hinfo *h) {
78     lock ml(mgr_mutex);
79     if (--h->refcnt == 0 && h->del)
80         delete_handle(h->m, ml);
81 }
82
83 void handle_mgr::delete_handle(const string & m) {
84     lock ml(mgr_mutex);
85     delete_handle(m, ml);
86 }
87
88 void handle_mgr::delete_handle(const string & m, lock &) {
89     if (hmap.find(m) == hmap.end()) {
90         LOG("handle_mgr::delete_handle: cl " << m << " isn't in cl list");
91         return;
92     }
93     LOG("handle_mgr::delete_handle: cl " << m << " refcnt " << hmap[m]->refcnt);
94     hinfo *h = hmap[m];
95     if (h->refcnt == 0) {
96         if (h->cl) {
97             h->cl->cancel();
98             delete h->cl;
99         }
100         hmap.erase(m);
101         delete h;
102     } else
103         h->del = true;
104 }
105
106 void invalidate_handle(const string & m) {
107     mgr.delete_handle(m);
108 }