Skip to content

Commit

Permalink
follow up on ways to reduce allocation on multi_get
Browse files Browse the repository at this point in the history
  • Loading branch information
danmayer committed Feb 14, 2025
1 parent 2351639 commit a6b0c90
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 13 deletions.
12 changes: 12 additions & 0 deletions bin/profile
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,18 @@ def sock_set_multi(sock, pairs)
sock.gets(TERMINATOR) # clear the buffer
end

def allocations
x = GC.stat(:total_allocated_objects)
yield
GC.stat(:total_allocated_objects) - x
end

if bench_target == 'get_multi_allocations'
puts "getting allocations"
puts allocations { client.get_multi(pairs.keys) }
exit 0
end

if %w[all get].include?(bench_target)
Vernier.profile(out: 'client_get_profile.json') do
start_time = Time.now
Expand Down
4 changes: 2 additions & 2 deletions lib/dalli/protocol/connection_manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,8 @@ def read(count)
error_on_request!(e)
end

def read_exact(count)
@sock.read(count)
def read_to_outstring(count, outstring)
@sock.read(count, outstring)
rescue SystemCallError, *TIMEOUT_ERRORS, EOFError => e
error_on_request!(e)
end
Expand Down
26 changes: 16 additions & 10 deletions lib/dalli/protocol/meta.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ module Protocol
##
class Meta < Base
TERMINATOR = "\r\n"
META_NOOP = "mn\r\n"
META_NOOP_RESP = 'MN'
META_VALUE_RESP = 'VA'
META_GET_REQ_NO_FLAGS = "v k q\r\n"
META_GET_REQ = "v f k q\r\n"
SUPPORTS_CAPACITY = Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.4.0')

def response_processor
Expand Down Expand Up @@ -58,26 +63,27 @@ def read_multi_req(keys)
results = SUPPORTS_CAPACITY ? Hash.new(nil, capacity: keys.size) : {}
optimized_for_raw = @value_marshaller.raw_by_default
key_index = optimized_for_raw ? 2 : 3
terminator_buffer = String.new(TERMINATOR, capacity: TERMINATOR.size)

post_get_req = optimized_for_raw ? "v k q\r\n" : "v f k q\r\n"
post_get_req = optimized_for_raw ? META_GET_REQ_NO_FLAGS : META_GET_REQ
keys.each do |key|
@connection_manager.write("mg #{key} #{post_get_req}")
end
@connection_manager.write("mn\r\n")
@connection_manager.write(META_NOOP)
@connection_manager.flush

terminator_length = TERMINATOR.length
while (line = @connection_manager.readline)
break if line == TERMINATOR || line[0, 2] == 'MN'
next unless line[0, 3] == 'VA '

# VA value_length flags key
tokens = line.split
value = @connection_manager.read_exact(tokens[1].to_i)
tokens = optimized_for_raw ? line.split(nil, 4) : line.split
break if tokens[0] == META_NOOP_RESP
next unless tokens[0] == META_VALUE_RESP

value = @connection_manager.read(tokens[1].to_i)
bitflags = optimized_for_raw ? 0 : @response_processor.bitflags_from_tokens(tokens)
@connection_manager.read_exact(terminator_length) # read the terminator
results[tokens[key_index].byteslice(1..-1)] =
@value_marshaller.retrieve(value, bitflags)
@connection_manager.read_to_outstring(terminator_length, terminator_buffer)
results[tokens[key_index].byteslice(1, 256)] =
optimized_for_raw ? value : @value_marshaller.retrieve(value, bitflags)
end
results
end
Expand Down
3 changes: 2 additions & 1 deletion lib/dalli/protocol/meta/response_processor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class ResponseProcessor
def initialize(io_source, value_marshaller)
@io_source = io_source
@value_marshaller = value_marshaller
@terminator_buffer = String.new(TERMINATOR, capacity: TERMINATOR.size)
end

def meta_get_with_value(cache_nils: false, skip_flags: false)
Expand Down Expand Up @@ -249,7 +250,7 @@ def next_line_to_tokens

def read_data(data_size)
resp_data = @io_source.read(data_size)
@io_source.read(TERMINATOR.bytesize)
@io_source.read_to_outstring(TERMINATOR.bytesize, @terminator_buffer)
resp_data
end
end
Expand Down

0 comments on commit a6b0c90

Please sign in to comment.