#include "include/filepath.h"
#include "MDSCacheObject.h"
+#include "MDSContext.h"
#include "SimpleLock.h"
#include "Capability.h"
+#include "BatchOp.h"
#include "common/TrackedOp.h"
+#include "messages/MClientRequest.h"
+#include "messages/MMDSPeerRequest.h"
+#include "messages/MClientReply.h"
class LogSegment;
-class Capability;
class CInode;
class CDir;
class CDentry;
class Session;
class ScatterLock;
-class MClientRequest;
-class MMDSSlaveRequest;
+struct sr_t;
+struct MDLockCache;
struct MutationImpl : public TrackedOp {
- metareqid_t reqid;
- __u32 attempt = 0; // which attempt for this request
- LogSegment *ls = nullptr; // the log segment i'm committing to
-
-private:
- utime_t mds_stamp; ///< mds-local timestamp (real time)
- utime_t op_stamp; ///< op timestamp (client provided)
-
public:
- // flag mutation as slave
- mds_rank_t slave_to_mds = MDS_RANK_NONE; // this is a slave request if >= 0.
-
- // -- my pins and locks --
- // cache pins (so things don't expire)
- set< MDSCacheObject* > pins;
- set<CInode*> stickydirs;
+ // -- my pins and auth_pins --
+ struct ObjectState {
+ bool pinned = false;
+ bool auth_pinned = false;
+ mds_rank_t remote_auth_pinned = MDS_RANK_NONE;
+ };
- // auth pins
- map<MDSCacheObject*, mds_rank_t> remote_auth_pins;
- set< MDSCacheObject* > auth_pins;
-
// held locks
- set< SimpleLock* > rdlocks; // always local.
- set< SimpleLock* > wrlocks; // always local.
- map< SimpleLock*, mds_rank_t > remote_wrlocks;
- set< SimpleLock* > xlocks; // local or remote.
- set< SimpleLock*, SimpleLock::ptr_lt > locks; // full ordering
-
- // lock we are currently trying to acquire. if we give up for some reason,
- // be sure to eval() this.
- SimpleLock *locking = nullptr;
- mds_rank_t locking_target_mds = -1;
-
- // if this flag is set, do not attempt to acquire further locks.
- // (useful for wrlock, which may be a moving auth target)
- bool done_locking = false;
- bool committing = false;
- bool aborted = false;
- bool killed = false;
+ struct LockOp {
+ enum {
+ RDLOCK = 1,
+ WRLOCK = 2,
+ XLOCK = 4,
+ REMOTE_WRLOCK = 8,
+ STATE_PIN = 16, // no RW after locked, just pin lock state
+ };
+
+ LockOp(SimpleLock *l, unsigned f=0, mds_rank_t t=MDS_RANK_NONE) :
+ lock(l), flags(f), wrlock_target(t) {}
+
+ bool is_rdlock() const { return !!(flags & RDLOCK); }
+ bool is_xlock() const { return !!(flags & XLOCK); }
+ bool is_wrlock() const { return !!(flags & WRLOCK); }
+ void clear_wrlock() const { flags &= ~WRLOCK; }
+ bool is_remote_wrlock() const { return !!(flags & REMOTE_WRLOCK); }
+ void clear_remote_wrlock() const {
+ flags &= ~REMOTE_WRLOCK;
+ wrlock_target = MDS_RANK_NONE;
+ }
+ bool is_state_pin() const { return !!(flags & STATE_PIN); }
+ bool operator<(const LockOp& r) const {
+ return lock < r.lock;
+ }
+
+ SimpleLock* lock;
+ mutable unsigned flags;
+ mutable mds_rank_t wrlock_target;
+ };
- // for applying projected inode changes
- list<CInode*> projected_inodes;
- list<CDir*> projected_fnodes;
- list<ScatterLock*> updated_locks;
+ struct LockOpVec : public std::vector<LockOp> {
+ LockOpVec() {
+ reserve(32);
+ }
+
+ void add_rdlock(SimpleLock *lock) {
+ emplace_back(lock, LockOp::RDLOCK);
+ }
+ void erase_rdlock(SimpleLock *lock);
+ void add_xlock(SimpleLock *lock, int idx=-1) {
+ if (idx >= 0)
+ emplace(cbegin() + idx, lock, LockOp::XLOCK);
+ else
+ emplace_back(lock, LockOp::XLOCK);
+ }
+ void add_wrlock(SimpleLock *lock, int idx=-1) {
+ if (idx >= 0)
+ emplace(cbegin() + idx, lock, LockOp::WRLOCK);
+ else
+ emplace_back(lock, LockOp::WRLOCK);
+ }
+ void add_remote_wrlock(SimpleLock *lock, mds_rank_t rank) {
+ ceph_assert(rank != MDS_RANK_NONE);
+ emplace_back(lock, LockOp::REMOTE_WRLOCK, rank);
+ }
+ void lock_scatter_gather(SimpleLock *lock) {
+ emplace_back(lock, LockOp::WRLOCK | LockOp::STATE_PIN);
+ }
+ void sort_and_merge();
+ };
- list<CInode*> dirty_cow_inodes;
- list<pair<CDentry*,version_t> > dirty_cow_dentries;
+ using lock_set = std::set<LockOp>;
+ using lock_iterator = lock_set::iterator;
// keep our default values synced with MDRequestParam's
MutationImpl() : TrackedOp(nullptr, utime_t()) {}
MutationImpl(OpTracker *tracker, utime_t initiated,
- metareqid_t ri, __u32 att=0, mds_rank_t slave_to=MDS_RANK_NONE)
+ const metareqid_t &ri, __u32 att=0, mds_rank_t peer_to=MDS_RANK_NONE)
: TrackedOp(tracker, initiated),
reqid(ri), attempt(att),
- slave_to_mds(slave_to) { }
+ peer_to_mds(peer_to) {}
~MutationImpl() override {
- assert(locking == NULL);
- assert(pins.empty());
- assert(auth_pins.empty());
- assert(xlocks.empty());
- assert(rdlocks.empty());
- assert(wrlocks.empty());
- assert(remote_wrlocks.empty());
+ ceph_assert(!locking);
+ ceph_assert(!lock_cache);
+ ceph_assert(num_pins == 0);
+ ceph_assert(num_auth_pins == 0);
+ }
+
+ const ObjectState* find_object_state(MDSCacheObject *obj) const {
+ auto it = object_states.find(obj);
+ return it != object_states.end() ? &it->second : nullptr;
+ }
+
+ bool is_any_remote_auth_pin() const { return num_remote_auth_pins > 0; }
+
+ void disable_lock_cache() {
+ lock_cache_disabled = true;
}
- bool is_master() const { return slave_to_mds == MDS_RANK_NONE; }
- bool is_slave() const { return slave_to_mds != MDS_RANK_NONE; }
+ lock_iterator emplace_lock(SimpleLock *l, unsigned f=0, mds_rank_t t=MDS_RANK_NONE) {
+ last_locked = l;
+ return locks.emplace(l, f, t).first;
+ }
+
+ bool is_rdlocked(SimpleLock *lock) const;
+ bool is_wrlocked(SimpleLock *lock) const;
+ bool is_xlocked(SimpleLock *lock) const {
+ auto it = locks.find(lock);
+ return it != locks.end() && it->is_xlock();
+ }
+ bool is_remote_wrlocked(SimpleLock *lock) const {
+ auto it = locks.find(lock);
+ return it != locks.end() && it->is_remote_wrlock();
+ }
+ bool is_last_locked(SimpleLock *lock) const {
+ return lock == last_locked;
+ }
+
+ bool is_leader() const { return peer_to_mds == MDS_RANK_NONE; }
+ bool is_peer() const { return peer_to_mds != MDS_RANK_NONE; }
client_t get_client() const {
if (reqid.name.is_client())
}
// pin items in cache
- void pin(MDSCacheObject *o);
- void unpin(MDSCacheObject *o);
+ void pin(MDSCacheObject *object);
+ void unpin(MDSCacheObject *object);
void set_stickydirs(CInode *in);
+ void put_stickydirs();
void drop_pins();
void start_locking(SimpleLock *lock, int target=-1);
void auth_pin(MDSCacheObject *object);
void auth_unpin(MDSCacheObject *object);
void drop_local_auth_pins();
- void add_projected_inode(CInode *in);
- void pop_and_dirty_projected_inodes();
- void add_projected_fnode(CDir *dir);
- void pop_and_dirty_projected_fnodes();
+ void set_remote_auth_pinned(MDSCacheObject* object, mds_rank_t from);
+ void _clear_remote_auth_pinned(ObjectState& stat);
+
+ void add_projected_node(MDSCacheObject* obj) {
+ projected_nodes.insert(obj);
+ }
+ void remove_projected_node(MDSCacheObject* obj) {
+ projected_nodes.erase(obj);
+ }
+ bool is_projected(MDSCacheObject *obj) const {
+ return projected_nodes.count(obj);
+ }
void add_updated_lock(ScatterLock *lock);
void add_cow_inode(CInode *in);
void add_cow_dentry(CDentry *dn);
void apply();
void cleanup();
- virtual void print(ostream &out) const {
+ virtual void print(std::ostream &out) const {
out << "mutation(" << this << ")";
}
- virtual void dump(Formatter *f) const {}
- void _dump_op_descriptor_unlocked(ostream& stream) const override;
-};
-
-inline ostream& operator<<(ostream &out, const MutationImpl &mut)
-{
- mut.print(out);
- return out;
-}
-
-typedef boost::intrusive_ptr<MutationImpl> MutationRef;
-
-
+ virtual void dump(ceph::Formatter *f) const {}
+ void _dump_op_descriptor_unlocked(std::ostream& stream) const override;
-/** active_request_t
- * state we track for requests we are currently processing.
- * mostly information about locks held, so that we can drop them all
- * the request is finished or forwarded. see request_*().
- */
-struct MDRequestImpl : public MutationImpl {
- Session *session;
- elist<MDRequestImpl*>::item item_session_request; // if not on list, op is aborted.
-
- // -- i am a client (master) request
- MClientRequest *client_request; // client request (if any)
+ metareqid_t reqid;
+ __u32 attempt = 0; // which attempt for this request
+ LogSegment *ls = nullptr; // the log segment i'm committing to
- // store up to two sets of dn vectors, inode pointers, for request path1 and path2.
- vector<CDentry*> dn[2];
- CDentry *straydn;
- CInode *in[2];
- snapid_t snapid;
+ // flag mutation as peer
+ mds_rank_t peer_to_mds = MDS_RANK_NONE; // this is a peer request if >= 0.
- CInode *tracei;
- CDentry *tracedn;
+ ceph::unordered_map<MDSCacheObject*, ObjectState> object_states;
+ int num_pins = 0;
+ int num_auth_pins = 0;
+ int num_remote_auth_pins = 0;
+ // cache pins (so things don't expire)
+ CInode* stickydiri = nullptr;
- inodeno_t alloc_ino, used_prealloc_ino;
- interval_set<inodeno_t> prealloc_inos;
+ lock_set locks; // full ordering
+ MDLockCache* lock_cache = nullptr;
+ bool lock_cache_disabled = false;
+ SimpleLock *last_locked = nullptr;
+ // Lock we are currently trying to acquire. If we give up for some reason,
+ // be sure to eval() this.
+ SimpleLock *locking = nullptr;
+ mds_rank_t locking_target_mds = -1;
- int snap_caps = 0;
- int getattr_caps = 0; ///< caps requested by getattr
- bool no_early_reply = false;
- bool did_early_reply = false;
- bool o_trunc = false; ///< request is an O_TRUNC mutation
- bool has_completed = false; ///< request has already completed
+ // if this flag is set, do not attempt to acquire further locks.
+ // (useful for wrlock, which may be a moving auth target)
+ enum {
+ SNAP_LOCKED = 1,
+ SNAP2_LOCKED = 2,
+ PATH_LOCKED = 4,
+ ALL_LOCKED = 8,
+ };
+ int locking_state = 0;
- bufferlist reply_extra_bl;
+ bool committing = false;
+ bool aborted = false;
+ bool killed = false;
- // inos we did a embedded cap release on, and may need to eval if we haven't since reissued
- map<vinodeno_t, ceph_seq_t> cap_releases;
+ // for applying projected inode changes
+ std::set<MDSCacheObject*> projected_nodes;
+ std::list<ScatterLock*> updated_locks;
- // -- i am a slave request
- MMDSSlaveRequest *slave_request; // slave request (if one is pending; implies slave == true)
+ std::list<CInode*> dirty_cow_inodes;
+ std::list<std::pair<CDentry*,version_t> > dirty_cow_dentries;
- // -- i am an internal op
- int internal_op;
- Context *internal_op_finish;
- void *internal_op_private;
-
- // indicates how may retries of request have been made
- int retry;
+private:
+ utime_t mds_stamp; ///< mds-local timestamp (real time)
+ utime_t op_stamp; ///< op timestamp (client provided)
+};
- // indicator for vxattr osdmap update
- bool waited_for_osdmap;
+/**
+ * MDRequestImpl: state we track for requests we are currently processing.
+ * mostly information about locks held, so that we can drop them all
+ * the request is finished or forwarded. see request_*().
+ */
+struct MDRequestImpl : public MutationImpl {
+ // TrackedOp stuff
+ typedef boost::intrusive_ptr<MDRequestImpl> Ref;
// break rarely-used fields into a separately allocated structure
// to save memory for most ops
struct More {
- int slave_error;
- set<mds_rank_t> slaves; // mds nodes that have slave requests to me (implies client_request)
- set<mds_rank_t> waiting_on_slave; // peers i'm waiting for slavereq replies from.
+ More() {}
+
+ int peer_error = 0;
+ std::set<mds_rank_t> peers; // mds nodes that have peer requests to me (implies client_request)
+ std::set<mds_rank_t> waiting_on_peer; // peers i'm waiting for peerreq replies from.
// for rename/link/unlink
- set<mds_rank_t> witnessed; // nodes who have journaled a RenamePrepare
- map<MDSCacheObject*,version_t> pvmap;
+ std::set<mds_rank_t> witnessed; // nodes who have journaled a RenamePrepare
+ std::map<MDSCacheObject*,version_t> pvmap;
- bool has_journaled_slaves;
- bool slave_update_journaled;
- bool slave_rolling_back;
+ bool has_journaled_peers = false;
+ bool peer_update_journaled = false;
+ bool peer_rolling_back = false;
// for rename
- set<mds_rank_t> extra_witnesses; // replica list from srcdn auth (rename)
- mds_rank_t srcdn_auth_mds;
- bufferlist inode_import;
- version_t inode_import_v;
- CInode* rename_inode;
- bool is_freeze_authpin;
- bool is_ambiguous_auth;
- bool is_remote_frozen_authpin;
- bool is_inode_exporter;
-
- map<client_t, pair<Session*, uint64_t> > imported_session_map;
- map<CInode*, map<client_t,Capability::Export> > cap_imports;
+ std::set<mds_rank_t> extra_witnesses; // replica list from srcdn auth (rename)
+ mds_rank_t srcdn_auth_mds = MDS_RANK_NONE;
+ ceph::buffer::list inode_import;
+ version_t inode_import_v = 0;
+ CInode* rename_inode = nullptr;
+ bool is_freeze_authpin = false;
+ bool is_ambiguous_auth = false;
+ bool is_remote_frozen_authpin = false;
+ bool is_inode_exporter = false;
+ bool rdonly_checks = false;
+
+ std::map<client_t, std::pair<Session*, uint64_t> > imported_session_map;
+ std::map<CInode*, std::map<client_t,Capability::Export> > cap_imports;
// for lock/flock
- bool flock_was_waiting;
+ bool flock_was_waiting = false;
// for snaps
- version_t stid;
- bufferlist snapidbl;
+ version_t stid = 0;
+ ceph::buffer::list snapidbl;
- // called when slave commits or aborts
- Context *slave_commit;
- bufferlist rollback_bl;
+ sr_t *srci_srnode = nullptr;
+ sr_t *desti_srnode = nullptr;
- list<MDSInternalContextBase*> waiting_for_finish;
+ // called when peer commits or aborts
+ Context *peer_commit = nullptr;
+ ceph::buffer::list rollback_bl;
+
+ MDSContext::vec waiting_for_finish;
// export & fragment
- CDir* export_dir;
+ CDir* export_dir = nullptr;
dirfrag_t fragment_base;
// for internal ops doing lookup
filepath filepath1;
filepath filepath2;
-
- More() :
- slave_error(0),
- has_journaled_slaves(false), slave_update_journaled(false),
- slave_rolling_back(false),
- srcdn_auth_mds(-1), inode_import_v(0), rename_inode(0),
- is_freeze_authpin(false), is_ambiguous_auth(false),
- is_remote_frozen_authpin(false), is_inode_exporter(false),
- flock_was_waiting(false), stid(0), slave_commit(0), export_dir(NULL) { }
- } *_more;
-
+ } *_more = nullptr;
// ---------------------------------------------------
struct Params {
+ // keep these default values synced to MutationImpl's
+ Params() {}
+ const utime_t& get_recv_stamp() const {
+ return initiated;
+ }
+ const utime_t& get_throttle_stamp() const {
+ return throttled;
+ }
+ const utime_t& get_recv_complete_stamp() const {
+ return all_read;
+ }
+ const utime_t& get_dispatch_stamp() const {
+ return dispatched;
+ }
metareqid_t reqid;
- __u32 attempt;
- MClientRequest *client_req;
- class Message *triggering_slave_req;
- mds_rank_t slave_to;
+ __u32 attempt = 0;
+ ceph::cref_t<MClientRequest> client_req;
+ ceph::cref_t<Message> triggering_peer_req;
+ mds_rank_t peer_to = MDS_RANK_NONE;
utime_t initiated;
utime_t throttled, all_read, dispatched;
- int internal_op;
- // keep these default values synced to MutationImpl's
- Params() : attempt(0), client_req(NULL),
- triggering_slave_req(NULL), slave_to(MDS_RANK_NONE), internal_op(-1) {}
+ int internal_op = -1;
};
- MDRequestImpl(const Params& params, OpTracker *tracker) :
- MutationImpl(tracker, params.initiated,
- params.reqid, params.attempt, params.slave_to),
- session(NULL), item_session_request(this),
- client_request(params.client_req), straydn(NULL), snapid(CEPH_NOSNAP),
- tracei(NULL), tracedn(NULL), alloc_ino(0), used_prealloc_ino(0),
- slave_request(NULL), internal_op(params.internal_op), internal_op_finish(NULL),
- internal_op_private(NULL),
- retry(0),
- waited_for_osdmap(false), _more(NULL) {
- in[0] = in[1] = NULL;
- if (!params.throttled.is_zero())
- mark_event("throttled", params.throttled);
- if (!params.all_read.is_zero())
- mark_event("all_read", params.all_read);
- if (!params.dispatched.is_zero())
- mark_event("dispatched", params.dispatched);
- }
+ MDRequestImpl(const Params* params, OpTracker *tracker) :
+ MutationImpl(tracker, params->initiated,
+ params->reqid, params->attempt, params->peer_to),
+ item_session_request(this), client_request(params->client_req),
+ internal_op(params->internal_op) {}
~MDRequestImpl() override;
More* more();
bool has_more() const;
bool has_witnesses();
- bool slave_did_prepare();
- bool slave_rolling_back();
- bool did_ino_allocation() const;
+ bool peer_did_prepare();
+ bool peer_rolling_back();
bool freeze_auth_pin(CInode *inode);
void unfreeze_auth_pin(bool clear_inode=false);
void set_remote_frozen_auth_pin(CInode *inode);
void set_filepath(const filepath& fp);
void set_filepath2(const filepath& fp);
bool is_queued_for_replay() const;
+ int compare_paths();
+
+ bool can_batch();
+ bool is_batch_head() {
+ return batch_op_map != nullptr;
+ }
+ std::unique_ptr<BatchOp> release_batch_op();
- void print(ostream &out) const override;
- void dump(Formatter *f) const override;
+ void print(std::ostream &out) const override;
+ void dump(ceph::Formatter *f) const override;
- // TrackedOp stuff
- typedef boost::intrusive_ptr<MDRequestImpl> Ref;
-protected:
- void _dump(Formatter *f) const override;
- void _dump_op_descriptor_unlocked(ostream& stream) const override;
-};
+ ceph::cref_t<MClientRequest> release_client_request();
+ void reset_peer_request(const ceph::cref_t<MMDSPeerRequest>& req=nullptr);
-typedef boost::intrusive_ptr<MDRequestImpl> MDRequestRef;
+ Session *session = nullptr;
+ elist<MDRequestImpl*>::item item_session_request; // if not on list, op is aborted.
+ // -- i am a client (leader) request
+ ceph::cref_t<MClientRequest> client_request; // client request (if any)
-struct MDSlaveUpdate {
- int origop;
- bufferlist rollback;
- elist<MDSlaveUpdate*>::item item;
- Context *waiter;
- set<CInode*> olddirs;
- set<CInode*> unlinked;
- MDSlaveUpdate(int oo, bufferlist &rbl, elist<MDSlaveUpdate*> &list) :
- origop(oo),
- item(this),
- waiter(0) {
- rollback.claim(rbl);
- list.push_back(&item);
+ // tree and depth info of path1 and path2
+ inodeno_t dir_root[2] = {0, 0};
+ int dir_depth[2] = {-1, -1};
+ file_layout_t dir_layout;
+ // store up to two sets of dn vectors, inode pointers, for request path1 and path2.
+ std::vector<CDentry*> dn[2];
+ CInode *in[2] = {};
+ CDentry *straydn = nullptr;
+ snapid_t snapid = CEPH_NOSNAP;
+
+ CInode *tracei = nullptr;
+ CDentry *tracedn = nullptr;
+
+ inodeno_t alloc_ino = 0, used_prealloc_ino = 0;
+ interval_set<inodeno_t> prealloc_inos;
+
+ int snap_caps = 0;
+ int getattr_caps = 0; ///< caps requested by getattr
+ bool no_early_reply = false;
+ bool did_early_reply = false;
+ bool o_trunc = false; ///< request is an O_TRUNC mutation
+ bool has_completed = false; ///< request has already completed
+
+ ceph::buffer::list reply_extra_bl;
+
+ // inos we did a embedded cap release on, and may need to eval if we haven't since reissued
+ std::map<vinodeno_t, ceph_seq_t> cap_releases;
+
+ // -- i am a peer request
+ ceph::cref_t<MMDSPeerRequest> peer_request; // peer request (if one is pending; implies peer == true)
+
+ // -- i am an internal op
+ int internal_op;
+ Context *internal_op_finish = nullptr;
+ void *internal_op_private = nullptr;
+
+ // indicates how may retries of request have been made
+ int retry = 0;
+
+ std::map<int, std::unique_ptr<BatchOp> > *batch_op_map = nullptr;
+
+ // indicator for vxattr osdmap update
+ bool waited_for_osdmap = false;
+
+protected:
+ void _dump(ceph::Formatter *f) const override;
+ void _dump_op_descriptor_unlocked(std::ostream& stream) const override;
+private:
+ mutable ceph::spinlock msg_lock;
+};
+
+struct MDPeerUpdate {
+ MDPeerUpdate(int oo, ceph::buffer::list &rbl) :
+ origop(oo) {
+ rollback = std::move(rbl);
}
- ~MDSlaveUpdate() {
- item.remove_myself();
+ ~MDPeerUpdate() {
if (waiter)
waiter->complete(0);
}
+ int origop;
+ ceph::buffer::list rollback;
+ Context *waiter = nullptr;
+ std::set<CInode*> olddirs;
+ std::set<CInode*> unlinked;
+};
+
+struct MDLockCacheItem {
+ MDLockCache *parent = nullptr;
+ elist<MDLockCacheItem*>::item item_lock;
+};
+
+struct MDLockCache : public MutationImpl {
+ using LockItem = MDLockCacheItem;
+
+ struct DirItem {
+ MDLockCache *parent = nullptr;
+ elist<DirItem*>::item item_dir;
+ };
+
+ MDLockCache(Capability *cap, int op) :
+ MutationImpl(), diri(cap->get_inode()), client_cap(cap), opcode(op) {
+ client_cap->lock_caches.push_back(&item_cap_lock_cache);
+ }
+
+ CInode *get_dir_inode() { return diri; }
+ void set_dir_layout(file_layout_t& layout) {
+ dir_layout = layout;
+ }
+ const file_layout_t& get_dir_layout() const {
+ return dir_layout;
+ }
+
+ void attach_locks();
+ void attach_dirfrags(std::vector<CDir*>&& dfv);
+ void detach_locks();
+ void detach_dirfrags();
+
+ CInode *diri;
+ Capability *client_cap;
+ int opcode;
+ file_layout_t dir_layout;
+
+ elist<MDLockCache*>::item item_cap_lock_cache;
+
+ // link myself to locked locks
+ std::unique_ptr<LockItem[]> items_lock;
+
+ // link myself to auth-pinned dirfrags
+ std::unique_ptr<DirItem[]> items_dir;
+ std::vector<CDir*> auth_pinned_dirfrags;
+
+ int ref = 1;
+ bool invalidating = false;
};
+typedef boost::intrusive_ptr<MutationImpl> MutationRef;
+typedef boost::intrusive_ptr<MDRequestImpl> MDRequestRef;
+inline std::ostream& operator<<(std::ostream &out, const MutationImpl &mut)
+{
+ mut.print(out);
+ return out;
+}
#endif