1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
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.
15 #ifndef CEPH_OSD_SESSION_H
16 #define CEPH_OSD_SESSION_H
18 #include "common/RefCountedObj.h"
19 #include "common/Mutex.h"
20 #include "include/Spinlock.h"
26 typedef boost::intrusive_ptr
<Session
> SessionRef
;
28 typedef boost::intrusive_ptr
<Backoff
> BackoffRef
;
31 #include "common/tracked_int_ptr.hpp"
32 typedef TrackedIntPtr
<PG
> PGRef
;
34 typedef boost::intrusive_ptr
<PG
> PGRef
;
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
43 * The Backoff has a lock that protects it's internal fields.
45 * The PG has a backoff_lock that protects it's maps to Backoffs.
46 * This lock is *inside* of Backoff::lock.
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*
56 * Session::backoff_lock
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.
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.
68 struct Backoff
: public RefCountedObject
{
70 STATE_NEW
= 1, ///< backoff in flight to client
71 STATE_ACKED
= 2, ///< backoff acked
72 STATE_DELETING
= 3 ///< backoff deleted, but un-acked
74 std::atomic_int state
= {STATE_NEW
};
75 spg_t pgid
; ///< owning pgid
76 uint64_t id
= 0; ///< unique id (within the Session)
79 return state
.load() == STATE_NEW
;
81 bool is_acked() const {
82 return state
.load() == STATE_ACKED
;
84 bool is_deleting() const {
85 return state
.load() == STATE_DELETING
;
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 "???";
97 // NOTE: the owning PG and session are either
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
105 Backoff(spg_t pgid
, PGRef pg
, SessionRef s
,
107 const hobject_t
& b
, const hobject_t
& e
)
108 : RefCountedObject(g_ceph_context
, 0),
111 lock("Backoff::lock"),
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
<< ")";
128 struct Session
: public RefCountedObject
{
129 EntityName entity_name
;
133 WatchConState wstate
;
135 Mutex session_dispatch_lock
;
136 boost::intrusive::list
<OpRequest
> waiting_on_map
;
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
143 /// protects backoffs; orders inside Backoff::lock *and* PG::backoff_lock
145 std::atomic_int backoff_count
= {0}; ///< simple count of backoffs
146 map
<spg_t
,map
<hobject_t
,set
<BackoffRef
>>> backoffs
;
148 std::atomic
<uint64_t> backoff_seq
= {0};
150 explicit Session(CephContext
*cct
) :
151 RefCountedObject(cct
),
154 session_dispatch_lock("Session::session_dispatch_lock"),
155 last_sent_epoch(0), received_map_epoch(0),
156 backoff_lock("Session::backoff_lock")
163 const hobject_t
& start
,
164 const hobject_t
& end
);
166 BackoffRef
have_backoff(spg_t pgid
, const hobject_t
& oid
) {
167 if (!backoff_count
.load()) {
170 Mutex::Locker
l(backoff_lock
);
171 assert(!backoff_count
== backoffs
.empty());
172 auto i
= backoffs
.find(pgid
);
173 if (i
== backoffs
.end()) {
176 auto p
= i
->second
.lower_bound(oid
);
177 if (p
!= i
->second
.begin() &&
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
) {
195 CephContext
*cct
, spg_t pgid
, const hobject_t
& oid
, const Message
*m
);
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
);
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()) {
218 if (p
->second
.empty()) {
220 if (i
->second
.empty()) {
227 assert(!backoff_count
== backoffs
.empty());
229 void clear_backoffs();