<commit_before>% Copyright 2010 Cloudant
%
% 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(fabric_db_create).
-export([go/2]).

-include("fabric.hrl").
-include_lib("mem3/include/mem3.hrl").
-include_lib("couch/include/couch_db.hrl").

-define(DBNAME_REGEX, "^[a-z][a-z0-9\\_\\$()\\+\\-\\/]*$").

%% @doc Create a new database, and all its partition files across the cluster
%%      Options is proplist with user_ctx, n, q, validate_name
go(DbName, Options) ->
    case validate_dbname(DbName, Options) of
    ok ->
        {Shards, Doc} = generate_shard_map(DbName, Options),
        case {create_shard_files(Shards), create_shard_db_doc(Doc)} of
        {ok, {ok, Status}} ->
            Status;
        {file_exists, {ok, _}} ->
            {error, file_exists};
        {_, Error} ->
            Error
        end;
    Error ->
        Error
    end.

validate_dbname(DbName, Options) ->
    case couch_util:get_value(validate_name, Options, true) of
    false ->
        ok;
    true ->
        case re:run(DbName, ?DBNAME_REGEX, [{capture,none}]) of
        match ->
            ok;
        nomatch when DbName =:= <<"_users">> ->
            ok;
        nomatch when DbName =:= <<"_replicator">> ->
            ok;
        nomatch ->
            {error, illegal_database_name}
        end
    end.

generate_shard_map(DbName, Options) ->
    {MegaSecs, Secs, _} = now(),
    Suffix = "." ++ integer_to_list(MegaSecs*1000000 + Secs),
    Shards = mem3:choose_shards(DbName, [{shard_suffix,Suffix} | Options]),
    case mem3_util:open_db_doc(DbName) of
    {ok, Doc} ->
        % the DB already exists, and may have a different Suffix
        ok;
    {not_found, _} ->
        Doc = make_document(Shards, Suffix)
    end,
    {Shards, Doc}.

create_shard_files(Shards) ->
    Workers = fabric_util:submit_jobs(Shards, create_db, []),
    RexiMon = fabric_util:create_monitors(Shards),
    try fabric_util:recv(Workers, #shard.ref, fun handle_message/3, Workers) of
    {error, file_exists} ->
        file_exists;
    _ ->
        ok
    after
        rexi_monitor:stop(RexiMon)
    end.

handle_message(file_exists, _, _) ->
    {error, file_exists};

handle_message({rexi_DOWN, _, {_, Node}, _}, _, Workers) ->
    case lists:filter(fun(S, _) -> S#shard.node =/= Node end, Workers) of
    [] ->
        {stop, ok};
    RemainingWorkers ->
        {ok, RemainingWorkers}
    end;

handle_message(_, Worker, Workers) ->
    case lists:delete(Worker, Workers) of
    [] ->
        {stop, ok};
    RemainingWorkers ->
        {ok, RemainingWorkers}
    end.<commit_msg>Fix invocation of lists:filter<commit_after>% Copyright 2010 Cloudant
%
% 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(fabric_db_create).
-export([go/2]).

-include("fabric.hrl").
-include_lib("mem3/include/mem3.hrl").
-include_lib("couch/include/couch_db.hrl").

-define(DBNAME_REGEX, "^[a-z][a-z0-9\\_\\$()\\+\\-\\/]*$").

%% @doc Create a new database, and all its partition files across the cluster
%%      Options is proplist with user_ctx, n, q, validate_name
go(DbName, Options) ->
    case validate_dbname(DbName, Options) of
    ok ->
        {Shards, Doc} = generate_shard_map(DbName, Options),
        case {create_shard_files(Shards), create_shard_db_doc(Doc)} of
        {ok, {ok, Status}} ->
            Status;
        {file_exists, {ok, _}} ->
            {error, file_exists};
        {_, Error} ->
            Error
        end;
    Error ->
        Error
    end.

validate_dbname(DbName, Options) ->
    case couch_util:get_value(validate_name, Options, true) of
    false ->
        ok;
    true ->
        case re:run(DbName, ?DBNAME_REGEX, [{capture,none}]) of
        match ->
            ok;
        nomatch when DbName =:= <<"_users">> ->
            ok;
        nomatch when DbName =:= <<"_replicator">> ->
            ok;
        nomatch ->
            {error, illegal_database_name}
        end
    end.

generate_shard_map(DbName, Options) ->
    {MegaSecs, Secs, _} = now(),
    Suffix = "." ++ integer_to_list(MegaSecs*1000000 + Secs),
    Shards = mem3:choose_shards(DbName, [{shard_suffix,Suffix} | Options]),
    case mem3_util:open_db_doc(DbName) of
    {ok, Doc} ->
        % the DB already exists, and may have a different Suffix
        ok;
    {not_found, _} ->
        Doc = make_document(Shards, Suffix)
    end,
    {Shards, Doc}.

create_shard_files(Shards) ->
    Workers = fabric_util:submit_jobs(Shards, create_db, []),
    RexiMon = fabric_util:create_monitors(Shards),
    try fabric_util:recv(Workers, #shard.ref, fun handle_message/3, Workers) of
    {error, file_exists} ->
        file_exists;
    _ ->
        ok
    after
        rexi_monitor:stop(RexiMon)
    end.

handle_message(file_exists, _, _) ->
    {error, file_exists};

handle_message({rexi_DOWN, _, {_, Node}, _}, _, Workers) ->
    case lists:filter(fun(S) -> S#shard.node =/= Node end, Workers) of
    [] ->
        {stop, ok};
    RemainingWorkers ->
        {ok, RemainingWorkers}
    end;

handle_message(_, Worker, Workers) ->
    case lists:delete(Worker, Workers) of
    [] ->
        {stop, ok};
    RemainingWorkers ->
        {ok, RemainingWorkers}
    end.
{'fraction_non_alphanumeric': 0.13238157040882545, 'fraction_numerical': 0.007462686567164179, 'mean_word_length': 2.693828639904134, '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': '4478592', 'n_tokens_mistral': 2084, 'n_tokens_neox': 2022, 'n_words': 518}