OvS DB Client C IDL 复合索引

143 阅读5分钟

ovs db client 集成了 c 实现的 IDL 组合索引机制

典型的使用的场景:快速查询

快速查询

根据不同的拓扑结构,网络设备的路由表可以管理数千条路由。像 “show ip route xxx” 这样的命令需要对路由表进行顺序查找以找到特定的路由。

创建索引后,查找时间可能会更快。 同样的场景也可以应用于其他特性,比如Access List规则,甚至接口列表。

字母表排序(Lexicographic order)

在许多情况下,需要按照特定的字典顺序检索数据。例如 SNMP。当管理员甚至 NMS 希望从特定设备检索数据时, 他们可能会从完整的表中请求数据,而不仅仅是从特定的值中请求数据。

此外,他们还希望按照 字母表顺序 显示这些信息。此操作可以由 SNMP 守护进程或 CLI 完成,但是如果数据库能够提供准备使用的数据就更好了。此外,还可以避免不同流程的重复工作。按字典顺序请求数据的另一个用例是用户界面(web 或 CLI),如果 DB 发送排序的数据,而不是让每个进程自己排序数据,这样会更好更快。

底层实现设计

该特性维护每个表的索引集合。应用程序可以为每个表创建任意数量的索引。

索引可以在任意数量的列上定义,并支持以下选项:

• 添加一个类型为 string、boolean、uuid、integer 或 real 的列(使用默认比较器)。 • 选择列的排序方向(升序或降序,创建索引时必须选择)。 • 使用自定义排序比较器(例如:将字符串列视为 IP ,或按 map 列中 “config” 键的值排序)。

为了查询索引,用户需要创建一个游标。该游标指向索引中的某个位置。然后,用户可以使用游标执行查找(按键)和或获取后续行。用户还可以将光标的当前值与记录进行比较。

对于查找,用户需要提供一个键,用于定位满足其标准的特定行。这个键可以是 IP 地址、MAC 地址、ACL 规则等。当在数据结构中找到信息时,将更新用户的游标以指向该行。如果有几行与查询匹配,那么用户可以通过更新游标轻松地按顺序获得下一行。

为了按字典顺序访问数据,用户可以使用范围迭代器。这些迭代器需要游标和 “from” 和 “to” 值来定义范围。

索引在本地副本中维护一个指向该行的指针,避免了对数据进行额外复制的需要,从而最大限度地减少了维护索引所需的额外内存和 CPU 开销。创建和维护索引的成本应该非常低。

另一个潜在的问题是创建数据结构所需的时间和添加/删除元素所需的时间。 索引总是与副本同步。由于这个原因,比较函数(内置的和用户提供的)是快速的是非常重要的。

跳跃列表(跳表)被用作实现索引的主要数据结构:

  • 因此,在插入、删除或修改一行时,索引的预期成本为O(log(n))
  • 在按键检索一行时,索引的预期成本为O(log(n))
  • 在检索第一行或下一行时,索引的预期成本为O(log(n))

当从 OVSDB 接收到数据库更改的通知时,索引在副本中以增量方式维护 服务器,如下图所示:

image.png

image.png

索引创建

每个索引必须使用 ovsdb_idl_create_index()函数创建。创建索引后,用户可以使用ovsdb_idl_index_add_column 向索引添加一个或多个列。在第一次调用 ovsdb_idl_run()之前,必须创建所有索引并添加所有列。

代码示例:

为表“Test”中的“stringField”列定义一个自定义比较器。(请注意,通常不需要自定义比较函数。)

image.png image.png

使用索引

1. 迭代器场景

推荐的查询方法是对索引使用:

  • ranged foreach
  • equal foreach
  • full foreach 其工作原理如下:
  1. 创建游标
  2. 创建索引行对象,将索引列设置为所需的搜索键值:
  • 对于 equal 迭代器需要一个
  • 对于 range 迭代器有两个
  • 对于全索引(full)迭代器不需要搜索键)
  1. 将游标、迭代变量和键值传递给迭代器
  2. 在迭代器循环中使用这些值

要为示例创建游标,我们使用以下代码:

image.png

现在可以使用游标执行查询。标准库实现了三种不同的迭代器:范围迭代器、相等迭代器和全索引迭代器。

  • 范围迭代器接收两个值,并遍历该范围内的所有行(包括定义该范围的两个值)。
  • 相等迭代器遍历与传递的值完全匹配的所有行。
  • 全索引迭代器迭代索引中的所有行,其顺序由比较函数和配置的方向(升序或降序)决定。

请注意,索引是按所有索引列中的值的“串联”排序的,因此 range 迭代器返回从之间的所有值。 “from.col1 from.col2 . . . from.coln” and “to.col1 to.col2 . . . to.coln”, 而不是列1中的 from.col1 and to.col1 的值,等等。

迭代器是特定于每个表的宏。下面是使用这些迭代器的示例:

image.png

image.png

通用索引访问

虽然当前定义的迭代器适用于许多用例,但也可以使用构建现有迭代器的更通用的 API 来创建自定义迭代器。该 API包括以下函数,在 “lib/ovsdb-idl.h” 中声明:

  1. ovsrec_table名_index_compare()

  2. ovsrec_table名_index_next()

  3. ovsrec_table名_index_find()

  4. ovsrec_table名_index_forward_to()

  5. ovsrec_table名_index_get_data()