aboutsummaryrefslogtreecommitdiffstats
path: root/lib/mnesia/src/mnesia_snmp_hook.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/mnesia/src/mnesia_snmp_hook.erl')
-rw-r--r--lib/mnesia/src/mnesia_snmp_hook.erl259
1 files changed, 259 insertions, 0 deletions
diff --git a/lib/mnesia/src/mnesia_snmp_hook.erl b/lib/mnesia/src/mnesia_snmp_hook.erl
new file mode 100644
index 0000000000..8b4b5231e1
--- /dev/null
+++ b/lib/mnesia/src/mnesia_snmp_hook.erl
@@ -0,0 +1,259 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+-module(mnesia_snmp_hook).
+
+%% Hooks (called from mnesia)
+-export([check_ustruct/1, create_table/3, delete_table/2,
+ key_to_oid/2, key_to_oid/3, oid_to_key/2,
+ update/1,
+ get_row/2, get_next_index/2, get_mnesia_key/2]).
+
+-export([key_to_oid_i/2, oid_to_key_1/2]). %% Test
+
+-include("mnesia.hrl").
+
+val(Var) ->
+ case ?catch_val(Var) of
+ {'EXIT', _ReASoN_} -> mnesia_lib:other_val(Var, _ReASoN_);
+ _VaLuE_ -> _VaLuE_
+ end.
+
+check_ustruct([]) ->
+ true; %% default value, not SNMP'ified
+check_ustruct([{key, Types}]) ->
+ is_snmp_type(to_list(Types));
+check_ustruct(_) -> false.
+
+to_list(Tuple) when is_tuple(Tuple) -> tuple_to_list(Tuple);
+to_list(X) -> [X].
+
+is_snmp_type([integer | T]) -> is_snmp_type(T);
+is_snmp_type([string | T]) -> is_snmp_type(T);
+is_snmp_type([fix_string | T]) -> is_snmp_type(T);
+is_snmp_type([]) -> true;
+is_snmp_type(_) -> false.
+
+create_table([], MnesiaTab, _Storage) ->
+ mnesia:abort({badarg, MnesiaTab, {snmp, empty_snmpstruct}});
+
+create_table([{key, Us}], MnesiaTab, Storage) ->
+ Tree = b_new(MnesiaTab, Us),
+ mnesia_lib:db_fixtable(Storage, MnesiaTab, true),
+ First = mnesia_lib:db_first(Storage, MnesiaTab),
+ build_table(First, MnesiaTab, Tree, Us, Storage),
+ mnesia_lib:db_fixtable(Storage, MnesiaTab, false),
+ Tree.
+
+build_table(MnesiaKey, MnesiaTab, Tree, Us, Storage)
+ when MnesiaKey /= '$end_of_table' ->
+ %%update(write, Tree, MnesiaKey, MnesiaKey),
+ SnmpKey = key_to_oid_i(MnesiaKey, Us),
+ b_insert(Tree, SnmpKey, MnesiaKey),
+ Next = mnesia_lib:db_next_key(Storage, MnesiaTab, MnesiaKey),
+ build_table(Next, MnesiaTab, Tree, Us, Storage);
+build_table('$end_of_table', _MnesiaTab, _Tree, _Us, _Storage) ->
+ ok.
+
+delete_table(_MnesiaTab, Tree) ->
+ b_delete_tree(Tree),
+ ok.
+
+%%-----------------------------------------------------------------
+%% update({Op, MnesiaTab, MnesiaKey, SnmpKey})
+%%-----------------------------------------------------------------
+
+update({clear_table, MnesiaTab}) ->
+ Tree = val({MnesiaTab, {index, snmp}}),
+ b_clear(Tree),
+ ok;
+
+update({Op, MnesiaTab, MnesiaKey, SnmpKey}) ->
+ Tree = val({MnesiaTab, {index, snmp}}),
+ update(Op, Tree, MnesiaKey, SnmpKey).
+
+update(Op, Tree, MnesiaKey, SnmpKey) ->
+ case Op of
+ write ->
+ b_insert(Tree, SnmpKey, MnesiaKey);
+ update_counter ->
+ ignore;
+ delete ->
+ b_delete(Tree, SnmpKey);
+ delete_object ->
+ b_delete(Tree, SnmpKey)
+ end,
+ ok.
+
+%%-----------------------------------------------------------------
+%% Func: key_to_oid(Tab, Key, Ustruct)
+%% Args: Key ::= key()
+%% key() ::= int() | string() | {int() | string()}
+%% Type ::= {fix_string | term()}
+%% Make an OBJECT IDENTIFIER out of it.
+%% Variable length objects are prepended by their length.
+%% Ex. Key = {"pelle", 42} AND Type = {string, integer} =>
+%% OID [5, $p, $e, $l, $l, $e, 42]
+%% Key = {"pelle", 42} AND Type = {fix_string, integer} =>
+%% OID [$p, $e, $l, $l, $e, 42]
+%%-----------------------------------------------------------------
+
+key_to_oid(Tab,Key) ->
+ Types = val({Tab,snmp}),
+ key_to_oid(Tab, Key, Types).
+
+key_to_oid(Tab, Key, [{key, Types}]) ->
+ try key_to_oid_i(Key,Types)
+ catch _:_ ->
+ mnesia:abort({bad_snmp_key, {Tab,Key}, Types})
+ end.
+
+key_to_oid_i(Key, integer) when is_integer(Key) -> [Key];
+key_to_oid_i(Key, fix_string) when is_list(Key) -> Key;
+key_to_oid_i(Key, string) when is_list(Key) -> [length(Key) | Key];
+key_to_oid_i(Key, Types) -> keys_to_oid(size(Key), Key, [], Types).
+
+keys_to_oid(0, _Key, Oid, _Types) -> Oid;
+keys_to_oid(N, Key, Oid, Types) ->
+ Oid2 = lists:append(key_to_oid_i(element(N, Key), element(N, Types)), Oid),
+ keys_to_oid(N-1, Key, Oid2, Types).
+
+%%--------------------------------------------------
+%% The reverse of the above, i.e. snmp oid to mnesia key.
+%% This can be lookup up in tree but that might be on a remote node.
+%% It's probably faster to look it up, but use when it migth be remote
+oid_to_key(Oid, Tab) ->
+ [{key, Types}] = val({Tab,snmp}),
+ oid_to_key_1(Types, Oid).
+
+oid_to_key_1(integer, [Key]) -> Key;
+oid_to_key_1(fix_string, Key) -> Key;
+oid_to_key_1(string, [_|Key]) -> Key;
+oid_to_key_1(Tuple, Oid) ->
+ try
+ List = oid_to_key_2(1, size(Tuple), Tuple, Oid),
+ list_to_tuple(List)
+ catch
+ _:_ -> unknown
+ end.
+
+oid_to_key_2(N, Sz, Tuple, Oid0) when N =< Sz ->
+ case element(N, Tuple) of
+ integer ->
+ [Key|Oid] = Oid0,
+ [Key|oid_to_key_2(N+1, Sz, Tuple, Oid)];
+ fix_string when N =:= Sz ->
+ [Oid0];
+ fix_string ->
+ throw(fix_string);
+ string ->
+ [Len|Oid1] = Oid0,
+ {Str,Oid} = lists:split(Len, Oid1),
+ [Str|oid_to_key_2(N+1, Sz, Tuple, Oid)]
+ end;
+oid_to_key_2(N, Sz, _, []) when N =:= (Sz+1) ->
+ [].
+
+%%-----------------------------------------------------------------
+%% Func: get_row/2
+%% Args: Name is the name of the table (atom)
+%% RowIndex is an Oid
+%% Returns: {ok, Row} | undefined
+%% Note that the Row returned might contain columns that
+%% are not visible via SNMP. e.g. the first column may be
+%% ifIndex, and the last MFA ({ifIndex, col1, col2, MFA}).
+%% where ifIndex is used only as index (not as a real col),
+%% and MFA as extra info, used by the application.
+%%-----------------------------------------------------------------
+get_row(Name, RowIndex) ->
+ Tree = mnesia_lib:val({Name, {index, snmp}}),
+ case b_lookup(Tree, RowIndex) of
+ {ok, {_RowIndex, Key}} ->
+ [Row] = mnesia:dirty_read({Name, Key}),
+ {ok, Row};
+ _ ->
+ undefined
+ end.
+
+%%-----------------------------------------------------------------
+%% Func: get_next_index/2
+%% Args: Name is the name of the table (atom)
+%% RowIndex is an Oid
+%% Returns: {NextIndex,MnesiaKey} | {endOfTable, undefined}
+%%-----------------------------------------------------------------
+get_next_index(Name, RowIndex) ->
+ Tree = mnesia_lib:val({Name, {index, snmp}}),
+ case b_lookup_next(Tree, RowIndex) of
+ {ok, R} ->
+ R;
+ _ ->
+ {endOfTable,undefined}
+ end.
+
+%%-----------------------------------------------------------------
+%% Func: get_mnesia_key/2
+%% Purpose: Get the mnesia key corresponding to the RowIndex.
+%% Args: Name is the name of the table (atom)
+%% RowIndex is an Oid
+%% Returns: {ok, Key} | undefiend
+%%-----------------------------------------------------------------
+get_mnesia_key(Name, RowIndex) ->
+ Tree = mnesia_lib:val({Name, {index, snmp}}),
+ case b_lookup(Tree, RowIndex) of
+ {ok, {_RowIndex, Key}} ->
+ {ok, Key};
+ _ ->
+ undefined
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Internal implementation, ordered_set ets.
+
+b_new(_Tab, _Us) ->
+ mnesia_monitor:unsafe_mktab(?MODULE, [public, ordered_set]).
+
+b_delete_tree(Tree) ->
+ ets:delete(Tree). %% Close via mnesia_monitor ?
+
+b_clear(Tree) ->
+ ets:delete_all_objects(Tree).
+
+b_insert(Tree, SnmpKey, MnesiaKey) ->
+ ets:insert(Tree, {SnmpKey, MnesiaKey}).
+
+b_delete(Tree, SnmpKey) ->
+ ets:delete(Tree, SnmpKey).
+
+b_lookup(Tree, RowIndex) ->
+ case ets:lookup(Tree, RowIndex) of
+ [X] ->
+ {ok, X};
+ _ ->
+ undefined
+ end.
+
+b_lookup_next(Tree,RowIndex) ->
+ case ets:next(Tree, RowIndex) of
+ '$end_of_table' ->
+ undefined;
+ Key ->
+ b_lookup(Tree, Key)
+ end.