bool empty() const { return _prev == this; }
bool is_on_list() const { return !empty(); }
+ bool is_singular() const {
+ return is_on_list() && _prev == _next;
+ }
bool remove_myself() {
if (_next == this) {
* Capability
*/
Capability::Capability(CInode *i, Session *s, uint64_t id) :
- item_session_caps(this), item_snaprealm_caps(this),
- item_revoking_caps(this), item_client_revoking_caps(this),
+ item_session_caps(this),
lock_caches(member_offset(MDLockCache, item_cap_lock_cache)),
inode(i), session(s), cap_id(id)
{
int64_t last_rsize = 0;
xlist<Capability*>::item item_session_caps;
- xlist<Capability*>::item item_snaprealm_caps;
- xlist<Capability*>::item item_revoking_caps;
- xlist<Capability*>::item item_client_revoking_caps;
+ elist<Capability*>::item item_snaprealm_caps;
+ elist<Capability*>::item item_revoking_caps;
+ elist<Capability*>::item item_client_revoking_caps;
elist<MDLockCache*> lock_caches;
int get_lock_cache_allowed() const { return lock_cache_allowed; }
};
Locker::Locker(MDSRank *m, MDCache *c) :
- need_snapflush_inodes(member_offset(CInode, item_to_flush)), mds(m), mdcache(c) {}
+ revoking_caps(member_offset(Capability, item_revoking_caps)),
+ need_snapflush_inodes(member_offset(CInode, item_to_flush)),
+ mds(m), mdcache(c) {}
void Locker::dispatch(const cref_t<Message> &m)
int op = (before & ~after) ? CEPH_CAP_OP_REVOKE : CEPH_CAP_OP_GRANT;
if (op == CEPH_CAP_OP_REVOKE) {
- if (mds->logger) mds->logger->inc(l_mdss_ceph_cap_op_revoke);
+ if (mds->logger) mds->logger->inc(l_mdss_ceph_cap_op_revoke);
revoking_caps.push_back(&cap->item_revoking_caps);
- revoking_caps_by_client[cap->get_client()].push_back(&cap->item_client_revoking_caps);
+ auto em = revoking_caps_by_client.emplace(cap->get_client(),
+ member_offset(Capability, item_client_revoking_caps));
+ em.first->second.push_back(&cap->item_client_revoking_caps);
cap->set_last_revoke_stamp(ceph_clock_now());
cap->reset_num_revoke_warnings();
} else {
try_eval(in, CEPH_CAP_LOCKS);
}
-
-/**
- * Return true if any currently revoking caps exceed the
- * session_timeout threshold.
- */
-bool Locker::any_late_revoking_caps(xlist<Capability*> const &revoking,
- double timeout) const
+std::set<client_t> Locker::get_late_revoking_clients(double timeout)
{
- xlist<Capability*>::const_iterator p = revoking.begin();
- if (p.end()) {
+ auto any_late_revoking = [timeout](elist<Capability*> &revoking) {
+ auto p = revoking.begin();
+ if (p.end())
// No revoking caps at the moment
return false;
- } else {
- utime_t now = ceph_clock_now();
- utime_t age = now - (*p)->get_last_revoke_stamp();
- if (age <= timeout) {
- return false;
- } else {
- return true;
- }
- }
-}
-std::set<client_t> Locker::get_late_revoking_clients(double timeout) const
-{
- std::set<client_t> result;
+ utime_t now = ceph_clock_now();
+ return now - (*p)->get_last_revoke_stamp() > timeout;
+ };
- if (any_late_revoking_caps(revoking_caps, timeout)) {
+ std::set<client_t> result;
+ if (!any_late_revoking(revoking_caps)) {
+ // Fast path: no misbehaving clients, execute in O(1)
+ } else {
// Slow path: execute in O(N_clients)
- for (auto &p : revoking_caps_by_client) {
- if (any_late_revoking_caps(p.second, timeout)) {
- result.insert(p.first);
+ for (auto it = revoking_caps_by_client.begin();
+ it != revoking_caps_by_client.end(); ) {
+ if (it->second.empty()) {
+ revoking_caps_by_client.erase(it++);
+ continue;
}
+ if (any_late_revoking(it->second))
+ result.insert(it->first);
+ ++it;
}
- } else {
- // Fast path: no misbehaving clients, execute in O(1)
}
return result;
}
}
}
- dout(20) << __func__ << " " << revoking_caps.size() << " revoking caps" << dendl;
now = ceph_clock_now();
int n = 0;
- for (xlist<Capability*>::iterator p = revoking_caps.begin(); !p.end(); ++p) {
+ for (auto p = revoking_caps.begin(); !p.end(); ++p) {
Capability *cap = *p;
utime_t age = now - cap->get_last_revoke_stamp();
void remove_client_cap(CInode *in, Capability *cap, bool kill=false);
- std::set<client_t> get_late_revoking_clients(double timeout) const;
+ std::set<client_t> get_late_revoking_clients(double timeout);
void snapflush_nudge(CInode *in);
void mark_need_snapflush_inode(CInode *in);
xlist<ScatterLock*> updated_scatterlocks;
// Maintain a global list to quickly find if any caps are late revoking
- xlist<Capability*> revoking_caps;
+ elist<Capability*> revoking_caps;
// Maintain a per-client list to find clients responsible for late ones quickly
- std::map<client_t, xlist<Capability*> > revoking_caps_by_client;
+ std::map<client_t, elist<Capability*> > revoking_caps_by_client;
elist<CInode*> need_snapflush_inodes;
void handle_quiesce_failure(const MDRequestRef& mdr, std::string_view& marker);
- bool any_late_revoking_caps(xlist<Capability*> const &revoking, double timeout) const;
uint64_t calc_new_max_size(const CInode::inode_const_ptr& pi, uint64_t size);
__u32 get_xattr_total_length(CInode::mempool_xattr_map &xattr);
void decode_new_xattrs(CInode::mempool_inode *inode,
split_realms.push_back((*p)->inode->ino());
for (const auto& p : realm->client_caps) {
- ceph_assert(!p.second->empty());
+ ceph_assert(!p.second.empty());
auto em = splits.emplace(std::piecewise_construct, std::forward_as_tuple(p.first), std::forward_as_tuple());
if (em.second) {
auto update = make_message<MClientSnap>(CEPH_SNAP_OP_SPLIT);
for (const auto& p : realm->client_caps) {
const auto& client = p.first;
const auto& caps = p.second;
- ceph_assert(!caps->empty());
+ ceph_assert(!caps.empty());
auto em = updates.emplace(std::piecewise_construct, std::forward_as_tuple(client), std::forward_as_tuple());
if (em.second) {
void merge_to(SnapRealm *newparent);
void add_cap(client_t client, Capability *cap) {
- auto client_caps_entry = client_caps.find(client);
- if (client_caps_entry == client_caps.end())
- client_caps_entry = client_caps.emplace(client,
- new xlist<Capability*>).first;
- client_caps_entry->second->push_back(&cap->item_snaprealm_caps);
+ auto em = client_caps.emplace(cap->get_client(),
+ member_offset(Capability, item_snaprealm_caps));
+ em.first->second.push_back(&cap->item_snaprealm_caps);
}
void remove_cap(client_t client, Capability *cap) {
+ bool last_cap = cap->item_snaprealm_caps.is_singular();
cap->item_snaprealm_caps.remove_myself();
- auto found = client_caps.find(client);
- if (found != client_caps.end() && found->second->empty()) {
- delete found->second;
- client_caps.erase(found);
+ if (last_cap) {
+ auto it = client_caps.find(client);
+ ceph_assert(it != client_caps.end());
+ ceph_assert(it->second.empty());
+ client_caps.erase(it);
}
}
std::set<SnapRealm*> open_children; // active children that are currently open
elist<CInode*> inodes_with_caps; // for efficient realm splits
- std::map<client_t, xlist<Capability*>* > client_caps; // to identify clients who need snap notifications
+ std::map<client_t, elist<Capability*> > client_caps; // to identify clients who need snap notifications
protected:
void check_cache() const;