SQLite busy handler

SQLite doesn‘t support high concurrency. In case of a lot of concurrent access from multi-process or multi-thread, calling a SQLite r/w function is prone to hit the case that the database is locked by another process or thread. The default behavior is that the SQLite r/w function return SQLITE_BUSY immediately, and the caller should retry the call later.

Below is an example function. When the SQLite function returns SQLITE_BUSY, the caller sleep one second then retry. The sleep is required to optimize the CPU utilization, without the sleep, the CPU will be occupied by a lot of retries.

bool Execute(const string& sql) {
  char* errmsg = NULL;
  while (true) {
    int status = sqlite3_exec(db_, sql.c_str(), NULL, NULL, &errmsg);
    if (status == SQLITE_OK) {
      return true;
    } else if (status == SQLITE_BUSY) {
      ++total_busycount;
      cerr << "Thread " << threadindex_ << ": failed to execute " << sql << " (" << errmsg << ")\n";
      sqlite3_free(errmsg);
      sleep(1);
    } else {
      cerr << "Thread " << threadindex_ << ": failed to execute " << sql << " (" << errmsg << ")\n";
      sqlite3_free(errmsg);
      return false;
    }
  }
  return false;
}

In fact, the caller doesn‘t need to sleep explicitly, calling sqlite3_busy_timeout before SQLite r/w functions will make SQLite automaticlly insert sleep between two sequential calls of a r/w function. It‘s safe to set a big timeout value. SQLite splits the big timeout value into many small timeout values. With the optimization, if the lock is available while the caller is waiting, the caller won‘t need to wait to timeout. See below code,

1452  static int sqliteDefaultBusyCallback(
1453   void *ptr,               /* Database connection */
1454   int count                /* Number of times table has been busy */
1455  ){
1456  #if SQLITE_OS_WIN || HAVE_USLEEP
1457    static const u8 delays[] =
1458       { 1, 2, 5, 10, 15, 20, 25, 25,  25,  50,  50, 100 };
1459    static const u8 totals[] =
1460       { 0, 1, 3,  8, 18, 33, 53, 78, 103, 128, 178, 228 };
1461  # define NDELAY ArraySize(delays)
1462    sqlite3 *db = (sqlite3 *)ptr;
1463    int timeout = db->busyTimeout;
1464    int delay, prior;
1465
1466    assert( count>=0 );
1467    if( count < NDELAY ){
1468      delay = delays[count];
1469      prior = totals[count];
1470    }else{
1471      delay = delays[NDELAY-1];
1472      prior = totals[NDELAY-1] + delay*(count-(NDELAY-1));
1473    }
1474    if( prior + delay > timeout ){
1475      delay = timeout - prior;
1476      if( delay<=0 ) return 0;
1477    }
1478    sqlite3OsSleep(db->pVfs, delay*1000);
1479    return 1;
1480  #else
1481    sqlite3 *db = (sqlite3 *)ptr;
1482    int timeout = ((sqlite3 *)ptr)->busyTimeout;
1483    if( (count+1)*1000 > timeout ){
1484      return 0;
1485    }
1486    sqlite3OsSleep(db->pVfs, 1000000);
1487    return 1;
1488  #endif
1489  }

Another alternative is set a busy hander by calling sqlite3_busy_handler. If the busy callback returns 0, then no additional attempts are made to access the database and SQLITE_BUSY is returned to the application. If the callback returns non-zero, then another attempt is made to access the database and the cycle repeats.

时间: 2024-10-08 10:44:56

SQLite busy handler的相关文章

SQLite Design and Concepts

API 分为两大类 core API. 基本的SQL操作 extension API. 创建自定义的SQL操作. 基本数据结构 需要了解的组成部分有连接.statments.B树.pager. 为了写好SQLite代码,需要了解的基本概念,API.事务和锁. 连接和statments 这两种数据结构和查询语句的基础.一个连接表示对数据库的一个连接,也是一个事务上下文.statments由这些连接产生.statments在内部由VDBE字节码表示. B-tree and pager 每个数据库连接

SQLite内核研究

先从全局的角度把握SQLite内核各个模块的设计和功能.SQLite采用了层次化.模块化的设计,而这些使得它的可扩展性和可移植性非常强.而且SQLite的架构与通用DBMS的结构差别不是很大,所以它对于理解通用DBMS具有重要意义.SQLite的内核总的来说分为三个部分,虚拟机(Virtual Machine).Back-end(后端)和compiler(编译器). 1.虚拟机(Virtual Machine)VDBE是SQLite的核心,它的上层模块和下层模块都是本质上都是为它服务的.它的实现

【原】FMDB源码阅读(一)

[原]FMDB源码阅读(一) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 说实话,之前的SDWebImage和AFNetworking这两个组件我还是使用过的,但是对于FMDB组件我是一点都没用过.好在FMDB源码中的main.m文件提供了大量的示例,况且网上也有很多最佳实践的例子,我就不在这献丑了.我们先从一个最简单的FMDB的例子开始: // 找到用户目录下的Documents文件夹位置 NSString* docsdir = [NSSearchPathFor

ArcGIS API For Android Errors汇总

API客户端异常错误的发生通常是由于不正确的方法参数,对象状态依赖,或网络条件. //*******推荐使用方法,按下Ctrl+F搜索错误代码,再查看与代码对应的解释.********// ArcGIS弹出错误 11000 Invalid attributes or geometry on the associated GeoElement. 11001 Null value is not allowed. 11002 Value is out of range. 11003 Value exc

android SQLite 使用实例

Android作为眼下主流的移动操作系统,全然符合SQLite占用资源少的优势,故在Android平台上,集成了一个嵌入式关系型数据库-SQLite.假设想要开发 Android 应用程序,须要在 Android 上存储数据,使用SQLite 数据库是一种很好的选择.在一般程序中使用数据库的过程都能够框架化,套路化,实比例如以下: 表说明: 1.班级 classes: class_id  主键 class_name 2.学生 students: student_id 主键 student_nam

Latest SQLite binary for January 2015

Latest SQLite binary for January 2015 Well I went through quite a few threads to find an updated, decent sqlite binary. Didn't find any that met that criteria. So I compiled one. Here's SQLite 3.8.7.4 combined into a single source file (the amalgamat

转:使用log4net完成程序异常日志记录(使用SQLite数据库记录和普通文本记录)

http://www.cnblogs.com/kyo-yo/archive/2010/06/11/use-log4net-to-log-exception.html 在前端时间开发的时候由于需要将异常保存到数据库中,所以就到网上搜了下专门的日志记录工具,一搜果然很多,比如:log4net,NLog,EntLib Logging等等,但是还是log4net名气最大,所以就下载下来试用了一番,果然很方便,其涵盖了所有常用的日志记录方式具体的可以看下表: AdoNetAppender 将日志记录到数据

Android+Sqlite 实现古诗阅读应用(二)

传送门:Android+Sqlite 实现古诗阅读应用(一):http://www.cnblogs.com/lfk-dsk/p/4492974.html Hi,又回来了,最近接到很多热情洋溢的小伙伴们的来信,吼开心哈,我会继续努力的=-=! 上回的东西我们做到了有个textview能随机选择诗来进行显示,这也是我做这个东西的初衷,我想找我到底有哪些古诗没有读过,更想感受一下风吹哪页看哪页的闲适(扯远了=-=!),所以功能现在差不多算是结束了, 不过一个古诗应用这么丑可不行,还有就是,我找到了我要

About SQLite

About SQLite See Also... Features When to use SQLite Frequently Asked Questions Well-known Users Books About SQLite Getting Started SQL Syntax Pragmas SQL functions Date & time functions Aggregate functions C/C++ Interface Spec Introduction List of C