]> git.proxmox.com Git - ceph.git/blob - ceph/src/osd/Session.h
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / osd / Session.h
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_OSD_SESSION_H
16 #define CEPH_OSD_SESSION_H
17
18 #include "common/RefCountedObj.h"
19 #include "common/Mutex.h"
20 #include "include/Spinlock.h"
21 #include "OSDCap.h"
22 #include "Watch.h"
23 #include "OSDMap.h"
24
25 struct Session;
26 typedef boost::intrusive_ptr<Session> SessionRef;
27 struct Backoff;
28 typedef boost::intrusive_ptr<Backoff> BackoffRef;
29 class PG;
30 typedef boost::intrusive_ptr<PG> PGRef;
31
32 /*
33 * A Backoff represents one instance of either a PG or an OID
34 * being plugged at the client. It's refcounted and linked from
35 * the PG {pg_oid}_backoffs map and from the client Session
36 * object.
37 *
38 * The Backoff has a lock that protects it's internal fields.
39 *
40 * The PG has a backoff_lock that protects it's maps to Backoffs.
41 * This lock is *inside* of Backoff::lock.
42 *
43 * The Session has a backoff_lock that protects it's map of pg and
44 * oid backoffs. This lock is *inside* the Backoff::lock *and*
45 * PG::backoff_lock.
46 *
47 * That's
48 *
49 * Backoff::lock
50 * PG::backoff_lock
51 * Session::backoff_lock
52 *
53 * When the Session goes away, we move our backoff lists aside,
54 * then we lock each of the Backoffs we
55 * previously referenced and clear the Session* pointer. If the PG
56 * is still linked, we unlink it, too.
57 *
58 * When the PG clears the backoff, it will send an unblock message
59 * if the Session* is still non-null, and unlink the session.
60 *
61 */
62
63 struct Backoff : public RefCountedObject {
64 enum {
65 STATE_NEW = 1, ///< backoff in flight to client
66 STATE_ACKED = 2, ///< backoff acked
67 STATE_DELETING = 3 ///< backoff deleted, but un-acked
68 };
69 std::atomic_int state = {STATE_NEW};
70 spg_t pgid; ///< owning pgid
71 uint64_t id = 0; ///< unique id (within the Session)
72
73 bool is_new() const {
74 return state.load() == STATE_NEW;
75 }
76 bool is_acked() const {
77 return state.load() == STATE_ACKED;
78 }
79 bool is_deleting() const {
80 return state.load() == STATE_DELETING;
81 }
82 const char *get_state_name() const {
83 switch (state.load()) {
84 case STATE_NEW: return "new";
85 case STATE_ACKED: return "acked";
86 case STATE_DELETING: return "deleting";
87 default: return "???";
88 }
89 }
90
91 Mutex lock;
92 // NOTE: the owning PG and session are either
93 // - *both* set, or
94 // - both null (teardown), or
95 // - only session is set (and state == DELETING)
96 PGRef pg; ///< owning pg
97 SessionRef session; ///< owning session
98 hobject_t begin, end; ///< [) range to block, unless ==, then single obj
99
100 Backoff(spg_t pgid, PGRef pg, SessionRef s,
101 uint64_t i,
102 const hobject_t& b, const hobject_t& e)
103 : RefCountedObject(g_ceph_context, 0),
104 pgid(pgid),
105 id(i),
106 lock("Backoff::lock"),
107 pg(pg),
108 session(s),
109 begin(b),
110 end(e) {}
111
112 friend ostream& operator<<(ostream& out, const Backoff& b) {
113 return out << "Backoff(" << &b << " " << b.pgid << " " << b.id
114 << " " << b.get_state_name()
115 << " [" << b.begin << "," << b.end << ") "
116 << " session " << b.session
117 << " pg " << b.pg << ")";
118 }
119 };
120
121
122
123 struct Session : public RefCountedObject {
124 EntityName entity_name;
125 OSDCap caps;
126 int64_t auid;
127 ConnectionRef con;
128 WatchConState wstate;
129
130 Mutex session_dispatch_lock;
131 boost::intrusive::list<OpRequest> waiting_on_map;
132
133 Spinlock sent_epoch_lock;
134 epoch_t last_sent_epoch;
135 Spinlock received_map_lock;
136 epoch_t received_map_epoch; // largest epoch seen in MOSDMap from here
137
138 /// protects backoffs; orders inside Backoff::lock *and* PG::backoff_lock
139 Mutex backoff_lock;
140 std::atomic_int backoff_count= {0}; ///< simple count of backoffs
141 map<spg_t,map<hobject_t,set<BackoffRef>>> backoffs;
142
143 std::atomic<uint64_t> backoff_seq = {0};
144
145 explicit Session(CephContext *cct) :
146 RefCountedObject(cct),
147 auid(-1), con(0),
148 wstate(cct),
149 session_dispatch_lock("Session::session_dispatch_lock"),
150 last_sent_epoch(0), received_map_epoch(0),
151 backoff_lock("Session::backoff_lock")
152 {}
153
154 void ack_backoff(
155 CephContext *cct,
156 spg_t pgid,
157 uint64_t id,
158 const hobject_t& start,
159 const hobject_t& end);
160
161 BackoffRef have_backoff(spg_t pgid, const hobject_t& oid) {
162 if (!backoff_count.load()) {
163 return nullptr;
164 }
165 Mutex::Locker l(backoff_lock);
166 assert(!backoff_count == backoffs.empty());
167 auto i = backoffs.find(pgid);
168 if (i == backoffs.end()) {
169 return nullptr;
170 }
171 auto p = i->second.lower_bound(oid);
172 if (p != i->second.begin() &&
173 p->first > oid) {
174 --p;
175 }
176 if (p != i->second.end()) {
177 int r = cmp(oid, p->first);
178 if (r == 0 || r > 0) {
179 for (auto& q : p->second) {
180 if (r == 0 || oid < q->end) {
181 return &(*q);
182 }
183 }
184 }
185 }
186 return nullptr;
187 }
188
189 bool check_backoff(
190 CephContext *cct, spg_t pgid, const hobject_t& oid, const Message *m);
191
192 void add_backoff(BackoffRef b) {
193 Mutex::Locker l(backoff_lock);
194 assert(!backoff_count == backoffs.empty());
195 backoffs[b->pgid][b->begin].insert(b);
196 ++backoff_count;
197 }
198
199 // called by PG::release_*_backoffs and PG::clear_backoffs()
200 void rm_backoff(BackoffRef b) {
201 Mutex::Locker l(backoff_lock);
202 assert(b->lock.is_locked_by_me());
203 assert(b->session == this);
204 auto i = backoffs.find(b->pgid);
205 if (i != backoffs.end()) {
206 // may race with clear_backoffs()
207 auto p = i->second.find(b->begin);
208 if (p != i->second.end()) {
209 auto q = p->second.find(b);
210 if (q != p->second.end()) {
211 p->second.erase(q);
212 --backoff_count;
213 if (p->second.empty()) {
214 i->second.erase(p);
215 if (i->second.empty()) {
216 backoffs.erase(i);
217 }
218 }
219 }
220 }
221 }
222 assert(!backoff_count == backoffs.empty());
223 }
224 void clear_backoffs();
225 };
226
227 #endif