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
;
30 typedef boost::intrusive_ptr
<PG
> PGRef
;
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
38 * The Backoff has a lock that protects it's internal fields.
40 * The PG has a backoff_lock that protects it's maps to Backoffs.
41 * This lock is *inside* of Backoff::lock.
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*
51 * Session::backoff_lock
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.
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.
63 struct Backoff
: public RefCountedObject
{
65 STATE_NEW
= 1, ///< backoff in flight to client
66 STATE_ACKED
= 2, ///< backoff acked
67 STATE_DELETING
= 3 ///< backoff deleted, but un-acked
69 std::atomic_int state
= {STATE_NEW
};
70 spg_t pgid
; ///< owning pgid
71 uint64_t id
= 0; ///< unique id (within the Session)
74 return state
.load() == STATE_NEW
;
76 bool is_acked() const {
77 return state
.load() == STATE_ACKED
;
79 bool is_deleting() const {
80 return state
.load() == STATE_DELETING
;
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 "???";
92 // NOTE: the owning PG and session are either
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
100 Backoff(spg_t pgid
, PGRef pg
, SessionRef s
,
102 const hobject_t
& b
, const hobject_t
& e
)
103 : RefCountedObject(g_ceph_context
, 0),
106 lock("Backoff::lock"),
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
<< ")";
123 struct Session
: public RefCountedObject
{
124 EntityName entity_name
;
128 WatchConState wstate
;
130 Mutex session_dispatch_lock
;
131 boost::intrusive::list
<OpRequest
> waiting_on_map
;
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
138 /// protects backoffs; orders inside Backoff::lock *and* PG::backoff_lock
140 std::atomic_int backoff_count
= {0}; ///< simple count of backoffs
141 map
<spg_t
,map
<hobject_t
,set
<BackoffRef
>>> backoffs
;
143 std::atomic
<uint64_t> backoff_seq
= {0};
145 explicit Session(CephContext
*cct
) :
146 RefCountedObject(cct
),
149 session_dispatch_lock("Session::session_dispatch_lock"),
150 last_sent_epoch(0), received_map_epoch(0),
151 backoff_lock("Session::backoff_lock")
158 const hobject_t
& start
,
159 const hobject_t
& end
);
161 BackoffRef
have_backoff(spg_t pgid
, const hobject_t
& oid
) {
162 if (!backoff_count
.load()) {
165 Mutex::Locker
l(backoff_lock
);
166 assert(!backoff_count
== backoffs
.empty());
167 auto i
= backoffs
.find(pgid
);
168 if (i
== backoffs
.end()) {
171 auto p
= i
->second
.lower_bound(oid
);
172 if (p
!= i
->second
.begin() &&
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
) {
190 CephContext
*cct
, spg_t pgid
, const hobject_t
& oid
, const Message
*m
);
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
);
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()) {
213 if (p
->second
.empty()) {
215 if (i
->second
.empty()) {
222 assert(!backoff_count
== backoffs
.empty());
224 void clear_backoffs();