<commit_before>%   Copyright 2007, 2008 <NAME> <<EMAIL>>
%
%   Licensed 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(couch_view).
-behaviour(gen_server).

-export([start_link/1,fold/4,fold/5,less_json/2, start_update_loop/3, start_temp_update_loop/5]).
-export([init/1,terminate/2,handle_call/3,handle_cast/2,handle_info/2,code_change/3]).
-export([get_reduce_view/1, get_map_view/1,get_row_count/1,reduce_to_count/1, reduce/3]).

-include("couch_db.hrl").

-record(group,
    {db,
    fd,
    name,
    def_lang,
    views,
    reductions=[], % list of reduction names and id_num of view that contains it.
    id_btree=nil,
    current_seq=0,
    query_server=nil
    }).

-record(view,
    {id_num,
    map_names=[],
    def,
    btree=nil,
    reduce_funs=[]
    }).

-record(server,
    {root_dir
    }).

start_link(RootDir) ->
    gen_server:start_link({local, couch_view}, couch_view, RootDir, []).



get_temp_updater(DbName, Type, MapSrc, RedSrc) ->
    {ok, Pid} = gen_server:call(couch_view, {start_temp_updater, DbName, Type, MapSrc, RedSrc}),
    Pid.

get_updater(DbName, GroupId) ->
    {ok, Pid} = gen_server:call(couch_view, {start_updater, DbName, GroupId}),
    Pid.
    
get_updated_group(Pid) ->
	Mref = erlang:monitor(process, Pid),
    receive
	{'DOWN', Mref, _, _, Reason} ->
	    throw(Reason)
    after 0 ->
	    Pid ! {self(), get_updated},
	    receive
    	{Pid, Response} ->
    	    erlang:demonitor(Mref),
    	    receive
        		{'DOWN', Mref, _, _, _} -> ok
        	    after 0 -> ok
    	    end,
    	    Response;
    	{'DOWN', Mref, _, _, Reason} ->
    	    throw(Reason)
        end
    end.

