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

mitigate .to_json segfaults on Ruby 1.8.7 #205

Merged
merged 4 commits into from
Dec 22, 2015

Conversation

duritong
Copy link
Contributor

Regularly we had processes on our puppetmaster - (still) running on
Ruby 1.8.7 - segfaulting on line 13 of consul_sorted_json.rb and we
then even had ghost processes (not tracked by passenger anymore)
consuming 100% of memory doing nothing when attaching with strace.

This might be a problem of either Ruby 1.8.7 itself (similar to
https://groups.google.com/forum/#!msg/puppet-users/ag1rAF7o_Uw/1hjtABrmzwgJ)
or the used C json library. Looking at what we are doing on line 13,
we figured out, that we could reduce the calls to .to_json and
hence might be able to mitigate the segfaults.

Only changing line 13 helped, but moved the segfaults to line 10,
looking at that line, we figured out, that we can avoid even
further .to_json calls.

Running this patch on 2 puppet masters for 8 hours didn't show any
segfaults, nor any high running cpu processes, which usually started
to appear quite quickly.

when Fixnum, Float, TrueClass, FalseClass, NilClass
return obj.to_json
when NilClass
return "null"
Copy link
Contributor

Choose a reason for hiding this comment

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

Uh, are you sure you want to literally return the string "null"? This sounds like a bad idea.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yea I'd agree, returning the String value for a NilClass seems like a bad idea

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Why?

$ ruby -rjson -e 'puts nil.to_json'
null

This is what .to_json gives back on nil-

Copy link
Contributor

Choose a reason for hiding this comment

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

Well, yes when you print it, it becomes a string, yes.

I understand that this function actually generates "content" for puppet, so maybe returning the string is ok.

Ug, I just don't like this function :(

Don't forget to adjust the "non"-pretty function as well.

Please add a test for this, I don't want to see this regress.

Something like:

it 'handles null correctly' do
  expect(subject.call({"foo" => null}).to eql('"foo"=>null')
end

Copy link
Contributor

Choose a reason for hiding this comment

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

I'd think that generating content having it return the value "null" becomes more problematic IMO. I'd personally like if something is actually null the generated content is empty with a null value.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well, but that's not how the current implementation works and also how json is specified.

Remember JSON is JavaScript Object Notation and in JavaScript nil is null.

I'm fine with adding the tests that represent/spec the current (pre-this-patch) behavior and hence I will show that the patch does not change it's current behvaior. I will also try to enable travis tests for 1.8.7, so that we could still support this ancient plattform. Yes, I'm very sad to not yet have had the option to move to puppet-server and hence jruby, BUT given that I will need this patch to have the current platform still working properly I thought it makes sense to give such things upstream, as others might run into the same problem on EL6.

Please let me know whether I should do the tests or you are generally not interested in merging that.

Copy link
Contributor

Choose a reason for hiding this comment

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

We just need to ensure that it is returning actual null, not the string "null" as those are in fact 2 different things in the JSON spec.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I agree, but then I would need to return "'null'" (quotes in the string), but we don't want that. .to_json returns a string that is then put into the template. It's confusing, we have layers of strings here...

@solarkennedy
Copy link
Contributor

Keep in mind that we do not officially support old versions of ruby in this module (although it isn't super clear from the readme)

If this is a real issue for you, I encourage you to submit a PR that re-expands the scope of the .travis.yaml to include your use case.
This will not prevent me from accepting this pr, just an fyi

@aj-jester
Copy link

If I remember correctly the last time we added 1.8.7 support it broke tests and we ended up removing it #154

@duritong
Copy link
Contributor Author

So I added:

  • tests that show the current behavior of simple types before my main commit, hence I would say that I'm showing that I don't introduce any regression with my optimizations.
  • put the optimizations into a private method, so that both - pretty and non pretty - generate methods can benefit from it.
  • re-enabled 1.8.7 support and fixed 2 minor issues in the specs
  • support for puppet 3.8.4
  • fixed an old stubbing behavior that was showing a warning

If you think that anything is missing, please let me know.

Regularly we had processes segfaulting on line 13 of
consul_sorted_json.rb and we then even had ghost processes (not
tracked by passenger anymore) consuming 100% of memory doing nothing
when attaching with strace.

This might be a problem of either Ruby 1.8.7 itself (similar to
https://groups.google.com/forum/#!msg/puppet-users/ag1rAF7o_Uw/1hjtABrmzwgJ)
or the used c json library. Looking at what we are doing on line 13,
we figured out, that we could reduce the calls to .to_json and
hence might be able to mitigate the segfaults.

Only changing line 13 helped but moved the segfaults to line 10,
looking at that line, we can actually avoid further .to_json calls.

Running this patch on 2 puppet masters for 8 hours didn't show any
segfaults, nor high running cpu processes, which usually started to
appear quite quickly.
@solarkennedy
Copy link
Contributor

Well. This looks pretty solid! Thanks!

solarkennedy added a commit that referenced this pull request Dec 22, 2015
mitigate .to_json segfaults on Ruby 1.8.7
@solarkennedy solarkennedy merged commit 57b0e94 into voxpupuli:master Dec 22, 2015
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.

4 participants