2020% %
2121% % -------------------------------------------------------------------
2222-module (basho_bench_config ).
23+ -behaviour (gen_server ).
24+
25+
26+ -ifdef (TEST ).
27+ -include_lib (" eunit/include/eunit.hrl" ).
28+ -compile (export_all ).
29+ -endif .
2330
2431-export ([load /1 ,
2532 normalize_ips /2 ,
2633 set /2 ,
2734 get /1 , get /2 ]).
2835
36+ -export ([start_link /0 ]).
37+
38+ % Gen server callbacks
39+ -export ([code_change /3 , init /1 , terminate /2 , handle_call /3 ]).
40+
2941-include (" basho_bench.hrl" ).
3042
43+ -record (basho_bench_config_state , {config_keys }).
44+
45+ -type state () :: # basho_bench_config_state {}.
3146% % ===================================================================
3247% % Public API
3348% % ===================================================================
3449
50+ ensure_started () ->
51+ start_link ().
52+
53+ start_link () ->
54+ gen_server :start_link ({global , ? MODULE }, ? MODULE , [], []).
55+
56+
3557load (Files ) ->
36- TermsList =
37- [ case file :consult (File ) of
38- {ok , Terms } ->
39- Terms ;
40- {error , Reason } ->
41- ? FAIL_MSG (" Failed to parse config file ~s : ~p \n " , [File , Reason ])
42- end || File <- Files ],
43- load_config (lists :append (TermsList )).
58+ ensure_started (),
59+ gen_server :call ({global , ? MODULE }, {load_files , Files }).
60+
61+ set (Key , Value ) ->
62+ gen_server :call ({global , ? MODULE }, {set , Key , Value }).
63+
64+ get (Key ) ->
65+ case gen_server :call ({global , ? MODULE }, {get , Key }) of
66+ {ok , Value } ->
67+ Value ;
68+ error ->
69+ erlang :error (" Missing configuration key" , [Key ])
70+ end .
71+
72+ get (Key , Default ) ->
73+ case gen_server :call ({global , ? MODULE }, {get , Key }) of
74+ {ok , Value } ->
75+ Value ;
76+ error ->
77+ Default
78+ end .
4479
4580% % @doc Normalize the list of IPs and Ports.
4681% %
@@ -58,42 +93,177 @@ normalize_ips(IPs, DefultPort) ->
5893 end ,
5994 lists :foldl (F , [], IPs ).
6095
61- set (Key , Value ) ->
62- ok = application :set_env (basho_bench , Key , Value ).
6396
64- get (Key ) ->
65- case application :get_env (basho_bench , Key ) of
66- {ok , Value } ->
67- Value ;
68- undefined ->
69- erlang :error (" Missing configuration key" , [Key ])
70- end .
7197
72- get (Key , Default ) ->
73- case application :get_env (basho_bench , Key ) of
74- {ok , Value } ->
75- Value ;
76- _ ->
77- Default
78- end .
7998
8099
81100% % ===================================================================
82101% % Internal functions
83102% % ===================================================================
84103
85- load_config ([]) ->
86- ok ;
87- load_config ([{Key , Value } | Rest ]) ->
88- ? MODULE :set (Key , Value ),
89- load_config (Rest );
90- load_config ([ Other | Rest ]) ->
91- ? WARN (" Ignoring non-tuple config value: ~p \n " , [Other ]),
92- load_config (Rest ).
93104
94105normalize_ip_entry ({IP , Ports }, Normalized , _ ) when is_list (Ports ) ->
95106 [{IP , Port } || Port <- Ports ] ++ Normalized ;
96107normalize_ip_entry ({IP , Port }, Normalized , _ ) ->
97108 [{IP , Port }|Normalized ];
98109normalize_ip_entry (IP , Normalized , DefaultPort ) ->
99110 [{IP , DefaultPort }|Normalized ].
111+
112+
113+ % % ===
114+ % % Gen_server Functions
115+ % % ===
116+
117+ -spec init (term ()) -> {ok , state ()}.
118+ init (_Args ) ->
119+ State = # basho_bench_config_state {config_keys = base_config ()},
120+ {ok , State }.
121+
122+ -spec code_change (term (), state (), term ()) -> {ok , state ()}.
123+ code_change (_OldVsn , State , _Extra ) ->
124+ {ok , State }.
125+
126+ -spec terminate (term (), state ()) -> 'ok' .
127+ terminate (_Reason , _State ) ->
128+ ok .
129+
130+ handle_call ({load_files , FileNames }, _From , State ) ->
131+ TermsList = get_keys_from_files (FileNames ),
132+ ConfigKeys2 = load_termlist (TermsList , State # basho_bench_config_state .config_keys ),
133+ State2 = State # basho_bench_config_state {config_keys = ConfigKeys2 },
134+ {reply , ok , State2 };
135+ handle_call ({set , app_run_mode , Value }, _From , State ) ->
136+ application :set_env (basho_bench_app , app_run_mode , Value ),
137+ {reply , ok , State };
138+ handle_call ({get , app_run_mode }, _From , State ) ->
139+ case application :get_env (basho_bench_app , app_run_mode ) of
140+ {ok , Value } ->
141+ {reply , {ok , Value }, State };
142+ undefined ->
143+ {reply , error , State }
144+ end ;
145+ handle_call ({set , Key , Value }, _From , State ) ->
146+ NewKVs = orddict :store (Key , Value , State # basho_bench_config_state .config_keys ),
147+ State2 = State # basho_bench_config_state {config_keys = NewKVs },
148+ {reply , ok , State2 };
149+ handle_call ({get , Key }, _From , State ) ->
150+ Value = orddict :find (Key , State # basho_bench_config_state .config_keys ),
151+ {reply , Value , State }.
152+ get_keys_from_files (Files ) ->
153+ [ case file :consult (File ) of
154+ {ok , Terms } ->
155+ Terms ;
156+ {error , Reason } ->
157+ ? FAIL_MSG (" Failed to parse config file ~s : ~p \n " , [File , Reason ]),
158+ throw (invalid_config ),
159+ notokay
160+ end || File <- Files ].
161+
162+
163+ load_termlist (TermList , ExistingConfig ) ->
164+ NewKVs = lists :flatten (TermList ),
165+ FoldFun = fun ({Key , Value }, Accum ) ->
166+ orddict :store (Key , Value , Accum )
167+ end ,
168+ lists :foldl (FoldFun , ExistingConfig , NewKVs ).
169+
170+ base_config () ->
171+ orddict :from_list ([
172+ % % Run mode: How should basho_bench started as a separate node, or part of an
173+ % % other node. The default is standalone, other option is included.
174+
175+ % %
176+ % % Mode of load generation:
177+ % % max - Generate as many requests as possible per worker
178+ % % {rate, Rate} - Exp. distributed Mean reqs/sec
179+ % %
180+ {mode , {rate , 5 }},
181+
182+ % %
183+ % % Default log level
184+ % %
185+ {log_level , debug },
186+
187+ % %
188+ % % Base test output directory
189+ % %
190+ {test_dir , " tests" },
191+
192+ % %
193+ % % Test duration (minutes)
194+ % %
195+ {duration , 5 },
196+
197+ % %
198+ % % Number of concurrent workers
199+ % %
200+ {concurrent , 3 },
201+
202+ % %
203+ % % Driver module for the current test
204+ % %
205+ {driver , basho_bench_driver_http_raw },
206+
207+ % %
208+ % % Operations (and associated mix). Note that
209+ % % the driver may not implement every operation.
210+ % %
211+ {operations , [{get , 4 },
212+ {put , 4 },
213+ {delete , 1 }]},
214+
215+ % %
216+ % % Interval on which to report latencies and status (seconds)
217+ % %
218+ {report_interval , 10 },
219+
220+ % %
221+ % % Key generators
222+ % %
223+ % % {uniform_int, N} - Choose a uniformly distributed integer between 0 and N
224+ % %
225+ {key_generator , {uniform_int , 100000 }},
226+
227+ % %
228+ % % Value generators
229+ % %
230+ % % {fixed_bin, N} - Fixed size binary blob of N bytes
231+ % %
232+ {value_generator , {fixed_bin , 100 }}
233+ ]).
234+ -ifdef (TEST ).
235+ load_files_test () ->
236+ % % Extracted from bitcask, and null test.
237+ KVs = [[{mode ,max },
238+ {duration ,1 },
239+ {report_interval ,1 },
240+ {concurrent ,8 },
241+ {driver ,basho_bench_driver_null },
242+ {key_generator ,{partitioned_sequential_int ,5000000 }},
243+ {disable_sequential_int_progress_report ,true },
244+ {value_generator ,{fixed_bin ,10248 }},
245+ {operations ,[{do_something ,7 },{an_error ,1 },{another_error ,2 }]}],
246+ [{mode ,max },
247+ {duration ,10 },
248+ {concurrent ,1 },
249+ {driver ,basho_bench_driver_bitcask },
250+ {key_generator ,{int_to_bin_bigendian ,{uniform_int ,5000000 }}},
251+ {value_generator ,{fixed_bin ,10000 }},
252+ {operations ,[{get ,1 },{put ,1 }]},
253+ {code_paths ,[" ../../public/bitcask" ]},
254+ {bitcask_dir ," /tmp/bitcask.bench" },
255+ {bitcask_flags ,[o_sync ]}]],
256+ KVOrdDict = [{bitcask_dir ," /tmp/bitcask.bench" },
257+ {bitcask_flags ,[o_sync ]},
258+ {code_paths ,[" ../../public/bitcask" ]},
259+ {concurrent ,1 },
260+ {disable_sequential_int_progress_report ,true },
261+ {driver ,basho_bench_driver_bitcask },
262+ {duration ,10 },
263+ {key_generator ,{int_to_bin_bigendian ,{uniform_int ,5000000 }}},
264+ {mode ,max },
265+ {operations ,[{get ,1 },{put ,1 }]},
266+ {report_interval ,1 },
267+ {value_generator ,{fixed_bin ,10000 }}],
268+ ? assertEqual (KVOrdDict , load_termlist (KVs , [])).
269+ -endif .
0 commit comments