get_row_count(#view{btree=Bt}) ->
    {ok, Reds} = couch_btree:partial_reduce(Bt, nil, nil),
    {ok, reduce_to_count(Reds)}.

get_reduce_view({temp, DbName, Type, MapSrc, RedSrc}) ->
    {ok, #group{views=[View]}} = get_updated_group(get_temp_updater(DbName, Type, MapSrc, RedSrc)),
    {ok, {temp_reduce, View}};
get_reduce_view({DbName, GroupId, Name}) ->
    {ok, #group{views=Views,def_lang=Lang}} =
            get_updated_group(get_updater(DbName, GroupId)),
    get_reduce_view0(Name, Lang, Views).

get_reduce_view0(_Name, _Lang, []) ->
    {not_found, missing_named_view};
get_reduce_view0(Name, Lang, [#view{reduce_funs=RedFuns}=View|Rest]) ->
    case get_key_pos(Name, RedFuns, 0) of
        0 -> get_reduce_view0(Name, Lang, Rest);
        N -> {ok, {reduce, N, Lang, View}}
    end.

reduce({temp_reduce, #view{btree=Bt}}, Key1, Key2) ->
    {ok, {_Count, [Reduction]}} = couch_btree:reduce(Bt, Key1, Key2),
    {ok, Reduction};

reduce({reduce, NthRed, Lang, #view{btree=Bt, reduce_funs=RedFuns}}, Key1, Key2) ->
    {ok, PartialReductions} = couch_btree:partial_reduce(Bt, Key1, Key2),
    PreResultPadding = lists:duplicate(NthRed - 1, []),
    PostResultPadding = lists:duplicate(length(RedFuns) - NthRed, []),
    {_Name, FunSrc} = lists:nth(NthRed,RedFuns),
    ReduceFun = 
        fun(reduce, KVs) ->
            {ok, Reduced} = couch_query_servers:reduce(Lang, [FunSrc], KVs),
            {0, PreResultPadding ++ Reduced ++ PostResultPadding};
        (combine, Reds) ->
            UserReds = [[lists:nth(NthRed, UserRedsList)] || {_, UserRedsList} <- Reds],
            {ok, Reduced} = couch_query_servers:combine(Lang, [FunSrc], UserReds),
            {0, PreResultPadding ++ Reduced ++ PostResultPadding}
        end,
    {0, [FinalReduction]} = couch_btree:final_reduce(ReduceFun, PartialReductions),
    {ok, FinalReduction}.
        
get_key_pos(_Key, [], _N) ->
    0;
get_key_pos(Key, [{Key1,_Value}|_], N) when Key == Key1 ->
    N + 1;
get_key_pos(Key, [_|Rest], N) ->
    get_key_pos(Key, Rest, N+1).
        
get_map_view({temp, DbName, Type, Src}) ->
    {ok, #group{views=[View]}} = get_updated_group(get_temp_updater(DbName, Type, Src, [])),
    {ok, View};
get_map_view({DbName, GroupId, Name}) ->
    {ok, #group{views=Views}} = get_updated_group(get_updater(DbName, GroupId)),
    get_map_view0(Name, Views).

get_map_view0(_Name, []) ->
    {not_found, missing_named_view};
get_map_view0(Name, [#view{map_names=MapNames}=View|Rest]) -><commit_msg>Fix for pattern matching bug during reduce<commit_after>%   Copyright 2007, 2008 <NAME> <<EMAIL>>
%
%   Licensed 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(couch_view).
-behaviour(gen_server).

-export([start_link/1,fold/4,fold/5,less_json/2, start_update_loop/3, start_temp_update_loop/5]).
-export([init/1,terminate/2,handle_call/3,handle_cast/2,handle_info/2,code_change/3]).
-export([get_reduce_view/1, get_map_view/1,get_row_count/1,reduce_to_count/1, reduce/3]).

-include("couch_db.hrl").

-record(group,
    {db,
    fd,
    name,
    def_lang,
    views,
    reductions=[], % list of reduction names and id_num of view that contains it.
    id_btree=nil,
    current_seq=0,
    query_server=nil
    }).

-record(view,
    {id_num,
    map_names=[],
    def,
    btree=nil,
    reduce_funs=[]
    }).

-record(server,
    {root_dir
    }).

start_link(RootDir) ->
    gen_server:start_link({local, couch_view}, couch_view, RootDir, []).



get_temp_updater(DbName, Type, MapSrc, RedSrc) ->
    {ok, Pid} = gen_server:call(couch_view, {start_temp_updater, DbName, Type, MapSrc, RedSrc}),
    Pid.

get_updater(DbName, GroupId) ->
    {ok, Pid} = gen_server:call(couch_view, {start_updater, DbName, GroupId}),
    Pid.
    
get_updated_group(Pid) ->
	Mref = erlang:monitor(process, Pid),
    receive
	{'DOWN', Mref, _, _, Reason} ->
	    throw(Reason)
    after 0 ->
	    Pid ! {self(), get_updated},
	    receive
    	{Pid, Response} ->
    	    erlang:demonitor(Mref),
    	    receive
        		{'DOWN', Mref, _, _, _} -> ok
        	    after 0 -> ok
    	    end,
    	    Response;
    	{'DOWN', Mref, _, _, Reason} ->
    	    throw(Reason)
        end
    end.

get_row_count(#view{btree=Bt}) ->
    {ok, Reds} = couch_btree:partial_reduce(Bt, nil, nil),
    {ok, reduce_to_count(Reds)}.

get_reduce_view({temp, DbName, Type, MapSrc, RedSrc}) ->
    {ok, #group{views=[View]}} = get_updated_group(get_temp_updater(DbName, Type, MapSrc, RedSrc)),
    {ok, {temp_reduce, View}};
get_reduce_view({DbName, GroupId, Name}) ->
    {ok, #group{views=Views,def_lang=Lang}} =
            get_updated_group(get_updater(DbName, GroupId)),
    get_reduce_view0(Name, Lang, Views).

get_reduce_view0(_Name, _Lang, []) ->
    {not_found, missing_named_view};
get_reduce_view0(Name, Lang, [#view{reduce_funs=RedFuns}=View|Rest]) ->
    case get_key_pos(Name, RedFuns, 0) of
        0 -> get_reduce_view0(Name, Lang, Rest);
        N -> {ok, {reduce, N, Lang, View}}
    end.

reduce({temp_reduce, #view{btree=Bt}}, Key1, Key2) ->
    {ok, {_Count, [Reduction]}} = couch_btree:reduce(Bt, Key1, Key2),
    {ok, Reduction};

reduce({reduce, NthRed, Lang, #view{btree=Bt, reduce_funs=RedFuns}}, Key1, Key2) ->
    {ok, PartialReductions} = couch_btree:partial_reduce(Bt, Key1, Key2),
    PreResultPadding = lists:duplicate(NthRed - 1, []),
    PostResultPadding = lists:duplicate(length(RedFuns) - NthRed, []),
    {_Name, FunSrc} = lists:nth(NthRed,RedFuns),
    ReduceFun = 
        fun(reduce, KVs) ->
            {ok, Reduced} = couch_query_servers:reduce(Lang, [FunSrc], KVs),
            {0, PreResultPadding ++ Reduced ++ PostResultPadding};
        (combine, Reds) ->
            UserReds = [[lists:nth(NthRed, UserRedsList)] || {_, UserRedsList} <- Reds],
            {ok, Reduced} = couch_query_servers:combine(Lang, [FunSrc], UserReds),
            {0, PreResultPadding ++ Reduced ++ PostResultPadding}
        end,
    {_, [FinalReduction]} = couch_btree:final_reduce(ReduceFun, PartialReductions),
    {ok, FinalReduction}.
        
get_key_pos(_Key, [], _N) ->
    0;
get_key_pos(Key, [{Key1,_Value}|_], N) when Key == Key1 ->
    N + 1;
get_key_pos(Key, [_|Rest], N) ->
    get_key_pos(Key, Rest, N+1).
        
get_map_view({temp, DbName, Type, Src}) ->
    {ok, #group{views=[View]}} = get_updated_group(get_temp_updater(DbName, Type, Src, [])),
    {ok, View};
get_map_view({DbName, GroupId, Name}) ->
    {ok, #group{views=Views}} = get_updated_group(get_updater(DbName, GroupId)),
    get_map_view0(Name, Views).

get_map_view0(_Name, []) ->
    {not_found, missing_named_view};
get_map_view0(Name, [#view{map_names=MapNames}=View|Rest]) ->
{'fraction_non_alphanumeric': 0.1533669852862206, 'fraction_numerical': 0.012350982708624208, 'mean_word_length': 3.5804230201672405, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 65, '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': '90964', 'n_tokens_mistral': 3512, 'n_tokens_neox': 3461, 'n_words': 701}