用于 SQLite 的异步 I/O 模块(二十四)

返回:SQLite—系列文章目录   

上一篇:SQLite的PRAGMA 声明(二十三)

下一篇:SQLite、MySQL 和 PostgreSQL 数据库速度比较(本文阐述时间很早比较,不具有最新参考性)(二十五)

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


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

1.0 功能

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

异步 I/O 似乎提供了更好的响应能力,但要付出代价。 您将失去 Durable 属性。使用 SQLite 的默认 I/O 后端, 写入完成后,您就知道您写入的信息是 安全地在磁盘上。对于异步 I/O,情况并非如此。如果 程序崩溃或数据库断电后 写入,但在异步写入线程完成之前,则 数据库更改可能永远不会进入磁盘,而 数据库可能看不到您的更改。

异步 I/O 会失去持久性,但仍会保留 ACID 的其他部分:原子、一致和隔离。多 应用程序在没有耐用性的情况下相处得很好。

1.1 它是如何工作的

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

从中读取使用异步 VFS 打开的文件时 (使用 vfs xRead() 方法),从 磁盘和写入队列,因此从 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 或其他 NFS 或其他 网络文件系统,因为与服务器的同步往返是 避免了建立文件锁所需的条件。但是,如果多个 连接在文件锁定时尝试访问同一数据库文件 被禁用,应用程序崩溃和数据库损坏是可能的 结果。

2.0 编译与使用

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

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

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

  1. 通过调用 sqlite3async_initialize() 函数。

  2. 创建后台线程以执行写入操作和调用 sqlite3async_run()。

  3. 使用普通的 SQLite API 通过以下方式读取和写入数据库 异步 IO VFS。

有关详细信息,请参阅 sqlite3async.h 头文件中的注释。或本文编写时最新代码如下:


