Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mds: manage Message lifetime with intrusive_ptr #22555

Merged
merged 12 commits into from
Aug 16, 2018

Conversation

batrick
Copy link
Member

@batrick batrick commented Jun 14, 2018

This change turned out to be far more extensive than I hoped but the end result
should prevent all Message-related memory leaks. I believe I fixed several
incidentally.

Fixes: http://tracker.ceph.com/issues/24306

This is a WIP.

@batrick batrick added bug-fix cephfs Ceph File System DNM labels Jun 14, 2018
@batrick
Copy link
Member Author

batrick commented Jun 14, 2018

Note: this doens't compile yet. Most of what's left to fix is to adjust the small amounts of code that tries to modify a dispatched message. e.g.:

/home/pdonnell/ceph/src/mds/Locker.cc: In member function ‘void Locker::handle_client_caps(const const_ref&)’:
/home/pdonnell/ceph/src/mds/Locker.cc:2699:22: error: passing ‘const MClientCaps’ as ‘this’ argument discards qualifiers [-fpermissive]
       m->clear_dirty();
                      ^
In file included from /home/pdonnell/ceph/src/mds/CInode.h:43:0,
                 from /home/pdonnell/ceph/src/mds/SessionMap.h:34,
                 from /home/pdonnell/ceph/src/mds/MDSRank.h:31,
                 from /home/pdonnell/ceph/src/mds/Locker.cc:17:
/home/pdonnell/ceph/src/messages/MClientCaps.h:128:8: note:   in call to ‘void MClientCaps::clear_dirty()’
   void clear_dirty() { head.dirty = 0; }
        ^~~~~~~~~~~

@ukernel
Copy link
Contributor

ukernel commented Jun 14, 2018

I haven't read the code carefully. But I think there is a simple way:

Let ms_dispatch() call message->put().
If any function want to delay handling a message, increase the message's reference count and put the message to the wait list.

@tchaikov tchaikov added the core label Jun 14, 2018
@batrick
Copy link
Member Author

batrick commented Jun 14, 2018

Let ms_dispatch() call message->put().
If any function want to delay handling a message, increase the message's reference count and put the message to the wait list.

That indeed would be simpler however this patch is trying to eliminate the manual reference management which is so prone to leaks.

@batrick batrick force-pushed the mds-message-smart-ptr branch 2 times, most recently from 1aa2c9e to a73fea1 Compare June 14, 2018 13:19
Copy link
Contributor

@cbodley cbodley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great improvements to the messenger interfaces. would love to see these intrusive_ptr overloads replace the raw pointer ones eventually


class Messenger;
class Message;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe just duplicate the existing MessageRef typedef here, so you can still use the forward declaration of Message? for that reason, i prefer MessageRef to the new nested Message::ref/const_ref

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved MessageRef to MessageRef.h. What do you think now @cbodley ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that works! in the seastar messenger, i added a net/Fwd.h with forward declarations for all of the messenger types. so i could see this living in a more general header, but it's up to you

@batrick batrick force-pushed the mds-message-smart-ptr branch 9 times, most recently from 03e480d to 5cc54ee Compare June 15, 2018 15:38
@batrick batrick changed the title [WIP] mds: manage Message lifetime with intrusive_ptr mds: manage Message lifetime with intrusive_ptr Jul 29, 2018
@batrick batrick removed the DNM label Jul 29, 2018
@batrick
Copy link
Member Author

batrick commented Jul 30, 2018

@cbodley @liewegas @tchaikov @ukernel please take a look. I think this is done.

@ukernel
Copy link
Contributor

ukernel commented Jul 31, 2018

Commit "msg: add factory method to correctly construct smart_ptr" add similar codes to all message types. why not make Message's operator new private and define a template factory function. Something like

struct A {
private:
        void * operator new(size_t size);
        template <class M, class... Args>
        friend std::shared_ptr<M> alloc_msg(Args&&... args);
public: 
};

template <class M, class... Args>
std::shared_ptr<M> alloc_msg(Args&&... args) {
        return std::make_shared<M>(std::forward<Args>(args)...);
}

struct B : public A {
};

