refactor(ds): Extract DS replication layer to a separate application
This commit is contained in:
parent
63f1856a2c
commit
a8ea0ae4e5
|
@ -0,0 +1,94 @@
|
||||||
|
Business Source License 1.1
|
||||||
|
|
||||||
|
Licensor: Hangzhou EMQ Technologies Co., Ltd.
|
||||||
|
Licensed Work: EMQX Enterprise Edition
|
||||||
|
The Licensed Work is (c) 2024
|
||||||
|
Hangzhou EMQ Technologies Co., Ltd.
|
||||||
|
Additional Use Grant: Students and educators are granted right to copy,
|
||||||
|
modify, and create derivative work for research
|
||||||
|
or education.
|
||||||
|
Change Date: 2028-06-13
|
||||||
|
Change License: Apache License, Version 2.0
|
||||||
|
|
||||||
|
For information about alternative licensing arrangements for the Software,
|
||||||
|
please contact Licensor: https://www.emqx.com/en/contact
|
||||||
|
|
||||||
|
Notice
|
||||||
|
|
||||||
|
The Business Source License (this document, or the “License”) is not an Open
|
||||||
|
Source license. However, the Licensed Work will eventually be made available
|
||||||
|
under an Open Source License, as stated in this License.
|
||||||
|
|
||||||
|
License text copyright (c) 2017, 2024 MariaDB Corporation Ab, All Rights Reserved.
|
||||||
|
“Business Source License” is a trademark of MariaDB Corporation Ab.
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Business Source License 1.1
|
||||||
|
|
||||||
|
Terms
|
||||||
|
|
||||||
|
The Licensor hereby grants you the right to copy, modify, create derivative
|
||||||
|
works, redistribute, and make non-production use of the Licensed Work. The
|
||||||
|
Licensor may make an Additional Use Grant, above, permitting limited
|
||||||
|
production use.
|
||||||
|
|
||||||
|
Effective on the Change Date, or the fourth anniversary of the first publicly
|
||||||
|
available distribution of a specific version of the Licensed Work under this
|
||||||
|
License, whichever comes first, the Licensor hereby grants you rights under
|
||||||
|
the terms of the Change License, and the rights granted in the paragraph
|
||||||
|
above terminate.
|
||||||
|
|
||||||
|
If your use of the Licensed Work does not comply with the requirements
|
||||||
|
currently in effect as described in this License, you must purchase a
|
||||||
|
commercial license from the Licensor, its affiliated entities, or authorized
|
||||||
|
resellers, or you must refrain from using the Licensed Work.
|
||||||
|
|
||||||
|
All copies of the original and modified Licensed Work, and derivative works
|
||||||
|
of the Licensed Work, are subject to this License. This License applies
|
||||||
|
separately for each version of the Licensed Work and the Change Date may vary
|
||||||
|
for each version of the Licensed Work released by Licensor.
|
||||||
|
|
||||||
|
You must conspicuously display this License on each original or modified copy
|
||||||
|
of the Licensed Work. If you receive the Licensed Work in original or
|
||||||
|
modified form from a third party, the terms and conditions set forth in this
|
||||||
|
License apply to your use of that work.
|
||||||
|
|
||||||
|
Any use of the Licensed Work in violation of this License will automatically
|
||||||
|
terminate your rights under this License for the current and all other
|
||||||
|
versions of the Licensed Work.
|
||||||
|
|
||||||
|
This License does not grant you any right in any trademark or logo of
|
||||||
|
Licensor or its affiliates (provided that you may use a trademark or logo of
|
||||||
|
Licensor as expressly required by this License).
|
||||||
|
|
||||||
|
TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
|
||||||
|
AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
|
||||||
|
TITLE.
|
||||||
|
|
||||||
|
MariaDB hereby grants you permission to use this License’s text to license
|
||||||
|
your works, and to refer to it using the trademark “Business Source License”,
|
||||||
|
as long as you comply with the Covenants of Licensor below.
|
||||||
|
|
||||||
|
Covenants of Licensor
|
||||||
|
|
||||||
|
In consideration of the right to use this License’s text and the “Business
|
||||||
|
Source License” name and trademark, Licensor covenants to MariaDB, and to all
|
||||||
|
other recipients of the licensed work to be provided by Licensor:
|
||||||
|
|
||||||
|
1. To specify as the Change License the GPL Version 2.0 or any later version,
|
||||||
|
or a license that is compatible with GPL Version 2.0 or a later version,
|
||||||
|
where “compatible” means that software provided under the Change License can
|
||||||
|
be included in a program with software provided under GPL Version 2.0 or a
|
||||||
|
later version. Licensor may specify additional Change Licenses without
|
||||||
|
limitation.
|
||||||
|
|
||||||
|
2. To either: (a) specify an additional grant of rights to use that does not
|
||||||
|
impose any additional restriction on the right granted in this License, as
|
||||||
|
the Additional Use Grant; or (b) insert the text “None”.
|
||||||
|
|
||||||
|
3. To specify a Change Date.
|
||||||
|
|
||||||
|
4. Not to modify this License in any other way.
|
|
@ -0,0 +1,3 @@
|
||||||
|
# `emqx_ds_builtin_raft`
|
||||||
|
|
||||||
|
Replication layer for the builtin EMQX durable storage backend that uses Raft algorithm.
|
|
@ -0,0 +1,5 @@
|
||||||
|
%% -*- mode:erlang -*-
|
||||||
|
|
||||||
|
{deps, [
|
||||||
|
{emqx_durable_storage, {path, "../emqx_durable_storage"}}
|
||||||
|
]}.
|
|
@ -0,0 +1,11 @@
|
||||||
|
%% -*- mode: erlang -*-
|
||||||
|
{application, emqx_ds_builtin_raft, [
|
||||||
|
{description, "Raft replication layer for the durable storage"},
|
||||||
|
% strict semver, bump manually!
|
||||||
|
{vsn, "0.1.0"},
|
||||||
|
{modules, []},
|
||||||
|
{registered, []},
|
||||||
|
{applications, [kernel, stdlib, gproc, mria, ra, emqx_durable_storage]},
|
||||||
|
{mod, {emqx_ds_builtin_raft_app, []}},
|
||||||
|
{env, []}
|
||||||
|
]}.
|
|
@ -0,0 +1,11 @@
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% Copyright (c) 2020-2024 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
|
-module(emqx_ds_builtin_raft_app).
|
||||||
|
|
||||||
|
-export([start/2]).
|
||||||
|
|
||||||
|
start(_Type, _Args) ->
|
||||||
|
emqx_ds:register_backend(builtin_raft, emqx_ds_replication_layer),
|
||||||
|
{ok, self()}.
|
|
@ -1,22 +1,10 @@
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Copyright (c) 2024 EMQ Technologies Co., Ltd. All Rights Reserved.
|
%% Copyright (c) 2024 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||||
%%
|
|
||||||
%% 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.
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
%% @doc Supervisor that contains all the processes that belong to a
|
%% @doc Supervisor that contains all the processes that belong to a
|
||||||
%% given builtin DS database.
|
%% given builtin DS database.
|
||||||
-module(emqx_ds_builtin_db_sup).
|
-module(emqx_ds_builtin_raft_db_sup).
|
||||||
|
|
||||||
-behaviour(supervisor).
|
-behaviour(supervisor).
|
||||||
|
|
||||||
|
@ -150,7 +138,7 @@ get_shard_workers(DB) ->
|
||||||
init({#?db_sup{db = DB}, DefaultOpts}) ->
|
init({#?db_sup{db = DB}, DefaultOpts}) ->
|
||||||
%% Spec for the top-level supervisor for the database:
|
%% Spec for the top-level supervisor for the database:
|
||||||
logger:notice("Starting DS DB ~p", [DB]),
|
logger:notice("Starting DS DB ~p", [DB]),
|
||||||
emqx_ds_builtin_sup:clean_gvars(DB),
|
emqx_ds_builtin_raft_sup:clean_gvars(DB),
|
||||||
emqx_ds_builtin_metrics:init_for_db(DB),
|
emqx_ds_builtin_metrics:init_for_db(DB),
|
||||||
Opts = emqx_ds_replication_layer_meta:open_db(DB, DefaultOpts),
|
Opts = emqx_ds_replication_layer_meta:open_db(DB, DefaultOpts),
|
||||||
ok = start_ra_system(DB, Opts),
|
ok = start_ra_system(DB, Opts),
|
||||||
|
@ -197,7 +185,7 @@ init({#?shard_sup{db = DB, shard = Shard}, _}) ->
|
||||||
{ok, {SupFlags, Children}}.
|
{ok, {SupFlags, Children}}.
|
||||||
|
|
||||||
start_ra_system(DB, #{replication_options := ReplicationOpts}) ->
|
start_ra_system(DB, #{replication_options := ReplicationOpts}) ->
|
||||||
DataDir = filename:join([emqx_ds:base_dir(), DB, dsrepl]),
|
DataDir = filename:join([emqx_ds_storage_layer:base_dir(), DB, dsrepl]),
|
||||||
Config = lists:foldr(fun maps:merge/2, #{}, [
|
Config = lists:foldr(fun maps:merge/2, #{}, [
|
||||||
ra_system:default_config(),
|
ra_system:default_config(),
|
||||||
#{
|
#{
|
|
@ -1,23 +1,11 @@
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Copyright (c) 2023-2024 EMQ Technologies Co., Ltd. All Rights Reserved.
|
%% Copyright (c) 2023-2024 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||||
%%
|
|
||||||
%% 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.
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
%% @doc This supervisor manages the global worker processes needed for
|
%% @doc This supervisor manages the global worker processes needed for
|
||||||
%% the functioning of builtin databases, and all builtin database
|
%% the functioning of builtin databases, and all builtin database
|
||||||
%% attach to it.
|
%% attach to it.
|
||||||
-module(emqx_ds_builtin_sup).
|
-module(emqx_ds_builtin_raft_sup).
|
||||||
|
|
||||||
-behaviour(supervisor).
|
-behaviour(supervisor).
|
||||||
|
|
||||||
|
@ -39,7 +27,6 @@
|
||||||
|
|
||||||
-define(top, ?MODULE).
|
-define(top, ?MODULE).
|
||||||
-define(databases, emqx_ds_builtin_databases_sup).
|
-define(databases, emqx_ds_builtin_databases_sup).
|
||||||
|
|
||||||
-define(gvar_tab, emqx_ds_builtin_gvar).
|
-define(gvar_tab, emqx_ds_builtin_gvar).
|
||||||
|
|
||||||
-record(gvar, {
|
-record(gvar, {
|
||||||
|
@ -57,7 +44,7 @@ start_db(DB, Opts) ->
|
||||||
ensure_top(),
|
ensure_top(),
|
||||||
ChildSpec = #{
|
ChildSpec = #{
|
||||||
id => DB,
|
id => DB,
|
||||||
start => {emqx_ds_builtin_db_sup, start_db, [DB, Opts]},
|
start => {emqx_ds_builtin_raft_db_sup, start_db, [DB, Opts]},
|
||||||
type => supervisor,
|
type => supervisor,
|
||||||
shutdown => infinity
|
shutdown => infinity
|
||||||
},
|
},
|
||||||
|
@ -158,5 +145,5 @@ start_databases_sup() ->
|
||||||
%%================================================================================
|
%%================================================================================
|
||||||
|
|
||||||
ensure_top() ->
|
ensure_top() ->
|
||||||
{ok, _} = emqx_ds_sup:attach_backend(builtin, {?MODULE, start_top, []}),
|
{ok, _} = emqx_ds_sup:attach_backend(builtin_raft, {?MODULE, start_top, []}),
|
||||||
ok.
|
ok.
|
|
@ -1,28 +1,17 @@
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Copyright (c) 2023-2024 EMQ Technologies Co., Ltd. All Rights Reserved.
|
%% Copyright (c) 2023-2024 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||||
%%
|
|
||||||
%% 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.
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
%% @doc Replication layer for DS backends that don't support
|
%% @doc Replication layer for DS backends that don't support
|
||||||
%% replication on their own.
|
%% replication on their own.
|
||||||
-module(emqx_ds_replication_layer).
|
-module(emqx_ds_replication_layer).
|
||||||
|
|
||||||
-behaviour(emqx_ds).
|
%-behaviour(emqx_ds).
|
||||||
|
|
||||||
-export([
|
-export([
|
||||||
list_shards/1,
|
list_shards/1,
|
||||||
open_db/2,
|
open_db/2,
|
||||||
|
close_db/1,
|
||||||
add_generation/1,
|
add_generation/1,
|
||||||
update_db_config/2,
|
update_db_config/2,
|
||||||
list_generations_with_lifetimes/1,
|
list_generations_with_lifetimes/1,
|
||||||
|
@ -176,7 +165,7 @@ list_shards(DB) ->
|
||||||
|
|
||||||
-spec open_db(emqx_ds:db(), builtin_db_opts()) -> ok | {error, _}.
|
-spec open_db(emqx_ds:db(), builtin_db_opts()) -> ok | {error, _}.
|
||||||
open_db(DB, CreateOpts) ->
|
open_db(DB, CreateOpts) ->
|
||||||
case emqx_ds_builtin_sup:start_db(DB, CreateOpts) of
|
case emqx_ds_builtin_raft_sup:start_db(DB, CreateOpts) of
|
||||||
{ok, _} ->
|
{ok, _} ->
|
||||||
ok;
|
ok;
|
||||||
{error, {already_started, _}} ->
|
{error, {already_started, _}} ->
|
||||||
|
@ -185,6 +174,10 @@ open_db(DB, CreateOpts) ->
|
||||||
{error, Err}
|
{error, Err}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
-spec close_db(emqx_ds:db()) -> ok.
|
||||||
|
close_db(DB) ->
|
||||||
|
emqx_ds_builtin_raft_sup:stop_db(DB).
|
||||||
|
|
||||||
-spec add_generation(emqx_ds:db()) -> ok | {error, _}.
|
-spec add_generation(emqx_ds:db()) -> ok | {error, _}.
|
||||||
add_generation(DB) ->
|
add_generation(DB) ->
|
||||||
foreach_shard(
|
foreach_shard(
|
||||||
|
@ -376,7 +369,7 @@ foreach_shard(DB, Fun) ->
|
||||||
%% local server
|
%% local server
|
||||||
-spec current_timestamp(emqx_ds:db(), emqx_ds_replication_layer:shard_id()) -> emqx_ds:time().
|
-spec current_timestamp(emqx_ds:db(), emqx_ds_replication_layer:shard_id()) -> emqx_ds:time().
|
||||||
current_timestamp(DB, Shard) ->
|
current_timestamp(DB, Shard) ->
|
||||||
emqx_ds_builtin_sup:get_gvar(DB, ?gv_timestamp(Shard), 0).
|
emqx_ds_builtin_raft_sup:get_gvar(DB, ?gv_timestamp(Shard), 0).
|
||||||
|
|
||||||
%%================================================================================
|
%%================================================================================
|
||||||
%% behavior callbacks
|
%% behavior callbacks
|
||||||
|
@ -402,7 +395,7 @@ current_timestamp(DB, Shard) ->
|
||||||
-spec do_drop_db_v1(emqx_ds:db()) -> ok | {error, _}.
|
-spec do_drop_db_v1(emqx_ds:db()) -> ok | {error, _}.
|
||||||
do_drop_db_v1(DB) ->
|
do_drop_db_v1(DB) ->
|
||||||
MyShards = emqx_ds_replication_layer_meta:my_shards(DB),
|
MyShards = emqx_ds_replication_layer_meta:my_shards(DB),
|
||||||
emqx_ds_builtin_sup:stop_db(DB),
|
emqx_ds_builtin_raft_sup:stop_db(DB),
|
||||||
lists:foreach(
|
lists:foreach(
|
||||||
fun(Shard) ->
|
fun(Shard) ->
|
||||||
emqx_ds_storage_layer:drop_shard({DB, Shard})
|
emqx_ds_storage_layer:drop_shard({DB, Shard})
|
||||||
|
@ -874,4 +867,4 @@ handle_custom_event(DBShard, Latest, Event) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
set_ts({DB, Shard}, TS) ->
|
set_ts({DB, Shard}, TS) ->
|
||||||
emqx_ds_builtin_sup:set_gvar(DB, ?gv_timestamp(Shard), TS).
|
emqx_ds_builtin_raft_sup:set_gvar(DB, ?gv_timestamp(Shard), TS).
|
|
@ -1,17 +1,5 @@
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Copyright (c) 2022, 2024 EMQ Technologies Co., Ltd. All Rights Reserved.
|
%% Copyright (c) 2022, 2024 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||||
%%
|
|
||||||
%% 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.
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
-ifndef(EMQX_DS_REPLICATION_LAYER_HRL).
|
-ifndef(EMQX_DS_REPLICATION_LAYER_HRL).
|
||||||
-define(EMQX_DS_REPLICATION_LAYER_HRL, true).
|
-define(EMQX_DS_REPLICATION_LAYER_HRL, true).
|
|
@ -1,17 +1,5 @@
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Copyright (c) 2023-2024 EMQ Technologies Co., Ltd. All Rights Reserved.
|
%% Copyright (c) 2023-2024 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||||
%%
|
|
||||||
%% 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.
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
%% @doc Egress servers are responsible for proxing the outcoming
|
%% @doc Egress servers are responsible for proxing the outcoming
|
|
@ -1,17 +1,5 @@
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Copyright (c) 2023-2024 EMQ Technologies Co., Ltd. All Rights Reserved.
|
%% Copyright (c) 2023-2024 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||||
%%
|
|
||||||
%% 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.
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
%% @doc Metadata storage for the builtin sharded database.
|
%% @doc Metadata storage for the builtin sharded database.
|
||||||
|
@ -678,7 +666,7 @@ ensure_tables() ->
|
||||||
ok = mria:wait_for_tables([?META_TAB, ?NODE_TAB, ?SHARD_TAB]).
|
ok = mria:wait_for_tables([?META_TAB, ?NODE_TAB, ?SHARD_TAB]).
|
||||||
|
|
||||||
ensure_site() ->
|
ensure_site() ->
|
||||||
Filename = filename:join(emqx_ds:base_dir(), "emqx_ds_builtin_site.eterm"),
|
Filename = filename:join(emqx_ds_storage_layer:base_dir(), "emqx_ds_builtin_site.eterm"),
|
||||||
case file:consult(Filename) of
|
case file:consult(Filename) of
|
||||||
{ok, [Site]} ->
|
{ok, [Site]} ->
|
||||||
ok;
|
ok;
|
|
@ -1,17 +1,5 @@
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Copyright (c) 2024 EMQ Technologies Co., Ltd. All Rights Reserved.
|
%% Copyright (c) 2024 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||||
%%
|
|
||||||
%% 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(emqx_ds_replication_layer_shard).
|
-module(emqx_ds_replication_layer_shard).
|
|
@ -1,17 +1,5 @@
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Copyright (c) 2024 EMQ Technologies Co., Ltd. All Rights Reserved.
|
%% Copyright (c) 2024 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||||
%%
|
|
||||||
%% 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(emqx_ds_replication_shard_allocator).
|
-module(emqx_ds_replication_shard_allocator).
|
||||||
|
@ -297,7 +285,7 @@ trans_drop_local(DB, Shard, {del, Site}) ->
|
||||||
do_drop_local(DB, Shard) ->
|
do_drop_local(DB, Shard) ->
|
||||||
case emqx_ds_replication_layer_shard:drop_local_server(DB, Shard) of
|
case emqx_ds_replication_layer_shard:drop_local_server(DB, Shard) of
|
||||||
ok ->
|
ok ->
|
||||||
ok = emqx_ds_builtin_db_sup:stop_shard({DB, Shard}),
|
ok = emqx_ds_builtin_raft_db_sup:stop_shard({DB, Shard}),
|
||||||
ok = emqx_ds_storage_layer:drop_shard({DB, Shard}),
|
ok = emqx_ds_storage_layer:drop_shard({DB, Shard}),
|
||||||
logger:info(#{msg => "Local shard replica dropped"});
|
logger:info(#{msg => "Local shard replica dropped"});
|
||||||
{error, recoverable, Reason} ->
|
{error, recoverable, Reason} ->
|
||||||
|
@ -428,7 +416,7 @@ start_shards(DB, Shards) ->
|
||||||
lists:foreach(fun(Shard) -> start_shard(DB, Shard) end, Shards).
|
lists:foreach(fun(Shard) -> start_shard(DB, Shard) end, Shards).
|
||||||
|
|
||||||
start_shard(DB, Shard) ->
|
start_shard(DB, Shard) ->
|
||||||
ok = emqx_ds_builtin_db_sup:ensure_shard({DB, Shard}),
|
ok = emqx_ds_builtin_raft_db_sup:ensure_shard({DB, Shard}),
|
||||||
ok = logger:info(#{msg => "Shard started", shard => Shard}),
|
ok = logger:info(#{msg => "Shard started", shard => Shard}),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
|
@ -436,7 +424,7 @@ start_egresses(DB, Shards) ->
|
||||||
lists:foreach(fun(Shard) -> start_egress(DB, Shard) end, Shards).
|
lists:foreach(fun(Shard) -> start_egress(DB, Shard) end, Shards).
|
||||||
|
|
||||||
start_egress(DB, Shard) ->
|
start_egress(DB, Shard) ->
|
||||||
ok = emqx_ds_builtin_db_sup:ensure_egress({DB, Shard}),
|
ok = emqx_ds_builtin_raft_db_sup:ensure_egress({DB, Shard}),
|
||||||
ok = logger:info(#{msg => "Egress started", shard => Shard}),
|
ok = logger:info(#{msg => "Egress started", shard => Shard}),
|
||||||
ok.
|
ok.
|
||||||
|
|
|
@ -195,7 +195,7 @@ start_snapshot_writer(WS) ->
|
||||||
msg => "dsrepl_snapshot_write_started",
|
msg => "dsrepl_snapshot_write_started",
|
||||||
shard => ShardId
|
shard => ShardId
|
||||||
}),
|
}),
|
||||||
_ = emqx_ds_builtin_db_sup:terminate_storage(ShardId),
|
_ = emqx_ds_builtin_raft_db_sup:terminate_storage(ShardId),
|
||||||
{ok, SnapWriter} = emqx_ds_storage_layer:accept_snapshot(ShardId),
|
{ok, SnapWriter} = emqx_ds_storage_layer:accept_snapshot(ShardId),
|
||||||
{ok, WS#ws{phase = storage_snapshot, writer = SnapWriter}}.
|
{ok, WS#ws{phase = storage_snapshot, writer = SnapWriter}}.
|
||||||
|
|
||||||
|
@ -223,7 +223,7 @@ complete_accept(WS = #ws{started_at = StartedAt, writer = SnapWriter}) ->
|
||||||
duration_ms => erlang:monotonic_time(millisecond) - StartedAt,
|
duration_ms => erlang:monotonic_time(millisecond) - StartedAt,
|
||||||
bytes_written => emqx_ds_storage_snapshot:writer_info(bytes_written, SnapWriter)
|
bytes_written => emqx_ds_storage_snapshot:writer_info(bytes_written, SnapWriter)
|
||||||
}),
|
}),
|
||||||
{ok, _} = emqx_ds_builtin_db_sup:restart_storage(ShardId),
|
{ok, _} = emqx_ds_builtin_raft_db_sup:restart_storage(ShardId),
|
||||||
write_machine_snapshot(WS).
|
write_machine_snapshot(WS).
|
||||||
|
|
||||||
write_machine_snapshot(#ws{dir = Dir, meta = Meta, state = MachineState}) ->
|
write_machine_snapshot(#ws{dir = Dir, meta = Meta, state = MachineState}) ->
|
|
@ -1,17 +1,5 @@
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Copyright (c) 2023-2024 EMQ Technologies Co., Ltd. All Rights Reserved.
|
%% Copyright (c) 2023-2024 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||||
%%
|
|
||||||
%% 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(emqx_ds_proto_v1).
|
-module(emqx_ds_proto_v1).
|
||||||
|
|
|
@ -1,17 +1,5 @@
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Copyright (c) 2023-2024 EMQ Technologies Co., Ltd. All Rights Reserved.
|
%% Copyright (c) 2023-2024 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||||
%%
|
|
||||||
%% 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(emqx_ds_proto_v2).
|
-module(emqx_ds_proto_v2).
|
||||||
|
|
|
@ -1,17 +1,5 @@
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Copyright (c) 2024 EMQ Technologies Co., Ltd. All Rights Reserved.
|
%% Copyright (c) 2024 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||||
%%
|
|
||||||
%% 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(emqx_ds_proto_v3).
|
-module(emqx_ds_proto_v3).
|
||||||
|
|
|
@ -1,17 +1,5 @@
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Copyright (c) 2024 EMQ Technologies Co., Ltd. All Rights Reserved.
|
%% Copyright (c) 2024 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||||
%%
|
|
||||||
%% 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(emqx_ds_proto_v4).
|
-module(emqx_ds_proto_v4).
|
||||||
|
|
|
@ -35,7 +35,7 @@ opts() ->
|
||||||
opts(Overrides) ->
|
opts(Overrides) ->
|
||||||
maps:merge(
|
maps:merge(
|
||||||
#{
|
#{
|
||||||
backend => builtin,
|
backend => builtin_raft,
|
||||||
%% storage => {emqx_ds_storage_reference, #{}},
|
%% storage => {emqx_ds_storage_reference, #{}},
|
||||||
storage => {emqx_ds_storage_bitfield_lts, #{epoch_bits => 10}},
|
storage => {emqx_ds_storage_bitfield_lts, #{epoch_bits => 10}},
|
||||||
n_shards => 16,
|
n_shards => 16,
|
||||||
|
@ -56,8 +56,52 @@ appspec(emqx_durable_storage) ->
|
||||||
override_env => [{egress_flush_interval, 1}]
|
override_env => [{egress_flush_interval, 1}]
|
||||||
}}.
|
}}.
|
||||||
|
|
||||||
|
t_metadata(init, Config) ->
|
||||||
|
emqx_cth_suite:start([emqx_ds_builtin_raft], #{
|
||||||
|
work_dir => emqx_cth_suite:work_dir(?FUNCTION_NAME, Config)
|
||||||
|
}),
|
||||||
|
Config;
|
||||||
|
t_metadata('end', Config) ->
|
||||||
|
emqx_cth_suite:stop([emqx_ds_builtin_raft]),
|
||||||
|
Config.
|
||||||
|
|
||||||
|
t_metadata(_Config) ->
|
||||||
|
DB = ?FUNCTION_NAME,
|
||||||
|
NShards = 1,
|
||||||
|
Options = #{
|
||||||
|
backend => builtin_raft,
|
||||||
|
storage => {emqx_ds_storage_reference, #{}},
|
||||||
|
n_shards => NShards,
|
||||||
|
n_sites => 1,
|
||||||
|
replication_factor => 1,
|
||||||
|
replication_options => #{}
|
||||||
|
},
|
||||||
|
try
|
||||||
|
?assertMatch(ok, emqx_ds:open_db(DB, Options)),
|
||||||
|
%% Check metadata:
|
||||||
|
%% We have only one site:
|
||||||
|
[Site] = emqx_ds_replication_layer_meta:sites(),
|
||||||
|
%% Check all shards:
|
||||||
|
Shards = emqx_ds_replication_layer_meta:shards(DB),
|
||||||
|
%% Since there is only one site all shards should be allocated
|
||||||
|
%% to this site:
|
||||||
|
MyShards = emqx_ds_replication_layer_meta:my_shards(DB),
|
||||||
|
?assertEqual(NShards, length(Shards)),
|
||||||
|
lists:foreach(
|
||||||
|
fun(Shard) ->
|
||||||
|
?assertEqual(
|
||||||
|
[Site], emqx_ds_replication_layer_meta:replica_set(DB, Shard)
|
||||||
|
)
|
||||||
|
end,
|
||||||
|
Shards
|
||||||
|
),
|
||||||
|
?assertEqual(lists:sort(Shards), lists:sort(MyShards))
|
||||||
|
after
|
||||||
|
?assertMatch(ok, emqx_ds:drop_db(DB))
|
||||||
|
end.
|
||||||
|
|
||||||
t_replication_transfers_snapshots(init, Config) ->
|
t_replication_transfers_snapshots(init, Config) ->
|
||||||
Apps = [appspec(emqx_durable_storage)],
|
Apps = [appspec(emqx_durable_storage), emqx_ds_builtin_raft],
|
||||||
NodeSpecs = emqx_cth_cluster:mk_nodespecs(
|
NodeSpecs = emqx_cth_cluster:mk_nodespecs(
|
||||||
[
|
[
|
||||||
{t_replication_transfers_snapshots1, #{apps => Apps}},
|
{t_replication_transfers_snapshots1, #{apps => Apps}},
|
||||||
|
@ -130,7 +174,7 @@ t_replication_transfers_snapshots(Config) ->
|
||||||
).
|
).
|
||||||
|
|
||||||
t_rebalance(init, Config) ->
|
t_rebalance(init, Config) ->
|
||||||
Apps = [appspec(emqx_durable_storage)],
|
Apps = [appspec(emqx_durable_storage), emqx_ds_builtin_raft],
|
||||||
Nodes = emqx_cth_cluster:start(
|
Nodes = emqx_cth_cluster:start(
|
||||||
[
|
[
|
||||||
{t_rebalance1, #{apps => Apps}},
|
{t_rebalance1, #{apps => Apps}},
|
||||||
|
@ -260,7 +304,7 @@ t_rebalance(Config) ->
|
||||||
).
|
).
|
||||||
|
|
||||||
t_join_leave_errors(init, Config) ->
|
t_join_leave_errors(init, Config) ->
|
||||||
Apps = [appspec(emqx_durable_storage)],
|
Apps = [appspec(emqx_durable_storage), emqx_ds_builtin_raft],
|
||||||
Nodes = emqx_cth_cluster:start(
|
Nodes = emqx_cth_cluster:start(
|
||||||
[
|
[
|
||||||
{t_join_leave_errors1, #{apps => Apps}},
|
{t_join_leave_errors1, #{apps => Apps}},
|
||||||
|
@ -322,7 +366,7 @@ t_join_leave_errors(Config) ->
|
||||||
?assertEqual([], emqx_ds_test_helpers:transitions(N1, ?DB)).
|
?assertEqual([], emqx_ds_test_helpers:transitions(N1, ?DB)).
|
||||||
|
|
||||||
t_rebalance_chaotic_converges(init, Config) ->
|
t_rebalance_chaotic_converges(init, Config) ->
|
||||||
Apps = [appspec(emqx_durable_storage)],
|
Apps = [appspec(emqx_durable_storage), emqx_ds_builtin_raft],
|
||||||
Nodes = emqx_cth_cluster:start(
|
Nodes = emqx_cth_cluster:start(
|
||||||
[
|
[
|
||||||
{t_rebalance_chaotic_converges1, #{apps => Apps}},
|
{t_rebalance_chaotic_converges1, #{apps => Apps}},
|
||||||
|
@ -418,7 +462,7 @@ t_rebalance_chaotic_converges(Config) ->
|
||||||
).
|
).
|
||||||
|
|
||||||
t_rebalance_offline_restarts(init, Config) ->
|
t_rebalance_offline_restarts(init, Config) ->
|
||||||
Apps = [appspec(emqx_durable_storage)],
|
Apps = [appspec(emqx_durable_storage), emqx_ds_builtin_raft],
|
||||||
Specs = emqx_cth_cluster:mk_nodespecs(
|
Specs = emqx_cth_cluster:mk_nodespecs(
|
||||||
[
|
[
|
||||||
{t_rebalance_offline_restarts1, #{apps => Apps}},
|
{t_rebalance_offline_restarts1, #{apps => Apps}},
|
||||||
|
@ -435,6 +479,7 @@ t_rebalance_offline_restarts('end', Config) ->
|
||||||
t_rebalance_offline_restarts(Config) ->
|
t_rebalance_offline_restarts(Config) ->
|
||||||
%% This testcase verifies that rebalancing progresses if nodes restart or
|
%% This testcase verifies that rebalancing progresses if nodes restart or
|
||||||
%% go offline and never come back.
|
%% go offline and never come back.
|
||||||
|
ok = snabbkaffe:start_trace(),
|
||||||
|
|
||||||
Nodes = [N1, N2, N3] = ?config(nodes, Config),
|
Nodes = [N1, N2, N3] = ?config(nodes, Config),
|
||||||
_Specs = [NS1, NS2, _] = ?config(nodespecs, Config),
|
_Specs = [NS1, NS2, _] = ?config(nodespecs, Config),
|
||||||
|
@ -477,7 +522,7 @@ t_rebalance_offline_restarts(Config) ->
|
||||||
?assertEqual(lists:sort([S1, S2]), ds_repl_meta(N1, db_sites, [?DB])).
|
?assertEqual(lists:sort([S1, S2]), ds_repl_meta(N1, db_sites, [?DB])).
|
||||||
|
|
||||||
t_drop_generation(Config) ->
|
t_drop_generation(Config) ->
|
||||||
Apps = [appspec(emqx_durable_storage)],
|
Apps = [appspec(emqx_durable_storage), emqx_ds_builtin_raft],
|
||||||
[_, _, NS3] =
|
[_, _, NS3] =
|
||||||
NodeSpecs = emqx_cth_cluster:mk_nodespecs(
|
NodeSpecs = emqx_cth_cluster:mk_nodespecs(
|
||||||
[
|
[
|
||||||
|
@ -554,6 +599,105 @@ t_drop_generation(Config) ->
|
||||||
end
|
end
|
||||||
).
|
).
|
||||||
|
|
||||||
|
t_error_mapping_replication_layer(init, Config) ->
|
||||||
|
emqx_cth_suite:start([emqx_ds_builtin_raft], #{
|
||||||
|
work_dir => emqx_cth_suite:work_dir(?FUNCTION_NAME, Config)
|
||||||
|
}),
|
||||||
|
Config;
|
||||||
|
t_error_mapping_replication_layer('end', Config) ->
|
||||||
|
emqx_cth_suite:stop([emqx_ds_builtin_raft]),
|
||||||
|
Config.
|
||||||
|
|
||||||
|
t_error_mapping_replication_layer(_Config) ->
|
||||||
|
%% This checks that the replication layer maps recoverable errors correctly.
|
||||||
|
|
||||||
|
ok = emqx_ds_test_helpers:mock_rpc(),
|
||||||
|
ok = snabbkaffe:start_trace(),
|
||||||
|
|
||||||
|
DB = ?FUNCTION_NAME,
|
||||||
|
?assertMatch(ok, emqx_ds:open_db(DB, (opts())#{n_shards => 2})),
|
||||||
|
[Shard1, Shard2] = emqx_ds_replication_layer_meta:shards(DB),
|
||||||
|
|
||||||
|
TopicFilter = emqx_topic:words(<<"foo/#">>),
|
||||||
|
Msgs = [
|
||||||
|
message(<<"C1">>, <<"foo/bar">>, <<"1">>, 0),
|
||||||
|
message(<<"C1">>, <<"foo/baz">>, <<"2">>, 1),
|
||||||
|
message(<<"C2">>, <<"foo/foo">>, <<"3">>, 2),
|
||||||
|
message(<<"C3">>, <<"foo/xyz">>, <<"4">>, 3),
|
||||||
|
message(<<"C4">>, <<"foo/bar">>, <<"5">>, 4),
|
||||||
|
message(<<"C5">>, <<"foo/oof">>, <<"6">>, 5)
|
||||||
|
],
|
||||||
|
|
||||||
|
?assertMatch(ok, emqx_ds:store_batch(DB, Msgs)),
|
||||||
|
|
||||||
|
?block_until(#{?snk_kind := emqx_ds_replication_layer_egress_flush, shard := Shard1}),
|
||||||
|
?block_until(#{?snk_kind := emqx_ds_replication_layer_egress_flush, shard := Shard2}),
|
||||||
|
|
||||||
|
Streams0 = emqx_ds:get_streams(DB, TopicFilter, 0),
|
||||||
|
Iterators0 = lists:map(
|
||||||
|
fun({_Rank, S}) ->
|
||||||
|
{ok, Iter} = emqx_ds:make_iterator(DB, S, TopicFilter, 0),
|
||||||
|
Iter
|
||||||
|
end,
|
||||||
|
Streams0
|
||||||
|
),
|
||||||
|
|
||||||
|
%% Disrupt the link to the second shard.
|
||||||
|
ok = emqx_ds_test_helpers:mock_rpc_result(
|
||||||
|
fun(_Node, emqx_ds_replication_layer, _Function, Args) ->
|
||||||
|
case Args of
|
||||||
|
[DB, Shard1 | _] -> passthrough;
|
||||||
|
[DB, Shard2 | _] -> unavailable
|
||||||
|
end
|
||||||
|
end
|
||||||
|
),
|
||||||
|
|
||||||
|
%% Result of `emqx_ds:get_streams/3` will just contain partial results, not an error.
|
||||||
|
Streams1 = emqx_ds:get_streams(DB, TopicFilter, 0),
|
||||||
|
?assert(
|
||||||
|
length(Streams1) > 0 andalso length(Streams1) =< length(Streams0),
|
||||||
|
Streams1
|
||||||
|
),
|
||||||
|
|
||||||
|
%% At least one of `emqx_ds:make_iterator/4` will end in an error.
|
||||||
|
Results1 = lists:map(
|
||||||
|
fun({_Rank, S}) ->
|
||||||
|
case emqx_ds:make_iterator(DB, S, TopicFilter, 0) of
|
||||||
|
Ok = {ok, _Iter} ->
|
||||||
|
Ok;
|
||||||
|
Error = {error, recoverable, {erpc, _}} ->
|
||||||
|
Error;
|
||||||
|
Other ->
|
||||||
|
ct:fail({unexpected_result, Other})
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
Streams0
|
||||||
|
),
|
||||||
|
?assert(
|
||||||
|
length([error || {error, _, _} <- Results1]) > 0,
|
||||||
|
Results1
|
||||||
|
),
|
||||||
|
|
||||||
|
%% At least one of `emqx_ds:next/3` over initial set of iterators will end in an error.
|
||||||
|
Results2 = lists:map(
|
||||||
|
fun(Iter) ->
|
||||||
|
case emqx_ds:next(DB, Iter, _BatchSize = 42) of
|
||||||
|
Ok = {ok, _Iter, [_ | _]} ->
|
||||||
|
Ok;
|
||||||
|
Error = {error, recoverable, {badrpc, _}} ->
|
||||||
|
Error;
|
||||||
|
Other ->
|
||||||
|
ct:fail({unexpected_result, Other})
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
Iterators0
|
||||||
|
),
|
||||||
|
?assert(
|
||||||
|
length([error || {error, _, _} <- Results2]) > 0,
|
||||||
|
Results2
|
||||||
|
),
|
||||||
|
meck:unload().
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
shard_server_info(Node, DB, Shard, Site, Info) ->
|
shard_server_info(Node, DB, Shard, Site, Info) ->
|
||||||
|
@ -583,7 +727,7 @@ shards(Node, DB) ->
|
||||||
erpc:call(Node, emqx_ds_replication_layer_meta, shards, [DB]).
|
erpc:call(Node, emqx_ds_replication_layer_meta, shards, [DB]).
|
||||||
|
|
||||||
shards_online(Node, DB) ->
|
shards_online(Node, DB) ->
|
||||||
erpc:call(Node, emqx_ds_builtin_db_sup, which_shards, [DB]).
|
erpc:call(Node, emqx_ds_builtin_raft_db_sup, which_shards, [DB]).
|
||||||
|
|
||||||
n_shards_online(Node, DB) ->
|
n_shards_online(Node, DB) ->
|
||||||
length(shards_online(Node, DB)).
|
length(shards_online(Node, DB)).
|
||||||
|
@ -635,7 +779,6 @@ all() -> emqx_common_test_helpers:all(?MODULE).
|
||||||
|
|
||||||
init_per_testcase(TCName, Config0) ->
|
init_per_testcase(TCName, Config0) ->
|
||||||
Config = emqx_common_test_helpers:init_per_testcase(?MODULE, TCName, Config0),
|
Config = emqx_common_test_helpers:init_per_testcase(?MODULE, TCName, Config0),
|
||||||
ok = snabbkaffe:start_trace(),
|
|
||||||
Config.
|
Config.
|
||||||
|
|
||||||
end_per_testcase(TCName, Config) ->
|
end_per_testcase(TCName, Config) ->
|
|
@ -103,7 +103,7 @@ Consumption of messages is done in several stages:
|
||||||
|
|
||||||
# Documentation links
|
# Documentation links
|
||||||
|
|
||||||
TBD
|
https://docs.emqx.com/en/enterprise/latest/durability/durability_introduction.html
|
||||||
|
|
||||||
# Usage
|
# Usage
|
||||||
|
|
||||||
|
@ -146,7 +146,39 @@ The following REST APIs are available for managing the builtin durable storages:
|
||||||
- `/ds/storages/:ds/replicas/:site` — add or remove replica of the durable storage on the site
|
- `/ds/storages/:ds/replicas/:site` — add or remove replica of the durable storage on the site
|
||||||
|
|
||||||
# Other
|
# Other
|
||||||
TBD
|
|
||||||
|
Note: this application contains main interface module and some common utility modules used by the backends, but it doesn't contain any ready-to-use DS backends.
|
||||||
|
The backends are instead implemented as separate OTP applications, such as `emqx_ds_backend_local` and `emqx_ds_backend_raft`.
|
||||||
|
|
||||||
|
There is a helper placeholder application `emqx_ds_backends` that depends on all backend applications available in the release.
|
||||||
|
Business logic applications must have `emqx_ds_backends` as a dependency.
|
||||||
|
|
||||||
|
The dependency diagram is the following:
|
||||||
|
|
||||||
|
```
|
||||||
|
+------------------------+
|
||||||
|
| emqx_durable_storage |
|
||||||
|
+------------------------+
|
||||||
|
/ | \
|
||||||
|
/ | \
|
||||||
|
/ | \
|
||||||
|
+------------------------+ +----------------------+ +------+
|
||||||
|
| emqx_ds_backend_local | | emqx_ds_builtin_raft | | ... |
|
||||||
|
+------------------------+ +-----------+----------+ +------+
|
||||||
|
\ | /
|
||||||
|
\ | /
|
||||||
|
\ | /
|
||||||
|
+-------------------------+
|
||||||
|
| emqx_ds_backends |
|
||||||
|
+-------------------------+
|
||||||
|
/ \
|
||||||
|
/ \
|
||||||
|
......................../.. business apps .\........................
|
||||||
|
/ \
|
||||||
|
+------+ +-------+
|
||||||
|
| emqx | | ... |
|
||||||
|
+------+ +-------+
|
||||||
|
```
|
||||||
|
|
||||||
# Contributing
|
# Contributing
|
||||||
Please see our [contributing.md](../../CONTRIBUTING.md).
|
Please see our [contributing.md](../../CONTRIBUTING.md).
|
||||||
|
|
|
@ -175,8 +175,7 @@
|
||||||
_ => _
|
_ => _
|
||||||
}.
|
}.
|
||||||
|
|
||||||
-type create_db_opts() ::
|
-type create_db_opts() :: generic_db_opts().
|
||||||
emqx_ds_replication_layer:builtin_db_opts() | generic_db_opts().
|
|
||||||
|
|
||||||
-type message_id() :: emqx_ds_replication_layer:message_id().
|
-type message_id() :: emqx_ds_replication_layer:message_id().
|
||||||
|
|
||||||
|
|
|
@ -135,7 +135,8 @@
|
||||||
emqx_bridge_confluent,
|
emqx_bridge_confluent,
|
||||||
emqx_ds_shared_sub,
|
emqx_ds_shared_sub,
|
||||||
emqx_auth_ext,
|
emqx_auth_ext,
|
||||||
emqx_cluster_link
|
emqx_cluster_link,
|
||||||
|
emqx_ds_builtin_raft
|
||||||
],
|
],
|
||||||
%% must always be of type `load'
|
%% must always be of type `load'
|
||||||
ce_business_apps =>
|
ce_business_apps =>
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
`builtin` durable storage backend has been replaced with the following two backends:
|
||||||
|
|
||||||
|
- `builtin_local`: A durable storage backend that doesn't support replication.
|
||||||
|
It can't be used in a multi-node cluster.
|
||||||
|
This backend is available in both open source and enterprise editions.
|
||||||
|
- `builtin_raft`: A durable storage backend that uses Raft algorithm for replication.
|
||||||
|
This backend is available enterprise edition.
|
5
mix.exs
5
mix.exs
|
@ -205,7 +205,8 @@ defmodule EMQXUmbrella.MixProject do
|
||||||
:emqx_bridge_syskeeper,
|
:emqx_bridge_syskeeper,
|
||||||
:emqx_ds_shared_sub,
|
:emqx_ds_shared_sub,
|
||||||
:emqx_auth_ext,
|
:emqx_auth_ext,
|
||||||
:emqx_cluster_link
|
:emqx_cluster_link,
|
||||||
|
:emqx_ds_builtin_raft
|
||||||
])
|
])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -341,6 +342,8 @@ defmodule EMQXUmbrella.MixProject do
|
||||||
:emqx_s3,
|
:emqx_s3,
|
||||||
:emqx_opentelemetry,
|
:emqx_opentelemetry,
|
||||||
:emqx_durable_storage,
|
:emqx_durable_storage,
|
||||||
|
:emqx_ds_builtin_local,
|
||||||
|
:emqx_ds_builtin_raft,
|
||||||
:rabbit_common,
|
:rabbit_common,
|
||||||
:emqx_eviction_agent,
|
:emqx_eviction_agent,
|
||||||
:emqx_node_rebalance
|
:emqx_node_rebalance
|
||||||
|
|
|
@ -124,6 +124,7 @@ is_community_umbrella_app("apps/emqx_node_rebalance") -> false;
|
||||||
is_community_umbrella_app("apps/emqx_ds_shared_sub") -> false;
|
is_community_umbrella_app("apps/emqx_ds_shared_sub") -> false;
|
||||||
is_community_umbrella_app("apps/emqx_auth_ext") -> false;
|
is_community_umbrella_app("apps/emqx_auth_ext") -> false;
|
||||||
is_community_umbrella_app("apps/emqx_cluster_link") -> false;
|
is_community_umbrella_app("apps/emqx_cluster_link") -> false;
|
||||||
|
is_community_umbrella_app("apps/emqx_ds_builtin_raft") -> false;
|
||||||
is_community_umbrella_app(_) -> true.
|
is_community_umbrella_app(_) -> true.
|
||||||
|
|
||||||
%% BUILD_WITHOUT_JQ
|
%% BUILD_WITHOUT_JQ
|
||||||
|
|
Loading…
Reference in New Issue