diff --git a/app/models/solid_cache/entry.rb b/app/models/solid_cache/entry.rb index 41014c3..f8478b5 100644 --- a/app/models/solid_cache/entry.rb +++ b/app/models/solid_cache/entry.rb @@ -14,6 +14,8 @@ class Entry < Record KEY_HASH_ID_RANGE = -(2**63)..(2**63 - 1) + MULTI_BATCH_SIZE = 1000 + class << self def write(key, value) write_multi([ { key: key, value: value } ]) @@ -21,9 +23,11 @@ def write(key, value) def write_multi(payloads) without_query_cache do - upsert_all \ - add_key_hash_and_byte_size(payloads), - unique_by: upsert_unique_by, on_duplicate: :update, update_only: [ :key, :value, :byte_size ] + payloads.each_slice(MULTI_BATCH_SIZE).each do |payload_batch| + upsert_all \ + add_key_hash_and_byte_size(payload_batch), + unique_by: upsert_unique_by, on_duplicate: :update, update_only: [ :key, :value, :byte_size ] + end end end @@ -33,9 +37,13 @@ def read(key) def read_multi(keys) without_query_cache do - query = Arel.sql(select_sql(keys), *key_hashes_for(keys)) + {}.tap do |results| + keys.each_slice(MULTI_BATCH_SIZE).each do |keys_batch| + query = Arel.sql(select_sql(keys_batch), *key_hashes_for(keys_batch)) - connection.select_all(query, "SolidCache::Entry Load").cast_values(attribute_types).to_h + results.merge!(connection.select_all(query, "SolidCache::Entry Load").cast_values(attribute_types).to_h) + end + end end end diff --git a/test/models/solid_cache/entry_test.rb b/test/models/solid_cache/entry_test.rb index 8f8836a..bce73b7 100644 --- a/test/models/solid_cache/entry_test.rb +++ b/test/models/solid_cache/entry_test.rb @@ -70,6 +70,18 @@ class EntryTest < ActiveSupport::TestCase end end + test "batching multi queries" do + stub_const(Entry, :MULTI_BATCH_SIZE, 2) do + assert_queries_count(2) do + Entry.write_multi([ { key: "hello".b, value: "there" }, { key: "foo".b, value: "bar" }, { key: "baz".b, value: "zab" } ]) + end + + assert_queries_count(2) do + assert_equal({ "foo" => "bar", "hello" => "there", "baz" => "zab" }, Entry.read_multi([ "hello".b, "foo".b, "baz".b, "bar".b ])) + end + end + end + private def write_entries(count = 20) Entry.write_multi(count.times.map { |i| { key: "key#{i}", value: "value#{i}" } })