<commit_before>%% -------------------------------------------------------------------
%%
%% riak_kv_yessir_backend: simulation backend for Riak
%%
%% Copyright (c) 2012 Basho Technologies, Inc.  All Rights Reserved.
%%
%% 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.
%%
%% -------------------------------------------------------------------

%% @doc riak_kv_yessir_backend is a backend for benchmarking Riak without
%%      any disk I/O or RAM constraints.
%%
%% Riak: "Store this key/value pair."
%% Backend: "Yes, sir!"
%% Riak: "Get me that key/value pair."
%% Backend: "Yes, sir!"
%%
%% This backend uses zero disk resources and uses constant memory.
%%
%% * All put requests are immediately acknowledged 'ok'.  No
%%   data about the put request is stored.
%% * All get requests are fulfilled by creating a constant binary for
%%   the value.  No attempt is made to correlate get keys with
%%   previously-put keys or to correlate get values with previously-put
%%   values.
%%   - Get operation keys that are formatted in with the convention
%%     <<"yessir.{integer}.anything">> will use integer (interpreted in
%%     base 10) as the returned binary's Size.
%%
%% fold_keys and fold_objects are implemented for both sync and async.
%% Each will return the same deterministic set of results for every call,
%% given the same set of configuration parameters. The size of the object
%% folded over is controlled by the "default_size" config var. The number
%% of keys folded over is controlled by the "key_count" config var. Folding
%% over the keys and objects will each return the same set of keys, so if
%% you fold over the keys and collect the list; and then you fold over the
%% objects and collect the list of keys again, the two lists will match.
%%
%% This backend is the Riak storage manager equivalent of:
%%
%% * cat > /dev/null
%% * cat < /dev/zero
%%
%% === Configuration Options ===
%%
%% The following configuration options are available for the yessir backend.
%% The options should be specified in the `yessir_backend' section of your
%% app.config file.
%%
%% <ul>
%% <li>`default_size' - The number of bytes of generated data for the value.</li>
%% <li>`key_count'    - The number of keys that will be folded over, e.g. list_keys().</li>
%% </ul>
%%
%% TODO list:
%%
%% * Add configuration option for random percent of not_found replies for get
%%   - Anything non-zero would trigger read-repair, which could be useful
%%     for some simulations.
%% * Is there a need for simulations for get to return different vclocks?
%% * Add variable latency before responding.  This callback API is
%%   synchronous, but adding constant- & uniform- & pareto-distributed
%%   delays would simulate disk I/O latencies because all other backend
%%   APIs are also synchronous.

-module(riak_kv_yessir_backend).
-behavior(riak_kv_backend).

%% KV Backend API
-export([api_version/0,
         capabilities/1,
         capabilities/2,
         start/2,
         stop/1,
         get/3,
         put/5,
         delete/4,
         drop/1,
         fold_buckets/4,
         fold_keys/4,
         fold_objects/4,
         is_empty/1,
         status/1,
         callback/3]).

-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-endif.

-define(API_VERSION, 1).
-define(CAPABILITIES, [async_fold]).

-record(state, {
          default_get = <<>>,
          default_size = 0,
          key_count = 0,
          op_get = 0,
          op_put = 0,
          op_delete = 0
         }).
-type state() :: #state{}.
-type config() :: [{atom(), term()}].

%% ===================================================================
%% Public API
%% ===================================================================

%% @doc Return the major version of the
%% current API.
-spec api_version() -> {ok, integer()}.
api_version() ->
    {ok, ?API_VERSION}.

%% @doc Return the capabilities of the backend.
-spec capabilities(state()) -> {ok, [atom()]}.
capabilities(_) ->
    {ok, ?CAPABILITIES}.

%% @doc Return the capabilities of the backend.
-spec capabilities(riak_object:bucket(), state()) -> {ok, [atom()]}.
capabilities(_, _) ->
    {ok, ?CAPABILITIES}.

%% @doc Start this backend, yes, sir!
-spec start(integer(), config()) -> {ok, state()} | {error, term()}.
start(_Partition, Config) ->
    DefaultLen = case app_helper:get_prop_or_env(
                        default_size, Config, yessir_backend) of
                     undefined -> 1024;
                     Len       -> Len
                 end,
    KeyCount = case app_helper:get_prop_or_env(
                      key_count, Config, yessir_backend) of
                   undefined -> 1024;
                   Count     -> Count
               end,
    {ok, #state{default_get = <<42:(DefaultLen*8)>>,
                default_size = DefaultLen,
                key_count = KeyCount}}.

%% @doc Stop this backend, yes, sir!
-spec stop(state()) -> ok.
stop(_State) ->
    ok.

%% @doc Get a fake object, yes, sir!
-spec get(riak_object:bucket(), riak_object:key(), state()) ->
                 {ok, any(), state()}.
get(Bucket, Key, #state{op_get = Gets} = S) ->
    Bin = case get_binsize(Key) of
              undefined    -> S#state.default_get;
              N            -> <<42:(N*8)>>
          end,<commit_msg>Change config key names to 'yessir_' prefix, edit EDoc accordingly<commit_after>%% -------------------------------------------------------------------
%%
%% riak_kv_yessir_backend: simulation backend for Riak
%%
%% Copyright (c) 2012 Basho Technologies, Inc.  All Rights Reserved.
%%
%% 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.
%%
%% -------------------------------------------------------------------

%% @doc riak_kv_yessir_backend is a backend for benchmarking Riak without
%%      any disk I/O or RAM constraints.
%%
%% Riak: "Store this key/value pair."
%% Backend: "Yes, sir!"
%% Riak: "Get me that key/value pair."
%% Backend: "Yes, sir!"
%%
%% This backend uses zero disk resources and uses constant memory.
%%
%% * All put requests are immediately acknowledged 'ok'.  No
%%   data about the put request is stored.
%% * All get requests are fulfilled by creating a constant binary for
%%   the value.  No attempt is made to correlate get keys with
%%   previously-put keys or to correlate get values with previously-put
%%   values.
%%   - Get operation keys that are formatted in with the convention
%%     <<"yessir.{integer}.anything">> will use integer (interpreted in
%%     base 10) as the returned binary's Size.
%%
%% fold_keys and fold_objects are implemented for both sync and async.
%% Each will return the same deterministic set of results for every call,
%% given the same set of configuration parameters. The size of the object
%% folded over is controlled by the "default_size" config var. The number
%% of keys folded over is controlled by the "key_count" config var. Folding
%% over the keys and objects will each return the same set of keys, so if
%% you fold over the keys and collect the list; and then you fold over the
%% objects and collect the list of keys again, the two lists will match.
%%
%% This backend is the Riak storage manager equivalent of:
%%
%% * cat > /dev/null
%% * cat < /dev/zero
%%
%% === Configuration Options ===
%%
%% The following configuration options are available for the yessir backend.
%% The options should be specified in the `riak_kv' section of your
%% app.config file.
%%
%% <ul>
%% <li>`yessir_default_size' - The number of bytes of generated data for the value.</li>
%% <li>`yessir_key_count'    - The number of keys that will be folded over, e.g. list_keys().</li>
%% </ul>
%%
%% TODO list:
%%
%% * Add configuration option for random percent of not_found replies for get
%%   - Anything non-zero would trigger read-repair, which could be useful
%%     for some simulations.
%% * Is there a need for simulations for get to return different vclocks?
%% * Add variable latency before responding.  This callback API is
%%   synchronous, but adding constant- & uniform- & pareto-distributed
%%   delays would simulate disk I/O latencies because all other backend
%%   APIs are also synchronous.

