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

libroach: Fix memory leak in row_counter #42529

Merged
merged 1 commit into from
Nov 18, 2019
Merged

Conversation

miretskiy
Copy link
Contributor

Free previous key memory when counting row keys.

Release note (bug fix): Do not leak memory when counting rows during backup.

@miretskiy miretskiy requested a review from dt November 17, 2019 19:43
@cockroach-teamcity
Copy link
Member

This change is Reviewable

Copy link
Contributor Author

@miretskiy miretskiy left a comment

Choose a reason for hiding this comment

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

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @dt and @petermattis)


c-deps/libroach/row_counter.cc, line 94 at r1 (raw file):

Previously, miretskiy (Yevgeniy Miretskiy) wrote…

Yeah... You're right... I'm totally unfamiliar with this code base.
Anyways, Fixed the comparison plus added row counter destructor to avoid leaking the last "prev_key" memory

Looks like instead of DBString we can use ToString method and do string comparison. Not sure whether we need to worry about nulls inside rockdb::Slice, that's why I kept it as it was before, just fixed comparison as you indicated. I simply don't know if std::string is appropriate here. Let me know.

Copy link
Collaborator

@petermattis petermattis left a comment

Choose a reason for hiding this comment

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

@miretskiy Thanks for tackling this. Something to be aware of is that DBString needs to be a plain C struct so that it can be used for Go. I think the author of the code here thought there was another reason for using DBString, but there really is no reason to use it unless we're returning data to Go (which isn't taking place here). For pure C++ code like this, we should be using std::string.

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @dt and @miretskiy)


c-deps/libroach/row_counter.cc, line 94 at r1 (raw file):

Previously, miretskiy (Yevgeniy Miretskiy) wrote…

Looks like instead of DBString we can use ToString method and do string comparison. Not sure whether we need to worry about nulls inside rockdb::Slice, that's why I kept it as it was before, just fixed comparison as you indicated. I simply don't know if std::string is appropriate here. Let me know.

std::string is definitely appropriate. Much more appropriate than using DBString which is intended only for passing data from this C++ code back to Go. We do have to worry about NUL bytes in the strings, but both std::string and rocksdb::Slice handle them properly.

My suggestion, change the type of prev_key to std::string. The line of code below then becomes:

prev_key.assign(decoded_key.data(), decoded_key.size())

The comparison above becomes decoded_key == prev_key.

This approach has the nice side-effect of reducing memory allocations as well as prev_key.assign will reuse the underlying storage when possible.

@miretskiy
Copy link
Contributor Author

@miretskiy Thanks for tackling this. Something to be aware of is that DBString needs to be a plain C struct so that it can be used for Go. I think the author of the code here thought there was another reason for using DBString, but there really is no reason to use it unless we're returning data to Go (which isn't taking place here). For pure C++ code like this, we should be using std::string.

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @dt and @miretskiy)

c-deps/libroach/row_counter.cc, line 94 at r1 (raw file):

Previously, miretskiy (Yevgeniy Miretskiy) wrote…
std::string is definitely appropriate. Much more appropriate than using DBString which is intended only for passing data from this C++ code back to Go. We do have to worry about NUL bytes in the strings, but both std::string and rocksdb::Slice handle them properly.

My suggestion, change the type of prev_key to std::string. The line of code below then becomes:

prev_key.assign(decoded_key.data(), decoded_key.size())

The comparison above becomes decoded_key == prev_key.

This approach has the nice side-effect of reducing memory allocations as well as prev_key.assign will reuse the underlying storage when possible.

Sounds great. Done.

Free previous key memory when counting row keys.

Release note (bug fix): Do not leak memory when counting rows during backup.
Copy link
Collaborator

@petermattis petermattis left a comment

Choose a reason for hiding this comment

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

LGTM

@miretskiy
Copy link
Contributor Author

bors r+

craig bot pushed a commit that referenced this pull request Nov 18, 2019
42529: libroach: Fix memory leak in row_counter r=miretskiy a=miretskiy

Free previous key memory when counting row keys.

Release note (bug fix): Do not leak memory when counting rows during backup.

Co-authored-by: Yevgeniy Miretskiy <[email protected]>
@craig
Copy link
Contributor

craig bot commented Nov 18, 2019

Build succeeded

@craig craig bot merged commit 52c1f3a into cockroachdb:master Nov 18, 2019
@miretskiy
Copy link
Contributor Author

miretskiy commented Nov 18, 2019 via email

@kenliu
Copy link

kenliu commented Nov 18, 2019

Definitely should be backported to 19.2 -- was introduced in 19.2.

Copy link
Collaborator

@petermattis petermattis left a comment

Choose a reason for hiding this comment

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

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @dt and @miretskiy)


c-deps/libroach/row_counter.h, line 33 at r2 (raw file):

  int GetRowPrefixLength(rocksdb::Slice* key);
  std::string prev_key;
  rocksdb::Slice prev;

Is prev unused?

@miretskiy
Copy link
Contributor Author

miretskiy commented Nov 18, 2019 via email

@tbg
Copy link
Member

tbg commented Nov 18, 2019

What's the C++ tool that we should've used to catch this?

@petermattis
Copy link
Collaborator

Do we not use compiler warnings for these things (-WUnused, etc)?

Our C++ build process is a bit unloved and it is mixed in with the Cmake files provided by RocksDB and our other C++ dependencies. We should be using compiler warnings.

What's the C++ tool that we should've used to catch this?

Catch the memory leak? I recall there being a leak detector built in to the C++ unit test framework used inside Google (gunit). My memory on how this worked is hazy. It might have depended on tcmalloc as well. @miretskiy ?

@miretskiy
Copy link
Contributor Author

miretskiy commented Nov 18, 2019 via email

@bdarnell
Copy link
Contributor

We use jemalloc for c++ memory allocation, which has good profiling tools. I haven't tried the leak checker but we should see if it works here: https://github.com/jemalloc/jemalloc/wiki/Use-Case:-Leak-Checking

@miretskiy
Copy link
Contributor Author

miretskiy commented Nov 19, 2019 via email

@miretskiy miretskiy deleted the memleak branch December 8, 2019 15:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants