- 浏览: 29891 次
- 性别:
- 来自: 广州
-
最新评论
写在前
面:SQLite封锁机制的实现需要底层文件系统的支持,不管是Linux,还是Windows,都提供了文件锁的机制,而这为SQLite提供了强大的
支持。本节就来谈谈SQLite使用到的文件锁——主要基于Linux和Windows平台。
Linux 支持的文件锁技术主要包括建议锁
(advisory
lock)和强制锁
(mandatory lock)这两种。此外,Linux
中还引入了两种强制锁的变种形式:共享模式强制锁(share-mode mandatory
lock)和租借锁(lease)。在这里,主要讨论建议锁(advisory lock)。 当一个进程处理完文件后,就可以调用unlink("somefile.lck")释放锁了——本质上是删除somefile.lck文件。 O_EXCL标志保证open()创建锁文件的过程是原子性的。 POSIX锁通过fcntl()系统来实现,如下:
建议锁并不由内核强制实行,也就是说如果有进程不遵
守“游戏规则”,不检查目标文件是否已经由别的进程加了锁就往其中写入数据,那么内核是不会加以阻拦的。因此,建议锁并不能阻止进程对文件的访问,而只能
依靠各个进程在访问文件之前检查该文件是否已经被其他进程加锁来实现并发控制。进程需要事先对锁的状态做一个约定,并根据锁的当前状态和相互关系来确定其
他进程是否能对文件执行指定的操作。而强制锁是由内核强制采用的文件锁——由于内核对每个
read()和write()操作都会检查相应的锁,所以会降低系统性能
。
对于建议锁,Linux提供两种实现方式:锁文件
(lock files)和记录锁
(
record locking)。
(1)锁文件(lock files)
锁文件是最简单的对文件加锁的方法,每个需要加锁的数
据文件都有一个锁文件(lock
file)。当锁文件存在时,就认为该数据文件已经被加锁,别的进程不应该访问(但是你非要访问,Linux也不会阻止)。当锁不存在,进程就可以创建一
个锁文件,然后访问相应的数据文件。只要创建锁的过程是原子的,就能保证某一时刻只有一个进程拥有该锁,这种方法保证某一时刻只有一个进程访问文件。
这
种想法很简单,当一个进程想访问文件时,可以按如下方式对文件加锁:
fd = open("somefile.lck", O_RDONLY, 0644);
if (fd >= 0) {
close(fd);
printf("the file is already locked");
return 1;
} else {
/* the lock file does not exist, we can lock it and access it */
fd = open("somefile.lck", O_CREAT | O_WRONLY, 0644");
if (fd < 0) {
perror("error creating lock file");
return 1;
}
/* we could write our pid to the file */
close(fd);
}
上
面这段代码实际上存在竞争情况,原因在于if语句块不是原子性的,进入if语句块,内核可能调度别的进程运行。更好的方式如下:
fd = open("somefile.lck", O_WRONLY | O_CREAT | O_EXCL, 0644);
if (fd < 0 && errno == EEXIST) {
printf("the file is already locked");
return 1;
} else if (fd < 0) {
perror("unexpected error checking lock");
return 1;
}
/* we could write our pid to the file */
close(fd);
注意以下几点:
1、任何时刻只有一个进程可以拥有锁。
2、
O_EXCL标志只对本志文件系统是可靠的,对于网络文件系统并不能很好的支持。
3、锁仅仅只是建议性的。
4、如果一个持有锁的进程不正
常结束,锁文件仍然存在。如果加锁进程的pid存储在锁文件中,其它进程可以检查锁进程是否存在,当它结束时就可以删除锁。但是,在检查的时候,如果
pid被其它进程使用了,此时就无能为力了。
(2)记录锁(Record Locking)
为了克服锁文件的缺点,System
V和BSD4.3引入了记录锁,相应的系统调用为lockf()和flock()。而POSIX对于记录锁提供了另外一种机制,其系统调用为
fcntl()。Linux提供三种接口,在这里仅讨论POSIX的接口。
记录锁和锁文件有两个很重要的区别:首先,记录锁可以对文件的任何一部
分加锁——
这对于DBMS这样的应用程序,有极大的帮助,SQLite当然没有放过这样的好处
。
其次,记录锁的另一个优点就是它由内核持有,而不是文件系统持有。当进程结束时,所有的锁也随之释放。
和锁文件一样,POSIX锁也是建议性的。
记录锁有两种锁:读锁(read locks)和写锁(write locks)。读锁也就是共享锁(shared
lock),写锁也就是排它锁(exclusive lock)。对于一个记录,只能有一个进程持有写锁,读锁不能存在。
对于一个进程本身而言,
多个锁绝不会冲突。如果一个进程对文件的200-250字节持有读锁,然后对200-225字节数据加写锁,是会成功的。此时,200-225为写锁,而
226-250字节数据为读锁,该规则主要是防止进程本身发生死锁(尽管多进程之间仍然可能发生死锁)。
#include <fcntl.h> int fcntl(int fd, int command, long arg); arg为指向flock结构体的指针: #include <fcntl.h> struct flock { short l_type; short l_whence; off_t l_start; off_t l_len; pid_t l_pid; };
在 flock 结构中,l_type
用来指明创建的是共享锁还是排他锁,其取值有三种:F_RDLCK(共享锁)、F_WRLCK(排他锁)和F_UNLCK(删除之前建立的
锁);l_pid 指明了该锁的拥有者;l_whence、l_start 和l_end
这些字段指明了进程需要对文件的哪个区域进行加锁,这个区域是一个连续的字节集合。因此,进程可以对同一个文件的不同部分加不同的锁。l_whence
必须是 SEEK_SET、SEEK_CUR 或 SEEK_END 这几个值中的一个,它们分别对应着文件头、当前位置和文件尾。l_whence
定义了相对于 l_start 的偏移量,l_start 是从文件开始计算的。 Windows中的锁都是强制锁(mandatory locks),Windows中的共享文件通过以下几个机制来管理: dwShareMode的取值通常为: SQLite的lock byte的定义如下: (1)PENDING_BYTE为何设置为0X4000 0000(1GB)?
可以执行的操作包括:
*
F_GETLK:进程可以通过它来获取通过 fd 打开的那个文件的加锁信息。执行该操作时,lock
指向的结构中就保存了希望对文件加的锁(或者说要查询的锁)。如果确实存在这样一把锁,它阻止 lock 指向的 flock
结构所给出的锁描述符,则把现存的锁的信息写到 lock 指向的 flock 结构中,并将该锁拥有者的 PID 写入 l_pid
字段中,然后返回;否则,就将 lock 指向的 flock 结构中的 l_type 设置为 F_UNLCK,并保持 flock
结构中其他信息不变返回,而不会对该文件真正加锁。
* F_SETLK:进程用它来对文件的某个区域进行加锁(l_type的值为
F_RDLCK 或 F_WRLCK)或者删除锁(l_type 的值为F_UNLCK),如果有其他锁阻止该锁被建立,那么 fcntl()
就出错返回
* F_SETLKW:与 F_SETLK 类似,唯一不同的是,
如果
有其他锁阻止该锁被建立,则调用进程进入睡眠状态
,等待该锁释放。一旦这个调用开始了等待,就只有在能够进行加锁或者收到信号时才会返回
需
要注意的是,F_GETLK 用于测试是否可以加锁,在 F_GETLK 测试可以加锁之后,F_SETLK 和 F_SETLKW
就会企图建立一把锁,但是这两者之间并不是一个原子操作,也就是说,在 F_SETLK 或者 F_SETLKW
还没有成功加锁之前,另外一个进程就有可能已经插进来加上了一把锁。而且,F_SETLKW
有可能导致程序长时间睡眠。还有,程序对某个文件拥有的各种锁会在相应的文件描述符被关闭时自动清除,程序运行结束后,其所加的各种锁也会自动清除。
(1)
通过共享访问控制方式,应用程序可以指定整个文件进行共享读,写或者删除。
(2) 通过字节范围锁(byte range
locks)可以对文件的某一部分进行读写访问。
(3) Windows文件系统不允许正在执行的文件被打开用来进行写或删除操作。
文
件的共享方式由WIN32 API中的打开文件函数CreateFile()中的sharing mode参数确定:
HANDLE CreateFile(
LPCTSTR lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile
);
FILE_SHARE_DELETE:
Enables subsequent open operations on an object to request delete
access.
Otherwise, other processes cannot open the object if they
request delete access.
If this flag is not specified, but the object
has been opened for delete access, the function fails.
FILE_SHARE_READ
:
Enables subsequent
open operations on an object to request read access.
Otherwise,
other processes cannot open the object if they request read access.
If
this flag is not specified, but the object has been opened for read
access, the function fails.
FILE_SHARE_WRITE
:
Enables
subsequent open operations on an object to request write access.
Otherwise,
other processes cannot open the object if they request write access.
If
this flag is not specified, but the object has been opened for write
access, the function fails.
具体的实现函数:
BOOL LockFile(
HANDLE hFile,
DWORD dwFileOffsetLow,
DWORD dwFileOffsetHigh,
DWORD nNumberOfBytesToLockLow,
DWORD nNumberOfBytesToLockHigh
);
#define PENDING_BYTE 0x40000000 /* First byte past the 1GB boundary */
#define RESERVED_BYTE (PENDING_BYTE+1)
#define SHARED_FIRST (PENDING_BYTE+2)
#define SHARED_SIZE 510
在Windows文件中,
被加锁的区域不要求有数据,并且它会阻止所有的进程写文件的该区域,包括第一个持有该锁的进程
.
为了防止出现由于对含有mandatory lock的页面进行读写操作而出现错误(
这在
Windows中是不允许的
),SQLite完全忽略包含pending byte的页面,所以pending
byte在数据库文件上产生一个”文件洞”。PENDING_BYTE设置得那么高,则大部分数据库文件不会遇到由于PENDING_BYTE产生”文件
洞”引起的空间损失(
除非文件特别大,超过1GB
)。
(2)对于
Windows来说,文件中加锁的区域不能重叠,为了使两个读进程可以同时访问文件,对于SHARED
LOCK选择一个SHARED_FIRST——SHARED_FIRST+
SHARED_SIZE范围内的随机数,所以有可能两个进程取得一样的lock byte,
所以对
于Windows,SQLite的并发性就受到限制
。
发表评论
-
(转)Andriod是什么
2010-12-02 11:24 1617导读:Sans Serif是Google的 ... -
(转)SQLite入门与分析(五)---Page Cache之并发控制
2010-11-19 00:05 1059写在前面:本节主要谈 ... -
(转)SQLite入门与分析(四)---Page Cache之事务处理(3)
2010-11-19 00:01 970Code 写在前面:由于 内容较多,所以断续没有写完的 ... -
(转)SQLite入门与分析(四)---Page Cache之事务处理(2)
2010-11-18 23:57 1165写在前面:个人认为pager层是SQLite实现最为核心的 ... -
(转)SQLite入门与分析(四)---Page Cache之事务处理(1)
2010-11-18 23:53 952写在前面:从本章开始,将对SQLite的每个模块进行讨论。 ... -
(转)SQLite入门与分析(三)---内核概述(2)
2010-11-18 23:48 1315写在前面:本节 是前 ... -
(转)SQLite入门与分析(三)---内核概述(1)
2010-11-18 23:41 803写在前面:从本 章开始, ... -
(转)SQLite入门与分析(二)---设计与概念(续)
2010-11-18 23:38 1045写在前面:本节 讨论事务,事务是DBMS最核心的技术之一 ... -
(转)SQLite入门与分析(二)---设计与概念
2010-11-18 23:35 803写在前面:谢谢各位的 ... -
(转)SQLite入门与分析(一)
2010-11-18 23:31 922写在前面:出于项目的 需要,最近打算对SQLite的内核 ... -
(转)深入研究B树索引(五)续
2010-11-18 15:10 9315.3 重建 B 树索引 ... -
(转)深入研究B树索引(五)
2010-11-18 15:07 11975. 重建 B ... -
(转)深入研究B树索引(四)续
2010-11-18 14:58 9274.2 B 树索引的对于删除( DEL ... -
(转)深入研究B树索引(三、四)
2010-11-18 14:44 7323. B 树索 ... -
(转)深入研究B树索引(二)
2010-11-18 14:20 7672. B 树索引的内部结构 ... -
(转)深入研究B树索引(一)
2010-11-18 14:12 1013摘要: 本文对B 树索引的结构、内部管理等方面做了一个全面 ... -
(转)B树、B-树、B+树、B*树都是什么
2010-11-17 23:46 678B 树 即二叉搜 ... -
画UML图时注意的几个原则(转)
2010-08-03 12:34 1642软件开发中,分析和设计时,文档的编写和思想的交流,经常要绘制各 ... -
你是个软件架构师吗?(转)
2010-07-14 11:11 672开发和架构的界限难以 ... -
(转)同曲异奏——高效能项目团队的五大特点
2010-03-29 00:24 869同曲异奏——高效能项 ...
相关推荐
在SQLite入门与分析(七)---浅谈SQLite的虚拟机.doc中,主要讲解了SQLite如何通过虚拟机执行SQL语句。SQLite的虚拟机,也称为VDBE(Virtual Database Engine),是SQLite的核心组件。它负责解析SQL语句,将其转化为一...
编译器则包括分词器和分析器,将 SQL 查询转化为语法树,再由代码生成器转换为针对 SQLite 的汇编代码,最终由虚拟机执行。虚拟机,即虚拟数据库引擎 (VDBE),类似 Java 虚拟机,解释执行字节码,实现数据库操作。...
### 嵌入式数据库SQLite入门与分析 #### 一、SQLite简介 SQLite是一种轻量级的嵌入式关系型数据库管理系统,最初于2000年由D.Richard Hipp开发并发布。作为一种嵌入式数据库,SQLite与其他传统数据库管理系统(如...
SQLite入门与分析(四)---Page Cache之事务处理.doc SQLite入门与分析(五)---Page Cache之并发控制.doc SQLite入门与分析(六)---再谈SQLite的锁.doc
2. 编译器(Compiler):SQLite的编译器包含了分词器(Tokenizer)和分析器(Parser),它们将SQL语句转化为语法树,然后传递给代码生成器。代码生成器负责将语法树转换为针对SQLite虚拟机的汇编代码,再由虚拟机...
### Sqlite3入门与分析知识点概述 #### 一、SQLite简介 SQLite是一个开源的嵌入式关系型数据库管理系统,最初由D. Richard Hipp在2000年发布。相较于传统的数据库管理系统,SQLite具有以下特点: - **零配置**:...
1. **SQLite安装与配置**:介绍如何在不同的操作系统(如Windows、Linux、Mac OS)上安装SQLite,以及如何配置SQLite命令行工具或集成开发环境(IDE),如DB Browser for SQLite。 2. **SQLite数据库操作**:包括...
我自己寻找整理的SQLite资料,希望对大家有帮助。清单如下: Android 数据库技术 sqlite3-基础教程 sqlite3使用详解 sqlite命令行手册(中文) ...SQLite入门与分析 SQLite数据库文件格式全面分析
以下是SQLite入门知识的详细说明: 1. SQLite的特点: - 独立性:使用标准C语言编写,几乎不需要外部库支持,这使得SQLite很容易移植到各种不同的系统和平台。 - 非服务式:不同于需要通过服务接口访问的传统...
SQLite源码分析: SQLite的源代码主要由C语言编写,其设计目标是实现ACID(原子性、一致性、隔离性、持久性)事务特性。源码中包含了数据库引擎的实现,包括SQL解析器、B树数据结构、事务处理、索引管理、锁机制等...
### SQLite入门概述 根据给定的信息,我们可以了解到此次课程的主题为SQLite数据库的入门学习,由哈尔滨瑞杰软件培训学校提供。下面将详细解读并总结出该课程中的几个关键知识点。 #### 一、SQLite简介 SQLite是...
2. **编译器(Compiler)**:编译器包括分词器和分析器,负责SQL语句的语法检查,将其转化为语法树,再由代码生成器将语法树转换为针对SQLite的汇编代码,最后由虚拟机执行。 3. **虚拟机(Virtual Machine)**:虚拟机...
### SQLite入门教程精要 #### 一、SQLite概览 SQLite是一种轻量级的数据库引擎,以其嵌入式特性著称。它不依赖任何独立的服务器进程或系统管理,这使得它非常适合移动设备、嵌入式系统以及桌面应用程序。根据描述...
"SQLite入门与分析.pdf"中可能详细解释了这一点。 6. **索引**: 为了加快查询速度,可以为表的列创建索引。SQLite支持B-Tree索引,同时也支持唯一性和主键约束。 7. **Android与SQLite**: "android-database....