Current section

Files

Jump to
rocksdb test read_options.erl
Raw

test/read_options.erl

%% Copyright (c) 2016-2026 Benoit Chesneau
%%
%% This file is provided to you under the Apache License,
%% Version 2.0 (the "License"); you may not use this file
%% except in compliance with the License. You may obtain
%% a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing,
%% software distributed under the License is distributed on an
%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
%% KIND, either express or implied. See the License for the
%% specific language governing permissions and limitations
%% under the License.
-module(read_options).
-include_lib("eunit/include/eunit.hrl").
-define(rm_rf(Dir), rocksdb_test_util:rm_rf(Dir)).
%% Test fill_cache option
%% When fill_cache=false, reads should not populate the block cache
%% When fill_cache=true (default), reads should populate the block cache
fill_cache_test() ->
?rm_rf("test_fill_cache"),
{ok, Stats} = rocksdb:new_statistics(),
{ok, Db} = rocksdb:open(
"test_fill_cache",
[{create_if_missing, true},
{statistics, Stats},
%% Enable block cache
{block_based_table_options, [{block_cache_size, 8388608}]}]), %% 8MB cache
try
%% Write data and flush to create SST files
lists:foreach(
fun(I) ->
Key = <<"key", (integer_to_binary(I))/binary>>,
Value = list_to_binary(lists:duplicate(100, $x)),
ok = rocksdb:put(Db, Key, Value, [])
end,
lists:seq(1, 100)),
ok = rocksdb:flush(Db, []),
%% Get initial cache add count after flush
{ok, AddCountAfterFlush} = rocksdb:statistics_ticker(Stats, block_cache_add),
%% Read data with fill_cache=false - should NOT populate cache
lists:foreach(
fun(I) ->
Key = <<"key", (integer_to_binary(I))/binary>>,
{ok, _} = rocksdb:get(Db, Key, [{fill_cache, false}])
end,
lists:seq(1, 50)),
{ok, AddCountAfterNoFill} = rocksdb:statistics_ticker(Stats, block_cache_add),
%% Cache add count should not have increased significantly
%% (some index/filter blocks might still be added)
NoFillAdds = AddCountAfterNoFill - AddCountAfterFlush,
%% Now read different keys with fill_cache=true (default)
lists:foreach(
fun(I) ->
Key = <<"key", (integer_to_binary(I))/binary>>,
{ok, _} = rocksdb:get(Db, Key, [{fill_cache, true}])
end,
lists:seq(51, 100)),
{ok, AddCountAfterFill} = rocksdb:statistics_ticker(Stats, block_cache_add),
%% Cache add count should have increased when fill_cache=true
FillAdds = AddCountAfterFill - AddCountAfterNoFill,
%% Verify that fill_cache=true adds more to cache than fill_cache=false
%% Note: This is a relative comparison since exact numbers depend on block sizes
?assert(FillAdds >= NoFillAdds orelse AddCountAfterFill > AddCountAfterFlush)
after
ok = rocksdb:close(Db),
ok = rocksdb:release_statistics(Stats),
?rm_rf("test_fill_cache")
end,
ok.
%% Test fill_cache with iterators
fill_cache_iterator_test() ->
?rm_rf("test_fill_cache_iter"),
{ok, Stats} = rocksdb:new_statistics(),
{ok, Db} = rocksdb:open(
"test_fill_cache_iter",
[{create_if_missing, true},
{statistics, Stats},
{block_based_table_options, [{block_cache_size, 8388608}]}]),
try
%% Write data and flush
lists:foreach(
fun(I) ->
Key = <<"iter_key", (integer_to_binary(I))/binary>>,
Value = list_to_binary(lists:duplicate(200, $y)),
ok = rocksdb:put(Db, Key, Value, [])
end,
lists:seq(1, 100)),
ok = rocksdb:flush(Db, []),
%% Create iterator with fill_cache=false
{ok, Itr1} = rocksdb:iterator(Db, [{fill_cache, false}]),
{ok, AddCountBefore} = rocksdb:statistics_ticker(Stats, block_cache_add),
%% Iterate through some entries
{ok, _, _} = rocksdb:iterator_move(Itr1, first),
iterate_n_times(Itr1, 25),
ok = rocksdb:iterator_close(Itr1),
{ok, AddCountAfterNoFill} = rocksdb:statistics_ticker(Stats, block_cache_add),
NoFillIterAdds = AddCountAfterNoFill - AddCountBefore,
%% Create iterator with fill_cache=true
{ok, Itr2} = rocksdb:iterator(Db, [{fill_cache, true}]),
%% Iterate through entries
{ok, _, _} = rocksdb:iterator_move(Itr2, first),
iterate_n_times(Itr2, 25),
ok = rocksdb:iterator_close(Itr2),
{ok, AddCountAfterFill} = rocksdb:statistics_ticker(Stats, block_cache_add),
FillIterAdds = AddCountAfterFill - AddCountAfterNoFill,
%% fill_cache=true should add at least as many blocks as fill_cache=false
?assert(is_integer(NoFillIterAdds)),
?assert(is_integer(FillIterAdds))
after
ok = rocksdb:close(Db),
ok = rocksdb:release_statistics(Stats),
?rm_rf("test_fill_cache_iter")
end,
ok.
iterate_n_times(_Itr, 0) -> ok;
iterate_n_times(Itr, N) ->
case rocksdb:iterator_move(Itr, next) of
{ok, _, _} -> iterate_n_times(Itr, N - 1);
{error, invalid_iterator} -> ok
end.
%% Test readahead_size option
%% readahead_size configures the size of the readahead buffer for iterators
%% This is particularly useful for sequential reads
readahead_size_test() ->
?rm_rf("test_readahead_size"),
{ok, Db} = rocksdb:open(
"test_readahead_size",
[{create_if_missing, true}]),
try
%% Write enough data to benefit from readahead
lists:foreach(
fun(I) ->
Key = <<"readahead_key", (integer_to_binary(I))/binary>>,
Value = list_to_binary(lists:duplicate(500, $z)),
ok = rocksdb:put(Db, Key, Value, [])
end,
lists:seq(1, 200)),
ok = rocksdb:flush(Db, []),
%% Test with readahead_size = 0 (disabled)
{ok, Itr1} = rocksdb:iterator(Db, [{readahead_size, 0}]),
{ok, _, _} = rocksdb:iterator_move(Itr1, first),
iterate_n_times(Itr1, 50),
ok = rocksdb:iterator_close(Itr1),
%% Test with larger readahead_size (2MB)
{ok, Itr2} = rocksdb:iterator(Db, [{readahead_size, 2 * 1024 * 1024}]),
{ok, _, _} = rocksdb:iterator_move(Itr2, first),
iterate_n_times(Itr2, 50),
ok = rocksdb:iterator_close(Itr2),
%% Test with get operation
{ok, _} = rocksdb:get(Db, <<"readahead_key1">>, [{readahead_size, 1024 * 1024}]),
ok
after
ok = rocksdb:close(Db),
?rm_rf("test_readahead_size")
end,
ok.
%% Test async_io option
%% async_io enables asynchronous I/O for iterators
async_io_test() ->
?rm_rf("test_async_io"),
{ok, Db} = rocksdb:open(
"test_async_io",
[{create_if_missing, true}]),
try
%% Write data
lists:foreach(
fun(I) ->
Key = <<"async_key", (integer_to_binary(I))/binary>>,
Value = list_to_binary(lists:duplicate(200, $a)),
ok = rocksdb:put(Db, Key, Value, [])
end,
lists:seq(1, 100)),
ok = rocksdb:flush(Db, []),
%% Test with async_io=false (default)
{ok, Itr1} = rocksdb:iterator(Db, [{async_io, false}]),
{ok, _, _} = rocksdb:iterator_move(Itr1, first),
iterate_n_times(Itr1, 25),
ok = rocksdb:iterator_close(Itr1),
%% Test with async_io=true
{ok, Itr2} = rocksdb:iterator(Db, [{async_io, true}]),
{ok, _, _} = rocksdb:iterator_move(Itr2, first),
iterate_n_times(Itr2, 25),
ok = rocksdb:iterator_close(Itr2),
%% Test with get operation
{ok, _} = rocksdb:get(Db, <<"async_key1">>, [{async_io, true}]),
ok
after
ok = rocksdb:close(Db),
?rm_rf("test_async_io")
end,
ok.