<commit_before>%% -------------------------------------------------------------------
%%
%% Copyright (c) 2007-2010 Basho Technologies, Inc.  All Rights Reserved.
%%
%% -------------------------------------------------------------------

-module(riak_sock_pool).

-behaviour(gen_server).

%% API
-export([start_link/3, checkout/1, checkin/2, current_count/1]).

%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
         terminate/2, code_change/3]).
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-export([new_conn/0]). % for unit testing
-endif.

%% wait up to 250ms before trying to checkout a connection again
-define(MAX_RETRY_WAIT, 250).

-record(state,
        {
          pool=[],          %% available connections
          openmod,          %% module to use to start connections
          closemod,         %% module to use to close connections
          countfun,         %% how many connections to start
          initialized=false %% have any conns been inited?
         }).

%% thanks to <NAME> for the idea
-record('DOWN',
	{
	  ref,   %% monitor reference
	  type,  %% type of object 'process'
	  id,    %% object id (pid)
	  reason %% reason for termination
	 }).

%% @spec start_link(atom(), {Open::atom(), Close::atom()}, function())
%%          -> {ok,Pid} | ignore | {error,Error}
%% @doc Start a new connection pool.
%%
%%      Name is the atom under which the pool will be registered.
%%
%%      Open should be the name of a module that exports a zero-arity
%%      function named 'new_conn', that returns {ok, pid()} after
%%      successfully starting a new connection.  Open:new_conn/0 will
%%      be called at least CountFun() times, plus as many times as
%%      necessary to replace connections that have failed.
%%
%%      Close should be the name of a module that exports an arity-one
%%      function named 'close', that takes a pid() (as returned from
%%      Open:new_conn/0) as its parameter, and closes the connection.
%%
%%      CountFun should be a zero-arity function that returns an
%%      integer, specifying the number of connections to keep alive.
start_link(Name, ConnMod={_,_}, CountFun) ->
    gen_server:start_link({local, Name}, ?MODULE,
                          [ConnMod, CountFun], []).

%% @spec checkout(atom()) -> {ok, pid()}
%% @doc Checkout a connection from the pool.  If no connections are
%%      available when this function is called, it will wait and try
%%      again until one is available.  This function does not return
%%      until either a connection is successfully checked out, or the
%%      gen_server for the pool dies.
checkout(Name) ->
    case gen_server:call(Name, checkout, infinity) of
        empty_pool ->
            timer:sleep(random:uniform(?MAX_RETRY_WAIT)),
            checkout(Name);
        R ->
            R
    end.

%% @spec checkin(atom(), pid()) -> ok
%% @doc Check a connection back into the pool.
checkin(Name, Conn) ->
    gen_server:cast(Name, {checkin, Conn}).

%% @spec current_count(atom()) -> integer()
%% @doc Get the number of connections currently available to be
%%      checked out
current_count(Name) ->
    gen_server:call(Name, current_count, infinity).