#ifndef __SQLITEASYNC_H_
#define __SQLITEASYNC_H_ 1/*
** Make sure we can call this stuff from C++.
*/
#ifdef __cplusplus
extern "C" {
#endif#define SQLITEASYNC_VFSNAME "sqlite3async"/*
** THREAD SAFETY NOTES:
**
** Of the four API functions in this file, the following are not threadsafe:
**
**   sqlite3async_initialize()
**   sqlite3async_shutdown()
**
** Care must be taken that neither of these functions is called while 
** another thread may be calling either any sqlite3async_XXX() function
** or an sqlite3_XXX() API function related to a database handle that
** is using the asynchronous IO VFS.
**
** These functions:
**
**   sqlite3async_run()
**   sqlite3async_control()
**
** are threadsafe. It is quite safe to call either of these functions even
** if another thread may also be calling one of them or an sqlite3_XXX()
** function related to a database handle that uses the asynchronous IO VFS.
*//*
** Initialize the asynchronous IO VFS and register it with SQLite using
** sqlite3_vfs_register(). If the asynchronous VFS is already initialized
** and registered, this function is a no-op. The asynchronous IO VFS
** is registered as "sqlite3async".
**
** The asynchronous IO VFS does not make operating system IO requests 
** directly. Instead, it uses an existing VFS implementation for all
** required file-system operations. If the first parameter to this function
** is NULL, then the current default VFS is used for IO. If it is not
** NULL, then it must be the name of an existing VFS. In other words, the
** first argument to this function is passed to sqlite3_vfs_find() to
** locate the VFS to use for all real IO operations. This VFS is known
** as the "parent VFS".
**
** If the second parameter to this function is non-zero, then the 
** asynchronous IO VFS is registered as the default VFS for all SQLite 
** database connections within the process. Otherwise, the asynchronous IO
** VFS is only used by connections opened using sqlite3_open_v2() that
** specifically request VFS "sqlite3async".
**
** If a parent VFS cannot be located, then SQLITE_ERROR is returned.
** In the unlikely event that operating system specific initialization
** fails (win32 systems create the required critical section and event 
** objects within this function), then SQLITE_ERROR is also returned.
** Finally, if the call to sqlite3_vfs_register() returns an error, then 
** the error code is returned to the user by this function. In all three
** of these cases, intialization has failed and the asynchronous IO VFS
** is not registered with SQLite.
**
** Otherwise, if no error occurs, SQLITE_OK is returned.
*/ 
int sqlite3async_initialize(const char *zParent, int isDefault);/*
** This function unregisters the asynchronous IO VFS using 
** sqlite3_vfs_unregister().
**
** On win32 platforms, this function also releases the small number of 
** critical section and event objects created by sqlite3async_initialize().
*/ 
void sqlite3async_shutdown(void);/*
** This function may only be called when the asynchronous IO VFS is 
** installed (after a call to sqlite3async_initialize()). It processes
** zero or more queued write operations before returning. It is expected
** (but not required) that this function will be called by a different 
** thread than those threads that use SQLite. The "background thread"
** that performs IO.
**
** How many queued write operations are performed before returning 
** depends on the global setting configured by passing the SQLITEASYNC_HALT
** verb to sqlite3async_control() (see below for details). By default
** this function never returns - it processes all pending operations and 
** then blocks waiting for new ones.
**
** If multiple simultaneous calls are made to sqlite3async_run() from two
** or more threads, then the calls are serialized internally.
*/
void sqlite3async_run(void);/*
** This function may only be called when the asynchronous IO VFS is 
** installed (after a call to sqlite3async_initialize()). It is used 
** to query or configure various parameters that affect the operation 
** of the asynchronous IO VFS. At present there are three parameters 
** supported:
**
**   * The "halt" parameter, which configures the circumstances under
**     which the sqlite3async_run() parameter is configured.
**
**   * The "delay" parameter. Setting the delay parameter to a non-zero
**     value causes the sqlite3async_run() function to sleep for the
**     configured number of milliseconds between each queued write 
**     operation.
**
**   * The "lockfiles" parameter. This parameter determines whether or 
**     not the asynchronous IO VFS locks the database files it operates
**     on. Disabling file locking can improve throughput.
**
** This function is always passed two arguments. When setting the value
** of a parameter, the first argument must be one of SQLITEASYNC_HALT,
** SQLITEASYNC_DELAY or SQLITEASYNC_LOCKFILES. The second argument must
** be passed the new value for the parameter as type "int".
**
** When querying the current value of a paramter, the first argument must
** be one of SQLITEASYNC_GET_HALT, GET_DELAY or GET_LOCKFILES. The second 
** argument to this function must be of type (int *). The current value
** of the queried parameter is copied to the memory pointed to by the
** second argument. For example:
**
**   int eCurrentHalt;
**   int eNewHalt = SQLITEASYNC_HALT_IDLE;
**
**   sqlite3async_control(SQLITEASYNC_HALT, eNewHalt);
**   sqlite3async_control(SQLITEASYNC_GET_HALT, &eCurrentHalt);
**   assert( eNewHalt==eCurrentHalt );
**
** See below for more detail on each configuration parameter.
**
** SQLITEASYNC_HALT:
**
**   This is used to set the value of the "halt" parameter. The second
**   argument must be one of the SQLITEASYNC_HALT_XXX symbols defined
**   below (either NEVER, IDLE and NOW).
**
**   If the parameter is set to NEVER, then calls to sqlite3async_run()
**   never return. This is the default setting. If the parameter is set
**   to IDLE, then calls to sqlite3async_run() return as soon as the
**   queue of pending write operations is empty. If the parameter is set
**   to NOW, then calls to sqlite3async_run() return as quickly as 
**   possible, without processing any pending write requests.
**
**   If an attempt is made to set this parameter to an integer value other
**   than SQLITEASYNC_HALT_NEVER, IDLE or NOW, then sqlite3async_control() 
**   returns SQLITE_MISUSE and the current value of the parameter is not 
**   modified.
**
**   Modifying the "halt" parameter affects calls to sqlite3async_run() 
**   made by other threads that are currently in progress.
**
** SQLITEASYNC_DELAY:
**
**   This is used to set the value of the "delay" parameter. If set to
**   a non-zero value, then after completing a pending write request, the
**   sqlite3async_run() function sleeps for the configured number of 
**   milliseconds.
**
**   If an attempt is made to set this parameter to a negative value,
**   sqlite3async_control() returns SQLITE_MISUSE and the current value
**   of the parameter is not modified.
**
**   Modifying the "delay" parameter affects calls to sqlite3async_run() 
**   made by other threads that are currently in progress.
**
** SQLITEASYNC_LOCKFILES:
**
**   This is used to set the value of the "lockfiles" parameter. This
**   parameter must be set to either 0 or 1. If set to 1, then the
**   asynchronous IO VFS uses the xLock() and xUnlock() methods of the
**   parent VFS to lock database files being read and/or written. If
**   the parameter is set to 0, then these locks are omitted.
**
**   This parameter may only be set when there are no open database
**   connections using the VFS and the queue of pending write requests
**   is empty. Attempting to set it when this is not true, or to set it 
**   to a value other than 0 or 1 causes sqlite3async_control() to return
**   SQLITE_MISUSE and the value of the parameter to remain unchanged.
**
**   If this parameter is set to zero, then it is only safe to access the
**   database via the asynchronous IO VFS from within a single process. If
**   while writing to the database via the asynchronous IO VFS the database
**   is also read or written from within another process, or via another
**   connection that does not use the asynchronous IO VFS within the same
**   process, the results are undefined (and may include crashes or database
**   corruption).
**
**   Alternatively, if this parameter is set to 1, then it is safe to access
**   the database from multiple connections within multiple processes using
**   either the asynchronous IO VFS or the parent VFS directly.
*/
int sqlite3async_control(int op, ...);/*
** Values that can be used as the first argument to sqlite3async_control().
*/
#define SQLITEASYNC_HALT          1
#define SQLITEASYNC_GET_HALT      2
#define SQLITEASYNC_DELAY         3
#define SQLITEASYNC_GET_DELAY     4
#define SQLITEASYNC_LOCKFILES     5
#define SQLITEASYNC_GET_LOCKFILES 6/*
** If the first argument to sqlite3async_control() is SQLITEASYNC_HALT,
** the second argument should be one of the following.
*/
#define SQLITEASYNC_HALT_NEVER 0       /* Never halt (default value) */
#define SQLITEASYNC_HALT_NOW   1       /* Halt as soon as possible */
#define SQLITEASYNC_HALT_IDLE  2       /* Halt when write-queue is empty */#ifdef __cplusplus
}  /* End of the 'extern "C"' block */
#endif
#endif        /* ifndef __SQLITEASYNC_H_ */

