1 |
|
-module(mongoose_cluster_id). |
2 |
|
|
3 |
|
-include("mongoose.hrl"). |
4 |
|
|
5 |
|
-export([ |
6 |
|
start/0, |
7 |
|
get_cached_cluster_id/0, |
8 |
|
get_backend_cluster_id/0 |
9 |
|
]). |
10 |
|
|
11 |
|
% For testing purposes only |
12 |
|
-export([clean_table/0]). |
13 |
|
|
14 |
|
-ignore_xref([clean_table/0, get_backend_cluster_id/0]). |
15 |
|
|
16 |
|
-record(mongoose_cluster_id, {key :: atom(), value :: cluster_id()}). |
17 |
|
-type cluster_id() :: binary(). |
18 |
|
-type maybe_cluster_id() :: {ok, cluster_id()} | {error, any()}. |
19 |
|
-type mongoose_backend() :: rdbms |
20 |
|
| mnesia. |
21 |
|
|
22 |
|
-spec start() -> maybe_cluster_id(). |
23 |
|
start() -> |
24 |
74 |
init_mnesia_cache(), |
25 |
74 |
Backend = which_backend_available(), |
26 |
74 |
maybe_prepare_queries(Backend), |
27 |
74 |
CachedRes = get_cached_cluster_id(), |
28 |
74 |
BackendRes = get_backend_cluster_id(), |
29 |
74 |
case {CachedRes, BackendRes} of |
30 |
|
{{ok, ID}, {ok, ID}} -> |
31 |
25 |
{ok, ID}; |
32 |
|
{{ok, ID}, {error, _}} -> |
33 |
1 |
set_new_cluster_id(ID, Backend); |
34 |
|
{{error, _}, {ok, ID}} -> |
35 |
47 |
set_new_cluster_id(ID, mnesia); |
36 |
|
{{error, _}, {error, _}} -> |
37 |
1 |
make_and_set_new_cluster_id(); |
38 |
|
{{ok, CachedID}, {ok, BackendID}} -> |
39 |
:-( |
?LOG_ERROR(#{what => cluster_id_setup_conflict, |
40 |
|
text => <<"Mnesia and Backend have different cluster IDs">>, |
41 |
:-( |
cached_id => CachedID, backend_id => BackendID}), |
42 |
:-( |
{error, conflict} |
43 |
|
end. |
44 |
|
|
45 |
|
%% Get cached version |
46 |
|
-spec get_cached_cluster_id() -> maybe_cluster_id(). |
47 |
|
get_cached_cluster_id() -> |
48 |
121 |
T = fun() -> mnesia:read(mongoose_cluster_id, cluster_id) end, |
49 |
121 |
case mnesia:transaction(T) of |
50 |
|
{atomic, [#mongoose_cluster_id{value = ClusterID}]} -> |
51 |
73 |
{ok, ClusterID}; |
52 |
|
{atomic, []} -> |
53 |
48 |
{error, cluster_id_not_in_mnesia}; |
54 |
|
{aborted, Reason} -> |
55 |
:-( |
{error, Reason} |
56 |
|
end. |
57 |
|
|
58 |
|
%% ==================================================================== |
59 |
|
%% Internal getters and setters |
60 |
|
%% ==================================================================== |
61 |
|
-spec get_backend_cluster_id() -> maybe_cluster_id(). |
62 |
|
get_backend_cluster_id() -> |
63 |
77 |
get_backend_cluster_id(which_backend_available()). |
64 |
|
|
65 |
|
-spec set_new_cluster_id(cluster_id()) -> maybe_cluster_id(). |
66 |
|
set_new_cluster_id(ID) -> |
67 |
1 |
set_new_cluster_id(ID, which_backend_available()). |
68 |
|
|
69 |
|
-spec make_and_set_new_cluster_id() -> maybe_cluster_id(). |
70 |
|
make_and_set_new_cluster_id() -> |
71 |
1 |
NewID = make_cluster_id(), |
72 |
1 |
set_new_cluster_id(NewID). |
73 |
|
|
74 |
|
%% ==================================================================== |
75 |
|
%% Internal functions |
76 |
|
%% ==================================================================== |
77 |
|
init_mnesia_cache() -> |
78 |
74 |
mnesia:create_table(mongoose_cluster_id, |
79 |
|
[{type, set}, |
80 |
|
{record_name, mongoose_cluster_id}, |
81 |
|
{attributes, record_info(fields, mongoose_cluster_id)}, |
82 |
|
{ram_copies, [node()]} |
83 |
|
]), |
84 |
74 |
mnesia:add_table_copy(mongoose_cluster_id, node(), ram_copies). |
85 |
|
|
86 |
|
-spec maybe_prepare_queries(mongoose_backend()) -> ok. |
87 |
:-( |
maybe_prepare_queries(mnesia) -> ok; |
88 |
|
maybe_prepare_queries(rdbms) -> |
89 |
74 |
mongoose_rdbms:prepare(cluster_insert_new, mongoose_cluster_id, [v], |
90 |
|
<<"INSERT INTO mongoose_cluster_id(k,v) VALUES ('cluster_id', ?)">>), |
91 |
74 |
mongoose_rdbms:prepare(cluster_select, mongoose_cluster_id, [], |
92 |
|
<<"SELECT v FROM mongoose_cluster_id WHERE k='cluster_id'">>), |
93 |
74 |
ok. |
94 |
|
|
95 |
|
-spec execute_cluster_insert_new(binary()) -> mongoose_rdbms:query_result(). |
96 |
|
execute_cluster_insert_new(ID) -> |
97 |
2 |
mongoose_rdbms:execute_successfully(global, cluster_insert_new, [ID]). |
98 |
|
|
99 |
|
-spec make_cluster_id() -> cluster_id(). |
100 |
|
make_cluster_id() -> |
101 |
1 |
uuid:uuid_to_string(uuid:get_v4(), binary_standard). |
102 |
|
|
103 |
|
%% Which backend is enabled |
104 |
|
-spec which_backend_available() -> mongoose_backend(). |
105 |
|
which_backend_available() -> |
106 |
153 |
case mongoose_wpool:get_pool_settings(rdbms, global, default) of |
107 |
:-( |
undefined -> mnesia; |
108 |
153 |
_ -> rdbms |
109 |
|
end. |
110 |
|
|
111 |
|
-spec set_new_cluster_id(cluster_id(), mongoose_backend()) -> ok | {error, any()}. |
112 |
|
set_new_cluster_id(ID, rdbms) -> |
113 |
2 |
try execute_cluster_insert_new(ID) of |
114 |
|
{updated, 1} -> |
115 |
2 |
set_new_cluster_id(ID, mnesia), |
116 |
2 |
{ok, ID} |
117 |
|
catch |
118 |
|
Class:Reason:Stacktrace -> |
119 |
:-( |
?LOG_WARNING(#{what => cluster_id_set_failed, |
120 |
|
text => <<"Error inserting cluster ID into RDBMS">>, |
121 |
|
cluster_id => ID, |
122 |
:-( |
class => Class, reason => Reason, stacktrace => Stacktrace}), |
123 |
:-( |
{error, {Class, Reason}} |
124 |
|
end; |
125 |
|
set_new_cluster_id(ID, mnesia) -> |
126 |
49 |
T = fun() -> mnesia:write(#mongoose_cluster_id{key = cluster_id, value = ID}) end, |
127 |
49 |
case mnesia:transaction(T) of |
128 |
|
{atomic, ok} -> |
129 |
49 |
{ok, ID}; |
130 |
|
{aborted, Reason} -> |
131 |
:-( |
{error, Reason} |
132 |
|
end. |
133 |
|
|
134 |
|
%% Get cluster ID |
135 |
|
-spec get_backend_cluster_id(mongoose_backend()) -> maybe_cluster_id(). |
136 |
|
get_backend_cluster_id(rdbms) -> |
137 |
77 |
try mongoose_rdbms:execute_successfully(global, cluster_select, []) of |
138 |
74 |
{selected, [{ID}]} -> {ok, ID}; |
139 |
3 |
{selected, []} -> {error, no_value_in_backend} |
140 |
|
catch |
141 |
|
Class:Reason:Stacktrace -> |
142 |
:-( |
?LOG_WARNING(#{what => cluster_id_get_failed, |
143 |
|
text => <<"Error getting cluster ID from RDBMS">>, |
144 |
:-( |
class => Class, reason => Reason, stacktrace => Stacktrace}), |
145 |
:-( |
{error, {Class, Reason}} |
146 |
|
end; |
147 |
|
get_backend_cluster_id(mnesia) -> |
148 |
:-( |
get_cached_cluster_id(). |
149 |
|
|
150 |
|
clean_table() -> |
151 |
1 |
clean_table(which_backend_available()). |
152 |
|
|
153 |
|
-spec clean_table(mongoose_backend()) -> ok | {error, any()}. |
154 |
|
clean_table(rdbms) -> |
155 |
1 |
SQLQuery = [<<"TRUNCATE TABLE mongoose_cluster_id;">>], |
156 |
1 |
try mongoose_rdbms:sql_query(global, SQLQuery) of |
157 |
:-( |
{selected, _} -> ok; |
158 |
1 |
{updated, _} -> ok; |
159 |
:-( |
{error, _} = Err -> Err |
160 |
|
catch |
161 |
|
Class:Reason:Stacktrace -> |
162 |
:-( |
?LOG_WARNING(#{what => cluster_id_clean_failed, |
163 |
|
text => <<"Error truncating mongoose_cluster_id table">>, |
164 |
|
sql_query => SQLQuery, |
165 |
:-( |
class => Class, reason => Reason, stacktrace => Stacktrace}), |
166 |
:-( |
{error, {Class, Reason}} |
167 |
|
end; |
168 |
:-( |
clean_table(_) -> ok. |