当前位置: 首页 > 工具软件 > WiredTiger > 使用案例 >

用户视角的wiredtiger -- Using the API -- cursors、事务、和错误处理

许安邦
2023-12-01

本文在阅读wiredtiger的官方文档后,总结该存储引擎的基本概念、功能和特点。
本章介绍主要的API的使用。

Getting Start with the API

Getting Start with the API 介绍了接口的使用的基本流程,包括WT_CONNECTION ,WT_SESSION 和WT_CURSOR的创建。WT_CONNECTION于一个进程绑定,其方法多线程安全;一个connection可以创建多个WT_SESSION,每个线程访问数据库要通过打开一个session。每个session通过新建WT_CURSOR访问和修改数据。(例子 ex_access.c)

Configuration String

Configuration String 讲述了wiredtiger通过字符串的方式将配置传递给接口,如配置connection,session,cursor等。如此做的原因是保持接口数目少,以及不同语言下接口相似。支持两种格式,一种是简单的通过逗号划分K[V]对的方式,一种是通过json的的方式。

Cursors

Cursors 介绍了Cursors的基本功能(操作),常用操作都是通过cursor完成的。一个cursor包含以下四种信息:

  • a position within a data source
  • getter/setters for key and value fields
  • encoding of fields to store in the data source
  • methods to navigate within and iterate through the data

cursor的类型,类型有很多,如table cursor、column group cursor、 index cursor、join cursor、backup cursor、 log cursor、metadata cursor 、database cursor、file cursor和LSM cursor等,看起来访问所有数据都是通过cursor进行的。打开cursor时,通过configuration string可以打开某一种类型的cursor,同时部分cursor类型如table,index和join等可以指定projection。

Projection,通过调用 WT_SESSION::open_cursor函数时,在URI的后面加上"(a list of column names)",可以使得cursor在get_value时只获得表的一部分value列。这对于index cursor尤为有用, 因为如果project的列都可以在index中获得( 包括 primary key columns, 其为index的value), 那么这些数据只需要从index或得即可,无需从其他列簇中获得。

cursor和事务的关系,cursor所读到的数据与事务的隔离级别有关。在open session时配置事务的隔离级别。在并发事务中,其他事务在满足隔离条件的情况下,还需一个session下的所有cursor没有position到某个位置,也就是说,如果有cursor正在使用,该session读取的快照不会变化。Cursor positions survive transaction boundaries, unless a transaction is rolled back. When a transaction is rolled-back either implicitly or explicitly, all cursors in the session are reset as if the WT_CURSOR::reset method was called, discarding any cursor position as well as any key and value.

cursor和evict,使用cursor访问数据时,会将正在访问的page pin住,阻止其被evict,故使用完后对其reset,释放所需要的资源。

Raw mode,cursor中的Key和Value都使用单个 WT_ITEM类型的参数,如此Key或Value的参数个数就是固定的了。读取时,可通过读取出WT_ITEM的类型再进行unpack 或 对写入时,对数据进行pack再写进数据库。

