1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 1996-2016. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20 21-module(ext_test). 22 23%% Initializations 24-export([init_backend/0, add_aliases/1, remove_aliases/1, 25 check_definition/4, semantics/2]). 26 27-export([ 28 create_table/3, load_table/4, 29 delete_table/2, close_table/2, sync_close_table/2, 30 31 sender_init/4, 32 receiver_first_message/4, receive_data/5, receive_done/4, 33 34 index_is_consistent/3, is_index_consistent/2, 35 36 real_suffixes/0, tmp_suffixes/0, 37 38 info/3, 39 fixtable/3, 40 validate_key/6, validate_record/6, 41 42 first/2, last/2, next/3, prev/3, slot/3, 43 44 insert/3, update_counter/4, 45 lookup/3, 46 delete/3, match_delete/3, 47 select/1, select/3, select/4, repair_continuation/2 48 ]). 49 50-ifdef(DEBUG). 51-define(DBG(DATA), io:format("~p:~p: ~p~n",[?MODULE, ?LINE, DATA])). 52-define(DBG(FORMAT, ARGS), io:format("~p:~p: " ++ FORMAT,[?MODULE, ?LINE] ++ ARGS)). 53-else. 54-define(DBG(DATA), ok). 55-define(DBG(FORMAT, ARGS), ok). 56-endif. 57 58%% types() -> 59%% [{fs_copies, ?MODULE}, 60%% {raw_fs_copies, ?MODULE}]. 61 62semantics(ext_ets, storage) -> ram_copies; 63semantics(ext_ets, types ) -> [set, ordered_set, bag]; 64semantics(ext_ets, index_types) -> [ordered]; 65semantics(_Alias, _) -> 66 undefined. 67 68%% valid_op(_, _) -> 69%% true. 70 71init_backend() -> 72 ?DBG(init_backend), 73 ct:log("init_backend ~p", [?MODULE]), 74 %% cheat and stuff a marker in mnesia_gvar 75 K = backend_init_marker(), 76 case try mnesia_lib:val(K) catch _:_ -> error end of 77 error -> 78 ct:log("BACKEND marker will be inserted (~p)", [?MODULE]), 79 mnesia_lib:set(K, true); 80 Other -> 81 ct:log("BACKEND marker already present (~p)", [?MODULE]), 82 error({backend_already_initialized, {?MODULE, Other}}) 83 end, 84 ok. 85 86backend_init_marker() -> 87 {test, ?MODULE, backend_init}. 88 89add_aliases(_As) -> 90 ?DBG(_As), 91 ct:log("add_aliases(~p)", [_As]), 92 true = mnesia_lib:val(backend_init_marker()), 93 ok. 94 95remove_aliases(_) -> 96 ok. 97 98 99%% Table operations 100 101check_definition(ext_ets, _Tab, _Nodes, _Props) -> 102 ?DBG("~p ~p ~p~n", [_Tab, _Nodes, _Props]), 103 ok. 104 105create_table(ext_ets, Tab, Props) when is_atom(Tab) -> 106 Tid = ets:new(Tab, [public, proplists:get_value(type, Props, set), {keypos, 2}]), 107 ?DBG("~p Create: ~p(~p) ~p~n", [self(), Tab, Tid, Props]), 108 mnesia_lib:set({?MODULE, Tab}, Tid), 109 ok; 110create_table(_, Tag={Tab, index, {_Where, Type0}}, _Opts) -> 111 Type = case Type0 of 112 ordered -> ordered_set; 113 _ -> Type0 114 end, 115 Tid = ets:new(Tab, [public, Type]), 116 ?DBG("~p(~p) ~p~n", [Tab, Tid, Tag]), 117 mnesia_lib:set({?MODULE, Tag}, Tid), 118 ok; 119create_table(_, Tag={_Tab, retainer, ChkPName}, _Opts) -> 120 Tid = ets:new(ChkPName, [set, public, {keypos, 2}]), 121 ?DBG("~p(~p) ~p~n", [_Tab, Tid, Tag]), 122 mnesia_lib:set({?MODULE, Tag}, Tid), 123 ok. 124 125delete_table(ext_ets, Tab) -> 126 try 127 ets:delete(mnesia_lib:val({?MODULE,Tab})), 128 mnesia_lib:unset({?MODULE,Tab}), 129 ok 130 catch _:_ -> 131 ?DBG({double_delete, Tab}), 132 ok 133 end. 134 135load_table(ext_ets, _Tab, init_index, _Cs) -> ok; 136load_table(ext_ets, _Tab, _LoadReason, _Cs) -> 137 ?DBG("Load ~p ~p~n", [_Tab, _LoadReason]), 138 ok. 139%% mnesia_monitor:unsafe_create_external(Tab, ext_ets, ?MODULE, Cs). 140 141sender_init(Alias, Tab, _RemoteStorage, _Pid) -> 142 KeysPerTransfer = 100, 143 {standard, 144 fun() -> mnesia_lib:db_init_chunk({ext,Alias,?MODULE}, Tab, KeysPerTransfer) end, 145 fun(Cont) -> mnesia_lib:db_chunk({ext,Alias,?MODULE}, Cont) end}. 146 147receiver_first_message(Sender, {first, Size}, _Alias, Tab) -> 148 ?DBG({first,Size}), 149 {Size, {Tab, Sender}}. 150 151receive_data(Data, ext_ets, Name, _Sender, {Name, Tab, _Sender}=State) -> 152 ?DBG({Data,State}), 153 true = ets:insert(Tab, Data), 154 {more, State}; 155receive_data(Data, Alias, Tab, Sender, {Name, Sender}) -> 156 receive_data(Data, Alias, Tab, Sender, {Name, mnesia_lib:val({?MODULE,Tab}), Sender}). 157 158receive_done(_Alias, _Tab, _Sender, _State) -> 159 ?DBG({done,_State}), 160 ok. 161 162close_table(Alias, Tab) -> sync_close_table(Alias, Tab). 163 164sync_close_table(ext_ets, _Tab) -> 165 ?DBG(_Tab). 166 167fixtable(ext_ets, Tab, Bool) -> 168 ?DBG({Tab,Bool}), 169 ets:safe_fixtable(mnesia_lib:val({?MODULE,Tab}), Bool). 170 171info(ext_ets, Tab, Type) -> 172 ?DBG({Tab,Type}), 173 Tid = mnesia_lib:val({?MODULE,Tab}), 174 try ets:info(Tid, Type) of 175 Val -> Val 176 catch _:_ -> 177 undefined 178 end. 179 180real_suffixes() -> 181 [".dat"]. 182 183tmp_suffixes() -> 184 []. 185 186%% Index 187 188index_is_consistent(_Alias, _Ix, _Bool) -> ok. % Ignore for now 189is_index_consistent(_Alias, _Ix) -> false. % Always rebuild 190 191%% Record operations 192 193validate_record(_Alias, _Tab, RecName, Arity, Type, _Obj) -> 194 {RecName, Arity, Type}. 195 196validate_key(_Alias, _Tab, RecName, Arity, Type, _Key) -> 197 {RecName, Arity, Type}. 198 199insert(ext_ets, Tab, Obj) -> 200 ?DBG({Tab,Obj}), 201 try 202 ets:insert(mnesia_lib:val({?MODULE,Tab}), Obj), 203 ok 204 catch _:Reason -> 205 io:format("CRASH ~p ~p~n",[Reason, mnesia_lib:val({?MODULE,Tab})]) 206 end. 207 208lookup(ext_ets, Tab, Key) -> 209 ets:lookup(mnesia_lib:val({?MODULE,Tab}), Key). 210 211delete(ext_ets, Tab, Key) -> 212 ets:delete(mnesia_lib:val({?MODULE,Tab}), Key). 213 214match_delete(ext_ets, Tab, Pat) -> 215 ets:match_delete(mnesia_lib:val({?MODULE,Tab}), Pat). 216 217first(ext_ets, Tab) -> 218 ets:first(mnesia_lib:val({?MODULE,Tab})). 219 220last(Alias, Tab) -> first(Alias, Tab). 221 222next(ext_ets, Tab, Key) -> 223 ets:next(mnesia_lib:val({?MODULE,Tab}), Key). 224 225prev(Alias, Tab, Key) -> 226 next(Alias, Tab, Key). 227 228slot(ext_ets, Tab, Pos) -> 229 ets:slot(mnesia_lib:val({?MODULE,Tab}), Pos). 230 231update_counter(ext_ets, Tab, C, Val) -> 232 ets:update_counter(mnesia_lib:val({?MODULE,Tab}), C, Val). 233 234select('$end_of_table' = End) -> End; 235select({ext_ets, C}) -> ets:select(C). 236 237select(Alias, Tab, Ms) -> 238 Res = select(Alias, Tab, Ms, 100000), 239 select_1(Res). 240 241select_1('$end_of_table') -> []; 242select_1({Acc, C}) -> 243 case ets:select(C) of 244 '$end_of_table' -> Acc; 245 {New, Cont} -> 246 select_1({New ++ Acc, Cont}) 247 end. 248 249select(ext_ets, Tab, Ms, Limit) when is_integer(Limit); Limit =:= infinity -> 250 ets:select(mnesia_lib:val({?MODULE,Tab}), Ms, Limit). 251 252repair_continuation(Cont, Ms) -> 253 ets:repair_continuation(Cont, Ms). 254