/ Check-in [92bc6be2]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Improve comments and documentation of the asynchronous IO VFS module. (CVS 6543)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:92bc6be2a86f8a68ceded2bc08fe7d6ff23b56fb
User & Date: danielk1977 2009-04-24 09:27:16
Context
2009-04-24
10:13
Make selecting the asynchronous IO file-locking mode a runtime operation. Still untested. (CVS 6544) check-in: 577277e8 user: danielk1977 tags: trunk
09:27
Improve comments and documentation of the asynchronous IO VFS module. (CVS 6543) check-in: 92bc6be2 user: danielk1977 tags: trunk
2009-04-23
19:08
os_win.c, winOpen(), changed to handle the SQLITE_OPEN_EXCLUSIVE flag and sharing modes in the same manner as os_unix.c. Ticket #3821. (CVS 6542) check-in: 18fef3fc user: shane tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Added ext/async/README.txt.









































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164

Normally, when SQLite writes to a database file, it waits until the write
operation is finished before returning control to the calling application.
Since writing to the file-system is usually very slow compared with CPU
bound operations, this can be a performance bottleneck. This directory
contains an extension that causes SQLite to perform all write requests
using a separate thread running in the background. Although this does not
reduce the overall system resources (CPU, disk bandwidth etc.) at all, it
allows SQLite to return control to the caller quickly even when writing to
the database, eliminating the bottleneck.

  1. Functionality

    1.1 How it Works
    1.2 Limitations
    1.3 Locking and Concurrency

  2. Compilation and Usage

  3. Porting



1. FUNCTIONALITY

  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 loss 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.

  1.1 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 the vfs xWrite() method), 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 the vfs xRead() method), 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 xWrite() appears to have already completed.

    The special vfs is registered (and unregistered) by calls to the 
    API functions sqlite3async_initialize() and sqlite3async_shutdown().
    See section "Compilation and Usage" below for details.

  1.2 Limitations

    In order to gain experience with the main ideas surrounding asynchronous 
    IO, this implementation is deliberately kept simple. Additional 
    capabilities may be added in the future.

    For example, as currently implemented, 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.
    If this goes on for long enough, the host system could run out of memory. 
    A more sophisticated module could to keep track of the quantity of 
    pending writes and stop accepting new write requests when the queue of 
    pending writes grows too large.

  1.3 Locking and 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 file-locking is enabled (it is enabled by default), then connections
    from multiple processes may also read and write the database file.
    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.

    File-locking may be disabled at runtime using the sqlite3async_control()
    API (see below). This may improve performance when an NFS or other 
    network file-system, as the synchronous round-trips to the server be 
    required to establish file locks are avoided. However, if multiple 
    connections attempt to access the same database file when file-locking
    is disabled, application crashes and database corruption is a likely
    outcome.


2. COMPILATION AND USAGE

  The asynchronous IO extension consists of a single file of C code
  (sqlite3async.c), and a header file (sqlite3async.h) that defines the 
  C API used by applications to activate and control the modules 
  functionality.

  To use the asynchronous IO extension, compile sqlite3async.c as
  part of the application that uses SQLite. Then use the API defined
  in sqlite3async.h to initialize and configure the module.

  The asynchronous IO VFS API is described in detail in comments in 
  sqlite3async.h. Using the API usually consists of the following steps:

    1. Register the asynchronous IO VFS with SQLite by calling the
       sqlite3async_initialize() function.

    2. Create a background thread to perform write operations and call
       sqlite3async_run().

    3. Use the normal SQLite API to read and write to databases via 
       the asynchronous IO VFS.

  Refer to sqlite3async.h for details.


3. PORTING

  Currently the asynchronous IO extension is compatible with win32 systems
  and systems that support the pthreads interface, including Mac OSX, Linux, 
  and other varieties of Unix. 

  To port the asynchronous IO extension to another platform, the user must
  implement mutex and condition variable primitives for the new platform.
  Currently there is no externally available interface to allow this, but
  modifying the code within sqlite3async.c to include the new platforms
  concurrency primitives is relatively easy. Search within sqlite3async.c
  for the comment string "PORTING FUNCTIONS" for details. Then implement
  new versions of each of the following:

    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);

  The functionality required of each of the above functions is described
  in comments in sqlite3async.c.

