首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

An Asynchronous I/O Module For SQLite

注意:将PRAGMA同步设置为NORMAL的WAL模式可避免在事务提交期间调用fsync(),并且仅在检查点操作期间调用fsync()。使用WAL模式很大程度上避免了对这种异步I / O模块的需求。因此,这个模块不再被支持。源代码继续存在于SQLite源代码树中,但它不是任何标准构建的一部分,也不再维护。本文档保留以供历史参考。

通常,当SQLite写入数据库文件时,它会等到写操作完成后再将控制权返回给调用应用程序。由于与CPU绑定操作相比,写入文件系统通常非常缓慢,因此这可能是性能瓶颈。异步I / O后端是一种扩展,它使SQLite使用在后台运行的单独线程执行所有写入请求。虽然这不会减少整个系统资源(CPU,磁盘带宽等),但它确实允许SQLite在写入数据库时​​快速将控制权返回给调用者。

1.0功能

使用异步I / O,写入请求由在后台运行的单独线程处理。这意味着启动数据库写入的线程不必等待(有时很慢)的磁盘I / O发生。写作似乎很快就会发生,尽管实际上它在背景中以通常缓慢的速度发生。

异步I / O似乎提供了更好的响应能力,但价格昂贵。你失去了耐久性财产。使用SQLite的默认I / O后端,一旦写入完成,您就知道您写入的信息在磁盘上是安全的。对于异步I / O,情况并非如此。如果程序崩溃或数据库写入后但在异步写入线程完成之前发生断电,则数据库更改可能永远不会将其写入磁盘,并且数据库的下一个用户可能看不到您的更改。

你失去了异步I / O的耐久性,但你仍然保留着ACID的其他部分:原子,一致和孤立。许多应用程序相处良好,没有耐久性。

1.1它是如何工作的

异步I / O通过创建SQLite VFS对象并将其注册到sqlite3_vfs_register()来工作。当通过这个VFS打开的文件被写入(使用vfs xWrite()方法)时,数据不会直接写入磁盘,而是被放置在由后台线程处理的“写入队列”中。

当使用vfs xRead()方法读取使用异步VFS打开的文件时,将从磁盘上的文件和写入队列中读取数据,以便从vfs读取器的角度来看xWrite()似乎已经完成。

异步I / O VFS通过调用API函数sqlite3async_initialize()和sqlite3async_shutdown()来注册(和未注册)。有关详细信息,请参见下面的“编译和使用”部分。

1.2限制

为了获得有关异步IO的主要想法的经验,这个实现是故意保持简单的。未来可能会添加其他功能。

例如,正如当前实现的那样,如果写操作发生在超过后台写入器线程的I / O能力的稳定流上,未决写入操作的队列将无限制地增长。如果持续时间足够长,主机系统可能会耗尽内存。一个更复杂的模块可以跟踪等待写入的数量,并在等待写入队列变得太大时停止接受新的写入请求。

1.3锁定和并发

使用此异步IO实现的单个进程中的多个连接可以同时访问单个数据库文件。从用户的角度来看,如果所有连接都来自单个进程,那么“正常”SQLite和使用异步后端的SQLite提供的并发性没有区别。

如果启用了文件锁定(默认启用),则来自多个进程的连接也可以读取和写入数据库文件。但并发性降低如下:

  • 当使用异步IO的连接开始数据库事务时,数据库立即被锁定。但是,直到写入队列中的所有相关操作都被刷新到磁盘后,锁才会被释放。这意味着(例如)在发出“COMMIT”或“ROLLBACK”后数据库可能会保持锁定一段时间。
  • 如果使用异步IO的应用程序快速连续执行事务,则其他数据库用户可能会被有效地锁定在数据库之外。这是因为在执行BEGIN时,立即建立数据库锁。但是,当相应的COMMIT或ROLLBACK发生时,只有在写入队列的相关部分被刷新后才会释放锁。因此,如果在刷新写入队列之前COMMIT之后是BEGIN,那么数据库永远不会解锁,从而阻止其他进程访问数据库。

可以在运行时使用sqlite3async_control()API禁用文件锁定(请参见下文)。这可以提高NFS性能或其他网络文件系统的性能,例如避免建立文件锁定所需的服务器同步往返。但是,如果禁用文件锁定时多个连接尝试访问同一个数据库文件,则应用程序崩溃和数据库损坏可能是结果。

2.0编译和使用

异步IO扩展由位于SQLite源代码树的子文件夹中的单个C代码文件(sqlite3async.c)和头文件(sqlite3async.h)组成,该文件定义应用程序用于激活和控制的C API模块功能。 ext/async/

要使用异步IO扩展,请将sqlite3async.c编译为使用SQLite的应用程序的一部分。然后使用sqlite3async.h中定义的API来初始化和配置模块。

在sqlite3async.h中的注释中详细描述了异步IO VFS API。使用API​​通常包含以下步骤:

  1. 通过调用sqlite3async_initialize()函数向SQLite注册异步IO VFS。
  1. 创建后台线程来执行写入操作并调用sqlite3async_run()。
  1. 使用普通的SQLite API通过异步IO VFS读写数据库。

有关详细信息,请参阅sqlite3async.h头文件中的注释

3.0 PORTING

目前,异步IO扩展与支持pthreads接口的win32系统和系统兼容,包括Mac OS X,Linux和其他各种Unix。

要将异步IO扩展移植到另一个平台,用户必须为新平台实现互斥和条件变量原语。目前没有外部可用的接口来允许这一点,但修改sqlite3async.c中的代码以包含新平台的并发原语相对容易。有关详细信息,请在sqlite3async.c中搜索注释字符串“PORTING FUNCTIONS”。然后实施以下每个版本的新版本:

代码语言:javascript
复制
static void async_mutex_enter(int eMutex);
static void async_mutex_leave(int eMutex);
static void async_cond_wait(int eCond, int eMutex);
static void async_cond_signal(int eCond);
static void async_sched_yield(void);

上述每个函数所需的功能在sqlite3async.c的注释中进行了描述。

代码语言:javascript
复制
 SQLite在公共领域。

扫码关注腾讯云开发者

领取腾讯云代金券