-module(riak_kv_yessir_backend).
-behavior(riak_kv_backend).

%% KV Backend API
-export([api_version/0,
         capabilities/1,
         capabilities/2,
         start/2,
         stop/1,
         get/3,
         put/5,
         delete/4,
         drop/1,
         fold_buckets/4,
         fold_keys/4,
         fold_objects/4,
         is_empty/1,
         status/1,
         callback/3]).

-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-endif.

-define(API_VERSION, 1).
-define(CAPABILITIES, [async_fold]).

-record(state, {
          default_get = <<>>,
          default_size = 0,
          key_count = 0,
          op_get = 0,
          op_put = 0,
          op_delete = 0
         }).
-type state() :: #state{}.
-type config() :: [{atom(), term()}].

%% ===================================================================
%% Public API
%% ===================================================================

%% @doc Return the major version of the
%% current API.
-spec api_version() -> {ok, integer()}.
api_version() ->
    {ok, ?API_VERSION}.

%% @doc Return the capabilities of the backend.
-spec capabilities(state()) -> {ok, [atom()]}.
capabilities(_) ->
    {ok, ?CAPABILITIES}.

%% @doc Return the capabilities of the backend.
-spec capabilities(riak_object:bucket(), state()) -> {ok, [atom()]}.
capabilities(_, _) ->
    {ok, ?CAPABILITIES}.

%% @doc Start this backend, yes, sir!
-spec start(integer(), config()) -> {ok, state()} | {error, term()}.
start(_Partition, Config) ->
    DefaultLen = case app_helper:get_prop_or_env(
                        yessir_default_size, Config, yessir_backend) of
                     undefined -> 1024;
                     Len       -> Len
                 end,
    KeyCount = case app_helper:get_prop_or_env(
                      yessir_key_count, Config, yessir_backend) of
                   undefined -> 1024;
                   Count     -> Count
               end,
    {ok, #state{default_get = <<42:(DefaultLen*8)>>,
                default_size = DefaultLen,
                key_count = KeyCount}}.

%% @doc Stop this backend, yes, sir!
-spec stop(state()) -> ok.
stop(_State) ->
    ok.

%% @doc Get a fake object, yes, sir!
-spec get(riak_object:bucket(), riak_object:key(), state()) ->
                 {ok, any(), state()}.
get(Bucket, Key, #state{op_get = Gets} = S) ->
    Bin = case get_binsize(Key) of
              undefined    -> S#state.default_get;
              N            -> <<42:(N*8)>>
          end,
{'fraction_non_alphanumeric': 0.16247863247863248, 'fraction_numerical': 0.007692307692307693, 'mean_word_length': 2.663431433938635, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 69, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6414237', 'n_tokens_mistral': 3362, 'n_tokens_neox': 3243, 'n_words': 1242}