cursor operation 讲述了 (例子ex_cursor.c)

  • cursor的基本方法,包括open、close、position、insert 、remove和 update等。其中Close可以通过调用cursor的接口,也可以通过关闭session或connection关闭。
  • Position的知识点
    • position可以在所有数据的开头、结尾、一个key上,一个key的附近;
    • 通过reset接口可以把position信息重置;
    • 一个未position的cursor调用next会从头开始,而调用prev会从末尾开始;
    • 通过search可以定位到某一个key;通过search_near,若存在key则定位到该key,否则定位到相邻的那个key(大于或小于都可能,需要用户筛选);
    • 对于行存的对象,还可以配置未random类型的cursor,即next返回的random(伪随机)的key;
    • Cursor positions do not survive transactions: cursors that are open during WT_SESSION::begin_transaction, WT_SESSION::commit_transaction or WT_SESSION::rollback_transaction will lose their position as if WT_CURSOR::reset was called. (暂不能理解, 和其他描述点冲突, 如上面的“cursor和事务”和下面的Transactions)
  • insert、remove或update,通过cursor操作,其overwrite选项默认true,即不管要操作的key的状态如何,总是能成功;若将cursor置未false,则若insert时,key存在会返回 WT_DUPLICATE_KEY错误;remove或update时,key不存在会返回 WT_NOTFOUND 错误。
  • Cursor position after error, 若在cursor的操作遇到错误,其position的位置undetermined, 但是key和value的内存还有效。若不能进行re-position, 则可通过open cursor,并通过to_dup参数对cursor进行复制,再进行re-position。对于backup, config and statistics 类型的cursor不支持dup
  • Cursor key/value memory scoping, 当传递指针 ( WT_ITEM 或a string)给WT_CURSOR::set_key or WT_CURSOR::set_value, 不拷贝指针所指向的内存,故在调用下一个操作(position操作,包括next、prev、search、 search_near,修改操作 insert、 update、remove,reset和关闭操作)成功执行前,需保证地址有效。而对于WT_CURSOR::get_key or WT_CURSOR::get_value返回的指针,只能保证在下次成功调用position操作,修改操作,reset和关闭操作前有效,若需要更长的使用期限,需要用户自己将指向的内容拷贝出去。(类似LevelDB/RocksDB的Slice逻辑)。

数据源(Data Sources),wiredtiger可以搜寻多种数据源;At the lowest level, data may be stored in a file using a tree structure. A relational schema supporting tables, indices and column groups is layered on top of file. Additional sources include LSM trees and statistics, and applications can further extend the supported types by implementing the WT_DATA_SOURCE interface. 内置数据源有很多,上述的cursor的每种类型就与一种数据源相对应。如通过file 类型的cursor即可访问raw file数据源。其他的如,索引数据源,统计数据(Statistics Data)源等。统计数据可以有两种级别,整个数据库的统计数据,某个数据源的统计数据。可以访问join cursor的统计数据,某个session的统计数据,等。统计数据的key有一个集合,而value的格式为 a printable description of the statistic, a printable version of the entry’s value, and the entry’s unsigned 64-bit integral value, respectively。
(从这里来看,cursor类似于LevelDB/RocksDB中的迭代器 + WriteBatch的组合)。

Transactions

Transactions 介绍了其满足数据的ACID特性。其最大的隔离级别为snapshot的隔离级别(wiredtiger中可以避免“不可重复读”,但是不能避免“幻读”,即未达到最高的可序列化的隔离级别);事务的修改通过结合checkpoint和日志达到持久化的特性(See Checkpoint durability for information on checkpoint durability and Commit-level durability for information on commit-level durability.);wiredtiger事务的所有修改操作缓存在内存中,只有当事务commit时才会写进log,也就是说不支持(超)大事务。

Transactional API,通过 WT_SESSION::begin_transaction、 WT_SESSION::commit_transaction、 WT_SESSION::rollback_transaction接口操作事务。Applications that use Application-specified Transaction Timestamps can utilize the WT_SESSION::prepare_transaction API as a basis for implementing a two phase commit protocol.
若事务commit失败,会自动回滚。若事务发生冲突,操作会返回WT_ROLLBACK错误,若发生此类错误,需要用户回滚。若事务发生回滚,事务的所有cursor会被隐式的reset而使得所有position以及其key/value失效。

隐式事务,若没有active的cursor,cursor读取的行为由 WT_CONNECTION::open_session时指定的隔离级别决定。修改操作在操作返回前会进行commit。多个修改操作需要显式的使用事务以达到原子性。若隐式的事务commit成功,cursor状态得以保持,若隐式事务失败,所有的cursor会被reset而使得其position和key/value失效。

并行控制, wiredtiger通过乐观锁的方式实现事务。其实现了读写之间不会互斥。进一步,写与写之间一般也不会发生互斥。只有在并行的事务在写同一key时,会发生 WT_ROLLBACK错误。事务在系统资源不够时,也可能发生 WT_ROLLBACK错误,如写缓存不够时。