3.0 移植

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

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

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 的注释中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/619962.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机网络——WEB服务器编程实验

实验目的 1. 处理一个 http 请求 2. 接收并解析 http 请求 3. 从服务器文件系统中获得被请求的文件 4. 创建一个包括被请求的文件的 http 响应信息 5. 直接发送该信息到客户端 具体内容 一、C 程序来实现 web 服务器功能。 二、用 HTML 语言编写两个 HTML文件,并…

webpack打包ts代码

前面一篇文章介绍了如何使用ts‘编译器编译ts代码。但是在实际开发中很少直接使用ts编译器编译ts代码,而是配合打包工具来进行编译。本篇文章将介绍如何通过webpack对ts代码进行编译! 生成package.json包 在新开的文件夹下运行以下命令 npm init -y安…

智慧医疗app

智慧医疗app是一套融合物联网、云计算和大数据等技术,以患者数据为中心的医疗服务模式,致力于为患者提供更加便捷、高效的医疗服务。 在线挂号、在线问诊、电子病历记录、健康管理以及药品购买等。患者可以通过app选择医生和挂号时间,并在线…

AI天使汇联合150家顶级基金、战投,征集优秀AI创业项目

鉴于AI天使汇主办的2024年3月期优秀项目征集活动效果超出预期,3月活动最后TOP20路演者中已有多家快速拿到了TS。 路演活动质量受到了AI创业公司和基金/战投伙伴的高度评价,现在开始四月期活动报名! 本期征集活动联合的顶级基金和战投数量增加到了150家…

数据可视化高级技术Echarts(桑基图入门)

目录 一、什么是桑基图 二、基本特征 三、设计注意事项 四、使用Echarts进行初级绘制 1.首先不能忘记五个基本步骤 2.绘制的时需要将图像类型series.type设定为sankey类型。 一、什么是桑基图 桑基图(Sankey diagram),即桑基能量分流图&…

【氮化镓】微波脉冲对GaN HEMT失效的影响

本文是一篇关于高功率微波脉冲作用下GaN HEMT(高电子迁移率晶体管)热电多物理场耦合失效的实验研究。文章由Xiangdong Li等人撰写,发表在2023年11月的《IEEE Transactions on Electron Devices》上。文章通过实验研究了在高功率微波脉冲应力下…

如何利用open3D来生成OCC

config.yaml depth: 10:#深度,设定为10,常用于决定处理或计算的层次或深入程度。 min_density: 0.1:#最小密度,设置为0.1,用于过滤或选择的密度阈值。 n_threads: -1:#线程数,设为-…

运行vue项目,控制台一直报错freeze ,删除node_modules缓存.cache,再npm 重启项目即可(2024-04-15)

控制台一直报错freeze Could not freeze ...: Cannot read property hash of undefined解决方案: 这个报错一般是由于npm运行缓存导致,清除即可: 删除 ./node_modules/.cache 再重新运行npm run start/dev/serve,即可重启项目…

Flink入门学习 | 大数据技术

⭐简单说两句⭐ ✨ 正在努力的小新~ 💖 超级爱分享,分享各种有趣干货! 👩‍💻 提供:模拟面试 | 简历诊断 | 独家简历模板 🌈 感谢关注,关注了你就是我的超级粉丝啦! &…

DrugBAN:基于双线性注意力网络进行药物-靶点结合预测。

DrugBan:一种可解释的双线性注意力网络进行药物-靶点结合预测。 提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 DrugBan:一种可解释的双线性注意力网络进行药物-靶点结合预测。前言一、模型…

gcn代码处理出现的问题

README 版本不一致 python 2.7 PYTHON 3.7 切换 TensorFlow系统的学习使用 数据集下载

LoRa无线电机温振传感器,FlexLua低代码技术助力快速实现。

在物联网时代,无线传感技术的应用愈发广泛。其中,LoRa(长距离低功耗无线技术)作为一种适用于远距离、低功耗的通信技术,被广泛应用于各种物联网场景。而结合温度和振动传感技术,能够构建出用于监测机器状态…