Changes to ext/async/sqlite3async.c.

6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
...
251
252
253
254
255
256
257


258
259
260
261
262
263
264
**
**    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: sqlite3async.c,v 1.1 2009/04/23 14:58:40 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 loss 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 processes 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.
*/

#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ASYNCIO)

#include "sqlite3async.h"

#define ENABLE_FILE_LOCKING

#ifndef SQLITE_AMALGAMATION
# include "sqliteInt.h"
# include <assert.h>
# include <string.h>
#endif

/* 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;
................................................................................
#ifndef NDEBUG
# define TESTONLY( X ) X
#else
# define TESTONLY( X )
#endif

/*


** There are two definitions of the following functions. One for pthreads
** compatible systems and one for Win32. These functions isolate the OS
** specific code required by each platform.
**
** The system uses three mutexes and a single condition variable. To
** block on a mutex, async_mutex_enter() is called. The parameter passed
** to async_mutex_enter(), which must be one of ASYNC_MUTEX_LOCK,







|

|
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<








<
<
<
<
<
<







 







>
>







6
7
8
9
10
11
12
13
14
15
16



























































































17
18
19
20
21
22
23
24






25
26
27
28
29
30
31
...
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
**
**    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: sqlite3async.c,v 1.2 2009/04/24 09:27:16 danielk1977 Exp $
**
** This file contains the implementation of an asynchronous IO backend 
** for SQLite.



























































































*/

#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ASYNCIO)

#include "sqlite3async.h"

#define ENABLE_FILE_LOCKING







/* 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;
................................................................................
#ifndef NDEBUG
# define TESTONLY( X ) X
#else
# define TESTONLY( X )
#endif

/*
** PORTING FUNCTIONS
**
** There are two definitions of the following functions. One for pthreads
** compatible systems and one for Win32. These functions isolate the OS
** specific code required by each platform.
**
** The system uses three mutexes and a single condition variable. To
** block on a mutex, async_mutex_enter() is called. The parameter passed
** to async_mutex_enter(), which must be one of ASYNC_MUTEX_LOCK,

Changes to ext/async/sqlite3async.h.

1
2
3
4
5
6
7










8









9

































10
11
12
13




14
15
16
17
18














19
20
21
22

































































































23
24
25
26
27
28
29
30

31
32

33
34
35
36
37
38
39
40
41
42
43
44

#ifndef __SQLITEASYNC_H_
#define __SQLITEASYNC_H_ 1

#define SQLITEASYNC_VFSNAME "sqlite3async"

/*










** Install the asynchronous IO VFS.









*/ 

































int sqlite3async_initialize(const char *zParent, int isDefault);

/*
** Uninstall the asynchronous IO VFS.




*/ 
void sqlite3async_shutdown();

/*
** Process events on the write-queue.














*/
void sqlite3async_run();

/*

































































































** Control/configure the asynchronous IO system.
*/
int sqlite3async_control(int op, ...);

/*
** Values that can be used as the first argument to sqlite3async_control().
*/
#define SQLITEASYNC_HALT       1

#define SQLITEASYNC_DELAY      2
#define SQLITEASYNC_GET_HALT   3

#define SQLITEASYNC_GET_DELAY  4

/*
** 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 */

#endif        /* ifndef __SQLITEASYNC_H_ */








>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



|
>
>
>
>




|
>
>
>
>
>
>
>
>
>
>
>
>
>
>




>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|






|
>
|
|
>
|











1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213

#ifndef __SQLITEASYNC_H_
#define __SQLITEASYNC_H_ 1

#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();

/*
** 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();

/*
** 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 */

#endif        /* ifndef __SQLITEASYNC_H_ */