用于 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.rhkb.cn/news/310706.html

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

相关文章

亚马逊、沃尔玛自养号测评技术解析:如何降低潜在风险

亚马逊等电商平台在全球范围内迅速扩张,竞争愈发激烈。为提升产品排名和销量,众多卖家选择采用自养号测评的策略。然而,自养号测评技术并非完美无缺,它存在着一定的技术局限性。由于缺乏对自养号原理及底层环境搭建的深入理解&…

华为配置通过流策略实现流量统计

配置通过流策略实现流量统计示例 组网图形 图1 配置流策略实现流量统计组网图 设备 接口 接口所属VLAN 对应的三层接口 IP地址 SwitchA GigabitEthernet1/0/1 VLAN 10 - - GigabitEthernet1/0/2 VLAN 20 - - GigabitEthernet1/0/3 VLAN 10、VLAN 20 - - S…

MapReduce原理简介

MapReduce 是一种用于处理大规模数据集的编程模型和计算框架,最初由 Google 提出,并被 Hadoop 等开源项目广泛应用。它主要包括两个阶段:Map 阶段和 Reduce 阶段。下面是 MapReduce 的基本原理: 图示不错 MapReduce 的基本原理&…

Java的Future机制详解

Java的Future机制详解 一、为什么出现Future机制二、Future的相关类图2.1 Future 接口2.2 FutureTask 类 三、FutureTask的使用方法四、FutureTask源码分析4.1 state字段4.2 其他变量4.4 构造函数4.5 run方法及其他 一、为什么出现Future机制 常见的两种创建线程的方式。一种是…

开源模型应用落地-chatglm3-6b-gradio-入门篇(七)

一、前言 早前的文章,我们都是通过输入命令的方式来使用Chatglm3-6b模型。现在,我们可以通过使用gradio,通过一个界面与模型进行交互。这样做可以减少重复加载模型和修改代码的麻烦, 让我们更方便地体验模型的效果。 二、术语 2.…

《剑指 Offer》专项突破版 - 面试题 110 : 所有路径(C++ 实现)

题目链接:所有路径 题目: 一个有向无环图由 n 个节点(标号从 0 到 n - 1,n > 2)组成,请找出从节点 0 到节点 n - 1 的所有路径。图用一个数组 graph 表示,数组的 graph[i] 包含所有从节点 …

组件与组件之间的传递-事件总线

两个组件之间的数据传递(属于非父子组件通讯) 当项目中只是两个组件的少量数据传递时使用事件总线这种方法会比较方便,但当遇到大量数据传递时推荐使用vuex 思路 组件与组件之间不能直接传递,这是候可以创建一个EventBus.js文件…

ELK日志分析系统之Zookeeper

一、Zookeeper简介 ZooKeeper是一种为分布式应用所设计的高可用、高性能且一致的开源协调服务,它提供了一项基本服务:分布式锁服务。分布式应用可以基于它实现更高级的服务,实现诸如同步服务、配置维护和集群管理或者命名的服务。 Zookeepe…

力扣:49. 字母异位词分组

知识点: 散列函数 散列函数能使对一个数据序列的访问过程更加迅速有效,通过散列函数,数据元素将被更快地定位: 1. 直接寻址法:取关键字或关键字的某个线性函数值为散列地址。即H(key)key或H&a…

计算机网络 Cisco路由器基本配置

一、实验内容 1、按照下表配置好PC机IP地址和路由器端口IP地址 2、配置好路由器特权密文密码“abcd+两位班内序号”和远程登录密码“star” 3、验证测试 a.验证各个接口的IP地址是否正确配置和开启 b.PC1 和 PC2 互ping c.验证PC1通过远程登陆到路由器上&#…

C#医学实验室/检验信息管理系统(LIS系统)源码

目录 检验系统的总体目标 LIS主要包括以下功能: LIS是集:申请、采样、核收、计费、检验、审核、发布、质控、耗材控制等检验科工作为一体的信息管理系统。LIS系统不仅是自动接收检验数据,打印检验报告,系统保存检验信息的工具&a…

初级软件测试常见问题

1.JMeter (1)在http请求的时候,消息体数据中的数据需要用{}和“”标记起来,变量要用${}括起来。 (2)在响应断言的时候,要根据测试模式输出的内容来改变测试字段,假如输出错误可以把…

系统学c#:1、基础准备(软件下载与安装)

一、Vs软件下载与安装 访问Visual Studio官方网站: https://visualstudio.microsoft.com/zh-hans/downloads 下载Visual Studio 运行exe文件,点击“继续” 初始文件安装完成后选择我们需要安装的项,并勾选好必要的单个组件,设…

代码随想录阅读笔记-回溯【全排列】

题目 给定一个 没有重复 数字的序列,返回其所有可能的全排列。 示例 输入: [1,2,3]输出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ] 思路 以[1,2,3]为例,抽象成树形结构如下: 回溯三部曲 1、递归函数参数 首先排列是有…

Emacs之实现复制当前已打开文件buffer(一百三十五)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒…

Day55 动态规划 part15

Day55 动态规划 part15 392.判断子序列 我的思路: 自己还是只能想到双指针法 解答: class Solution {public boolean isSubsequence(String s, String t) {if(s.length() 0) {return true;}if(s.length() > t.length() || t.length() 0) {return false;}ch…

(九)C++自制植物大战僵尸游戏自定义对话框的实现

植物大战僵尸游戏开发教程专栏地址http://t.csdnimg.cn/m0EtD 对话框在游戏的交互中非常重要。在游戏中,对话框不仅可以提醒用户下达任务指令,而且还可以让用户进行操作,自定义游戏中的各种属性。对话框在游戏的交互中非常常见且大量使用。Co…

LigaAI x 极狐GitLab,共探 AI 时代研发提效新范式

近日,LigaAI 和极狐GitLab 宣布合作,双方将一起探索 AI 时代的研发效能新范式,提供 AI 赋能的一站式研发效能解决方案,让 AI 成为中国程序员和企业发展的新质生产力。 软件研发是一个涉及人员多、流程多、系统多的复杂工程&#…

[docker] 核心知识 - 概念和运行

[docker] 核心知识 - 概念和运行 之前 docker 学了个开头就去搞项目去了,不过项目也开展了好久了,前端差不多吃透了,有些新功能需要用 docker 和 k8s……是时候重新学习一下了。 这一部分简单的过一下概念和讲一下怎么运行 docker 镜像和启…

wps使用Latex编辑公式没有Latex formula

wps使用Latex编辑公式没有Latex formula 1. 下载CTEX2. 下载LaTeXEE3. 配置Miktex4. 配置latexee5. 用管理员权限运行latexeqedit.exe6. wps插入latex公式 1. 下载CTEX 下载CTEX网址,我下载的下图这个,下载完了之后运行exe文件安装ctex。 2. 下载LaTe…