⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 test_async.c

📁 最新的sqlite3.6.2源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/*** 2005 December 14**** The author disclaims copyright to this source code.  In place of** a legal notice, here is a blessing:****    May you do good and not evil.**    May you find forgiveness for yourself and forgive others.**    May you share freely, never taking more than you give.******************************************************************************* $Id: test_async.c,v 1.45 2008/06/26 10:41:19 danielk1977 Exp $**** This file contains an example implementation of an asynchronous IO ** backend for SQLite.**** WHAT IS ASYNCHRONOUS I/O?**** With asynchronous I/O, write requests are handled by a separate thread** running in the background.  This means that the thread that initiates** a database write does not have to wait for (sometimes slow) disk I/O** to occur.  The write seems to happen very quickly, though in reality** it is happening at its usual slow pace in the background.**** Asynchronous I/O appears to give better responsiveness, but at a price.** You lose the Durable property.  With the default I/O backend of SQLite,** once a write completes, you know that the information you wrote is** safely on disk.  With the asynchronous I/O, this is not the case.  If** your program crashes or if a power lose occurs after the database** write but before the asynchronous write thread has completed, then the** database change might never make it to disk and the next user of the** database might not see your change.**** You lose Durability with asynchronous I/O, but you still retain the** other parts of ACID:  Atomic,  Consistent, and Isolated.  Many** appliations get along fine without the Durablity.**** HOW IT WORKS**** Asynchronous I/O works by creating a special SQLite "vfs" structure** and registering it with sqlite3_vfs_register(). When files opened via ** this vfs are written to (using sqlite3OsWrite()), the data is not ** written directly to disk, but is placed in the "write-queue" to be** handled by the background thread.**** When files opened with the asynchronous vfs are read from ** (using sqlite3OsRead()), the data is read from the file on ** disk and the write-queue, so that from the point of view of** the vfs reader the OsWrite() appears to have already completed.**** The special vfs is registered (and unregistered) by calls to ** function asyncEnable() (see below).**** LIMITATIONS**** This demonstration code is deliberately kept simple in order to keep** the main ideas clear and easy to understand.  Real applications that** want to do asynchronous I/O might want to add additional capabilities.** For example, in this demonstration if writes are happening at a steady** stream that exceeds the I/O capability of the background writer thread,** the queue of pending write operations will grow without bound until we** run out of memory.  Users of this technique may want to keep track of** the quantity of pending writes and stop accepting new write requests** when the buffer gets to be too big.**** LOCKING + CONCURRENCY**** Multiple connections from within a single process that use this** implementation of asynchronous IO may access a single database** file concurrently. From the point of view of the user, if all** connections are from within a single process, there is no difference** between the concurrency offered by "normal" SQLite and SQLite** using the asynchronous backend.**** If connections from within multiple database files may access the** database file, the ENABLE_FILE_LOCKING symbol (see below) must be** defined. If it is not defined, then no locks are established on ** the database file. In this case, if multiple processes access ** the database file, corruption will quickly result.**** If ENABLE_FILE_LOCKING is defined (the default), then connections ** from within multiple processes may access a single database file ** without risking corruption. However concurrency is reduced as** follows:****   * When a connection using asynchronous IO begins a database**     transaction, the database is locked immediately. However the**     lock is not released until after all relevant operations**     in the write-queue have been flushed to disk. This means**     (for example) that the database may remain locked for some **     time after a "COMMIT" or "ROLLBACK" is issued.****   * If an application using asynchronous IO executes transactions**     in quick succession, other database users may be effectively**     locked out of the database. This is because when a BEGIN**     is executed, a database lock is established immediately. But**     when the corresponding COMMIT or ROLLBACK occurs, the lock**     is not released until the relevant part of the write-queue **     has been flushed through. As a result, if a COMMIT is followed**     by a BEGIN before the write-queue is flushed through, the database **     is never unlocked,preventing other processes from accessing **     the database.**** Defining ENABLE_FILE_LOCKING when using an NFS or other remote ** file-system may slow things down, as synchronous round-trips to the ** server may be required to establish database file locks.*/#define ENABLE_FILE_LOCKING#ifndef SQLITE_AMALGAMATION# include "sqliteInt.h"#endif#include <tcl.h>/*** This test uses pthreads and hence only works on unix and with** a threadsafe build of SQLite.*/#if SQLITE_OS_UNIX && SQLITE_THREADSAFE/*** This demo uses pthreads.  If you do not have a pthreads implementation** for your operating system, you will need to recode the threading ** logic.*/#include <pthread.h>#include <sched.h>/* Useful macros used in several places */#define MIN(x,y) ((x)<(y)?(x):(y))#define MAX(x,y) ((x)>(y)?(x):(y))/* Forward references */typedef struct AsyncWrite AsyncWrite;typedef struct AsyncFile AsyncFile;typedef struct AsyncFileData AsyncFileData;typedef struct AsyncFileLock AsyncFileLock;typedef struct AsyncLock AsyncLock;/* Enable for debugging */static int sqlite3async_trace = 0;# define ASYNC_TRACE(X) if( sqlite3async_trace ) asyncTrace Xstatic void asyncTrace(const char *zFormat, ...){  char *z;  va_list ap;  va_start(ap, zFormat);  z = sqlite3_vmprintf(zFormat, ap);  va_end(ap);  fprintf(stderr, "[%d] %s", (int)pthread_self(), z);  sqlite3_free(z);}/*** THREAD SAFETY NOTES**** Basic rules:****     * Both read and write access to the global write-op queue must be **       protected by the async.queueMutex. As are the async.ioError and**       async.nFile variables.****     * The async.aLock hash-table and all AsyncLock and AsyncFileLock**       structures must be protected by the async.lockMutex mutex.****     * The file handles from the underlying system are assumed not to **       be thread safe.****     * See the last two paragraphs under "The Writer Thread" for**       an assumption to do with file-handle synchronization by the Os.**** Deadlock prevention:****     There are three mutex used by the system: the "writer" mutex, **     the "queue" mutex and the "lock" mutex. Rules are:****     * It is illegal to block on the writer mutex when any other mutex**       are held, and ****     * It is illegal to block on the queue mutex when the lock mutex**       is held.****     i.e. mutex's must be grabbed in the order "writer", "queue", "lock".**** File system operations (invoked by SQLite thread):****     xOpen**     xDelete**     xFileExists**** File handle operations (invoked by SQLite thread):****         asyncWrite, asyncClose, asyncTruncate, asyncSync **    **     The operations above add an entry to the global write-op list. They**     prepare the entry, acquire the async.queueMutex momentarily while**     list pointers are  manipulated to insert the new entry, then release**     the mutex and signal the writer thread to wake up in case it happens**     to be asleep.****    **         asyncRead, asyncFileSize.****     Read operations. Both of these read from both the underlying file**     first then adjust their result based on pending writes in the **     write-op queue.   So async.queueMutex is held for the duration**     of these operations to prevent other threads from changing the**     queue in mid operation.**    ****         asyncLock, asyncUnlock, asyncCheckReservedLock**    **     These primitives implement in-process locking using a hash table**     on the file name.  Files are locked correctly for connections coming**     from the same process.  But other processes cannot see these locks**     and will therefore not honor them.****** The writer thread:****     The async.writerMutex is used to make sure only there is only**     a single writer thread running at a time.****     Inside the writer thread is a loop that works like this:****         WHILE (write-op list is not empty)**             Do IO operation at head of write-op list**             Remove entry from head of write-op list**         END WHILE****     The async.queueMutex is always held during the <write-op list is **     not empty> test, and when the entry is removed from the head**     of the write-op list. Sometimes it is held for the interim**     period (while the IO is performed), and sometimes it is**     relinquished. It is relinquished if (a) the IO op is an**     ASYNC_CLOSE or (b) when the file handle was opened, two of**     the underlying systems handles were opened on the same**     file-system entry.****     If condition (b) above is true, then one file-handle **     (AsyncFile.pBaseRead) is used exclusively by sqlite threads to read the**     file, the other (AsyncFile.pBaseWrite) by sqlite3_async_flush() **     threads to perform write() operations. This means that read **     operations are not blocked by asynchronous writes (although **     asynchronous writes may still be blocked by reads).****     This assumes that the OS keeps two handles open on the same file**     properly in sync. That is, any read operation that starts after a**     write operation on the same file system entry has completed returns**     data consistent with the write. We also assume that if one thread **     reads a file while another is writing it all bytes other than the**     ones actually being written contain valid data.****     If the above assumptions are not true, set the preprocessor symbol**     SQLITE_ASYNC_TWO_FILEHANDLES to 0.*/#ifndef SQLITE_ASYNC_TWO_FILEHANDLES/* #define SQLITE_ASYNC_TWO_FILEHANDLES 0 */#define SQLITE_ASYNC_TWO_FILEHANDLES 1#endif/*** State information is held in the static variable "async" defined** as the following structure.**** Both async.ioError and async.nFile are protected by async.queueMutex.*/static struct TestAsyncStaticData {  pthread_mutex_t lockMutex;   /* For access to aLock hash table */  pthread_mutex_t queueMutex;  /* Mutex for access to write operation queue */  pthread_mutex_t writerMutex; /* Prevents multiple writer threads */  pthread_cond_t queueSignal;  /* For waking up sleeping writer thread */  pthread_cond_t emptySignal;  /* Notify when the write queue is empty */  AsyncWrite *pQueueFirst;     /* Next write operation to be processed */  AsyncWrite *pQueueLast;      /* Last write operation on the list */  Hash aLock;                  /* Files locked */  volatile int ioDelay;             /* Extra delay between write operations */  volatile int writerHaltWhenIdle;  /* Writer thread halts when queue empty */  volatile int writerHaltNow;       /* Writer thread halts after next op */  int ioError;                 /* True if an IO error has occured */  int nFile;                   /* Number of open files (from sqlite pov) */} async = {  PTHREAD_MUTEX_INITIALIZER,  PTHREAD_MUTEX_INITIALIZER,  PTHREAD_MUTEX_INITIALIZER,  PTHREAD_COND_INITIALIZER,  PTHREAD_COND_INITIALIZER,};/* Possible values of AsyncWrite.op */#define ASYNC_NOOP          0#define ASYNC_WRITE         1#define ASYNC_SYNC          2#define ASYNC_TRUNCATE      3#define ASYNC_CLOSE         4#define ASYNC_DELETE        5#define ASYNC_OPENEXCLUSIVE 6#define ASYNC_UNLOCK        7/* Names of opcodes.  Used for debugging only.** Make sure these stay in sync with the macros above!*/static const char *azOpcodeName[] = {  "NOOP", "WRITE", "SYNC", "TRUNCATE", "CLOSE", "DELETE", "OPENEX", "UNLOCK"};/*** Entries on the write-op queue are instances of the AsyncWrite** structure, defined here.**** The interpretation of the iOffset and nByte variables varies depending ** on the value of AsyncWrite.op:**** ASYNC_NOOP:**     No values used.**** ASYNC_WRITE:**     iOffset -> Offset in file to write to.**     nByte   -> Number of bytes of data to write (pointed to by zBuf).**** ASYNC_SYNC:**     nByte   -> flags to pass to sqlite3OsSync().**** ASYNC_TRUNCATE:**     iOffset -> Size to truncate file to.**     nByte   -> Unused.**** ASYNC_CLOSE:**     iOffset -> Unused.**     nByte   -> Unused.**** ASYNC_DELETE:**     iOffset -> Contains the "syncDir" flag.**     nByte   -> Number of bytes of zBuf points to (file name).**** ASYNC_OPENEXCLUSIVE:**     iOffset -> Value of "delflag".**     nByte   -> Number of bytes of zBuf points to (file name).**** ASYNC_UNLOCK:**     nByte   -> Argument to sqlite3OsUnlock().****** For an ASYNC_WRITE operation, zBuf points to the data to write to the file. ** This space is sqlite3_malloc()d along with the AsyncWrite structure in a** single blob, so is deleted when sqlite3_free() is called on the parent ** structure.*/struct AsyncWrite {  AsyncFileData *pFileData;    /* File to write data to or sync */  int op;                      /* One of ASYNC_xxx etc. */  i64 iOffset;        /* See above */  int nByte;          /* See above */  char *zBuf;         /* Data to write to file (or NULL if op!=ASYNC_WRITE) */  AsyncWrite *pNext;  /* Next write operation (to any file) */};/*** An instance of this structure is created for each distinct open file ** (i.e. if two handles are opened on the one file, only one of these** structures is allocated) and stored in the async.aLock hash table. The** keys for async.aLock are the full pathnames of the opened files.**** AsyncLock.pList points to the head of a linked list of AsyncFileLock** structures, one for each handle currently open on the file.**** If the opened file is not a main-database (the SQLITE_OPEN_MAIN_DB is** not passed to the sqlite3OsOpen() call), or if ENABLE_FILE_LOCKING is ** not defined at compile time, variables AsyncLock.pFile and ** AsyncLock.eLock are never used. Otherwise, pFile is a file handle** opened on the file in question and used to obtain the file-system ** locks required by database connections within this process.**** See comments above the asyncLock() function for more details on ** the implementation of database locking used by this backend.*/struct AsyncLock {  sqlite3_file *pFile;  int eLock;  AsyncFileLock *pList;};/*** An instance of the following structure is allocated along with each** AsyncFileData structure (see AsyncFileData.lock), but is only used if the** file was opened with the SQLITE_OPEN_MAIN_DB.*/struct AsyncFileLock {  int eLock;                /* Internally visible lock state (sqlite pov) */  int eAsyncLock;           /* Lock-state with write-queue unlock */  AsyncFileLock *pNext;};/* ** The AsyncFile structure is a subclass of sqlite3_file used for ** asynchronous IO. **** All of the actual data for the structure is stored in the structure** pointed to by AsyncFile.pData, which is allocated as part of the** sqlite3OsOpen() using sqlite3_malloc(). The reason for this is that the** lifetime of the AsyncFile structure is ended by the caller after OsClose()** is called, but the data in AsyncFileData may be required by the** writer thread after that point.*/struct AsyncFile {  sqlite3_io_methods *pMethod;  AsyncFileData *pData;};struct AsyncFileData {  char *zName;               /* Underlying OS filename - used for debugging */  int nName;                 /* Number of characters in zName */  sqlite3_file *pBaseRead;   /* Read handle to the underlying Os file */  sqlite3_file *pBaseWrite;  /* Write handle to the underlying Os file */  AsyncFileLock lock;  AsyncWrite close;};/*** The following async_XXX functions are debugging wrappers around the** corresponding pthread_XXX functions:****     pthread_mutex_lock();**     pthread_mutex_unlock();**     pthread_mutex_trylock();**     pthread_cond_wait();**** It is illegal to pass any mutex other than those stored in the** following global variables of these functions.**

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -