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

Optimize json encoding #2481

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ gem 'net-ssh'
gem 'netaddr', '>= 2.0.4'
gem 'newrelic_rpm'
gem 'nokogiri', '>=1.10.5'
gem 'oj'
gem 'palm_civet'
gem 'posix-spawn', '~> 0.3.15'
gem 'protobuf', '3.6.12'
Expand Down
2 changes: 2 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ GEM
racc (~> 1.4)
nokogiri (1.12.5-x86_64-linux)
racc (~> 1.4)
oj (3.13.2)
os (1.0.1)
palm_civet (1.1.0)
parallel (1.21.0)
Expand Down Expand Up @@ -551,6 +552,7 @@ DEPENDENCIES
netaddr (>= 2.0.4)
newrelic_rpm
nokogiri (>= 1.10.5)
oj
palm_civet
parallel_tests
pg
Expand Down
20 changes: 17 additions & 3 deletions config/initializers/json.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
require 'active_support/json/encoding'

module CCInitializers
def self.json(_cc_config)
def self.json(cc_config)
if cc_config[:use_optimized_json_encoder]
MultiJson.use(:oj)
Oj::Rails.optimize # Use optimized encoders instead of as_json() methods for available classes.
Oj.default_options = {
bigdecimal_load: :bigdecimal,
}
end

ActiveSupport.json_encoder = Class.new do
attr_reader :options

Expand All @@ -10,10 +18,16 @@ def initialize(options=nil)
end

def encode(value)
if MultiJson.default_adapter == :oj && value.is_a?(VCAP::CloudController::Presenters::V3::BasePresenter)
v = value.to_hash
else
v = value.as_json(options.dup)
end

if Rails.env.test?
MultiJson.dump(value.as_json(options.dup))
MultiJson.dump(v)
else
MultiJson.dump(value.as_json(options.dup), options.merge(pretty: true))
MultiJson.dump(v, options.merge(pretty: true))
end
end
end
Expand Down
2 changes: 2 additions & 0 deletions lib/cloud_controller/config_schemas/base/api_schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,8 @@ class ApiSchema < VCAP::Config
write_key: String,
dataset: String,
},

optional(:use_optimized_json_encoder) => bool,
}
end
# rubocop:enable Metrics/BlockLength
Expand Down
3 changes: 3 additions & 0 deletions lib/cloud_controller/http_response_error.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ def initialize(message, method, response)

begin
source = MultiJson.load(response.body)
rescue ArgumentError
# Either Oj should raise Oj::ParseError instead of ArgumentError, or MultiJson should also wrap
# ArgumentError into MultiJson::Adapters::Oj::ParseError
rescue MultiJson::ParseError
source = response.body
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,16 @@

it 'sends the broker the X-Broker-Api-Originating-Identity header' do
user = VCAP::CloudController::User.make
base64_encoded_user_id = Base64.strict_encode64("{\"user_id\":\"#{user.guid}\"}")

get("/v2/service_bindings/#{@binding_guid}/parameters",
{}.to_json,
headers_for(user, scopes: %w(cloud_controller.admin)))

expect(
a_request(:get, %r{/v2/service_instances/#{@service_instance_guid}/service_bindings/[[:alnum:]-]+}).with do |req|
req.headers['X-Broker-Api-Originating-Identity'] == "cloudfoundry #{base64_encoded_user_id}"
m = req.headers['X-Broker-Api-Originating-Identity'].match /(?<platform>\S+) (?<value>\S+)/
value = MultiJson.load(Base64.strict_decode64(m[:value]))
m[:platform] == 'cloudfoundry' && value['user_id'] == user.guid
end
).to have_been_made
end
Expand Down Expand Up @@ -177,7 +178,7 @@
async_bind_service(status: 202)

service_binding = VCAP::CloudController::ServiceBinding.find(guid: @binding_guid)
stub_request(:get, service_binding_url(service_binding)).to_return(status: 200, body: '{"credentials": {"foo": true}')
stub_request(:get, service_binding_url(service_binding)).to_return(status: 200, body: '{"credentials": {"foo": true}}')

Delayed::Worker.new.work_off

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
'broker_api_v2.11_spec.rb' => '99e61dc50ceb635b09b3bd16901a4fa6',
'broker_api_v2.12_spec.rb' => '4023dffdcaae014556dcdba9f7d206bb',
'broker_api_v2.13_spec.rb' => 'ceecc106d1a203002e277a37812b6df3',
'broker_api_v2.14_spec.rb' => 'a1e7485793ba1916ea2f4080943530a5',
'broker_api_v2.14_spec.rb' => 'a9fbd1d91bcc9c33c054c7854be1ab5a',
'broker_api_v2.15_spec.rb' => 'c575fd37bc6dc8df4f773719ccef3288',
}
end
Expand Down
8 changes: 4 additions & 4 deletions spec/unit/controllers/runtime/routes_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,7 @@ module VCAP::CloudController
post '/v2/routes?generate_port=true', MultiJson.dump(req), headers_for(user)

expect(last_response.status).to eq(201)
expect(last_response.body).to include("\"port\": #{generated_port}")
expect(MultiJson.load(last_response.body)['entity']['port']).to eq(generated_port)
expect(last_response.headers).not_to include('X-CF-Warnings')
end
end
Expand All @@ -617,7 +617,7 @@ module VCAP::CloudController
post '/v2/routes?generate_port=true', MultiJson.dump(req), headers_for(user)

expect(last_response.status).to eq(201)
expect(last_response.body).to include("\"port\": #{generated_port}")
expect(MultiJson.load(last_response.body)['entity']['port']).to eq(generated_port)
expect(last_response.headers).to include('X-Cf-Warnings')
expect(last_response.headers['X-Cf-Warnings']).to include(port_override_warning)
end
Expand All @@ -640,7 +640,7 @@ module VCAP::CloudController
post '/v2/routes?generate_port=true', MultiJson.dump(req), headers_for(user)

expect(last_response.status).to eq(201)
expect(last_response.body).to include("\"port\": #{generated_port + 1}")
expect(MultiJson.load(last_response.body)['entity']['port']).to eq(generated_port + 1)
expect(last_response.headers).not_to include('X-Cf-Warnings')
end
end
Expand Down Expand Up @@ -734,7 +734,7 @@ module VCAP::CloudController
post '/v2/routes?generate_port=false', MultiJson.dump(req), headers_for(user)

expect(last_response.status).to eq(201)
expect(last_response.body).to include("\"port\": #{port}")
expect(MultiJson.load(last_response.body)['entity']['port']).to eq(port)
end
end
end
Expand Down