1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/persistentdata/persistentstorage/sqlite3api/TEST/SRC/test_async.c Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1794 @@
1.4 +/*
1.5 +** 2005 December 14
1.6 +**
1.7 +** The author disclaims copyright to this source code. In place of
1.8 +** a legal notice, here is a blessing:
1.9 +**
1.10 +** May you do good and not evil.
1.11 +** May you find forgiveness for yourself and forgive others.
1.12 +** May you share freely, never taking more than you give.
1.13 +**
1.14 +*************************************************************************
1.15 +**
1.16 +** $Id: test_async.c,v 1.48 2008/09/26 20:02:50 drh Exp $
1.17 +**
1.18 +** This file contains an example implementation of an asynchronous IO
1.19 +** backend for SQLite.
1.20 +**
1.21 +** WHAT IS ASYNCHRONOUS I/O?
1.22 +**
1.23 +** With asynchronous I/O, write requests are handled by a separate thread
1.24 +** running in the background. This means that the thread that initiates
1.25 +** a database write does not have to wait for (sometimes slow) disk I/O
1.26 +** to occur. The write seems to happen very quickly, though in reality
1.27 +** it is happening at its usual slow pace in the background.
1.28 +**
1.29 +** Asynchronous I/O appears to give better responsiveness, but at a price.
1.30 +** You lose the Durable property. With the default I/O backend of SQLite,
1.31 +** once a write completes, you know that the information you wrote is
1.32 +** safely on disk. With the asynchronous I/O, this is not the case. If
1.33 +** your program crashes or if a power loss occurs after the database
1.34 +** write but before the asynchronous write thread has completed, then the
1.35 +** database change might never make it to disk and the next user of the
1.36 +** database might not see your change.
1.37 +**
1.38 +** You lose Durability with asynchronous I/O, but you still retain the
1.39 +** other parts of ACID: Atomic, Consistent, and Isolated. Many
1.40 +** appliations get along fine without the Durablity.
1.41 +**
1.42 +** HOW IT WORKS
1.43 +**
1.44 +** Asynchronous I/O works by creating a special SQLite "vfs" structure
1.45 +** and registering it with sqlite3_vfs_register(). When files opened via
1.46 +** this vfs are written to (using sqlite3OsWrite()), the data is not
1.47 +** written directly to disk, but is placed in the "write-queue" to be
1.48 +** handled by the background thread.
1.49 +**
1.50 +** When files opened with the asynchronous vfs are read from
1.51 +** (using sqlite3OsRead()), the data is read from the file on
1.52 +** disk and the write-queue, so that from the point of view of
1.53 +** the vfs reader the OsWrite() appears to have already completed.
1.54 +**
1.55 +** The special vfs is registered (and unregistered) by calls to
1.56 +** function asyncEnable() (see below).
1.57 +**
1.58 +** LIMITATIONS
1.59 +**
1.60 +** This demonstration code is deliberately kept simple in order to keep
1.61 +** the main ideas clear and easy to understand. Real applications that
1.62 +** want to do asynchronous I/O might want to add additional capabilities.
1.63 +** For example, in this demonstration if writes are happening at a steady
1.64 +** stream that exceeds the I/O capability of the background writer thread,
1.65 +** the queue of pending write operations will grow without bound until we
1.66 +** run out of memory. Users of this technique may want to keep track of
1.67 +** the quantity of pending writes and stop accepting new write requests
1.68 +** when the buffer gets to be too big.
1.69 +**
1.70 +** LOCKING + CONCURRENCY
1.71 +**
1.72 +** Multiple connections from within a single process that use this
1.73 +** implementation of asynchronous IO may access a single database
1.74 +** file concurrently. From the point of view of the user, if all
1.75 +** connections are from within a single process, there is no difference
1.76 +** between the concurrency offered by "normal" SQLite and SQLite
1.77 +** using the asynchronous backend.
1.78 +**
1.79 +** If connections from within multiple database files may access the
1.80 +** database file, the ENABLE_FILE_LOCKING symbol (see below) must be
1.81 +** defined. If it is not defined, then no locks are established on
1.82 +** the database file. In this case, if multiple processes access
1.83 +** the database file, corruption will quickly result.
1.84 +**
1.85 +** If ENABLE_FILE_LOCKING is defined (the default), then connections
1.86 +** from within multiple processes may access a single database file
1.87 +** without risking corruption. However concurrency is reduced as
1.88 +** follows:
1.89 +**
1.90 +** * When a connection using asynchronous IO begins a database
1.91 +** transaction, the database is locked immediately. However the
1.92 +** lock is not released until after all relevant operations
1.93 +** in the write-queue have been flushed to disk. This means
1.94 +** (for example) that the database may remain locked for some
1.95 +** time after a "COMMIT" or "ROLLBACK" is issued.
1.96 +**
1.97 +** * If an application using asynchronous IO executes transactions
1.98 +** in quick succession, other database users may be effectively
1.99 +** locked out of the database. This is because when a BEGIN
1.100 +** is executed, a database lock is established immediately. But
1.101 +** when the corresponding COMMIT or ROLLBACK occurs, the lock
1.102 +** is not released until the relevant part of the write-queue
1.103 +** has been flushed through. As a result, if a COMMIT is followed
1.104 +** by a BEGIN before the write-queue is flushed through, the database
1.105 +** is never unlocked,preventing other processes from accessing
1.106 +** the database.
1.107 +**
1.108 +** Defining ENABLE_FILE_LOCKING when using an NFS or other remote
1.109 +** file-system may slow things down, as synchronous round-trips to the
1.110 +** server may be required to establish database file locks.
1.111 +*/
1.112 +#define ENABLE_FILE_LOCKING
1.113 +
1.114 +#ifndef SQLITE_AMALGAMATION
1.115 +# include "sqlite3.h"
1.116 +# include <assert.h>
1.117 +# include <string.h>
1.118 +#endif
1.119 +#include "tcl.h"
1.120 +
1.121 +/*
1.122 +** This test uses pthreads and hence only works on unix and with
1.123 +** a threadsafe build of SQLite.
1.124 +*/
1.125 +#if SQLITE_OS_UNIX && SQLITE_THREADSAFE
1.126 +
1.127 +/*
1.128 +** This demo uses pthreads. If you do not have a pthreads implementation
1.129 +** for your operating system, you will need to recode the threading
1.130 +** logic.
1.131 +*/
1.132 +#include <pthread.h>
1.133 +#include <sched.h>
1.134 +
1.135 +/* Useful macros used in several places */
1.136 +#define MIN(x,y) ((x)<(y)?(x):(y))
1.137 +#define MAX(x,y) ((x)>(y)?(x):(y))
1.138 +
1.139 +/* Forward references */
1.140 +typedef struct AsyncWrite AsyncWrite;
1.141 +typedef struct AsyncFile AsyncFile;
1.142 +typedef struct AsyncFileData AsyncFileData;
1.143 +typedef struct AsyncFileLock AsyncFileLock;
1.144 +typedef struct AsyncLock AsyncLock;
1.145 +
1.146 +/* Enable for debugging */
1.147 +static int sqlite3async_trace = 0;
1.148 +# define ASYNC_TRACE(X) if( sqlite3async_trace ) asyncTrace X
1.149 +static void asyncTrace(const char *zFormat, ...){
1.150 + char *z;
1.151 + va_list ap;
1.152 + va_start(ap, zFormat);
1.153 + z = sqlite3_vmprintf(zFormat, ap);
1.154 + va_end(ap);
1.155 + fprintf(stderr, "[%d] %s", (int)pthread_self(), z);
1.156 + sqlite3_free(z);
1.157 +}
1.158 +
1.159 +/*
1.160 +** THREAD SAFETY NOTES
1.161 +**
1.162 +** Basic rules:
1.163 +**
1.164 +** * Both read and write access to the global write-op queue must be
1.165 +** protected by the async.queueMutex. As are the async.ioError and
1.166 +** async.nFile variables.
1.167 +**
1.168 +** * The async.pLock list and all AsyncLock and AsyncFileLock
1.169 +** structures must be protected by the async.lockMutex mutex.
1.170 +**
1.171 +** * The file handles from the underlying system are not assumed to
1.172 +** be thread safe.
1.173 +**
1.174 +** * See the last two paragraphs under "The Writer Thread" for
1.175 +** an assumption to do with file-handle synchronization by the Os.
1.176 +**
1.177 +** Deadlock prevention:
1.178 +**
1.179 +** There are three mutex used by the system: the "writer" mutex,
1.180 +** the "queue" mutex and the "lock" mutex. Rules are:
1.181 +**
1.182 +** * It is illegal to block on the writer mutex when any other mutex
1.183 +** are held, and
1.184 +**
1.185 +** * It is illegal to block on the queue mutex when the lock mutex
1.186 +** is held.
1.187 +**
1.188 +** i.e. mutex's must be grabbed in the order "writer", "queue", "lock".
1.189 +**
1.190 +** File system operations (invoked by SQLite thread):
1.191 +**
1.192 +** xOpen
1.193 +** xDelete
1.194 +** xFileExists
1.195 +**
1.196 +** File handle operations (invoked by SQLite thread):
1.197 +**
1.198 +** asyncWrite, asyncClose, asyncTruncate, asyncSync
1.199 +**
1.200 +** The operations above add an entry to the global write-op list. They
1.201 +** prepare the entry, acquire the async.queueMutex momentarily while
1.202 +** list pointers are manipulated to insert the new entry, then release
1.203 +** the mutex and signal the writer thread to wake up in case it happens
1.204 +** to be asleep.
1.205 +**
1.206 +**
1.207 +** asyncRead, asyncFileSize.
1.208 +**
1.209 +** Read operations. Both of these read from both the underlying file
1.210 +** first then adjust their result based on pending writes in the
1.211 +** write-op queue. So async.queueMutex is held for the duration
1.212 +** of these operations to prevent other threads from changing the
1.213 +** queue in mid operation.
1.214 +**
1.215 +**
1.216 +** asyncLock, asyncUnlock, asyncCheckReservedLock
1.217 +**
1.218 +** These primitives implement in-process locking using a hash table
1.219 +** on the file name. Files are locked correctly for connections coming
1.220 +** from the same process. But other processes cannot see these locks
1.221 +** and will therefore not honor them.
1.222 +**
1.223 +**
1.224 +** The writer thread:
1.225 +**
1.226 +** The async.writerMutex is used to make sure only there is only
1.227 +** a single writer thread running at a time.
1.228 +**
1.229 +** Inside the writer thread is a loop that works like this:
1.230 +**
1.231 +** WHILE (write-op list is not empty)
1.232 +** Do IO operation at head of write-op list
1.233 +** Remove entry from head of write-op list
1.234 +** END WHILE
1.235 +**
1.236 +** The async.queueMutex is always held during the <write-op list is
1.237 +** not empty> test, and when the entry is removed from the head
1.238 +** of the write-op list. Sometimes it is held for the interim
1.239 +** period (while the IO is performed), and sometimes it is
1.240 +** relinquished. It is relinquished if (a) the IO op is an
1.241 +** ASYNC_CLOSE or (b) when the file handle was opened, two of
1.242 +** the underlying systems handles were opened on the same
1.243 +** file-system entry.
1.244 +**
1.245 +** If condition (b) above is true, then one file-handle
1.246 +** (AsyncFile.pBaseRead) is used exclusively by sqlite threads to read the
1.247 +** file, the other (AsyncFile.pBaseWrite) by sqlite3_async_flush()
1.248 +** threads to perform write() operations. This means that read
1.249 +** operations are not blocked by asynchronous writes (although
1.250 +** asynchronous writes may still be blocked by reads).
1.251 +**
1.252 +** This assumes that the OS keeps two handles open on the same file
1.253 +** properly in sync. That is, any read operation that starts after a
1.254 +** write operation on the same file system entry has completed returns
1.255 +** data consistent with the write. We also assume that if one thread
1.256 +** reads a file while another is writing it all bytes other than the
1.257 +** ones actually being written contain valid data.
1.258 +**
1.259 +** If the above assumptions are not true, set the preprocessor symbol
1.260 +** SQLITE_ASYNC_TWO_FILEHANDLES to 0.
1.261 +*/
1.262 +
1.263 +#ifndef SQLITE_ASYNC_TWO_FILEHANDLES
1.264 +/* #define SQLITE_ASYNC_TWO_FILEHANDLES 0 */
1.265 +#define SQLITE_ASYNC_TWO_FILEHANDLES 1
1.266 +#endif
1.267 +
1.268 +/*
1.269 +** State information is held in the static variable "async" defined
1.270 +** as the following structure.
1.271 +**
1.272 +** Both async.ioError and async.nFile are protected by async.queueMutex.
1.273 +*/
1.274 +static struct TestAsyncStaticData {
1.275 + pthread_mutex_t lockMutex; /* For access to aLock hash table */
1.276 + pthread_mutex_t queueMutex; /* Mutex for access to write operation queue */
1.277 + pthread_mutex_t writerMutex; /* Prevents multiple writer threads */
1.278 + pthread_cond_t queueSignal; /* For waking up sleeping writer thread */
1.279 + pthread_cond_t emptySignal; /* Notify when the write queue is empty */
1.280 + AsyncWrite *pQueueFirst; /* Next write operation to be processed */
1.281 + AsyncWrite *pQueueLast; /* Last write operation on the list */
1.282 + AsyncLock *pLock; /* Linked list of all AsyncLock structures */
1.283 + volatile int ioDelay; /* Extra delay between write operations */
1.284 + volatile int writerHaltWhenIdle; /* Writer thread halts when queue empty */
1.285 + volatile int writerHaltNow; /* Writer thread halts after next op */
1.286 + int ioError; /* True if an IO error has occured */
1.287 + int nFile; /* Number of open files (from sqlite pov) */
1.288 +} async = {
1.289 + PTHREAD_MUTEX_INITIALIZER,
1.290 + PTHREAD_MUTEX_INITIALIZER,
1.291 + PTHREAD_MUTEX_INITIALIZER,
1.292 + PTHREAD_COND_INITIALIZER,
1.293 + PTHREAD_COND_INITIALIZER,
1.294 +};
1.295 +
1.296 +/* Possible values of AsyncWrite.op */
1.297 +#define ASYNC_NOOP 0
1.298 +#define ASYNC_WRITE 1
1.299 +#define ASYNC_SYNC 2
1.300 +#define ASYNC_TRUNCATE 3
1.301 +#define ASYNC_CLOSE 4
1.302 +#define ASYNC_DELETE 5
1.303 +#define ASYNC_OPENEXCLUSIVE 6
1.304 +#define ASYNC_UNLOCK 7
1.305 +
1.306 +/* Names of opcodes. Used for debugging only.
1.307 +** Make sure these stay in sync with the macros above!
1.308 +*/
1.309 +static const char *azOpcodeName[] = {
1.310 + "NOOP", "WRITE", "SYNC", "TRUNCATE", "CLOSE", "DELETE", "OPENEX", "UNLOCK"
1.311 +};
1.312 +
1.313 +/*
1.314 +** Entries on the write-op queue are instances of the AsyncWrite
1.315 +** structure, defined here.
1.316 +**
1.317 +** The interpretation of the iOffset and nByte variables varies depending
1.318 +** on the value of AsyncWrite.op:
1.319 +**
1.320 +** ASYNC_NOOP:
1.321 +** No values used.
1.322 +**
1.323 +** ASYNC_WRITE:
1.324 +** iOffset -> Offset in file to write to.
1.325 +** nByte -> Number of bytes of data to write (pointed to by zBuf).
1.326 +**
1.327 +** ASYNC_SYNC:
1.328 +** nByte -> flags to pass to sqlite3OsSync().
1.329 +**
1.330 +** ASYNC_TRUNCATE:
1.331 +** iOffset -> Size to truncate file to.
1.332 +** nByte -> Unused.
1.333 +**
1.334 +** ASYNC_CLOSE:
1.335 +** iOffset -> Unused.
1.336 +** nByte -> Unused.
1.337 +**
1.338 +** ASYNC_DELETE:
1.339 +** iOffset -> Contains the "syncDir" flag.
1.340 +** nByte -> Number of bytes of zBuf points to (file name).
1.341 +**
1.342 +** ASYNC_OPENEXCLUSIVE:
1.343 +** iOffset -> Value of "delflag".
1.344 +** nByte -> Number of bytes of zBuf points to (file name).
1.345 +**
1.346 +** ASYNC_UNLOCK:
1.347 +** nByte -> Argument to sqlite3OsUnlock().
1.348 +**
1.349 +**
1.350 +** For an ASYNC_WRITE operation, zBuf points to the data to write to the file.
1.351 +** This space is sqlite3_malloc()d along with the AsyncWrite structure in a
1.352 +** single blob, so is deleted when sqlite3_free() is called on the parent
1.353 +** structure.
1.354 +*/
1.355 +struct AsyncWrite {
1.356 + AsyncFileData *pFileData; /* File to write data to or sync */
1.357 + int op; /* One of ASYNC_xxx etc. */
1.358 + sqlite_int64 iOffset; /* See above */
1.359 + int nByte; /* See above */
1.360 + char *zBuf; /* Data to write to file (or NULL if op!=ASYNC_WRITE) */
1.361 + AsyncWrite *pNext; /* Next write operation (to any file) */
1.362 +};
1.363 +
1.364 +/*
1.365 +** An instance of this structure is created for each distinct open file
1.366 +** (i.e. if two handles are opened on the one file, only one of these
1.367 +** structures is allocated) and stored in the async.aLock hash table. The
1.368 +** keys for async.aLock are the full pathnames of the opened files.
1.369 +**
1.370 +** AsyncLock.pList points to the head of a linked list of AsyncFileLock
1.371 +** structures, one for each handle currently open on the file.
1.372 +**
1.373 +** If the opened file is not a main-database (the SQLITE_OPEN_MAIN_DB is
1.374 +** not passed to the sqlite3OsOpen() call), or if ENABLE_FILE_LOCKING is
1.375 +** not defined at compile time, variables AsyncLock.pFile and
1.376 +** AsyncLock.eLock are never used. Otherwise, pFile is a file handle
1.377 +** opened on the file in question and used to obtain the file-system
1.378 +** locks required by database connections within this process.
1.379 +**
1.380 +** See comments above the asyncLock() function for more details on
1.381 +** the implementation of database locking used by this backend.
1.382 +*/
1.383 +struct AsyncLock {
1.384 + char *zFile;
1.385 + int nFile;
1.386 + sqlite3_file *pFile;
1.387 + int eLock;
1.388 + AsyncFileLock *pList;
1.389 + AsyncLock *pNext; /* Next in linked list headed by async.pLock */
1.390 +};
1.391 +
1.392 +/*
1.393 +** An instance of the following structure is allocated along with each
1.394 +** AsyncFileData structure (see AsyncFileData.lock), but is only used if the
1.395 +** file was opened with the SQLITE_OPEN_MAIN_DB.
1.396 +*/
1.397 +struct AsyncFileLock {
1.398 + int eLock; /* Internally visible lock state (sqlite pov) */
1.399 + int eAsyncLock; /* Lock-state with write-queue unlock */
1.400 + AsyncFileLock *pNext;
1.401 +};
1.402 +
1.403 +/*
1.404 +** The AsyncFile structure is a subclass of sqlite3_file used for
1.405 +** asynchronous IO.
1.406 +**
1.407 +** All of the actual data for the structure is stored in the structure
1.408 +** pointed to by AsyncFile.pData, which is allocated as part of the
1.409 +** sqlite3OsOpen() using sqlite3_malloc(). The reason for this is that the
1.410 +** lifetime of the AsyncFile structure is ended by the caller after OsClose()
1.411 +** is called, but the data in AsyncFileData may be required by the
1.412 +** writer thread after that point.
1.413 +*/
1.414 +struct AsyncFile {
1.415 + sqlite3_io_methods *pMethod;
1.416 + AsyncFileData *pData;
1.417 +};
1.418 +struct AsyncFileData {
1.419 + char *zName; /* Underlying OS filename - used for debugging */
1.420 + int nName; /* Number of characters in zName */
1.421 + sqlite3_file *pBaseRead; /* Read handle to the underlying Os file */
1.422 + sqlite3_file *pBaseWrite; /* Write handle to the underlying Os file */
1.423 + AsyncFileLock lock; /* Lock state for this handle */
1.424 + AsyncLock *pLock; /* AsyncLock object for this file system entry */
1.425 + AsyncWrite close;
1.426 +};
1.427 +
1.428 +/*
1.429 +** The following async_XXX functions are debugging wrappers around the
1.430 +** corresponding pthread_XXX functions:
1.431 +**
1.432 +** pthread_mutex_lock();
1.433 +** pthread_mutex_unlock();
1.434 +** pthread_mutex_trylock();
1.435 +** pthread_cond_wait();
1.436 +**
1.437 +** It is illegal to pass any mutex other than those stored in the
1.438 +** following global variables of these functions.
1.439 +**
1.440 +** async.queueMutex
1.441 +** async.writerMutex
1.442 +** async.lockMutex
1.443 +**
1.444 +** If NDEBUG is defined, these wrappers do nothing except call the
1.445 +** corresponding pthreads function. If NDEBUG is not defined, then the
1.446 +** following variables are used to store the thread-id (as returned
1.447 +** by pthread_self()) currently holding the mutex, or 0 otherwise:
1.448 +**
1.449 +** asyncdebug.queueMutexHolder
1.450 +** asyncdebug.writerMutexHolder
1.451 +** asyncdebug.lockMutexHolder
1.452 +**
1.453 +** These variables are used by some assert() statements that verify
1.454 +** the statements made in the "Deadlock Prevention" notes earlier
1.455 +** in this file.
1.456 +*/
1.457 +#ifndef NDEBUG
1.458 +
1.459 +static struct TestAsyncDebugData {
1.460 + pthread_t lockMutexHolder;
1.461 + pthread_t queueMutexHolder;
1.462 + pthread_t writerMutexHolder;
1.463 +} asyncdebug = {0, 0, 0};
1.464 +
1.465 +/*
1.466 +** Wrapper around pthread_mutex_lock(). Checks that we have not violated
1.467 +** the anti-deadlock rules (see "Deadlock prevention" above).
1.468 +*/
1.469 +static int async_mutex_lock(pthread_mutex_t *pMutex){
1.470 + int iIdx;
1.471 + int rc;
1.472 + pthread_mutex_t *aMutex = (pthread_mutex_t *)(&async);
1.473 + pthread_t *aHolder = (pthread_t *)(&asyncdebug);
1.474 +
1.475 + /* The code in this 'ifndef NDEBUG' block depends on a certain alignment
1.476 + * of the variables in TestAsyncStaticData and TestAsyncDebugData. The
1.477 + * following assert() statements check that this has not been changed.
1.478 + *
1.479 + * Really, these only need to be run once at startup time.
1.480 + */
1.481 + assert(&(aMutex[0])==&async.lockMutex);
1.482 + assert(&(aMutex[1])==&async.queueMutex);
1.483 + assert(&(aMutex[2])==&async.writerMutex);
1.484 + assert(&(aHolder[0])==&asyncdebug.lockMutexHolder);
1.485 + assert(&(aHolder[1])==&asyncdebug.queueMutexHolder);
1.486 + assert(&(aHolder[2])==&asyncdebug.writerMutexHolder);
1.487 +
1.488 + assert( pthread_self()!=0 );
1.489 +
1.490 + for(iIdx=0; iIdx<3; iIdx++){
1.491 + if( pMutex==&aMutex[iIdx] ) break;
1.492 +
1.493 + /* This is the key assert(). Here we are checking that if the caller
1.494 + * is trying to block on async.writerMutex, neither of the other two
1.495 + * mutex are held. If the caller is trying to block on async.queueMutex,
1.496 + * lockMutex is not held.
1.497 + */
1.498 + assert(!pthread_equal(aHolder[iIdx], pthread_self()));
1.499 + }
1.500 + assert(iIdx<3);
1.501 +
1.502 + rc = pthread_mutex_lock(pMutex);
1.503 + if( rc==0 ){
1.504 + assert(aHolder[iIdx]==0);
1.505 + aHolder[iIdx] = pthread_self();
1.506 + }
1.507 + return rc;
1.508 +}
1.509 +
1.510 +/*
1.511 +** Wrapper around pthread_mutex_unlock().
1.512 +*/
1.513 +static int async_mutex_unlock(pthread_mutex_t *pMutex){
1.514 + int iIdx;
1.515 + int rc;
1.516 + pthread_mutex_t *aMutex = (pthread_mutex_t *)(&async);
1.517 + pthread_t *aHolder = (pthread_t *)(&asyncdebug);
1.518 +
1.519 + for(iIdx=0; iIdx<3; iIdx++){
1.520 + if( pMutex==&aMutex[iIdx] ) break;
1.521 + }
1.522 + assert(iIdx<3);
1.523 +
1.524 + assert(pthread_equal(aHolder[iIdx], pthread_self()));
1.525 + aHolder[iIdx] = 0;
1.526 + rc = pthread_mutex_unlock(pMutex);
1.527 + assert(rc==0);
1.528 +
1.529 + return 0;
1.530 +}
1.531 +
1.532 +/*
1.533 +** Wrapper around pthread_mutex_trylock().
1.534 +*/
1.535 +static int async_mutex_trylock(pthread_mutex_t *pMutex){
1.536 + int iIdx;
1.537 + int rc;
1.538 + pthread_mutex_t *aMutex = (pthread_mutex_t *)(&async);
1.539 + pthread_t *aHolder = (pthread_t *)(&asyncdebug);
1.540 +
1.541 + for(iIdx=0; iIdx<3; iIdx++){
1.542 + if( pMutex==&aMutex[iIdx] ) break;
1.543 + }
1.544 + assert(iIdx<3);
1.545 +
1.546 + rc = pthread_mutex_trylock(pMutex);
1.547 + if( rc==0 ){
1.548 + assert(aHolder[iIdx]==0);
1.549 + aHolder[iIdx] = pthread_self();
1.550 + }
1.551 + return rc;
1.552 +}
1.553 +
1.554 +/*
1.555 +** Wrapper around pthread_cond_wait().
1.556 +*/
1.557 +static int async_cond_wait(pthread_cond_t *pCond, pthread_mutex_t *pMutex){
1.558 + int iIdx;
1.559 + int rc;
1.560 + pthread_mutex_t *aMutex = (pthread_mutex_t *)(&async);
1.561 + pthread_t *aHolder = (pthread_t *)(&asyncdebug);
1.562 +
1.563 + for(iIdx=0; iIdx<3; iIdx++){
1.564 + if( pMutex==&aMutex[iIdx] ) break;
1.565 + }
1.566 + assert(iIdx<3);
1.567 +
1.568 + assert(pthread_equal(aHolder[iIdx],pthread_self()));
1.569 + aHolder[iIdx] = 0;
1.570 + rc = pthread_cond_wait(pCond, pMutex);
1.571 + if( rc==0 ){
1.572 + aHolder[iIdx] = pthread_self();
1.573 + }
1.574 + return rc;
1.575 +}
1.576 +
1.577 +/*
1.578 +** Assert that the mutex is held by the current thread.
1.579 +*/
1.580 +static void assert_mutex_is_held(pthread_mutex_t *pMutex){
1.581 + int iIdx;
1.582 + pthread_mutex_t *aMutex = (pthread_mutex_t *)(&async);
1.583 + pthread_t *aHolder = (pthread_t *)(&asyncdebug);
1.584 +
1.585 + for(iIdx=0; iIdx<3; iIdx++){
1.586 + if( pMutex==&aMutex[iIdx] ) break;
1.587 + }
1.588 + assert(iIdx<3);
1.589 + assert( aHolder[iIdx]==pthread_self() );
1.590 +}
1.591 +
1.592 +/* Call our async_XX wrappers instead of selected pthread_XX functions */
1.593 +#define pthread_mutex_lock async_mutex_lock
1.594 +#define pthread_mutex_unlock async_mutex_unlock
1.595 +#define pthread_mutex_trylock async_mutex_trylock
1.596 +#define pthread_cond_wait async_cond_wait
1.597 +
1.598 +#else /* if defined(NDEBUG) */
1.599 +
1.600 +#define assert_mutex_is_held(X) /* A no-op when not debugging */
1.601 +
1.602 +#endif /* !defined(NDEBUG) */
1.603 +
1.604 +/*
1.605 +** Add an entry to the end of the global write-op list. pWrite should point
1.606 +** to an AsyncWrite structure allocated using sqlite3_malloc(). The writer
1.607 +** thread will call sqlite3_free() to free the structure after the specified
1.608 +** operation has been completed.
1.609 +**
1.610 +** Once an AsyncWrite structure has been added to the list, it becomes the
1.611 +** property of the writer thread and must not be read or modified by the
1.612 +** caller.
1.613 +*/
1.614 +static void addAsyncWrite(AsyncWrite *pWrite){
1.615 + /* We must hold the queue mutex in order to modify the queue pointers */
1.616 + pthread_mutex_lock(&async.queueMutex);
1.617 +
1.618 + /* Add the record to the end of the write-op queue */
1.619 + assert( !pWrite->pNext );
1.620 + if( async.pQueueLast ){
1.621 + assert( async.pQueueFirst );
1.622 + async.pQueueLast->pNext = pWrite;
1.623 + }else{
1.624 + async.pQueueFirst = pWrite;
1.625 + }
1.626 + async.pQueueLast = pWrite;
1.627 + ASYNC_TRACE(("PUSH %p (%s %s %d)\n", pWrite, azOpcodeName[pWrite->op],
1.628 + pWrite->pFileData ? pWrite->pFileData->zName : "-", pWrite->iOffset));
1.629 +
1.630 + if( pWrite->op==ASYNC_CLOSE ){
1.631 + async.nFile--;
1.632 + }
1.633 +
1.634 + /* Drop the queue mutex */
1.635 + pthread_mutex_unlock(&async.queueMutex);
1.636 +
1.637 + /* The writer thread might have been idle because there was nothing
1.638 + ** on the write-op queue for it to do. So wake it up. */
1.639 + pthread_cond_signal(&async.queueSignal);
1.640 +}
1.641 +
1.642 +/*
1.643 +** Increment async.nFile in a thread-safe manner.
1.644 +*/
1.645 +static void incrOpenFileCount(){
1.646 + /* We must hold the queue mutex in order to modify async.nFile */
1.647 + pthread_mutex_lock(&async.queueMutex);
1.648 + if( async.nFile==0 ){
1.649 + async.ioError = SQLITE_OK;
1.650 + }
1.651 + async.nFile++;
1.652 + pthread_mutex_unlock(&async.queueMutex);
1.653 +}
1.654 +
1.655 +/*
1.656 +** This is a utility function to allocate and populate a new AsyncWrite
1.657 +** structure and insert it (via addAsyncWrite() ) into the global list.
1.658 +*/
1.659 +static int addNewAsyncWrite(
1.660 + AsyncFileData *pFileData,
1.661 + int op,
1.662 + sqlite3_int64 iOffset,
1.663 + int nByte,
1.664 + const char *zByte
1.665 +){
1.666 + AsyncWrite *p;
1.667 + if( op!=ASYNC_CLOSE && async.ioError ){
1.668 + return async.ioError;
1.669 + }
1.670 + p = sqlite3_malloc(sizeof(AsyncWrite) + (zByte?nByte:0));
1.671 + if( !p ){
1.672 + /* The upper layer does not expect operations like OsWrite() to
1.673 + ** return SQLITE_NOMEM. This is partly because under normal conditions
1.674 + ** SQLite is required to do rollback without calling malloc(). So
1.675 + ** if malloc() fails here, treat it as an I/O error. The above
1.676 + ** layer knows how to handle that.
1.677 + */
1.678 + return SQLITE_IOERR;
1.679 + }
1.680 + p->op = op;
1.681 + p->iOffset = iOffset;
1.682 + p->nByte = nByte;
1.683 + p->pFileData = pFileData;
1.684 + p->pNext = 0;
1.685 + if( zByte ){
1.686 + p->zBuf = (char *)&p[1];
1.687 + memcpy(p->zBuf, zByte, nByte);
1.688 + }else{
1.689 + p->zBuf = 0;
1.690 + }
1.691 + addAsyncWrite(p);
1.692 + return SQLITE_OK;
1.693 +}
1.694 +
1.695 +/*
1.696 +** Close the file. This just adds an entry to the write-op list, the file is
1.697 +** not actually closed.
1.698 +*/
1.699 +static int asyncClose(sqlite3_file *pFile){
1.700 + AsyncFileData *p = ((AsyncFile *)pFile)->pData;
1.701 +
1.702 + /* Unlock the file, if it is locked */
1.703 + pthread_mutex_lock(&async.lockMutex);
1.704 + p->lock.eLock = 0;
1.705 + pthread_mutex_unlock(&async.lockMutex);
1.706 +
1.707 + addAsyncWrite(&p->close);
1.708 + return SQLITE_OK;
1.709 +}
1.710 +
1.711 +/*
1.712 +** Implementation of sqlite3OsWrite() for asynchronous files. Instead of
1.713 +** writing to the underlying file, this function adds an entry to the end of
1.714 +** the global AsyncWrite list. Either SQLITE_OK or SQLITE_NOMEM may be
1.715 +** returned.
1.716 +*/
1.717 +static int asyncWrite(
1.718 + sqlite3_file *pFile,
1.719 + const void *pBuf,
1.720 + int amt,
1.721 + sqlite3_int64 iOff
1.722 +){
1.723 + AsyncFileData *p = ((AsyncFile *)pFile)->pData;
1.724 + return addNewAsyncWrite(p, ASYNC_WRITE, iOff, amt, pBuf);
1.725 +}
1.726 +
1.727 +/*
1.728 +** Read data from the file. First we read from the filesystem, then adjust
1.729 +** the contents of the buffer based on ASYNC_WRITE operations in the
1.730 +** write-op queue.
1.731 +**
1.732 +** This method holds the mutex from start to finish.
1.733 +*/
1.734 +static int asyncRead(
1.735 + sqlite3_file *pFile,
1.736 + void *zOut,
1.737 + int iAmt,
1.738 + sqlite3_int64 iOffset
1.739 +){
1.740 + AsyncFileData *p = ((AsyncFile *)pFile)->pData;
1.741 + int rc = SQLITE_OK;
1.742 + sqlite3_int64 filesize;
1.743 + int nRead;
1.744 + sqlite3_file *pBase = p->pBaseRead;
1.745 +
1.746 + /* Grab the write queue mutex for the duration of the call */
1.747 + pthread_mutex_lock(&async.queueMutex);
1.748 +
1.749 + /* If an I/O error has previously occurred in this virtual file
1.750 + ** system, then all subsequent operations fail.
1.751 + */
1.752 + if( async.ioError!=SQLITE_OK ){
1.753 + rc = async.ioError;
1.754 + goto asyncread_out;
1.755 + }
1.756 +
1.757 + if( pBase->pMethods ){
1.758 + rc = pBase->pMethods->xFileSize(pBase, &filesize);
1.759 + if( rc!=SQLITE_OK ){
1.760 + goto asyncread_out;
1.761 + }
1.762 + nRead = MIN(filesize - iOffset, iAmt);
1.763 + if( nRead>0 ){
1.764 + rc = pBase->pMethods->xRead(pBase, zOut, nRead, iOffset);
1.765 + ASYNC_TRACE(("READ %s %d bytes at %d\n", p->zName, nRead, iOffset));
1.766 + }
1.767 + }
1.768 +
1.769 + if( rc==SQLITE_OK ){
1.770 + AsyncWrite *pWrite;
1.771 + char *zName = p->zName;
1.772 +
1.773 + for(pWrite=async.pQueueFirst; pWrite; pWrite = pWrite->pNext){
1.774 + if( pWrite->op==ASYNC_WRITE && (
1.775 + (pWrite->pFileData==p) ||
1.776 + (zName && pWrite->pFileData->zName==zName)
1.777 + )){
1.778 + int iBeginOut = (pWrite->iOffset-iOffset);
1.779 + int iBeginIn = -iBeginOut;
1.780 + int nCopy;
1.781 +
1.782 + if( iBeginIn<0 ) iBeginIn = 0;
1.783 + if( iBeginOut<0 ) iBeginOut = 0;
1.784 + nCopy = MIN(pWrite->nByte-iBeginIn, iAmt-iBeginOut);
1.785 +
1.786 + if( nCopy>0 ){
1.787 + memcpy(&((char *)zOut)[iBeginOut], &pWrite->zBuf[iBeginIn], nCopy);
1.788 + ASYNC_TRACE(("OVERREAD %d bytes at %d\n", nCopy, iBeginOut+iOffset));
1.789 + }
1.790 + }
1.791 + }
1.792 + }
1.793 +
1.794 +asyncread_out:
1.795 + pthread_mutex_unlock(&async.queueMutex);
1.796 + return rc;
1.797 +}
1.798 +
1.799 +/*
1.800 +** Truncate the file to nByte bytes in length. This just adds an entry to
1.801 +** the write-op list, no IO actually takes place.
1.802 +*/
1.803 +static int asyncTruncate(sqlite3_file *pFile, sqlite3_int64 nByte){
1.804 + AsyncFileData *p = ((AsyncFile *)pFile)->pData;
1.805 + return addNewAsyncWrite(p, ASYNC_TRUNCATE, nByte, 0, 0);
1.806 +}
1.807 +
1.808 +/*
1.809 +** Sync the file. This just adds an entry to the write-op list, the
1.810 +** sync() is done later by sqlite3_async_flush().
1.811 +*/
1.812 +static int asyncSync(sqlite3_file *pFile, int flags){
1.813 + AsyncFileData *p = ((AsyncFile *)pFile)->pData;
1.814 + return addNewAsyncWrite(p, ASYNC_SYNC, 0, flags, 0);
1.815 +}
1.816 +
1.817 +/*
1.818 +** Read the size of the file. First we read the size of the file system
1.819 +** entry, then adjust for any ASYNC_WRITE or ASYNC_TRUNCATE operations
1.820 +** currently in the write-op list.
1.821 +**
1.822 +** This method holds the mutex from start to finish.
1.823 +*/
1.824 +int asyncFileSize(sqlite3_file *pFile, sqlite3_int64 *piSize){
1.825 + AsyncFileData *p = ((AsyncFile *)pFile)->pData;
1.826 + int rc = SQLITE_OK;
1.827 + sqlite3_int64 s = 0;
1.828 + sqlite3_file *pBase;
1.829 +
1.830 + pthread_mutex_lock(&async.queueMutex);
1.831 +
1.832 + /* Read the filesystem size from the base file. If pBaseRead is NULL, this
1.833 + ** means the file hasn't been opened yet. In this case all relevant data
1.834 + ** must be in the write-op queue anyway, so we can omit reading from the
1.835 + ** file-system.
1.836 + */
1.837 + pBase = p->pBaseRead;
1.838 + if( pBase->pMethods ){
1.839 + rc = pBase->pMethods->xFileSize(pBase, &s);
1.840 + }
1.841 +
1.842 + if( rc==SQLITE_OK ){
1.843 + AsyncWrite *pWrite;
1.844 + for(pWrite=async.pQueueFirst; pWrite; pWrite = pWrite->pNext){
1.845 + if( pWrite->op==ASYNC_DELETE
1.846 + && p->zName
1.847 + && strcmp(p->zName, pWrite->zBuf)==0
1.848 + ){
1.849 + s = 0;
1.850 + }else if( pWrite->pFileData && (
1.851 + (pWrite->pFileData==p)
1.852 + || (p->zName && pWrite->pFileData->zName==p->zName)
1.853 + )){
1.854 + switch( pWrite->op ){
1.855 + case ASYNC_WRITE:
1.856 + s = MAX(pWrite->iOffset + (sqlite3_int64)(pWrite->nByte), s);
1.857 + break;
1.858 + case ASYNC_TRUNCATE:
1.859 + s = MIN(s, pWrite->iOffset);
1.860 + break;
1.861 + }
1.862 + }
1.863 + }
1.864 + *piSize = s;
1.865 + }
1.866 + pthread_mutex_unlock(&async.queueMutex);
1.867 + return rc;
1.868 +}
1.869 +
1.870 +/*
1.871 +** Lock or unlock the actual file-system entry.
1.872 +*/
1.873 +static int getFileLock(AsyncLock *pLock){
1.874 + int rc = SQLITE_OK;
1.875 + AsyncFileLock *pIter;
1.876 + int eRequired = 0;
1.877 +
1.878 + if( pLock->pFile ){
1.879 + for(pIter=pLock->pList; pIter; pIter=pIter->pNext){
1.880 + assert(pIter->eAsyncLock>=pIter->eLock);
1.881 + if( pIter->eAsyncLock>eRequired ){
1.882 + eRequired = pIter->eAsyncLock;
1.883 + assert(eRequired>=0 && eRequired<=SQLITE_LOCK_EXCLUSIVE);
1.884 + }
1.885 + }
1.886 +
1.887 + if( eRequired>pLock->eLock ){
1.888 + rc = pLock->pFile->pMethods->xLock(pLock->pFile, eRequired);
1.889 + if( rc==SQLITE_OK ){
1.890 + pLock->eLock = eRequired;
1.891 + }
1.892 + }
1.893 + else if( eRequired<pLock->eLock && eRequired<=SQLITE_LOCK_SHARED ){
1.894 + rc = pLock->pFile->pMethods->xUnlock(pLock->pFile, eRequired);
1.895 + if( rc==SQLITE_OK ){
1.896 + pLock->eLock = eRequired;
1.897 + }
1.898 + }
1.899 + }
1.900 +
1.901 + return rc;
1.902 +}
1.903 +
1.904 +/*
1.905 +** Return the AsyncLock structure from the global async.pLock list
1.906 +** associated with the file-system entry identified by path zName
1.907 +** (a string of nName bytes). If no such structure exists, return 0.
1.908 +*/
1.909 +static AsyncLock *findLock(const char *zName, int nName){
1.910 + AsyncLock *p = async.pLock;
1.911 + while( p && (p->nFile!=nName || memcmp(p->zFile, zName, nName)) ){
1.912 + p = p->pNext;
1.913 + }
1.914 + return p;
1.915 +}
1.916 +
1.917 +/*
1.918 +** The following two methods - asyncLock() and asyncUnlock() - are used
1.919 +** to obtain and release locks on database files opened with the
1.920 +** asynchronous backend.
1.921 +*/
1.922 +static int asyncLock(sqlite3_file *pFile, int eLock){
1.923 + int rc = SQLITE_OK;
1.924 + AsyncFileData *p = ((AsyncFile *)pFile)->pData;
1.925 +
1.926 + if( p->zName ){
1.927 + pthread_mutex_lock(&async.lockMutex);
1.928 + if( p->lock.eLock<eLock ){
1.929 + AsyncLock *pLock = p->pLock;
1.930 + AsyncFileLock *pIter;
1.931 + assert(pLock && pLock->pList);
1.932 + for(pIter=pLock->pList; pIter; pIter=pIter->pNext){
1.933 + if( pIter!=&p->lock && (
1.934 + (eLock==SQLITE_LOCK_EXCLUSIVE && pIter->eLock>=SQLITE_LOCK_SHARED) ||
1.935 + (eLock==SQLITE_LOCK_PENDING && pIter->eLock>=SQLITE_LOCK_RESERVED) ||
1.936 + (eLock==SQLITE_LOCK_RESERVED && pIter->eLock>=SQLITE_LOCK_RESERVED) ||
1.937 + (eLock==SQLITE_LOCK_SHARED && pIter->eLock>=SQLITE_LOCK_PENDING)
1.938 + )){
1.939 + rc = SQLITE_BUSY;
1.940 + }
1.941 + }
1.942 + if( rc==SQLITE_OK ){
1.943 + p->lock.eLock = eLock;
1.944 + p->lock.eAsyncLock = MAX(p->lock.eAsyncLock, eLock);
1.945 + }
1.946 + assert(p->lock.eAsyncLock>=p->lock.eLock);
1.947 + if( rc==SQLITE_OK ){
1.948 + rc = getFileLock(pLock);
1.949 + }
1.950 + }
1.951 + pthread_mutex_unlock(&async.lockMutex);
1.952 + }
1.953 +
1.954 + ASYNC_TRACE(("LOCK %d (%s) rc=%d\n", eLock, p->zName, rc));
1.955 + return rc;
1.956 +}
1.957 +static int asyncUnlock(sqlite3_file *pFile, int eLock){
1.958 + int rc = SQLITE_OK;
1.959 + AsyncFileData *p = ((AsyncFile *)pFile)->pData;
1.960 + if( p->zName ){
1.961 + AsyncFileLock *pLock = &p->lock;
1.962 + pthread_mutex_lock(&async.lockMutex);
1.963 + pLock->eLock = MIN(pLock->eLock, eLock);
1.964 + pthread_mutex_unlock(&async.lockMutex);
1.965 + rc = addNewAsyncWrite(p, ASYNC_UNLOCK, 0, eLock, 0);
1.966 + }
1.967 + return rc;
1.968 +}
1.969 +
1.970 +/*
1.971 +** This function is called when the pager layer first opens a database file
1.972 +** and is checking for a hot-journal.
1.973 +*/
1.974 +static int asyncCheckReservedLock(sqlite3_file *pFile, int *pResOut){
1.975 + int ret = 0;
1.976 + AsyncFileLock *pIter;
1.977 + AsyncFileData *p = ((AsyncFile *)pFile)->pData;
1.978 +
1.979 + pthread_mutex_lock(&async.lockMutex);
1.980 + for(pIter=p->pLock->pList; pIter; pIter=pIter->pNext){
1.981 + if( pIter->eLock>=SQLITE_LOCK_RESERVED ){
1.982 + ret = 1;
1.983 + }
1.984 + }
1.985 + pthread_mutex_unlock(&async.lockMutex);
1.986 +
1.987 + ASYNC_TRACE(("CHECK-LOCK %d (%s)\n", ret, p->zName));
1.988 + *pResOut = ret;
1.989 + return SQLITE_OK;
1.990 +}
1.991 +
1.992 +/*
1.993 +** sqlite3_file_control() implementation.
1.994 +*/
1.995 +static int asyncFileControl(sqlite3_file *id, int op, void *pArg){
1.996 + switch( op ){
1.997 + case SQLITE_FCNTL_LOCKSTATE: {
1.998 + pthread_mutex_lock(&async.lockMutex);
1.999 + *(int*)pArg = ((AsyncFile*)id)->pData->lock.eLock;
1.1000 + pthread_mutex_unlock(&async.lockMutex);
1.1001 + return SQLITE_OK;
1.1002 + }
1.1003 + }
1.1004 + return SQLITE_ERROR;
1.1005 +}
1.1006 +
1.1007 +/*
1.1008 +** Return the device characteristics and sector-size of the device. It
1.1009 +** is not tricky to implement these correctly, as this backend might
1.1010 +** not have an open file handle at this point.
1.1011 +*/
1.1012 +static int asyncSectorSize(sqlite3_file *pFile){
1.1013 + return 512;
1.1014 +}
1.1015 +static int asyncDeviceCharacteristics(sqlite3_file *pFile){
1.1016 + return 0;
1.1017 +}
1.1018 +
1.1019 +static int unlinkAsyncFile(AsyncFileData *pData){
1.1020 + AsyncFileLock **ppIter;
1.1021 + int rc = SQLITE_OK;
1.1022 +
1.1023 + if( pData->zName ){
1.1024 + AsyncLock *pLock = pData->pLock;
1.1025 + for(ppIter=&pLock->pList; *ppIter; ppIter=&((*ppIter)->pNext)){
1.1026 + if( (*ppIter)==&pData->lock ){
1.1027 + *ppIter = pData->lock.pNext;
1.1028 + break;
1.1029 + }
1.1030 + }
1.1031 + if( !pLock->pList ){
1.1032 + AsyncLock **pp;
1.1033 + if( pLock->pFile ){
1.1034 + pLock->pFile->pMethods->xClose(pLock->pFile);
1.1035 + }
1.1036 + for(pp=&async.pLock; *pp!=pLock; pp=&((*pp)->pNext));
1.1037 + *pp = pLock->pNext;
1.1038 + sqlite3_free(pLock);
1.1039 + }else{
1.1040 + rc = getFileLock(pLock);
1.1041 + }
1.1042 + }
1.1043 +
1.1044 + return rc;
1.1045 +}
1.1046 +
1.1047 +/*
1.1048 +** Open a file.
1.1049 +*/
1.1050 +static int asyncOpen(
1.1051 + sqlite3_vfs *pAsyncVfs,
1.1052 + const char *zName,
1.1053 + sqlite3_file *pFile,
1.1054 + int flags,
1.1055 + int *pOutFlags
1.1056 +){
1.1057 + static sqlite3_io_methods async_methods = {
1.1058 + 1, /* iVersion */
1.1059 + asyncClose, /* xClose */
1.1060 + asyncRead, /* xRead */
1.1061 + asyncWrite, /* xWrite */
1.1062 + asyncTruncate, /* xTruncate */
1.1063 + asyncSync, /* xSync */
1.1064 + asyncFileSize, /* xFileSize */
1.1065 + asyncLock, /* xLock */
1.1066 + asyncUnlock, /* xUnlock */
1.1067 + asyncCheckReservedLock, /* xCheckReservedLock */
1.1068 + asyncFileControl, /* xFileControl */
1.1069 + asyncSectorSize, /* xSectorSize */
1.1070 + asyncDeviceCharacteristics /* xDeviceCharacteristics */
1.1071 + };
1.1072 +
1.1073 + sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
1.1074 + AsyncFile *p = (AsyncFile *)pFile;
1.1075 + int nName = 0;
1.1076 + int rc = SQLITE_OK;
1.1077 + int nByte;
1.1078 + AsyncFileData *pData;
1.1079 + AsyncLock *pLock = 0;
1.1080 + char *z;
1.1081 + int isExclusive = (flags&SQLITE_OPEN_EXCLUSIVE);
1.1082 +
1.1083 + /* If zName is NULL, then the upper layer is requesting an anonymous file */
1.1084 + if( zName ){
1.1085 + nName = strlen(zName)+1;
1.1086 + }
1.1087 +
1.1088 + nByte = (
1.1089 + sizeof(AsyncFileData) + /* AsyncFileData structure */
1.1090 + 2 * pVfs->szOsFile + /* AsyncFileData.pBaseRead and pBaseWrite */
1.1091 + nName /* AsyncFileData.zName */
1.1092 + );
1.1093 + z = sqlite3_malloc(nByte);
1.1094 + if( !z ){
1.1095 + return SQLITE_NOMEM;
1.1096 + }
1.1097 + memset(z, 0, nByte);
1.1098 + pData = (AsyncFileData*)z;
1.1099 + z += sizeof(pData[0]);
1.1100 + pData->pBaseRead = (sqlite3_file*)z;
1.1101 + z += pVfs->szOsFile;
1.1102 + pData->pBaseWrite = (sqlite3_file*)z;
1.1103 + pData->close.pFileData = pData;
1.1104 + pData->close.op = ASYNC_CLOSE;
1.1105 +
1.1106 + if( zName ){
1.1107 + z += pVfs->szOsFile;
1.1108 + pData->zName = z;
1.1109 + pData->nName = nName;
1.1110 + memcpy(pData->zName, zName, nName);
1.1111 + }
1.1112 +
1.1113 + if( !isExclusive ){
1.1114 + rc = pVfs->xOpen(pVfs, zName, pData->pBaseRead, flags, pOutFlags);
1.1115 + if( rc==SQLITE_OK && ((*pOutFlags)&SQLITE_OPEN_READWRITE) ){
1.1116 + rc = pVfs->xOpen(pVfs, zName, pData->pBaseWrite, flags, 0);
1.1117 + }
1.1118 + }
1.1119 +
1.1120 + pthread_mutex_lock(&async.lockMutex);
1.1121 +
1.1122 + if( zName && rc==SQLITE_OK ){
1.1123 + pLock = findLock(pData->zName, pData->nName);
1.1124 + if( !pLock ){
1.1125 + int nByte = pVfs->szOsFile + sizeof(AsyncLock) + pData->nName + 1;
1.1126 + pLock = (AsyncLock *)sqlite3_malloc(nByte);
1.1127 + if( pLock ){
1.1128 + memset(pLock, 0, nByte);
1.1129 +#ifdef ENABLE_FILE_LOCKING
1.1130 + if( flags&SQLITE_OPEN_MAIN_DB ){
1.1131 + pLock->pFile = (sqlite3_file *)&pLock[1];
1.1132 + rc = pVfs->xOpen(pVfs, zName, pLock->pFile, flags, 0);
1.1133 + if( rc!=SQLITE_OK ){
1.1134 + sqlite3_free(pLock);
1.1135 + pLock = 0;
1.1136 + }
1.1137 + }
1.1138 +#endif
1.1139 + if( pLock ){
1.1140 + pLock->nFile = pData->nName;
1.1141 + pLock->zFile = &((char *)(&pLock[1]))[pVfs->szOsFile];
1.1142 + memcpy(pLock->zFile, pData->zName, pLock->nFile);
1.1143 + pLock->pNext = async.pLock;
1.1144 + async.pLock = pLock;
1.1145 + }
1.1146 + }else{
1.1147 + rc = SQLITE_NOMEM;
1.1148 + }
1.1149 + }
1.1150 + }
1.1151 +
1.1152 + if( rc==SQLITE_OK ){
1.1153 + p->pMethod = &async_methods;
1.1154 + p->pData = pData;
1.1155 +
1.1156 + /* Link AsyncFileData.lock into the linked list of
1.1157 + ** AsyncFileLock structures for this file.
1.1158 + */
1.1159 + if( zName ){
1.1160 + pData->lock.pNext = pLock->pList;
1.1161 + pLock->pList = &pData->lock;
1.1162 + pData->zName = pLock->zFile;
1.1163 + }
1.1164 + }else{
1.1165 + if( pData->pBaseRead->pMethods ){
1.1166 + pData->pBaseRead->pMethods->xClose(pData->pBaseRead);
1.1167 + }
1.1168 + if( pData->pBaseWrite->pMethods ){
1.1169 + pData->pBaseWrite->pMethods->xClose(pData->pBaseWrite);
1.1170 + }
1.1171 + sqlite3_free(pData);
1.1172 + }
1.1173 +
1.1174 + pthread_mutex_unlock(&async.lockMutex);
1.1175 +
1.1176 + if( rc==SQLITE_OK ){
1.1177 + incrOpenFileCount();
1.1178 + pData->pLock = pLock;
1.1179 + }
1.1180 +
1.1181 + if( rc==SQLITE_OK && isExclusive ){
1.1182 + rc = addNewAsyncWrite(pData, ASYNC_OPENEXCLUSIVE, (sqlite3_int64)flags,0,0);
1.1183 + if( rc==SQLITE_OK ){
1.1184 + if( pOutFlags ) *pOutFlags = flags;
1.1185 + }else{
1.1186 + pthread_mutex_lock(&async.lockMutex);
1.1187 + unlinkAsyncFile(pData);
1.1188 + pthread_mutex_unlock(&async.lockMutex);
1.1189 + sqlite3_free(pData);
1.1190 + }
1.1191 + }
1.1192 + return rc;
1.1193 +}
1.1194 +
1.1195 +/*
1.1196 +** Implementation of sqlite3OsDelete. Add an entry to the end of the
1.1197 +** write-op queue to perform the delete.
1.1198 +*/
1.1199 +static int asyncDelete(sqlite3_vfs *pAsyncVfs, const char *z, int syncDir){
1.1200 + return addNewAsyncWrite(0, ASYNC_DELETE, syncDir, strlen(z)+1, z);
1.1201 +}
1.1202 +
1.1203 +/*
1.1204 +** Implementation of sqlite3OsAccess. This method holds the mutex from
1.1205 +** start to finish.
1.1206 +*/
1.1207 +static int asyncAccess(
1.1208 + sqlite3_vfs *pAsyncVfs,
1.1209 + const char *zName,
1.1210 + int flags,
1.1211 + int *pResOut
1.1212 +){
1.1213 + int rc;
1.1214 + int ret;
1.1215 + AsyncWrite *p;
1.1216 + sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
1.1217 +
1.1218 + assert(flags==SQLITE_ACCESS_READWRITE
1.1219 + || flags==SQLITE_ACCESS_READ
1.1220 + || flags==SQLITE_ACCESS_EXISTS
1.1221 + );
1.1222 +
1.1223 + pthread_mutex_lock(&async.queueMutex);
1.1224 + rc = pVfs->xAccess(pVfs, zName, flags, &ret);
1.1225 + if( rc==SQLITE_OK && flags==SQLITE_ACCESS_EXISTS ){
1.1226 + for(p=async.pQueueFirst; p; p = p->pNext){
1.1227 + if( p->op==ASYNC_DELETE && 0==strcmp(p->zBuf, zName) ){
1.1228 + ret = 0;
1.1229 + }else if( p->op==ASYNC_OPENEXCLUSIVE
1.1230 + && p->pFileData->zName
1.1231 + && 0==strcmp(p->pFileData->zName, zName)
1.1232 + ){
1.1233 + ret = 1;
1.1234 + }
1.1235 + }
1.1236 + }
1.1237 + ASYNC_TRACE(("ACCESS(%s): %s = %d\n",
1.1238 + flags==SQLITE_ACCESS_READWRITE?"read-write":
1.1239 + flags==SQLITE_ACCESS_READ?"read":"exists"
1.1240 + , zName, ret)
1.1241 + );
1.1242 + pthread_mutex_unlock(&async.queueMutex);
1.1243 + *pResOut = ret;
1.1244 + return rc;
1.1245 +}
1.1246 +
1.1247 +/*
1.1248 +** Fill in zPathOut with the full path to the file identified by zPath.
1.1249 +*/
1.1250 +static int asyncFullPathname(
1.1251 + sqlite3_vfs *pAsyncVfs,
1.1252 + const char *zPath,
1.1253 + int nPathOut,
1.1254 + char *zPathOut
1.1255 +){
1.1256 + int rc;
1.1257 + sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
1.1258 + rc = pVfs->xFullPathname(pVfs, zPath, nPathOut, zPathOut);
1.1259 +
1.1260 + /* Because of the way intra-process file locking works, this backend
1.1261 + ** needs to return a canonical path. The following block assumes the
1.1262 + ** file-system uses unix style paths.
1.1263 + */
1.1264 + if( rc==SQLITE_OK ){
1.1265 + int iIn;
1.1266 + int iOut = 0;
1.1267 + int nPathOut = strlen(zPathOut);
1.1268 +
1.1269 + for(iIn=0; iIn<nPathOut; iIn++){
1.1270 +
1.1271 + /* Replace any occurences of "//" with "/" */
1.1272 + if( iIn<=(nPathOut-2) && zPathOut[iIn]=='/' && zPathOut[iIn+1]=='/'
1.1273 + ){
1.1274 + continue;
1.1275 + }
1.1276 +
1.1277 + /* Replace any occurences of "/./" with "/" */
1.1278 + if( iIn<=(nPathOut-3)
1.1279 + && zPathOut[iIn]=='/' && zPathOut[iIn+1]=='.' && zPathOut[iIn+2]=='/'
1.1280 + ){
1.1281 + iIn++;
1.1282 + continue;
1.1283 + }
1.1284 +
1.1285 + /* Replace any occurences of "<path-component>/../" with "" */
1.1286 + if( iOut>0 && iIn<=(nPathOut-4)
1.1287 + && zPathOut[iIn]=='/' && zPathOut[iIn+1]=='.'
1.1288 + && zPathOut[iIn+2]=='.' && zPathOut[iIn+3]=='/'
1.1289 + ){
1.1290 + iIn += 3;
1.1291 + iOut--;
1.1292 + for( ; iOut>0 && zPathOut[iOut-1]!='/'; iOut--);
1.1293 + continue;
1.1294 + }
1.1295 +
1.1296 + zPathOut[iOut++] = zPathOut[iIn];
1.1297 + }
1.1298 + zPathOut[iOut] = '\0';
1.1299 + }
1.1300 +
1.1301 + return rc;
1.1302 +}
1.1303 +static void *asyncDlOpen(sqlite3_vfs *pAsyncVfs, const char *zPath){
1.1304 + sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
1.1305 + return pVfs->xDlOpen(pVfs, zPath);
1.1306 +}
1.1307 +static void asyncDlError(sqlite3_vfs *pAsyncVfs, int nByte, char *zErrMsg){
1.1308 + sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
1.1309 + pVfs->xDlError(pVfs, nByte, zErrMsg);
1.1310 +}
1.1311 +static void *asyncDlSym(
1.1312 + sqlite3_vfs *pAsyncVfs,
1.1313 + void *pHandle,
1.1314 + const char *zSymbol
1.1315 +){
1.1316 + sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
1.1317 + return pVfs->xDlSym(pVfs, pHandle, zSymbol);
1.1318 +}
1.1319 +static void asyncDlClose(sqlite3_vfs *pAsyncVfs, void *pHandle){
1.1320 + sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
1.1321 + pVfs->xDlClose(pVfs, pHandle);
1.1322 +}
1.1323 +static int asyncRandomness(sqlite3_vfs *pAsyncVfs, int nByte, char *zBufOut){
1.1324 + sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
1.1325 + return pVfs->xRandomness(pVfs, nByte, zBufOut);
1.1326 +}
1.1327 +static int asyncSleep(sqlite3_vfs *pAsyncVfs, int nMicro){
1.1328 + sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
1.1329 + return pVfs->xSleep(pVfs, nMicro);
1.1330 +}
1.1331 +static int asyncCurrentTime(sqlite3_vfs *pAsyncVfs, double *pTimeOut){
1.1332 + sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
1.1333 + return pVfs->xCurrentTime(pVfs, pTimeOut);
1.1334 +}
1.1335 +
1.1336 +static sqlite3_vfs async_vfs = {
1.1337 + 1, /* iVersion */
1.1338 + sizeof(AsyncFile), /* szOsFile */
1.1339 + 0, /* mxPathname */
1.1340 + 0, /* pNext */
1.1341 + "async", /* zName */
1.1342 + 0, /* pAppData */
1.1343 + asyncOpen, /* xOpen */
1.1344 + asyncDelete, /* xDelete */
1.1345 + asyncAccess, /* xAccess */
1.1346 + asyncFullPathname, /* xFullPathname */
1.1347 + asyncDlOpen, /* xDlOpen */
1.1348 + asyncDlError, /* xDlError */
1.1349 + asyncDlSym, /* xDlSym */
1.1350 + asyncDlClose, /* xDlClose */
1.1351 + asyncRandomness, /* xDlError */
1.1352 + asyncSleep, /* xDlSym */
1.1353 + asyncCurrentTime /* xDlClose */
1.1354 +};
1.1355 +
1.1356 +/*
1.1357 +** Call this routine to enable or disable the
1.1358 +** asynchronous IO features implemented in this file.
1.1359 +**
1.1360 +** This routine is not even remotely threadsafe. Do not call
1.1361 +** this routine while any SQLite database connections are open.
1.1362 +*/
1.1363 +static void asyncEnable(int enable){
1.1364 + if( enable ){
1.1365 + if( !async_vfs.pAppData ){
1.1366 + async_vfs.pAppData = (void *)sqlite3_vfs_find(0);
1.1367 + async_vfs.mxPathname = ((sqlite3_vfs *)async_vfs.pAppData)->mxPathname;
1.1368 + sqlite3_vfs_register(&async_vfs, 1);
1.1369 + }
1.1370 + }else{
1.1371 + if( async_vfs.pAppData ){
1.1372 + sqlite3_vfs_unregister(&async_vfs);
1.1373 + async_vfs.pAppData = 0;
1.1374 + }
1.1375 + }
1.1376 +}
1.1377 +
1.1378 +/*
1.1379 +** This procedure runs in a separate thread, reading messages off of the
1.1380 +** write queue and processing them one by one.
1.1381 +**
1.1382 +** If async.writerHaltNow is true, then this procedure exits
1.1383 +** after processing a single message.
1.1384 +**
1.1385 +** If async.writerHaltWhenIdle is true, then this procedure exits when
1.1386 +** the write queue is empty.
1.1387 +**
1.1388 +** If both of the above variables are false, this procedure runs
1.1389 +** indefinately, waiting for operations to be added to the write queue
1.1390 +** and processing them in the order in which they arrive.
1.1391 +**
1.1392 +** An artifical delay of async.ioDelay milliseconds is inserted before
1.1393 +** each write operation in order to simulate the effect of a slow disk.
1.1394 +**
1.1395 +** Only one instance of this procedure may be running at a time.
1.1396 +*/
1.1397 +static void *asyncWriterThread(void *pIsStarted){
1.1398 + sqlite3_vfs *pVfs = (sqlite3_vfs *)(async_vfs.pAppData);
1.1399 + AsyncWrite *p = 0;
1.1400 + int rc = SQLITE_OK;
1.1401 + int holdingMutex = 0;
1.1402 +
1.1403 + if( pthread_mutex_trylock(&async.writerMutex) ){
1.1404 + return 0;
1.1405 + }
1.1406 + (*(int *)pIsStarted) = 1;
1.1407 + while( async.writerHaltNow==0 ){
1.1408 + int doNotFree = 0;
1.1409 + sqlite3_file *pBase = 0;
1.1410 +
1.1411 + if( !holdingMutex ){
1.1412 + pthread_mutex_lock(&async.queueMutex);
1.1413 + }
1.1414 + while( (p = async.pQueueFirst)==0 ){
1.1415 + pthread_cond_broadcast(&async.emptySignal);
1.1416 + if( async.writerHaltWhenIdle ){
1.1417 + pthread_mutex_unlock(&async.queueMutex);
1.1418 + break;
1.1419 + }else{
1.1420 + ASYNC_TRACE(("IDLE\n"));
1.1421 + pthread_cond_wait(&async.queueSignal, &async.queueMutex);
1.1422 + ASYNC_TRACE(("WAKEUP\n"));
1.1423 + }
1.1424 + }
1.1425 + if( p==0 ) break;
1.1426 + holdingMutex = 1;
1.1427 +
1.1428 + /* Right now this thread is holding the mutex on the write-op queue.
1.1429 + ** Variable 'p' points to the first entry in the write-op queue. In
1.1430 + ** the general case, we hold on to the mutex for the entire body of
1.1431 + ** the loop.
1.1432 + **
1.1433 + ** However in the cases enumerated below, we relinquish the mutex,
1.1434 + ** perform the IO, and then re-request the mutex before removing 'p' from
1.1435 + ** the head of the write-op queue. The idea is to increase concurrency with
1.1436 + ** sqlite threads.
1.1437 + **
1.1438 + ** * An ASYNC_CLOSE operation.
1.1439 + ** * An ASYNC_OPENEXCLUSIVE operation. For this one, we relinquish
1.1440 + ** the mutex, call the underlying xOpenExclusive() function, then
1.1441 + ** re-aquire the mutex before seting the AsyncFile.pBaseRead
1.1442 + ** variable.
1.1443 + ** * ASYNC_SYNC and ASYNC_WRITE operations, if
1.1444 + ** SQLITE_ASYNC_TWO_FILEHANDLES was set at compile time and two
1.1445 + ** file-handles are open for the particular file being "synced".
1.1446 + */
1.1447 + if( async.ioError!=SQLITE_OK && p->op!=ASYNC_CLOSE ){
1.1448 + p->op = ASYNC_NOOP;
1.1449 + }
1.1450 + if( p->pFileData ){
1.1451 + pBase = p->pFileData->pBaseWrite;
1.1452 + if(
1.1453 + p->op==ASYNC_CLOSE ||
1.1454 + p->op==ASYNC_OPENEXCLUSIVE ||
1.1455 + (pBase->pMethods && (p->op==ASYNC_SYNC || p->op==ASYNC_WRITE) )
1.1456 + ){
1.1457 + pthread_mutex_unlock(&async.queueMutex);
1.1458 + holdingMutex = 0;
1.1459 + }
1.1460 + if( !pBase->pMethods ){
1.1461 + pBase = p->pFileData->pBaseRead;
1.1462 + }
1.1463 + }
1.1464 +
1.1465 + switch( p->op ){
1.1466 + case ASYNC_NOOP:
1.1467 + break;
1.1468 +
1.1469 + case ASYNC_WRITE:
1.1470 + assert( pBase );
1.1471 + ASYNC_TRACE(("WRITE %s %d bytes at %d\n",
1.1472 + p->pFileData->zName, p->nByte, p->iOffset));
1.1473 + rc = pBase->pMethods->xWrite(pBase, (void *)(p->zBuf), p->nByte, p->iOffset);
1.1474 + break;
1.1475 +
1.1476 + case ASYNC_SYNC:
1.1477 + assert( pBase );
1.1478 + ASYNC_TRACE(("SYNC %s\n", p->pFileData->zName));
1.1479 + rc = pBase->pMethods->xSync(pBase, p->nByte);
1.1480 + break;
1.1481 +
1.1482 + case ASYNC_TRUNCATE:
1.1483 + assert( pBase );
1.1484 + ASYNC_TRACE(("TRUNCATE %s to %d bytes\n",
1.1485 + p->pFileData->zName, p->iOffset));
1.1486 + rc = pBase->pMethods->xTruncate(pBase, p->iOffset);
1.1487 + break;
1.1488 +
1.1489 + case ASYNC_CLOSE: {
1.1490 + AsyncFileData *pData = p->pFileData;
1.1491 + ASYNC_TRACE(("CLOSE %s\n", p->pFileData->zName));
1.1492 + if( pData->pBaseWrite->pMethods ){
1.1493 + pData->pBaseWrite->pMethods->xClose(pData->pBaseWrite);
1.1494 + }
1.1495 + if( pData->pBaseRead->pMethods ){
1.1496 + pData->pBaseRead->pMethods->xClose(pData->pBaseRead);
1.1497 + }
1.1498 +
1.1499 + /* Unlink AsyncFileData.lock from the linked list of AsyncFileLock
1.1500 + ** structures for this file. Obtain the async.lockMutex mutex
1.1501 + ** before doing so.
1.1502 + */
1.1503 + pthread_mutex_lock(&async.lockMutex);
1.1504 + rc = unlinkAsyncFile(pData);
1.1505 + pthread_mutex_unlock(&async.lockMutex);
1.1506 +
1.1507 + if( !holdingMutex ){
1.1508 + pthread_mutex_lock(&async.queueMutex);
1.1509 + holdingMutex = 1;
1.1510 + }
1.1511 + assert_mutex_is_held(&async.queueMutex);
1.1512 + async.pQueueFirst = p->pNext;
1.1513 + sqlite3_free(pData);
1.1514 + doNotFree = 1;
1.1515 + break;
1.1516 + }
1.1517 +
1.1518 + case ASYNC_UNLOCK: {
1.1519 + AsyncFileData *pData = p->pFileData;
1.1520 + int eLock = p->nByte;
1.1521 + pthread_mutex_lock(&async.lockMutex);
1.1522 + pData->lock.eAsyncLock = MIN(
1.1523 + pData->lock.eAsyncLock, MAX(pData->lock.eLock, eLock)
1.1524 + );
1.1525 + assert(pData->lock.eAsyncLock>=pData->lock.eLock);
1.1526 + rc = getFileLock(pData->pLock);
1.1527 + pthread_mutex_unlock(&async.lockMutex);
1.1528 + break;
1.1529 + }
1.1530 +
1.1531 + case ASYNC_DELETE:
1.1532 + ASYNC_TRACE(("DELETE %s\n", p->zBuf));
1.1533 + rc = pVfs->xDelete(pVfs, p->zBuf, (int)p->iOffset);
1.1534 + break;
1.1535 +
1.1536 + case ASYNC_OPENEXCLUSIVE: {
1.1537 + int flags = (int)p->iOffset;
1.1538 + AsyncFileData *pData = p->pFileData;
1.1539 + ASYNC_TRACE(("OPEN %s flags=%d\n", p->zBuf, (int)p->iOffset));
1.1540 + assert(pData->pBaseRead->pMethods==0 && pData->pBaseWrite->pMethods==0);
1.1541 + rc = pVfs->xOpen(pVfs, pData->zName, pData->pBaseRead, flags, 0);
1.1542 + assert( holdingMutex==0 );
1.1543 + pthread_mutex_lock(&async.queueMutex);
1.1544 + holdingMutex = 1;
1.1545 + break;
1.1546 + }
1.1547 +
1.1548 + default: assert(!"Illegal value for AsyncWrite.op");
1.1549 + }
1.1550 +
1.1551 + /* If we didn't hang on to the mutex during the IO op, obtain it now
1.1552 + ** so that the AsyncWrite structure can be safely removed from the
1.1553 + ** global write-op queue.
1.1554 + */
1.1555 + if( !holdingMutex ){
1.1556 + pthread_mutex_lock(&async.queueMutex);
1.1557 + holdingMutex = 1;
1.1558 + }
1.1559 + /* ASYNC_TRACE(("UNLINK %p\n", p)); */
1.1560 + if( p==async.pQueueLast ){
1.1561 + async.pQueueLast = 0;
1.1562 + }
1.1563 + if( !doNotFree ){
1.1564 + assert_mutex_is_held(&async.queueMutex);
1.1565 + async.pQueueFirst = p->pNext;
1.1566 + sqlite3_free(p);
1.1567 + }
1.1568 + assert( holdingMutex );
1.1569 +
1.1570 + /* An IO error has occured. We cannot report the error back to the
1.1571 + ** connection that requested the I/O since the error happened
1.1572 + ** asynchronously. The connection has already moved on. There
1.1573 + ** really is nobody to report the error to.
1.1574 + **
1.1575 + ** The file for which the error occured may have been a database or
1.1576 + ** journal file. Regardless, none of the currently queued operations
1.1577 + ** associated with the same database should now be performed. Nor should
1.1578 + ** any subsequently requested IO on either a database or journal file
1.1579 + ** handle for the same database be accepted until the main database
1.1580 + ** file handle has been closed and reopened.
1.1581 + **
1.1582 + ** Furthermore, no further IO should be queued or performed on any file
1.1583 + ** handle associated with a database that may have been part of a
1.1584 + ** multi-file transaction that included the database associated with
1.1585 + ** the IO error (i.e. a database ATTACHed to the same handle at some
1.1586 + ** point in time).
1.1587 + */
1.1588 + if( rc!=SQLITE_OK ){
1.1589 + async.ioError = rc;
1.1590 + }
1.1591 +
1.1592 + if( async.ioError && !async.pQueueFirst ){
1.1593 + pthread_mutex_lock(&async.lockMutex);
1.1594 + if( 0==async.pLock ){
1.1595 + async.ioError = SQLITE_OK;
1.1596 + }
1.1597 + pthread_mutex_unlock(&async.lockMutex);
1.1598 + }
1.1599 +
1.1600 + /* Drop the queue mutex before continuing to the next write operation
1.1601 + ** in order to give other threads a chance to work with the write queue.
1.1602 + */
1.1603 + if( !async.pQueueFirst || !async.ioError ){
1.1604 + pthread_mutex_unlock(&async.queueMutex);
1.1605 + holdingMutex = 0;
1.1606 + if( async.ioDelay>0 ){
1.1607 + pVfs->xSleep(pVfs, async.ioDelay);
1.1608 + }else{
1.1609 + sched_yield();
1.1610 + }
1.1611 + }
1.1612 + }
1.1613 +
1.1614 + pthread_mutex_unlock(&async.writerMutex);
1.1615 + return 0;
1.1616 +}
1.1617 +
1.1618 +/**************************************************************************
1.1619 +** The remaining code defines a Tcl interface for testing the asynchronous
1.1620 +** IO implementation in this file.
1.1621 +**
1.1622 +** To adapt the code to a non-TCL environment, delete or comment out
1.1623 +** the code that follows.
1.1624 +*/
1.1625 +
1.1626 +/*
1.1627 +** sqlite3async_enable ?YES/NO?
1.1628 +**
1.1629 +** Enable or disable the asynchronous I/O backend. This command is
1.1630 +** not thread-safe. Do not call it while any database connections
1.1631 +** are open.
1.1632 +*/
1.1633 +static int testAsyncEnable(
1.1634 + void * clientData,
1.1635 + Tcl_Interp *interp,
1.1636 + int objc,
1.1637 + Tcl_Obj *CONST objv[]
1.1638 +){
1.1639 + if( objc!=1 && objc!=2 ){
1.1640 + Tcl_WrongNumArgs(interp, 1, objv, "?YES/NO?");
1.1641 + return TCL_ERROR;
1.1642 + }
1.1643 + if( objc==1 ){
1.1644 + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(async_vfs.pAppData!=0));
1.1645 + }else{
1.1646 + int en;
1.1647 + if( Tcl_GetBooleanFromObj(interp, objv[1], &en) ) return TCL_ERROR;
1.1648 + asyncEnable(en);
1.1649 + }
1.1650 + return TCL_OK;
1.1651 +}
1.1652 +
1.1653 +/*
1.1654 +** sqlite3async_halt "now"|"idle"|"never"
1.1655 +**
1.1656 +** Set the conditions at which the writer thread will halt.
1.1657 +*/
1.1658 +static int testAsyncHalt(
1.1659 + void * clientData,
1.1660 + Tcl_Interp *interp,
1.1661 + int objc,
1.1662 + Tcl_Obj *CONST objv[]
1.1663 +){
1.1664 + const char *zCond;
1.1665 + if( objc!=2 ){
1.1666 + Tcl_WrongNumArgs(interp, 1, objv, "\"now\"|\"idle\"|\"never\"");
1.1667 + return TCL_ERROR;
1.1668 + }
1.1669 + zCond = Tcl_GetString(objv[1]);
1.1670 + if( strcmp(zCond, "now")==0 ){
1.1671 + async.writerHaltNow = 1;
1.1672 + pthread_cond_broadcast(&async.queueSignal);
1.1673 + }else if( strcmp(zCond, "idle")==0 ){
1.1674 + async.writerHaltWhenIdle = 1;
1.1675 + async.writerHaltNow = 0;
1.1676 + pthread_cond_broadcast(&async.queueSignal);
1.1677 + }else if( strcmp(zCond, "never")==0 ){
1.1678 + async.writerHaltWhenIdle = 0;
1.1679 + async.writerHaltNow = 0;
1.1680 + }else{
1.1681 + Tcl_AppendResult(interp,
1.1682 + "should be one of: \"now\", \"idle\", or \"never\"", (char*)0);
1.1683 + return TCL_ERROR;
1.1684 + }
1.1685 + return TCL_OK;
1.1686 +}
1.1687 +
1.1688 +/*
1.1689 +** sqlite3async_delay ?MS?
1.1690 +**
1.1691 +** Query or set the number of milliseconds of delay in the writer
1.1692 +** thread after each write operation. The default is 0. By increasing
1.1693 +** the memory delay we can simulate the effect of slow disk I/O.
1.1694 +*/
1.1695 +static int testAsyncDelay(
1.1696 + void * clientData,
1.1697 + Tcl_Interp *interp,
1.1698 + int objc,
1.1699 + Tcl_Obj *CONST objv[]
1.1700 +){
1.1701 + if( objc!=1 && objc!=2 ){
1.1702 + Tcl_WrongNumArgs(interp, 1, objv, "?MS?");
1.1703 + return TCL_ERROR;
1.1704 + }
1.1705 + if( objc==1 ){
1.1706 + Tcl_SetObjResult(interp, Tcl_NewIntObj(async.ioDelay));
1.1707 + }else{
1.1708 + int ioDelay;
1.1709 + if( Tcl_GetIntFromObj(interp, objv[1], &ioDelay) ) return TCL_ERROR;
1.1710 + async.ioDelay = ioDelay;
1.1711 + }
1.1712 + return TCL_OK;
1.1713 +}
1.1714 +
1.1715 +/*
1.1716 +** sqlite3async_start
1.1717 +**
1.1718 +** Start a new writer thread.
1.1719 +*/
1.1720 +static int testAsyncStart(
1.1721 + void * clientData,
1.1722 + Tcl_Interp *interp,
1.1723 + int objc,
1.1724 + Tcl_Obj *CONST objv[]
1.1725 +){
1.1726 + pthread_t x;
1.1727 + int rc;
1.1728 + volatile int isStarted = 0;
1.1729 + rc = pthread_create(&x, 0, asyncWriterThread, (void *)&isStarted);
1.1730 + if( rc ){
1.1731 + Tcl_AppendResult(interp, "failed to create the thread", 0);
1.1732 + return TCL_ERROR;
1.1733 + }
1.1734 + pthread_detach(x);
1.1735 + while( isStarted==0 ){
1.1736 + sched_yield();
1.1737 + }
1.1738 + return TCL_OK;
1.1739 +}
1.1740 +
1.1741 +/*
1.1742 +** sqlite3async_wait
1.1743 +**
1.1744 +** Wait for the current writer thread to terminate.
1.1745 +**
1.1746 +** If the current writer thread is set to run forever then this
1.1747 +** command would block forever. To prevent that, an error is returned.
1.1748 +*/
1.1749 +static int testAsyncWait(
1.1750 + void * clientData,
1.1751 + Tcl_Interp *interp,
1.1752 + int objc,
1.1753 + Tcl_Obj *CONST objv[]
1.1754 +){
1.1755 + int cnt = 10;
1.1756 + if( async.writerHaltNow==0 && async.writerHaltWhenIdle==0 ){
1.1757 + Tcl_AppendResult(interp, "would block forever", (char*)0);
1.1758 + return TCL_ERROR;
1.1759 + }
1.1760 +
1.1761 + while( cnt-- && !pthread_mutex_trylock(&async.writerMutex) ){
1.1762 + pthread_mutex_unlock(&async.writerMutex);
1.1763 + sched_yield();
1.1764 + }
1.1765 + if( cnt>=0 ){
1.1766 + ASYNC_TRACE(("WAIT\n"));
1.1767 + pthread_mutex_lock(&async.queueMutex);
1.1768 + pthread_cond_broadcast(&async.queueSignal);
1.1769 + pthread_mutex_unlock(&async.queueMutex);
1.1770 + pthread_mutex_lock(&async.writerMutex);
1.1771 + pthread_mutex_unlock(&async.writerMutex);
1.1772 + }else{
1.1773 + ASYNC_TRACE(("NO-WAIT\n"));
1.1774 + }
1.1775 + return TCL_OK;
1.1776 +}
1.1777 +
1.1778 +
1.1779 +#endif /* SQLITE_OS_UNIX and SQLITE_THREADSAFE */
1.1780 +
1.1781 +/*
1.1782 +** This routine registers the custom TCL commands defined in this
1.1783 +** module. This should be the only procedure visible from outside
1.1784 +** of this module.
1.1785 +*/
1.1786 +int Sqlitetestasync_Init(Tcl_Interp *interp){
1.1787 +#if SQLITE_OS_UNIX && SQLITE_THREADSAFE
1.1788 + Tcl_CreateObjCommand(interp,"sqlite3async_enable",testAsyncEnable,0,0);
1.1789 + Tcl_CreateObjCommand(interp,"sqlite3async_halt",testAsyncHalt,0,0);
1.1790 + Tcl_CreateObjCommand(interp,"sqlite3async_delay",testAsyncDelay,0,0);
1.1791 + Tcl_CreateObjCommand(interp,"sqlite3async_start",testAsyncStart,0,0);
1.1792 + Tcl_CreateObjCommand(interp,"sqlite3async_wait",testAsyncWait,0,0);
1.1793 + Tcl_LinkVar(interp, "sqlite3async_trace",
1.1794 + (char*)&sqlite3async_trace, TCL_LINK_INT);
1.1795 +#endif /* SQLITE_OS_UNIX and SQLITE_THREADSAFE */
1.1796 + return TCL_OK;
1.1797 +}