-define(STORAGE_TYPES, [disc_copies, disc_only_copies, ram_copies]).
-define(NEED_RESET, [local_content, type]).
-create(Module, Name, TabDef) ->
- Schema = schema(Module, Name, TabDef),
+-include("logger.hrl").
+
+create(Module, Name, TabDef)
+ when is_atom(Module), is_atom(Name), is_list(TabDef) ->
+ Path = os:getenv("EJABBERD_SCHEMA_PATH"),
+ Schema = schema(Path, Module, Name, TabDef),
{attributes, Attrs} = lists:keyfind(attributes, 1, Schema),
case catch mnesia:table_info(Name, attributes) of
{'EXIT', _} ->
- mnesia:create_table(Name, Schema);
+ mnesia_op(create, [Name, TabDef]);
Attrs ->
case need_reset(TabDef, Schema) of
true -> reset(Name, Schema);
true -> fun(Old) -> Module:transform(Old) end;
false -> fun(Old) -> transform(OldAttrs, Attrs, Old) end
end,
- mnesia:transform_table(Name, Fun, Attrs)
+ mnesia_op(transform_table, [Name, Fun, Attrs])
end.
-reset(Name, TabDef) ->
- mnesia:delete_table(Name),
- ejabberd_mnesia:create(?MODULE, Name, TabDef).
+reset(Name, TabDef)
+ when is_atom(Name), is_list(TabDef) ->
+ mnesia_op(delete_table, [Name]),
+ mnesia_op(create, [Name, TabDef]).
-update(Name, TabDef) ->
+update(Name, TabDef)
+ when is_atom(Name), is_list(TabDef) ->
{attributes, Attrs} = lists:keyfind(attributes, 1, TabDef),
update(Name, Attrs, TabDef).
update(Name, Attrs, TabDef) ->
- Storage = mnesia:table_info(Name, storage_type),
+ Storage = case catch mnesia:table_info(Name, storage_type) of
+ {'EXIT', _} -> unknown;
+ Type -> Type
+ end,
NewStorage = lists:foldl(
fun({Key, _}, Acc) ->
case lists:member(Key, ?STORAGE_TYPES) of
false -> Acc
end
end, Storage, TabDef),
- R1 = if Storage=/=NewStorage ->
- mnesia:change_table_copy_type(Name, node(), NewStorage);
- true ->
- {atomic, ok}
- end,
+ R1 = [mnesia_op(change_table_copy_type, [Name, node(), NewStorage])
+ || Storage=/=NewStorage],
CurIndexes = [lists:nth(N-1, Attrs) || N<-mnesia:table_info(Name, index)],
NewIndexes = proplists:get_value(index, TabDef, []),
- [mnesia:del_table_index(Name, Attr)
- || Attr <- CurIndexes--NewIndexes],
- R2 = [mnesia:add_table_index(Name, Attr)
+ R2 = [mnesia_op(del_table_index, [Name, Attr])
+ || Attr <- CurIndexes--NewIndexes],
+ R3 = [mnesia_op(add_table_index, [Name, Attr])
|| Attr <- NewIndexes--CurIndexes],
lists:foldl(
fun({atomic, ok}, Acc) -> Acc;
(Error, _Acc) -> Error
- end, {atomic, ok}, [R1|R2]).
+ end, {atomic, ok}, R1++R2++R3).
%
% utilities
%
-schema(Module, Name, TabDef) ->
- case parse(Module) of
+schema(false, Module, _Name, TabDef) ->
+ ?DEBUG("No custom ~s schema path", [Module]),
+ TabDef;
+schema(Path, Module, Name, TabDef) ->
+ File = filename:join(Path, atom_to_list(Module)++".mnesia"),
+ case parse(File) of
{ok, CustomDefs} ->
case lists:keyfind(Name, 1, CustomDefs) of
- {Name, CustomDef} -> merge(TabDef, CustomDef);
- _ -> TabDef
+ {Name, CustomDef} ->
+ ?INFO_MSG("Using custom ~s schema for table ~s",
+ [Module, Name]),
+ merge(TabDef, CustomDef);
+ _ ->
+ TabDef
end;
- _ ->
+ {error, Error} ->
+ ?ERROR_MSG("Can not use custom ~s schema for table ~s: ~p",
+ [Module, Name, Error]),
TabDef
end.
lists:ukeysort(1, CustomDef),
lists:ukeysort(1, CleanDef)).
-parse(Module) ->
- case os:getenv("EJABBERD_SCHEMA_PATH") of
- false ->
- {error, undefined};
- Path ->
- File = filename:join(Path, atom_to_list(Module)++".mnesia"),
- case file:consult(File) of
- {ok, Terms} -> parse(Terms, []);
- Error -> Error
- end
+parse(File) ->
+ case file:consult(File) of
+ {ok, Terms} -> parse(Terms, []);
+ Error -> Error
end.
-
parse([], Acc) ->
{ok, lists:reverse(Acc)};
parse([{Name, Storage, TabDef}|Tail], Acc)
- when is_atom(Name),
- is_atom(Storage),
- is_list(TabDef) ->
+ when is_atom(Name), is_atom(Storage), is_list(TabDef) ->
NewDef = case lists:member(Storage, ?STORAGE_TYPES) of
true -> [{Storage, [node()]} | TabDef];
false -> TabDef
end, [], lists:reverse(Attrs)),
{Attrs, NewRecord} = lists:unzip(After),
list_to_tuple([Name|NewRecord]).
+
+mnesia_op(Fun, Args) ->
+ case apply(mnesia, Fun, Args) of
+ {atomic, ok} ->
+ {atomic, ok};
+ Other ->
+ ?ERROR_MSG("failure on mnesia ~s ~p: ~p",
+ [Fun, Args, Other]),
+ Other
+ end.