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