Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Improved comments on the server and asynchronous I/O demo programs. (CVS 2909) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
c0f47ccbc915f20d56f393383c21b402 |
User & Date: | drh 2006-01-10 20:01:19.000 |
Context
2006-01-10
| ||
20:32 | Combine multiple small calls to sqlite3OsWrite into one larger call. (CVS 2910) (check-in: e6e6750c24 user: drh tags: trunk) | |
20:01 | Improved comments on the server and asynchronous I/O demo programs. (CVS 2909) (check-in: c0f47ccbc9 user: drh tags: trunk) | |
19:45 | More pedantic changes to comments in VDBE. No changes to code. Ticket #1596. (CVS 2908) (check-in: 1cf6855430 user: drh tags: trunk) | |
Changes
Changes to src/server.c.
︙ | ︙ | |||
58 59 60 61 62 63 64 | ** to SQLite version 3.3.0 it probably was not worth the trouble. But ** with SQLite version 3.3.0 and beyond you can get significant performance ** and concurrency improvements and memory usage reductions by going ** client/server. ** ** Note: The extra features of version 3.3.0 described by points (2) ** through (4) above are only available if you compile without the | | < | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | ** to SQLite version 3.3.0 it probably was not worth the trouble. But ** with SQLite version 3.3.0 and beyond you can get significant performance ** and concurrency improvements and memory usage reductions by going ** client/server. ** ** Note: The extra features of version 3.3.0 described by points (2) ** through (4) above are only available if you compile without the ** option -DSQLITE_OMIT_SHARED_CACHE. ** ** Here is how the client/server approach works: The database server ** thread is started on this procedure: ** ** void *sqlite3_server(void *NotUsed); ** ** The sqlite_server procedure runs as long as the g.serverHalt variable |
︙ | ︙ | |||
252 253 254 255 256 257 258 | ** sqlite3_prepare ** sqlite3_step ** sqlite3_reset ** sqlite3_finalize ** sqlite3_close ** ** Clients should use the following client-side routines instead of | | | 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 | ** sqlite3_prepare ** sqlite3_step ** sqlite3_reset ** sqlite3_finalize ** sqlite3_close ** ** Clients should use the following client-side routines instead of ** the core routines above. ** ** sqlite3_client_open ** sqlite3_client_prepare ** sqlite3_client_step ** sqlite3_client_reset ** sqlite3_client_finalize ** sqlite3_client_close |
︙ | ︙ |
Changes to src/test_async.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2005 December 14 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains an example implementation of an asynchronous IO | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > < < < < < | < < < < > > > > > > > > > | > | > | > | | | > | | > | < < | | 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 | /* ** 2005 December 14 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** 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 no the case. If ** your program crashes or if you take a power lose 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 overloading the OS-layer disk I/O routines ** with modified versions that store the data to be written in queue of ** pending write operations. Look at the asyncEnable() subroutine to see ** how overloading works. Six os-layer routines are overloaded: ** ** sqlite3OsOpenReadWrite; ** sqlite3OsOpenReadOnly; ** sqlite3OsOpenExclusive; ** sqlite3OsDelete; ** sqlite3OsFileExists; ** sqlite3OsSyncDirectory; ** ** The original implementations of these routines are saved and are ** used by the writer thread to do the real I/O. The substitute ** implementations typically put the I/O operation on a queue ** to be handled later by the writer thread, though read operations ** must be handled right away, obviously. ** ** Asynchronous I/O is disabled by setting the os-layer interface routines ** back to their original values. ** ** 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. */ #include "sqliteInt.h" #include "os.h" #include <tcl.h> /* If the THREADSAFE macro is not set, assume that it is turned off. */ #ifndef THREADSAFE # define THREADSAFE 0 #endif /* ** This test uses pthreads and hence only works on unix and with ** a threadsafe build of SQLite. It also requires that the redefinable ** I/O feature of SQLite be turned on. This feature is turned off by ** default. If a required element is missing, almost all of the code ** in this file is commented out. */ #if OS_UNIX && THREADSAFE && defined(SQLITE_ENABLE_REDEF_IO) /* ** This demo uses pthreads. If you do not have a pthreads implementation ** for your operating system, you will need to recode the threading ** logic. */ #include <pthread.h> #include <sched.h> /* Useful macros used in several places */ #define MIN(x,y) ((x)<(y)?(x):(y)) #define MAX(x,y) ((x)>(y)?(x):(y)) /* Forward references */ typedef struct AsyncWrite AsyncWrite; typedef struct AsyncFile AsyncFile; /* Enable for debugging */ #if 0 # define TRACE(X,Y) \ fprintf(stderr,"THRD=%d: ", (int)pthread_self()); \ fprintf(stderr,X,Y); #else # define TRACE(X,Y) /* noop */ #endif /* ** THREAD SAFETY NOTES ** ** Basic rules: ** ** * Both read and write access to the global write-op queue must be ** protected by the async.queueMutex. ** ** * The file handles from the underlying system are assumed not to ** be thread safe. ** ** * See the last two paragraphs under "The Writer Thread" for ** an assumption to do with file-handle synchronization by the Os. ** ** File system operations (invoked by SQLite thread): ** ** xOpenXXX (three versions) ** xDelete ** xFileExists ** xSyncDirectory ** ** File handle operations (invoked by SQLite thread): ** ** asyncWrite, asyncClose, asyncTruncate, asyncSync, ** asyncSetFullSync, asyncOpenDirectory. ** ** The operations above add an entry to the global write-op list. They ** prepare the entry, acquire the async.queueMutex momentarily while ** list pointers are manipulated to insert the new entry, then release ** the mutex and signal the writer thread to wake up in case it happens ** to be asleep. ** ** ** asyncRead, asyncFileSize. ** ** Read operations. Both of these read from both the underlying file ** first then adjust their result based on pending writes in the ** write-op queue. So async.queueMutex is held for the duration ** of these operations to prevent other threads from changing the ** queue in mid operation. ** ** ** asyncLock, asyncUnlock, asyncLockState, asyncCheckReservedLock ** ** These locking primitives become no-ops. Files are always opened for ** exclusive access when using this IO backend. ** ** ** asyncFileHandle. ** ** The sqlite3OsFileHandle() function is currently only used when ** debugging the pager module. Unless sqlite3OsClose() is called on the ** file (shouldn't be possible for other reasons), the underlying ** implementations are safe to call without grabbing any mutex. So we just ** go ahead and call it no matter what any other threads are doing. ** ** ** asyncSeek. ** ** Calling this method just manipulates the AsyncFile.iOffset variable. ** Since this variable is never accessed by writer thread, this ** function does not require the mutex. Actual calls to OsSeek() take ** place just before OsWrite() or OsRead(), which are always protected by ** the mutex. ** ** The writer thread: ** ** The async.writerMutex is used to make sure only there is only ** a single writer thread running at a time. ** ** Inside the writer thread is a loop that works like this: ** ** WHILE (write-op list is not empty) ** Do IO operation at head of write-op list ** Remove entry from head of write-op list ** END WHILE ** ** The async.queueMutex is always held during the <write-op list is ** not empty> test, and when the entry is removed from the head ** of the write-op list. Sometimes it is held for the interim ** period (while the IO is performed), and sometimes it is ** relinquished. It is relinquished if (a) the IO op is an ** ASYNC_CLOSE or (b) when the file handle was opened, two of ** the underlying systems handles were opened on the same ** file-system entry. ** ** If condition (b) above is true, then one file-handle ** (AsyncFile.pBaseRead) is used exclusively by sqlite threads to read the |
︙ | ︙ | |||
182 183 184 185 186 187 188 189 190 191 192 193 194 195 | #define ASYNC_SETFULLSYNC 6 #define ASYNC_DELETE 7 #define ASYNC_OPENEXCLUSIVE 8 #define ASYNC_SYNCDIRECTORY 9 /* ** The interpretation of the iOffset and nByte variables varies depending ** on the value of AsyncWrite.op: ** ** ASYNC_WRITE: ** iOffset -> Offset in file to write to. ** nByte -> Number of bytes of data to write (pointed to by zBuf). ** | > > > | 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 | #define ASYNC_SETFULLSYNC 6 #define ASYNC_DELETE 7 #define ASYNC_OPENEXCLUSIVE 8 #define ASYNC_SYNCDIRECTORY 9 /* ** Entries on the write-op queue are instances of the AsyncWrite ** structure, defined here. ** ** The interpretation of the iOffset and nByte variables varies depending ** on the value of AsyncWrite.op: ** ** ASYNC_WRITE: ** iOffset -> Offset in file to write to. ** nByte -> Number of bytes of data to write (pointed to by zBuf). ** |
︙ | ︙ | |||
244 245 246 247 248 249 250 | i64 iOffset; /* Current seek() offset in file */ OsFile *pBaseRead; /* Read handle to the underlying Os file */ OsFile *pBaseWrite; /* Write handle to the underlying Os file */ }; /* ** Add an entry to the end of the global write-op list. pWrite should point | | | > | > | < > > > > > > > > | 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 | i64 iOffset; /* Current seek() offset in file */ OsFile *pBaseRead; /* Read handle to the underlying Os file */ OsFile *pBaseWrite; /* Write handle to the underlying Os file */ }; /* ** Add an entry to the end of the global write-op list. pWrite should point ** to an AsyncWrite structure allocated using sqlite3OsMalloc(). The writer ** thread will call sqlite3OsFree() to free the structure after the specified ** operation has been completed. ** ** Once an AsyncWrite structure has been added to the list, it becomes the ** property of the writer thread and must not be read or modified by the ** caller. */ static void addAsyncWrite(AsyncWrite *pWrite){ /* We must hold the queue mutex in order to modify the queue pointers */ pthread_mutex_lock(&async.queueMutex); /* Add the record to the end of the write-op queue */ assert( !pWrite->pNext ); if( async.pQueueLast ){ assert( async.pQueueFirst ); async.pQueueLast->pNext = pWrite; }else{ async.pQueueFirst = pWrite; } async.pQueueLast = pWrite; TRACE("PUSH %p\n", pWrite); /* Drop the queue mutex */ pthread_mutex_unlock(&async.queueMutex); /* The writer thread might have been idle because there was nothing ** on the write-op queue for it to do. So wake it up. */ pthread_cond_signal(&async.queueSignal); } /* ** This is a utility function to allocate and populate a new AsyncWrite ** structure and insert it (via addAsyncWrite() ) into the global list. */ |
︙ | ︙ | |||
354 355 356 357 358 359 360 | static void asyncSetFullSync(OsFile *id, int value){ addNewAsyncWrite((AsyncFile *)id, ASYNC_SETFULLSYNC, 0, value, 0); } /* ** Read data from the file. First we read from the filesystem, then adjust ** the contents of the buffer based on ASYNC_WRITE operations in the | | < | 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 | static void asyncSetFullSync(OsFile *id, int value){ addNewAsyncWrite((AsyncFile *)id, ASYNC_SETFULLSYNC, 0, value, 0); } /* ** Read data from the file. First we read from the filesystem, then adjust ** the contents of the buffer based on ASYNC_WRITE operations in the ** write-op queue. ** ** This method holds the mutex from start to finish. */ static int asyncRead(OsFile *id, void *obuf, int amt){ int rc = SQLITE_OK; i64 filesize; int nRead; |
︙ | ︙ | |||
474 475 476 477 478 479 480 481 482 483 484 485 486 487 | ** Return the operating system file handle. This is only used for debugging ** at the moment anyway. */ static int asyncFileHandle(OsFile *id){ return sqlite3OsFileHandle(((AsyncFile *)id)->pBaseRead); } static int asyncLock(OsFile *id, int lockType){ return SQLITE_OK; } static int asyncUnlock(OsFile *id, int lockType){ return SQLITE_OK; } | > > > > | 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 | ** Return the operating system file handle. This is only used for debugging ** at the moment anyway. */ static int asyncFileHandle(OsFile *id){ return sqlite3OsFileHandle(((AsyncFile *)id)->pBaseRead); } /* ** No file locking occurs with this version of the asynchronous backend. ** So the locking routines are no-ops. */ static int asyncLock(OsFile *id, int lockType){ return SQLITE_OK; } static int asyncUnlock(OsFile *id, int lockType){ return SQLITE_OK; } |
︙ | ︙ | |||
498 499 500 501 502 503 504 | */ static int asyncLockState(OsFile *id){ return SQLITE_OK; } /* ** The following variables hold pointers to the original versions of | | | | > > > | | | | | 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 | */ static int asyncLockState(OsFile *id){ return SQLITE_OK; } /* ** The following variables hold pointers to the original versions of ** OS-layer interface routines that are overloaded in order to create ** the asynchronous I/O backend. */ static int (*xOrigOpenReadWrite)(const char*, OsFile**, int*) = 0; static int (*xOrigOpenExclusive)(const char*, OsFile**, int) = 0; static int (*xOrigOpenReadOnly)(const char*, OsFile**) = 0; static int (*xOrigDelete)(const char*) = 0; static int (*xOrigFileExists)(const char*) = 0; static int (*xOrigSyncDirectory)(const char*) = 0; /* ** This routine does most of the work of opening a file and building ** the OsFile structure. */ static int asyncOpenFile( const char *zName, /* The name of the file to be opened */ OsFile **pFile, /* Put the OsFile structure here */ OsFile *pBaseRead, /* The real OsFile from the real I/O routine */ int openForWriting /* Open a second file handle for writing if true */ ){ int rc; AsyncFile *p; OsFile *pBaseWrite = 0; static IoMethod iomethod = { asyncClose, |
︙ | ︙ | |||
536 537 538 539 540 541 542 | asyncFileSize, asyncLock, asyncUnlock, asyncLockState, asyncCheckReservedLock }; | | | 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 | asyncFileSize, asyncLock, asyncUnlock, asyncLockState, asyncCheckReservedLock }; if( openForWriting && SQLITE_ASYNC_TWO_FILEHANDLES ){ int dummy; rc = xOrigOpenReadWrite(zName, &pBaseWrite, &dummy); if( rc!=SQLITE_OK ){ goto error_out; } } |
︙ | ︙ |