init([{OpenMod, CloseMod}, CountFun]) ->
    {ok, #state{countfun=CountFun, openmod=OpenMod, closemod=CloseMod}}.

handle_call(checkout, _From,
            #state{initialized=false,
                   countfun=CountFun,
                   openmod=ConnMod
                  }=State) ->
    %% we've never started any connections - fire them all up
    Conns = CountFun(),
    [H|T] = add_to_pool(ConnMod, Conns),
    {reply, {ok, H}, State#state{pool=T, initialized=true}};
handle_call(checkout, _From, #state{pool=[]}=State) ->
    %% nothing available for checkout right now
    {reply, empty_pool, State};
handle_call(checkout, _From, #state{pool=[H|T]}=State) ->
    %% simple: hand back the available connection
    {reply, {ok, H}, State#state{pool=T}};
handle_call(current_count, _From, #state{pool=Pool}=State) ->
    %% grab the number of connections available for checkout
    {reply, length(Pool), State};
handle_call(_Request, _From, State) ->
    {reply, ignore, State}.

handle_cast({checkin, Conn}, #state{pool=Pool}=State) ->
    case is_process_alive(Conn) of
        true ->
            {noreply, State#state{pool=Pool ++ [Conn]}};
        false ->
            %% process death will have triggered handle_info(#'DOWN'{})
            {noreply, State}
    end;
handle_cast(_Msg, State) ->
    {noreply, State}.

handle_info(#'DOWN'{id=DownPid},
            #state{openmod=ConnMod, pool=Pool}=State) ->
    %% Create a new pid to replace the downed one
    Pool1 = lists:delete(DownPid, Pool) ++ [init_conn(ConnMod)],
    {noreply, State#state{pool=Pool1}};<commit_msg>separate initialization and checkout logic<commit_after>%% -------------------------------------------------------------------
%%
%% Copyright (c) 2007-2010 Basho Technologies, Inc.  All Rights Reserved.
%%
%% -------------------------------------------------------------------

-module(riak_sock_pool).

-behaviour(gen_server).

%% API
-export([start_link/3, checkout/1, checkin/2, current_count/1]).

%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
         terminate/2, code_change/3]).
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-export([new_conn/0]). % for unit testing
-endif.

%% wait up to 250ms before trying to checkout a connection again
-define(MAX_RETRY_WAIT, 250).

-record(state,
        {
          pool=[],          %% available connections
          openmod,          %% module to use to start connections
          closemod,         %% module to use to close connections
          countfun,         %% how many connections to start
          initialized=false %% have any conns been inited?
         }).

%% thanks to <NAME> for the idea
-record('DOWN',
	{
	  ref,   %% monitor reference
	  type,  %% type of object 'process'
	  id,    %% object id (pid)
	  reason %% reason for termination
	 }).

%% @spec start_link(atom(), {Open::atom(), Close::atom()}, function())
%%          -> {ok,Pid} | ignore | {error,Error}
%% @doc Start a new connection pool.
%%
%%      Name is the atom under which the pool will be registered.
%%
%%      Open should be the name of a module that exports a zero-arity
%%      function named 'new_conn', that returns {ok, pid()} after
%%      successfully starting a new connection.  Open:new_conn/0 will
%%      be called at least CountFun() times, plus as many times as
%%      necessary to replace connections that have failed.
%%
%%      Close should be the name of a module that exports an arity-one
%%      function named 'close', that takes a pid() (as returned from
%%      Open:new_conn/0) as its parameter, and closes the connection.
%%
%%      CountFun should be a zero-arity function that returns an
%%      integer, specifying the number of connections to keep alive.
start_link(Name, ConnMod={_,_}, CountFun) ->
    gen_server:start_link({local, Name}, ?MODULE,
                          [ConnMod, CountFun], []).

%% @spec checkout(atom()) -> {ok, pid()}
%% @doc Checkout a connection from the pool.  If no connections are
%%      available when this function is called, it will wait and try
%%      again until one is available.  This function does not return
%%      until either a connection is successfully checked out, or the
%%      gen_server for the pool dies.
checkout(Name) ->
    case gen_server:call(Name, checkout, infinity) of
        empty_pool ->
            timer:sleep(random:uniform(?MAX_RETRY_WAIT)),
            checkout(Name);
        R ->
            R
    end.

%% @spec checkin(atom(), pid()) -> ok
%% @doc Check a connection back into the pool.
checkin(Name, Conn) ->
    gen_server:cast(Name, {checkin, Conn}).

%% @spec current_count(atom()) -> integer()
%% @doc Get the number of connections currently available to be
%%      checked out
current_count(Name) ->
    gen_server:call(Name, current_count, infinity).

init([{OpenMod, CloseMod}, CountFun]) ->
    {ok, #state{countfun=CountFun, openmod=OpenMod, closemod=CloseMod}}.

handle_call(checkout, From,
            #state{initialized=false,
                   countfun=CountFun,
                   openmod=ConnMod
                  }=State) ->
    %% we've never started any connections - fire them all up
    Conns = CountFun(),
    Pool = add_to_pool(ConnMod, Conns),
    handle_call(checkout, From, State#state{initialized=true, pool=Pool});
handle_call(checkout, _From, #state{pool=[]}=State) ->
    %% nothing available for checkout right now
    {reply, empty_pool, State};
handle_call(checkout, _From, #state{pool=[H|T]}=State) ->
    %% simple: hand back the available connection
    {reply, {ok, H}, State#state{pool=T}};
handle_call(current_count, _From, #state{pool=Pool}=State) ->
    %% grab the number of connections available for checkout
    {reply, length(Pool), State};
handle_call(_Request, _From, State) ->
    {reply, ignore, State}.

handle_cast({checkin, Conn}, #state{pool=Pool}=State) ->
    case is_process_alive(Conn) of
        true ->
            {noreply, State#state{pool=Pool ++ [Conn]}};
        false ->
            %% process death will have triggered handle_info(#'DOWN'{})
            {noreply, State}
    end;
handle_cast(_Msg, State) ->
    {noreply, State}.

handle_info(#'DOWN'{id=DownPid},
            #state{openmod=ConnMod, pool=Pool}=State) ->
    %% Create a new pid to replace the downed one
    Pool1 = lists:delete(DownPid, Pool) ++ [init_conn(ConnMod)],
    {noreply, State#state{pool=Pool1}};
{'fraction_non_alphanumeric': 0.15609756097560976, 'fraction_numerical': 0.006019719771665801, 'mean_word_length': 2.7348837209302324, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 47, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '7381558', 'n_tokens_mistral': 2898, 'n_tokens_neox': 2768, 'n_words': 886}