查看源码 snmp_index (snmp v5.18)

SNMP 索引的抽象数据类型

模块 snmp_index 为 SNMP 表实现了一种 SNMP 索引结构的抽象数据类型(ADT)。它被实现为 ordered_set 数据类型的 ets 表,这意味着所有操作的时间复杂度都是 O(log n)。在表中,键是 ASN.1 OBJECT IDENTIFIER。

此索引用于将 SNMP 排序的实现与表的实际实现分离。SNMP 排序,即 GET NEXT 的实现,在此模块中实现。

例如,假设有一个 SNMP 表,在 Erlang 中最佳的实现方式是每个 SNMP 表行一个进程。进一步假设 SNMP 表中的 INDEX 是一个 OCTET STRING。索引结构将如下创建

snmp_index:new(string)

对于我们创建的每个新进程,我们在 snmp_index 结构中插入一个项

new_process(Name, SnmpIndex) ->
  Pid = start_process(),
  NewSnmpIndex =
    snmp_index:insert(SnmpIndex, Name, Pid),
  <...>

有了这个结构,我们现在可以将例如 GET NEXT 请求中的 OBJECT IDENTIFIER 映射到正确的进程

get_next_pid(Oid, SnmpIndex) ->
  {ok, {_, Pid}} = snmp_index:get_next(SnmpIndex, Oid),
  Pid.

警告

警告

所有更新索引的 API 函数都返回一个 NewIndex 项。这是为了向后兼容之前使用纯 Erlang 编写的 B+ 树作为索引的实现。NewIndex 返回值现在可以忽略。返回值现在是 ets 表的未更改的表标识符。

使用 ets 表的实现引入了与旧实现的语义不兼容。在那些使用纯 Erlang 项的旧实现中,索引像任何其他 Erlang 项一样被垃圾回收,并且在丢弃时不必删除。只有当创建它的进程显式删除它或创建进程终止时,ets 表才会被删除。

现在添加了一个新的接口 delete/1 来处理进程想要丢弃索引表(即构建一个全新的索引表)的情况。任何使用瞬态 snmp 索引的应用程序都必须进行修改以处理这种情况。

由于 snmp 适配通常在整个系统的生命周期中保留索引,因此这很少成为问题。

概要

类型

此类型表示 snmp 索引结构。

此类型与 key_types/0 类型相关。如果 key_types/0 是单个原子,则相应的 key/0 也是单个类型,但是如果 key_types/0 是一个元组,则 key/0 必须是相同大小的元组。

此类型在创建索引结构时使用,而 key/0 类型在从结构中插入和删除项时使用。

函数

删除完整的索引结构(即保存索引的 ets 表)。在此调用之后,该索引将不再被引用。请参阅上面的 警告说明

从索引结构中删除键及其值。返回一个新的结构。

获取键为 KeyOid 的项。可以从 SNMP 检测函数内部使用。

获取索引结构中的最后一项。

获取索引结构中 KeyOid 之后的 SNMP 词典排序中的下一项。KeyOid 不必引用索引中现有的项。

将新的键值元组插入索引结构。如果已存在具有相同键的项,则新的 Value 会覆盖旧值。

Key 转换为 OBJECT IDENTIFIER。

创建一个新的匿名 snmp 索引结构。

创建一个新的命名 snmp 索引结构。

类型

-opaque index()

此类型表示 snmp 索引结构。

-type key() :: key_spec() | tuple().

此类型与 key_types/0 类型相关。如果 key_types/0 是单个原子,则相应的 key/0 也是单个类型,但是如果 key_types/0 是一个元组,则 key/0 必须是相同大小的元组。

在上面的示例中,有效的 keys 可以是 {"hi", "mom"}{"no", "thanks"},而 "hi"{"hi", 42}{"hello", "there"} 将是无效的。

在 erlang 类型语言中无法正确描述此类型,这就是为什么上面使用了 tuple/0。正确的定义如下所示

key() = key_spec() | {key_spec(), key_spec(), ...}

-type key_spec() :: string() | integer().
-type key_types() :: type_spec() | tuple().

此类型在创建索引结构时使用,而 key/0 类型在从结构中插入和删除项时使用。

如果 INDEX 列的类型为 INTEGER 或从 INTEGER 派生,则相应的类型应为 integer。 如果它是可变长度类型(例如,OBJECT IDENTIFIER、OCTET STRING),则相应的类型应为 string。最后,如果类型是可变长度的,但具有固定大小限制(例如,IpAddress),则相应的类型应为 fix_string

在 erlang 类型语言中无法正确描述此类型,这就是为什么上面使用了 tuple/0。正确的定义如下所示

key_types = type_spec() | {type_spec(), type_spec(), ...}

-type type_spec() :: fix_string | string | integer.

函数

-spec delete(Index) -> true when Index :: index().

删除完整的索引结构(即保存索引的 ets 表)。在此调用之后,该索引将不再被引用。请参阅上面的 警告说明

-spec delete(Index, Key) -> NewIndex when Index :: index(), Key :: key(), NewIndex :: index().

从索引结构中删除键及其值。返回一个新的结构。

-spec get(Index, KeyOid) -> {ok, {KeyOid, Value}} | undefined
             when Index :: index(), KeyOid :: snmp:oid(), Value :: term().

获取键为 KeyOid 的项。可以从 SNMP 检测函数内部使用。

-spec get_last(Index) -> {ok, {KeyOid, Value}} | undefined
                  when Index :: index(), KeyOid :: snmp:oid(), Value :: term().

获取索引结构中的最后一项。

链接到此函数

get_next(Index, KeyOid)

查看源码
-spec get_next(Index, KeyOid) -> {ok, {NextKeyOid, Value}} | undefined
                  when Index :: index(), KeyOid :: snmp:oid(), NextKeyOid :: snmp:oid(), Value :: term().

获取索引结构中 KeyOid 之后的 SNMP 词典排序中的下一项。KeyOid 不必引用索引中现有的项。

链接到此函数

insert(Index, Key, Value)

查看源码
-spec insert(Index, Key, Value) -> NewIndex
                when Index :: index(), Key :: key(), Value :: term(), NewIndex :: index().

将新的键值元组插入索引结构。如果已存在具有相同键的项,则新的 Value 会覆盖旧值。

链接到此函数

key_to_oid(Index, Key)

查看源码
-spec key_to_oid(Index, Key) -> KeyOid when Index :: index(), Key :: key(), KeyOid :: snmp:oid().

Key 转换为 OBJECT IDENTIFIER。

-spec new(KeyTypes) -> Index when KeyTypes :: key_types(), Index :: index().

创建一个新的匿名 snmp 索引结构。

链接到此函数

new(KeyTypes, Name)

查看源码 (自 OTP 27.0 起)
-spec new(KeyTypes, Name) -> Index when KeyTypes :: key_types(), Name :: atom(), Index :: index().

创建一个新的命名 snmp 索引结构。