diff --git a/lib/hpax/table.ex b/lib/hpax/table.ex index b494bf8..c1e746d 100644 --- a/lib/hpax/table.ex +++ b/lib/hpax/table.ex @@ -264,15 +264,6 @@ defmodule HPAX.Table do In all cases, the table's `:protocol_max_table_size` is updated accordingly """ @spec resize(t(), non_neg_integer()) :: t() - def resize(%__MODULE__{max_table_size: max_table_size} = table, new_protocol_max_table_size) - when new_protocol_max_table_size >= max_table_size do - %__MODULE__{ - table - | protocol_max_table_size: new_protocol_max_table_size, - max_table_size: new_protocol_max_table_size - } - end - def resize(%__MODULE__{} = table, new_protocol_max_table_size) do pending_minimum_resize = case table.pending_minimum_resize do @@ -280,8 +271,15 @@ defmodule HPAX.Table do current -> min(current, new_protocol_max_table_size) end + table = + if new_protocol_max_table_size < table.size do + evict_to_size(table, new_protocol_max_table_size) + else + table + end + %__MODULE__{ - evict_to_size(table, new_protocol_max_table_size) + table | protocol_max_table_size: new_protocol_max_table_size, max_table_size: new_protocol_max_table_size, pending_minimum_resize: pending_minimum_resize diff --git a/test/hpax_test.exs b/test/hpax_test.exs index 1510b36..72bcc68 100644 --- a/test/hpax_test.exs +++ b/test/hpax_test.exs @@ -109,7 +109,6 @@ defmodule HPAXTest do property "encode/3 prepends dynamic resizes at the start of a block" do enc_table = HPAX.new(20_000) - # Start with a non-empty decode table dec_table = HPAX.new(20_000) # Put a record in both to prime the pump. The table sizes should match @@ -120,14 +119,45 @@ defmodule HPAXTest do assert enc_table.max_table_size == 20_000 assert dec_table.max_table_size == 20_000 - # Encode a record after resizing the table. We expect a dynamic resize to be - # encoded and the for two table sizes to be identical after decoding + # Scenario 1: Simulate the decoder growing the table via settings + + # First, the decoder resizes its table to some maximum size + dec_table = HPAX.resize(dec_table, 40_000) + + # It then communicates that size to the encoder, who chooses a smaller size + enc_table = HPAX.resize(enc_table, 30_000) + + # Now, encode a header + {encoded, enc_table} = HPAX.encode([{:store, "lame", "LAME"}], enc_table) + encoded = IO.iodata_to_binary(encoded) + + # Ensure that we encoded a resize on the wire + assert <<0b001::3, rest::bitstring>> = encoded + assert {:ok, 30_000, _rest} = HPAX.Types.decode_integer(rest, 5) + + # Finally, ensure that the decoder makes proper sense of this encoding and that it resizes + # back down to the size chosen by the encoder + assert {:ok, _decoded, dec_table} = HPAX.decode(encoded, dec_table) + assert dec_table.size == enc_table.size + assert enc_table.max_table_size == 30_000 + assert dec_table.max_table_size == 30_000 + + # Scenario 2: Simulate the decoder shrinking the table ia settings + + # First, the decoder resizes its table to some maximum size + dec_table = HPAX.resize(dec_table, 10_000) + + # It then communicates that size to the encoder, who chooses a smaller size enc_table = HPAX.resize(enc_table, 0) + + # It then changes its mind and goes back up to a size still smaller than the decoder's choice enc_table = HPAX.resize(enc_table, 1234) + + # Now, encode a header {encoded, enc_table} = HPAX.encode([{:store, "lame", "LAME"}], enc_table) encoded = IO.iodata_to_binary(encoded) - # Ensure that we see two resizes in order + # Ensure that we encoded two resizes in order on the wire assert <<0b001::3, rest::bitstring>> = encoded assert {:ok, 0, rest} = HPAX.Types.decode_integer(rest, 5) assert <<0b001::3, rest::bitstring>> = rest