%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 1996-2016. 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.
%%
%% %CopyrightEnd%
%%
-module(ext_test).
%% Initializations
-export([init_backend/0, add_aliases/1, remove_aliases/1,
check_definition/4, semantics/2]).
-export([
create_table/3, load_table/4,
delete_table/2, close_table/2, sync_close_table/2,
sender_init/4,
receiver_first_message/4, receive_data/5, receive_done/4,
index_is_consistent/3, is_index_consistent/2,
real_suffixes/0, tmp_suffixes/0,
info/3,
fixtable/3,
validate_key/6, validate_record/6,
first/2, last/2, next/3, prev/3, slot/3,
insert/3, update_counter/4,
lookup/3,
delete/3, match_delete/3,
select/1, select/3, select/4, repair_continuation/2
]).
-ifdef(DEBUG).
-define(DBG(DATA), io:format("~p:~p: ~p~n",[?MODULE, ?LINE, DATA])).
-define(DBG(FORMAT, ARGS), io:format("~p:~p: " ++ FORMAT,[?MODULE, ?LINE] ++ ARGS)).
-else.
-define(DBG(DATA), ok).
-define(DBG(FORMAT, ARGS), ok).
-endif.
%% types() ->
%% [{fs_copies, ?MODULE},
%% {raw_fs_copies, ?MODULE}].
semantics(ext_ets, storage) -> ram_copies;
semantics(ext_ets, types ) -> [set, ordered_set, bag];
semantics(ext_ets, index_types) -> [ordered];
semantics(_Alias, _) ->
undefined.
%% valid_op(_, _) ->
%% true.
init_backend() ->
?DBG(init_backend),
ok.
add_aliases(_As) ->
?DBG(_As),
ok.
remove_aliases(_) ->
ok.
%% Table operations
check_definition(ext_ets, _Tab, _Nodes, _Props) ->
?DBG("~p ~p ~p~n", [_Tab, _Nodes, _Props]),
ok.
create_table(ext_ets, Tab, Props) when is_atom(Tab) ->
Tid = ets:new(Tab, [public, proplists:get_value(type, Props, set), {keypos, 2}]),
?DBG("~p Create: ~p(~p) ~p~n", [self(), Tab, Tid, Props]),
mnesia_lib:set({?MODULE, Tab}, Tid),
ok;
create_table(_, Tag={Tab, index, {_Where, Type0}}, _Opts) ->
Type = case Type0 of
ordered -> ordered_set;
_ -> Type0
end,
Tid = ets:new(Tab, [public, Type]),
?DBG("~p(~p) ~p~n", [Tab, Tid, Tag]),
mnesia_lib:set({?MODULE, Tag}, Tid),
ok;
create_table(_, Tag={_Tab, retainer, ChkPName}, _Opts) ->
Tid = ets:new(ChkPName, [set, public, {keypos, 2}]),
?DBG("~p(~p) ~p~n", [_Tab, Tid, Tag]),
mnesia_lib:set({?MODULE, Tag}, Tid),
ok.
delete_table(ext_ets, Tab) ->
try
ets:delete(mnesia_lib:val({?MODULE,Tab})),
mnesia_lib:unset({?MODULE,Tab}),
ok
catch _:_ ->
?DBG({double_delete, Tab}),
ok
end.
load_table(ext_ets, _Tab, init_index, _Cs) -> ok;
load_table(ext_ets, _Tab, _LoadReason, _Cs) ->
?DBG("Load ~p ~p~n", [_Tab, _LoadReason]),
ok.
%% mnesia_monitor:unsafe_create_external(Tab, ext_ets, ?MODULE, Cs).
sender_init(Alias, Tab, _RemoteStorage, _Pid) ->
KeysPerTransfer = 100,
{standard,
fun() -> mnesia_lib:db_init_chunk({ext,Alias,?MODULE}, Tab, KeysPerTransfer) end,
fun(Cont) -> mnesia_lib:db_chunk({ext,Alias,?MODULE}, Cont) end}.
receiver_first_message(Sender, {first, Size}, _Alias, Tab) ->
?DBG({first,Size}),
{Size, {Tab, Sender}}.
receive_data(Data, ext_ets, Name, _Sender, {Name, Tab, _Sender}=State) ->
?DBG({Data,State}),
true = ets:insert(Tab, Data),
{more, State};
receive_data(Data, Alias, Tab, Sender, {Name, Sender}) ->
receive_data(Data, Alias, Tab, Sender, {Name, mnesia_lib:val({?MODULE,Tab}), Sender}).
receive_done(_Alias, _Tab, _Sender, _State) ->
?DBG({done,_State}),
ok.
close_table(Alias, Tab) -> sync_close_table(Alias, Tab).
sync_close_table(ext_ets, _Tab) ->
?DBG(_Tab).
fixtable(ext_ets, Tab, Bool) ->
?DBG({Tab,Bool}),
ets:safe_fixtable(mnesia_lib:val({?MODULE,Tab}), Bool).
info(ext_ets, Tab, Type) ->
?DBG({Tab,Type}),
Tid = mnesia_lib:val({?MODULE,Tab}),
try ets:info(Tid, Type) of
Val -> Val
catch _:_ ->
undefined
end.
real_suffixes() ->
[".dat"].
tmp_suffixes() ->
[].
%% Index
index_is_consistent(_Alias, _Ix, _Bool) -> ok. % Ignore for now
is_index_consistent(_Alias, _Ix) -> false. % Always rebuild
%% Record operations
validate_record(_Alias, _Tab, RecName, Arity, Type, _Obj) ->
{RecName, Arity, Type}.
validate_key(_Alias, _Tab, RecName, Arity, Type, _Key) ->
{RecName, Arity, Type}.
insert(ext_ets, Tab, Obj) ->
?DBG({Tab,Obj}),
try
ets:insert(mnesia_lib:val({?MODULE,Tab}), Obj),
ok
catch _:Reason ->
io:format("CRASH ~p ~p~n",[Reason, mnesia_lib:val({?MODULE,Tab})])
end.
lookup(ext_ets, Tab, Key) ->
ets:lookup(mnesia_lib:val({?MODULE,Tab}), Key).
delete(ext_ets, Tab, Key) ->
ets:delete(mnesia_lib:val({?MODULE,Tab}), Key).
match_delete(ext_ets, Tab, Pat) ->
ets:match_delete(mnesia_lib:val({?MODULE,Tab}), Pat).
first(ext_ets, Tab) ->
ets:first(mnesia_lib:val({?MODULE,Tab})).
last(Alias, Tab) -> first(Alias, Tab).
next(ext_ets, Tab, Key) ->
ets:next(mnesia_lib:val({?MODULE,Tab}), Key).
prev(Alias, Tab, Key) ->
next(Alias, Tab, Key).
slot(ext_ets, Tab, Pos) ->
ets:slot(mnesia_lib:val({?MODULE,Tab}), Pos).
update_counter(ext_ets, Tab, C, Val) ->
ets:update_counter(mnesia_lib:val({?MODULE,Tab}), C, Val).
select('$end_of_table' = End) -> End;
select({ext_ets, C}) -> ets:select(C).
select(Alias, Tab, Ms) ->
Res = select(Alias, Tab, Ms, 100000),
select_1(Res).
select_1('$end_of_table') -> [];
select_1({Acc, C}) ->
case ets:select(C) of
'$end_of_table' -> Acc;
{New, Cont} ->
select_1({New ++ Acc, Cont})
end.
select(ext_ets, Tab, Ms, Limit) when is_integer(Limit); Limit =:= infinity ->
ets:select(mnesia_lib:val({?MODULE,Tab}), Ms, Limit).
repair_continuation(Cont, Ms) ->
ets:repair_continuation(Cont, Ms).