隔离级别,wiredtiger支持读未提交、读已提交(默认)、快照,三种隔离级别。wiredtiger中,快照的隔离级别可以避免脏读、不可重复读,但是不能避免幻读,即未达到最高的可序列化的隔离级别。具体来说,Snapshot isolation is a strong guarantee, but not equivalent to a single-threaded execution of the transactions, known as serializable isolation. Concurrent transactions T1 and T2 running under snapshot isolation may both commit and produce a state that neither (T1 followed by T2) nor (T2 followed by T1) could have produced, if there is overlap between T1’s reads and T2’s writes, and between T1’s writes and T2’s reads. 事务的隔离级别既可以通过WT_SESSION::begin_transaction为每一个事务指定隔离级别,也可以在WT_CONNECTION::open_session时指定隔离级别,WT_CONNECTION::reconfigure重新配置隔离级别。

命名快照(Named Snapshots) 通过WT_SESSION::snapshot函数指定name参数可以生成命名的快照;使用该快照的(后续)事务,就像在调用snapshot函数处进行了begin transaction一样。该快照通过WT_SESSION::snapshot函数指定drop参数关闭。命名快照是没有进行持久化的,当connection关闭后将消失。

Application-specified Transaction Timestamps 允许用户对事务指定时间戳;为事务的更新指定不同时间戳;prepare操作指定时间戳等(以支持两阶段提交,2PC);逻辑较为复杂,暂时略过。

Error Handling

Error Handling 讲述了wiredtiger的操作的各种错误码的含义;通过暴露给用户的WT_EVENT_HANDLER参数可进行对错误消息的处理。(ex_event_handler.c)
错误码分为正错误码和负错误码(范围为[-31,800,-31,999]),正的为POSIX文件系统的标准错误码如EINVAL和EBUSY等,负的为wiredtiger特有的错误码(完整的错误码列表包括WT_ROLLBACK、WT_DUPLICATE_KEY、WT_ERROR、WT_NOTFOUND、WT_PANIC、WT_RUN_RECOVERY、WT_CACHE_FULL、WT_PREPARE_CONFLICT、WT_TRY_SALVAGE)。当返回EBUSY表示获取某种排他性资源失败, 如 WT_SESSION::drop or WT_SESSION::verify函数对于已经打开了cursor的会返回该错误。注意wiredtiger会临时的对某些objects进行open cursors操作(如进行statistics logging),使得用户即使没有打开cursor,可能也会返回EBUSY错误。

Translating errors 用户可以通过 WT_SESSION::strerror 或 wiredtiger_strerror函数将错误码转换为message,其中前者多线程安全而后者不是。

Message handling using the WT_EVENT_HANDLER 用户可以通过实现WT_EVENT_HANDLER(参数包括错误码和错误消息)并将其作为参数传递给wiredtiger_open 或 WT_CONNECTION::open_session 以进行 informational and error messages 的处理(如,加上时间戳打日志)。其中WT_PANIC错误比较特殊,出现该错误后总会error handler callback,该错误需要用户重启数据库(对wiredtiger的任何API调用都会fail)。一个正确的处理方式很可能是,在出现该错误后通过调用error handler立即exit或进行错误处理。WT_EVENT_HANDLER内包含四种函数指针,分别为handle_error,handle_message,handle_progress,handle_close;若某个函数指针被置为NULL,将对其采用默认行为。
handle_error为处理error messages的回调函数; 默认情况下 error messages写入stderr流。
handle_message为处理informational messages的回调函数; 默认情况下 informational messages写入stdout流。
handle_progress为处理progress messages的回调函数; 默认情况下 progress messages不进行写操作。
handle_close为处理 WiredTiger handle(session handle 或cursor handle)自动关闭的回调函数,无默认情况。
这些函数的返回值不会被忽略, if the handler returns non-zero, the error may cause the WiredTiger function posting the event to fail, and may even cause operation or library failure.

 类似资料: