200 lines
5.2 KiB
Erlang
200 lines
5.2 KiB
Erlang
%% -*- mode: erlang; erlang-indent-level: 4; indent-tabs-mode: nil -*-
|
|
%%----------------------------------------------------------------
|
|
%% Copyright (c) 2013-2016 Klarna AB
|
|
%%
|
|
%% 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(mnesia_rocksdb_tuning).
|
|
|
|
-export([describe_env/0,
|
|
get_maxfiles/0, get_maxfiles/1,
|
|
get_avail_ram/0,
|
|
rdb_tabs/0, rdb_tabs/1,
|
|
rdb_indexes/0, rdb_indexes/1,
|
|
count_rdb_tabs/0, count_rdb_tabs/1,
|
|
calc_sizes/0, calc_sizes/1,
|
|
ideal_max_files/0, ideal_max_files/1,
|
|
max_files/1,
|
|
write_buffer/1,
|
|
cache/1,
|
|
default/1]).
|
|
|
|
-include("mnesia_rocksdb_tuning.hrl").
|
|
|
|
-define(KB, 1024).
|
|
-define(MB, 1024 * 1024).
|
|
-define(GB, 1024 * 1024 * 1024).
|
|
|
|
describe_env() ->
|
|
#tuning{max_files = get_maxfiles(),
|
|
avail_ram = get_avail_ram()}.
|
|
|
|
get_maxfiles() ->
|
|
get_maxfiles(os:type()).
|
|
|
|
get_maxfiles({unix,darwin}) ->
|
|
Limit = os:cmd("launchctl limit maxfiles"),
|
|
[_, Soft, _] = string:tokens(Limit, " \t\n"),
|
|
list_to_integer(Soft);
|
|
get_maxfiles({unix,linux}) ->
|
|
[L|_] = string:tokens(os:cmd("ulimit -n"), "\n"),
|
|
list_to_integer(L).
|
|
|
|
%% Returns installed RAM in Gigabytes
|
|
get_avail_ram() ->
|
|
get_avail_ram(os:type()).
|
|
|
|
get_avail_ram({unix,darwin}) ->
|
|
{match, [S]} =
|
|
re:run(os:cmd("/usr/sbin/system_profiler SPHardwareDataType"),
|
|
"Memory: (.+) GB", [{capture, [1], list}]),
|
|
list_to_integer(S);
|
|
get_avail_ram({unix,linux}) ->
|
|
{match, [S]} =
|
|
re:run(os:cmd("free -g"), "Mem:[ ]+([0-9]+) ",[{capture,[1],list}]),
|
|
list_to_integer(S).
|
|
|
|
rdb_tabs() ->
|
|
rdb_tabs(mnesia_lib:dir()).
|
|
|
|
rdb_tabs(Db) ->
|
|
rdb_tabs(list_dir(Db), Db).
|
|
|
|
rdb_tabs(Fs, _Db) ->
|
|
lists:flatmap(
|
|
fun(F) ->
|
|
case re:run(F, "(.+)-_tab\\.extrdb",
|
|
[global,{capture,[1],list}]) of
|
|
{match, [Match]} ->
|
|
Match;
|
|
_ ->
|
|
[]
|
|
end
|
|
end, Fs).
|
|
|
|
rdb_indexes() ->
|
|
rdb_indexes(mnesia_lib:dir()).
|
|
|
|
rdb_indexes(Db) ->
|
|
rdb_indexes(list_dir(Db), Db).
|
|
|
|
rdb_indexes(Fs, _Db) ->
|
|
lists:flatmap(
|
|
fun(F) ->
|
|
case re:run(F, "(.+)-([0-9]+)-_ix\\.extrdb",
|
|
[global,{capture,[1,2],list}]) of
|
|
{match, [[T,P]]} ->
|
|
[{T,P}];
|
|
_ ->
|
|
[]
|
|
end
|
|
end, Fs).
|
|
|
|
list_dir(D) ->
|
|
case file:list_dir(D) of
|
|
{ok, Fs} -> Fs;
|
|
{error, Reason} -> erlang:error({Reason,D})
|
|
end.
|
|
|
|
fname({Tab,IxPos}, Dir) ->
|
|
filename:join(Dir, Tab ++ "-" ++ IxPos ++ "-_ix.extrdb");
|
|
fname(Tab, Dir) when is_list(Tab) ->
|
|
filename:join(Dir, Tab ++ "-_tab.extrdb").
|
|
|
|
%% Number of rocksdb tables + indexes
|
|
count_rdb_tabs() ->
|
|
count_rdb_tabs(mnesia_lib:dir()).
|
|
|
|
count_rdb_tabs(Db) ->
|
|
Fs = list_dir(Db),
|
|
length(rdb_tabs(Fs, Db)) + length(rdb_indexes(Fs, Db)).
|
|
|
|
calc_sizes() ->
|
|
calc_sizes(mnesia_lib:dir()).
|
|
|
|
calc_sizes(D) ->
|
|
lists:sort(
|
|
fun(A,B) -> sort_size(B,A) end, % rev sort
|
|
[{T, dir_size(fname(T, D))} || T <- rdb_tabs(D)]
|
|
++ [{I, dir_size(fname(I, D))} || I <- rdb_indexes(D)]).
|
|
|
|
ideal_max_files() ->
|
|
ideal_max_files(mnesia_lib:dir()).
|
|
|
|
ideal_max_files(D) ->
|
|
[{T,Sz,max_files(Sz)} || {T, Sz} <- calc_sizes(D)].
|
|
|
|
max_files({I,g}) ->
|
|
round(I * 1000) div 20;
|
|
max_files({I,m}) when I > 400 ->
|
|
round(I) div 20;
|
|
max_files(_) ->
|
|
default(max_open_files).
|
|
|
|
write_buffer({_,g}) ->
|
|
120 * ?MB;
|
|
write_buffer({I,m}) when I > 400 ->
|
|
120 * ?MB;
|
|
write_buffer(_) ->
|
|
default(write_buffer).
|
|
|
|
cache({_,g}) ->
|
|
8 * ?MB;
|
|
cache({I,m}) when I > 400 ->
|
|
6 * ?MB;
|
|
cache(_) ->
|
|
default(cache).
|
|
|
|
default(write_buffer) -> 2 * ?MB;
|
|
default(max_open_files) -> 20;
|
|
default(cache) -> 2 * ?MB.
|
|
|
|
%% open_file_memory() ->
|
|
%% (max_open_files-10) *
|
|
%% (184 + (average_sst_filesize/2048) *
|
|
%% (8 + ((average_key_size+average_value_size)/2048 +1) * 0.6).
|
|
|
|
dir_size(D) ->
|
|
R = os:cmd("du -hc " ++ D ++ " | grep total"),
|
|
parse_sz(hd(string:tokens(R," \t\n"))).
|
|
|
|
parse_sz(S) ->
|
|
{match,[I,U]} = re:run(S, "([\\.0-9]+)([BKMG])", [{capture,[1,2],list}]),
|
|
{scan_num(I), unit(U)}.
|
|
|
|
scan_num(S) ->
|
|
case erl_scan:string(S) of
|
|
{ok, [{integer,_,I}],_} ->
|
|
I;
|
|
{ok, [{float,_,F}],_} ->
|
|
F
|
|
end.
|
|
|
|
unit("B") -> b;
|
|
unit("K") -> k;
|
|
unit("M") -> m;
|
|
unit("G") -> g.
|
|
|
|
%% Custom sort: b < k < m < g
|
|
sort_size({_,{A,U}},{_,{B,U}}) -> A < B;
|
|
sort_size({_,{_,U1}},{_,{_,U2}}) ->
|
|
case {U1,U2} of
|
|
{b,_} -> true;
|
|
{k,_} when U2 =/= b -> true;
|
|
{m,g} -> true;
|
|
_ -> false
|
|
end.
|