]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | /* | |
4 | * Ceph - scalable distributed file system | |
5 | * | |
6 | * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net> | |
7 | * | |
8 | * This is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU Lesser General Public | |
10 | * License version 2.1, as published by the Free Software | |
11 | * Foundation. See file COPYING. | |
12 | * | |
13 | */ | |
14 | ||
15 | #ifndef CEPH_MON_SESSION_H | |
16 | #define CEPH_MON_SESSION_H | |
17 | ||
18 | #include "include/xlist.h" | |
19 | #include "msg/msg_types.h" | |
20 | ||
21 | #include "auth/AuthServiceHandler.h" | |
22 | #include "osd/OSDMap.h" | |
23 | ||
24 | #include "MonCap.h" | |
25 | ||
26 | struct MonSession; | |
27 | ||
28 | struct Subscription { | |
29 | MonSession *session; | |
30 | string type; | |
31 | xlist<Subscription*>::item type_item; | |
32 | version_t next; | |
33 | bool onetime; | |
34 | bool incremental_onetime; // has CEPH_FEATURE_INCSUBOSDMAP | |
35 | ||
36 | Subscription(MonSession *s, const string& t) : session(s), type(t), type_item(this), | |
37 | next(0), onetime(false), incremental_onetime(false) {} | |
38 | }; | |
39 | ||
40 | struct MonSession : public RefCountedObject { | |
41 | ConnectionRef con; | |
42 | entity_inst_t inst; | |
43 | utime_t session_timeout; | |
44 | utime_t time_established; | |
45 | bool closed; | |
46 | xlist<MonSession*>::item item; | |
47 | set<uint64_t> routed_request_tids; | |
48 | MonCap caps; | |
49 | uint64_t auid; | |
50 | uint64_t global_id; | |
51 | ||
52 | map<string, Subscription*> sub_map; | |
53 | epoch_t osd_epoch; // the osdmap epoch sent to the mon client | |
54 | ||
55 | AuthServiceHandler *auth_handler; | |
56 | EntityName entity_name; | |
57 | ||
58 | ConnectionRef proxy_con; | |
59 | uint64_t proxy_tid; | |
60 | ||
61 | MonSession(const entity_inst_t& i, Connection *c) : | |
62 | RefCountedObject(g_ceph_context), | |
63 | con(c), inst(i), closed(false), item(this), | |
64 | auid(0), | |
65 | global_id(0), | |
66 | osd_epoch(0), | |
67 | auth_handler(NULL), | |
68 | proxy_con(NULL), proxy_tid(0) { | |
69 | time_established = ceph_clock_now(); | |
70 | } | |
71 | ~MonSession() override { | |
72 | //generic_dout(0) << "~MonSession " << this << dendl; | |
73 | // we should have been removed before we get destructed; see MonSessionMap::remove_session() | |
74 | assert(!item.is_on_list()); | |
75 | assert(sub_map.empty()); | |
76 | delete auth_handler; | |
77 | } | |
78 | ||
79 | bool is_capable(string service, int mask) { | |
80 | map<string,string> args; | |
81 | return caps.is_capable( | |
82 | g_ceph_context, | |
83 | CEPH_ENTITY_TYPE_MON, | |
84 | entity_name, | |
85 | service, "", args, | |
86 | mask & MON_CAP_R, mask & MON_CAP_W, mask & MON_CAP_X); | |
87 | } | |
88 | }; | |
89 | ||
90 | ||
91 | struct MonSessionMap { | |
92 | xlist<MonSession*> sessions; | |
93 | map<string, xlist<Subscription*>* > subs; | |
94 | multimap<int, MonSession*> by_osd; | |
95 | ||
96 | MonSessionMap() {} | |
97 | ~MonSessionMap() { | |
98 | while (!subs.empty()) { | |
99 | assert(subs.begin()->second->empty()); | |
100 | delete subs.begin()->second; | |
101 | subs.erase(subs.begin()); | |
102 | } | |
103 | } | |
104 | ||
105 | unsigned get_size() const { | |
106 | return sessions.size(); | |
107 | } | |
108 | ||
109 | void remove_session(MonSession *s) { | |
110 | assert(!s->closed); | |
111 | for (map<string,Subscription*>::iterator p = s->sub_map.begin(); p != s->sub_map.end(); ++p) { | |
112 | p->second->type_item.remove_myself(); | |
113 | delete p->second; | |
114 | } | |
115 | s->sub_map.clear(); | |
116 | s->item.remove_myself(); | |
117 | if (s->inst.name.is_osd()) { | |
118 | for (multimap<int,MonSession*>::iterator p = by_osd.find(s->inst.name.num()); | |
119 | p->first == s->inst.name.num(); | |
120 | ++p) | |
121 | if (p->second == s) { | |
122 | by_osd.erase(p); | |
123 | break; | |
124 | } | |
125 | } | |
126 | s->closed = true; | |
127 | s->put(); | |
128 | } | |
129 | ||
130 | MonSession *new_session(const entity_inst_t& i, Connection *c) { | |
131 | MonSession *s = new MonSession(i, c); | |
132 | assert(s); | |
133 | sessions.push_back(&s->item); | |
134 | if (i.name.is_osd()) | |
135 | by_osd.insert(pair<int,MonSession*>(i.name.num(), s)); | |
136 | s->get(); // caller gets a ref | |
137 | return s; | |
138 | } | |
139 | ||
140 | MonSession *get_random_osd_session(OSDMap *osdmap) { | |
141 | // ok, this isn't actually random, but close enough. | |
142 | if (by_osd.empty()) | |
143 | return 0; | |
144 | int n = by_osd.rbegin()->first + 1; | |
145 | int r = rand() % n; | |
146 | ||
147 | multimap<int,MonSession*>::iterator p = by_osd.lower_bound(r); | |
148 | if (p == by_osd.end()) | |
149 | --p; | |
150 | ||
151 | if (!osdmap) { | |
152 | return p->second; | |
153 | } | |
154 | ||
155 | MonSession *s = NULL; | |
156 | ||
157 | multimap<int,MonSession*>::iterator b = p, f = p; | |
158 | bool backward = true, forward = true; | |
159 | while (backward || forward) { | |
160 | if (backward) { | |
161 | if (osdmap->is_up(b->first) && | |
162 | osdmap->get_addr(b->first) == b->second->con->get_peer_addr()) { | |
163 | s = b->second; | |
164 | break; | |
165 | } | |
166 | if (b != by_osd.begin()) | |
167 | --b; | |
168 | else | |
169 | backward = false; | |
170 | } | |
171 | ||
172 | forward = (f != by_osd.end()); | |
173 | if (forward) { | |
174 | if (osdmap->is_up(f->first)) { | |
175 | s = f->second; | |
176 | break; | |
177 | } | |
178 | ++f; | |
179 | } | |
180 | } | |
181 | ||
182 | return s; | |
183 | } | |
184 | ||
185 | void add_update_sub(MonSession *s, const string& what, version_t start, bool onetime, bool incremental_onetime) { | |
186 | Subscription *sub = 0; | |
187 | if (s->sub_map.count(what)) { | |
188 | sub = s->sub_map[what]; | |
189 | } else { | |
190 | sub = new Subscription(s, what); | |
191 | s->sub_map[what] = sub; | |
192 | ||
193 | if (!subs.count(what)) | |
194 | subs[what] = new xlist<Subscription*>; | |
195 | subs[what]->push_back(&sub->type_item); | |
196 | } | |
197 | sub->next = start; | |
198 | sub->onetime = onetime; | |
199 | sub->incremental_onetime = onetime && incremental_onetime; | |
200 | } | |
201 | ||
202 | void remove_sub(Subscription *sub) { | |
203 | sub->session->sub_map.erase(sub->type); | |
204 | sub->type_item.remove_myself(); | |
205 | delete sub; | |
206 | } | |
207 | }; | |
208 | ||
209 | inline ostream& operator<<(ostream& out, const MonSession& s) | |
210 | { | |
211 | out << "MonSession(" << s.inst << " is " | |
212 | << (s.closed ? "closed" : "open"); | |
213 | out << s.caps << ")"; | |
214 | return out; | |
215 | } | |
216 | ||
217 | #endif |