int main(int argc, char *argv[])
{
        // auto b1 = new B;
        auto b2 = alloc_msg < B > ();
}

@tchaikov
Copy link
Contributor

#include <iostream>
#include <memory>
#include <boost/smart_ptr/intrusive_ref_counter.hpp>
#include <boost/smart_ptr/intrusive_ptr.hpp>

using namespace std;

template <class A>
class Creater {
public:
  using ref = boost::intrusive_ptr<A>;
  template<typename... Args>
  static ref create(Args&&... args) {
    return ref{new A{std::forward<Args>(args)...}};
  }
};

class Message : public boost::intrusive_ref_counter<Message>
{
public:
  virtual ~Message() = default;
};

class MOSDMap : public Message, public Creater<MOSDMap> {
public:
  MOSDMap(int i) {
    cout << "hello world" << endl;
  }
  ~MOSDMap() {
    cout << "goodbye, cruel world" << endl;
  }
  friend class Creater<MOSDMap>;
};

int main(int argc, char *argv[])
{
  auto p = MOSDMap::create(1);
}

i'd suggest use the CRTP pattern here. so we can have the ref alias also.

@batrick batrick force-pushed the mds-message-smart-ptr branch 3 times, most recently from 656f2de to bdc8e4b Compare August 14, 2018 18:40
To improve cache locality.

Signed-off-by: Patrick Donnelly <pdonnell@redhat.com>
This codifies the giving of a reference to the Dispatcher and helps avoid
memory leaks. Old-style dispatch is kept to allow older code to continue
working.

Signed-off-by: Patrick Donnelly <pdonnell@redhat.com>
This avoids an allocation for each new message (amortized via deque).

Additionally, use std::move to avoid atomic update to the Message ref.

Signed-off-by: Patrick Donnelly <pdonnell@redhat.com>
Signed-off-by: Patrick Donnelly <pdonnell@redhat.com>
For use to create Contexts only when needed.

Signed-off-by: Patrick Donnelly <pdonnell@redhat.com>
@batrick batrick force-pushed the mds-message-smart-ptr branch 2 times, most recently from dfe6552 to 97a73bb Compare August 15, 2018 17:29
This change turned out to be far more extensive than I hoped but the end result
should prevent all Message-related memory leaks. I believe I fixed several
incidentally.

Fixes: http://tracker.ceph.com/issues/24306

Signed-off-by: Patrick Donnelly <pdonnell@redhat.com>
Signed-off-by: Patrick Donnelly <pdonnell@redhat.com>
This is to avoid easy leaks of the form:

    boost::intrusive_ptr(new M*(...));

where a ref is leaked because constructing the intrusive_ptr adds a ref.

It is expected that eventually all constructors move to protected/private so
that the message's factory is the only way to build a new message (safely).

Signed-off-by: Patrick Donnelly <pdonnell@redhat.com>
Fixes: http://tracker.ceph.com/issues/24306

Signed-off-by: Patrick Donnelly <pdonnell@redhat.com>
This eliminates duplicate code definitions.

Signed-off-by: Patrick Donnelly <pdonnell@redhat.com>
Signed-off-by: Patrick Donnelly <pdonnell@redhat.com>
@batrick
Copy link
Member Author

batrick commented Aug 16, 2018

Signed-off-by: "Yan, Zheng" <zyan@redhat.com>
@batrick batrick merged commit c0d3e5b into ceph:master Aug 16, 2018
batrick added a commit that referenced this pull request Aug 16, 2018
* refs/pull/22555/head:
	msg: define MFoo::create helper
	msg: add msgref cast method
	msg: cleanup factory/ref definition in messages
	mds: use message factory to avoid leaks
	msg: add factory method to correctly construct smart_ptr
	mds: remove dead MDS-MDS forwarding code
	mds: manage Message lifetime with intrusive_ptr
	common: add templated Context factory
	msg: add const version of get_payload
	msg: use queue of messages for dispatch
	msg: dispatch intrusive_ptr Messages
	msg: use deque for dispatcher pointers

Reviewed-by: Zheng Yan <zyan@redhat.com>
@batrick batrick deleted the mds-message-smart-ptr branch August 17, 2018 16:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
6 participants