Concurrent control in SQLite
This document describes the technologies to concurrent access to a SQLite database. There are also some code analysis to reveal the low level implementations.
Multi-process
See the official FAQ Can multiple applications or multiple instances of the same application access a single database file at the same time?
Multiple processes can have the same database open at the same time. Multiple processes can be doing a SELECT at the same time. But only one process can be making changes to the database at any moment in time, however.
SQLite uses reader/writer locks to control access to the database. (Under Win95/98/ME which lacks support for reader/writer locks, a probabilistic simulation is used instead.) But use caution: this locking mechanism might not work correctly if the database file is kept on an NFS filesystem. This is because fcntl() file locking is broken on many NFS implementations. You should avoid putting SQLite database files on NFS if multiple processes might try to access the file at the same time. On Windows, Microsoft's documentation says that locking may not work under FAT filesystems if you are not running the Share.exe daemon. People who have a lot of experience with Windows tell me that file locking of network files is very buggy and is not dependable. If what they say is true, sharing an SQLite database between two or more Windows machines might cause unexpected problems.
We are aware of no other embedded SQL database engine that supports as much concurrency as SQLite. SQLite allows multiple processes to have the database file open at once, and for multiple processes to read the database at once. When any process wants to write, it must lock the entire database file for the duration of its update. But that normally only takes a few milliseconds. Other processes just wait on the writer to finish then continue about their business. Other embedded SQL database engines typically only allow a single process to connect to the database at once.
However, client/server database engines (such as PostgreSQL, MySQL, or Oracle) usually support a higher level of concurrency and allow multiple processes to be writing to the same database at the same time. This is possible in a client/server database because there is always a single well-controlled server process available to coordinate access. If your application has a need for a lot of concurrency, then you should consider using a client/server database. But experience suggests that most applications need much less concurrency than their designers imagine.
When SQLite tries to access a file that is locked by another process, the default behavior is to return SQLITE_BUSY. You can adjust this behavior from C code using the sqlite3_busy_handler() or sqlite3_busy_timeout() API functions.
Code analysis
Multi-process concurrent control is implemented using fcntl on Linux/Unix, LockFileEx/UnlockFileEx on Windows, and probabilistic locking on Win95/98/ME.
See https://sqlite.org/lockingv3.html for more details
- UNLOCKED No locks are held on the database. The database may be neither read nor written. Any internally cached data is considered suspect and subject to verification against the database file before being used. Other processes can read or write the database as their own locking states permit. This is the default state.
- SHARED The database may be read but not written. Any number of processes can hold SHARED locks at the same time, hence there can be many simultaneous readers. But no other thread or process is allowed to write to the database file while one or more SHARED locks are active.
- RESERVED A RESERVED lock means that the process is planning on writing to the database file at some point in the future but that it is currently just reading from the file. Only a single RESERVED lock may be active at one time, though multiple SHARED locks can coexist with a single RESERVED lock. RESERVED differs from PENDING in that new SHARED locks can be acquired while there is a RESERVED lock.
- PENDING A PENDING lock means that the process holding the lock wants to write to the database as soon as possible and is just waiting on all current SHARED locks to clear so that it can get an * * EXCLUSIVE lock. No new SHARED locks are permitted against the database if a PENDING lock is active, though existing SHARED locks are allowed to continue.
- EXCLUSIVE An EXCLUSIVE lock is needed in order to write to the database file. Only one EXCLUSIVE lock is allowed on the file and no other locks of any kind are allowed to coexist with an EXCLUSIVE lock. In order to maximize concurrency, SQLite works to minimize the amount of time that EXCLUSIVE locks are held.
Multi-thread
See Using SQLite In Multi-Threaded Applications
1 Overview
SQLite supports three different threading modes:
Single-thread. In this mode, all mutexes are disabled and SQLite is unsafe to use in more than a single thread at once.
Multi-thread. In this mode, SQLite can be safely used by multiple threads provided that no single database connection is used simultaneously in two or more threads.
Serialized. In serialized mode, SQLite can be safely used by multiple threads with no restriction.
The threading mode can be selected at compile-time (when the SQLite library is being compiled from source code) or at start-time (when the application that intends to use SQLite is initializing) or at run-time (when a new SQLite database connection is being created). Generally speaking, run-time overrides start-time and start-time overrides compile-time. Except, single-thread mode cannot be overridden once selected.
The default mode is serialized.
2 Compile-time selection of threading mode
Use the SQLITE_THREADSAFE compile-time parameter to selected the threading mode. If no SQLITE_THREADSAFE compile-time parameter is present, then serialized mode is used. This can be made explicit with -DSQLITE_THREADSAFE=1. With -DSQLITE_THREADSAFE=0 the threading mode is single-thread. With -DSQLITE_THREADSAFE=2 the threading mode is multi-thread.
The return value of the sqlite3_threadsafe() interface is determined by the compile-time threading mode selection. If single-thread mode is selected at compile-time, then sqlite3_threadsafe() returns false. If either the multi-thread or serialized modes are selected, then sqlite3_threadsafe() returns true. The sqlite3_threadsafe() interface predates the multi-thread mode and start-time and run-time mode selection and so is unable to distinguish between multi-thread and serialized mode nor is it able to report start-time or run-time mode changes.
If single-thread mode is selected at compile-time, then critical mutexing logic is omitted from the build and it is impossible to enable either multi-thread or serialized modes at start-time or run-time.
3 Start-time selection of threading mode
Assuming that the compile-time threading mode is not single-thread, then the threading mode can be changed during initialization using the sqlite3_config() interface. The SQLITE_CONFIG_SINGLETHREAD verb puts SQLite into single-thread mode, the SQLITE_CONFIG_MULTITHREAD verb sets multi-thread mode, and the SQLITE_CONFIG_SERIALIZED verb sets serialized mode.
4 Run-time selection of threading mode
If single-thread mode has not been selected at compile-time or start-time, then individual database connections can be created as either multi-thread or serialized. It is not possible to downgrade an individual database connection to single-thread mode. Nor is it possible to escalate an individual database connection if the compile-time or start-time mode is single-thread.
The threading mode for an individual database connection is determined by flags given as the third argument to sqlite3_open_v2(). The SQLITE_OPEN_NOMUTEX flag causes the database connection to be in the multi-thread mode and the SQLITE_OPEN_FULLMUTEX flag causes the connection to be in serialized mode. If neither flag is specified or if sqlite3_open() or sqlite3_open16() are used instead of sqlite3_open_v2(), then the default mode determined by the compile-time and start-time settings is used.
Code analysis
SQLITE_THREADSAFE=0
See below code, once SQLITE_THREADSAFE=0, the mutex operations are omitted. That's why if single-thread mode is selected at compile-time, it is impossible to enable either multi-thread or serialized modes at start-time or run-time.
#if SQLITE_THREADSAFE
sqlite3_mutex *mutex;
#endif
#if SQLITE_THREADSAFE
# include
# define SQLITE_UNIX_THREADS 1
#endif
SQLITE_THREADSAFE=1 and SQLITE_THREADSAFE=2
SQLITE_THREADSAFE=1 means serialized mode, and -DSQLITE_THREADSAFE=2 means multi-thread mode.
In both modes, mutexes are used to protect critical resource. So what's the difference? See below code,
global.c
SQLITE_WSD struct Sqlite3Config sqlite3Config = {
SQLITE_DEFAULT_MEMSTATUS, /* bMemstat */
1, /* bCoreMutex */
SQLITE_THREADSAFE==1, /* bFullMutex */
main.c
isThreadsafe = sqlite3GlobalConfig.bFullMutex;
...
if( isThreadsafe ){
db->mutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE);
vdbeblob.c
148 sqlite3_mutex_enter(db->mutex); in sqlite3_blob_open()
361 sqlite3_mutex_enter(db->mutex); in sqlite3_blob_close()
388 sqlite3_mutex_enter(db->mutex); in blobReadWrite()
486 sqlite3_mutex_enter(db->mutex); in sqlite3_blob_reopen()
If SQLITE_THREADSAFE=1, SQLite allocates a mutex for each connection and use the mutex to serialize the operations on the connection.
In fact, for SQLITE_THREADSAFE, there is no difference between 2 and any value other than 0 and 1, in which case, only access to the global resources are proteced by mutex, no per connection serialization, concurrently access a connection from multiple threads can cause errors.
Concurrent control in SQLite的更多相关文章
- Haskell语言学习笔记(84)Concurrent
Control.Concurrent Prelude> import Control.Concurrent Prelude Control.Concurrent> Control.Conc ...
- Concurrent.Thread.js
(function(){ if ( !this.Data || (typeof this.Data != 'object' && typeof this.Data != 'functi ...
- HBase中MVCC的实现机制及应用情况
MVCC(Multi-Version Concurrent Control),即多版本并发控制协议,广泛使用于数据库系统.本文将介绍HBase中对于MVCC的实现及应用情况. MVCC基本原理 在介绍 ...
- lmdb简介——结合MVCC的B+树嵌入式数据库
lmdb简介 lmdb是openLDAP项目开发的嵌入式(作为一个库嵌入到宿主程序)存储引擎.其主要特性有: 基于文件映射IO(mmap) 基于B+树的key-value接口 基于MVCC(Multi ...
- mvcc摘抄
MVCC浅析原文:---->>>>>> http://blog.csdn.net/chosen0ne/article/details/18093187 在并发读写数 ...
- MVCC浅析(转)
在并发读写数据库时,读操作可能会不一致的数据(脏读).为了避免这种情况,需要实现数据库的并发访问控制,最简单的方式就是加锁访问.由于,加锁会将读写操作串行化,所以不会出现不一致的状态.但是,读操作会被 ...
- MyBatis一级缓存引起的无穷递归
MyBatis一级缓存引起的无穷递归 引言: 最近在项目中参与了一个领取优惠劵的活动,当多个用户领取同一张优惠劵的时候,使用了数据库锁控制并发,起初的设想是:如果多个人同时领一张劵,第一个到达的人领取 ...
- Concurrency Is Not Parallelism (Rob pike)
Rob pike发表过一个有名的演讲<Concurrency is not parallelism>(https://blog.golang.org/concurrency-is-not- ...
- 关于InnoDB的读写锁类型以及加锁方式
(本文为了方便,英文关键词都都采用小写方式,相关知识点会简单介绍,争取做到可以独立阅读) 文章开始我会先介绍本文需要的知识点如下: innodb的聚簇索引(聚集索引)和非聚簇索引(二级索引.非聚集索引 ...
随机推荐
- 在JAR中打包使用JAR库
不知大家在写Java程序的时候有没有这种需求: 将引用其他第三方JAR库的项目打包成一个JAR文件执行.也就是说在你打包好的JAR文件里再包括那些你引用的第三方JAR文件,合成一个JAR包,这样仅仅需 ...
- 通俗理解LDA主题模型
通俗理解LDA主题模型 0 前言 印象中,最開始听说"LDA"这个名词,是缘于rickjin在2013年3月写的一个LDA科普系列,叫LDA数学八卦,我当时一直想看来着,记得还打印 ...
- S5P4418裸机开发系列教程--源代码下载
S5P4418裸机系列教程之stdio S5P4418裸机系列教程之shell命令行 S5P4418裸机系列教程之串口回显 S5P4418裸机系列教程之复位測试 S5P4418裸机系列教程之led跑马 ...
- HDU5294 Tricks Device(最大流+SPFA) 2015 Multi-University Training Contest 1
Tricks Device Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) To ...
- NSoup解析处理Html
以前在做网页静态生成的时候,使用正则表达式分析提取网页链接.最近搜索了解到java有个Jsoup解析网页,对应.net有个nsoup.处理网页非常好用. Document doc = NSoupCli ...
- cojs 1001. [WZOI2011 S3] 消息传递
1001. [WZOI2011 S3] 消息传递 ★★ 输入文件:messagew.in 输出文件:messagew.out 简单对比时间限制:1 s 内存限制:128 MB Prob ...
- ASP.NET和C#的区别/
1..NET是一个平台,一个抽象的平台的概念. .NET平台其本身实现的方式其实还是库,抽象层面上来看是一个平台. 个人理解.NET核心就只是.NET Framework. .NET Framewor ...
- hdoj--1877--又一版 A+B(水题)
又一版 A+B Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total ...
- 利用 C# dynamic 减少创建模型类
C# 的 dynamic 关键字可以是C#可以像 javascript 这种弱类型语言一样具有随时可以添加属性的能力.C# 是一种强类型语言,dynamic 要摆脱类型的限制,自然是有代价的.这里不讨 ...
- Spring中AOP的两种代理方式(Java动态代理和CGLIB代理-转载
内容是摘抄的,不知最初的原作者,见谅 Java 动态代理.具体有如下四步骤: 通过实现 InvocationHandler 接口创建自己的调用处理器: 通过为 Proxy 类指定 ClassLoade ...