memjournal.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. /*
  2. ** 2008 October 7
  3. **
  4. ** The author disclaims copyright to this source code. In place of
  5. ** a legal notice, here is a blessing:
  6. **
  7. ** May you do good and not evil.
  8. ** May you find forgiveness for yourself and forgive others.
  9. ** May you share freely, never taking more than you give.
  10. **
  11. *************************************************************************
  12. **
  13. ** This file contains code use to implement an in-memory rollback journal.
  14. ** The in-memory rollback journal is used to journal transactions for
  15. ** ":memory:" databases and when the journal_mode=MEMORY pragma is used.
  16. */
  17. #include "sqliteInt.h"
  18. /* Forward references to internal structures */
  19. typedef struct MemJournal MemJournal;
  20. typedef struct FilePoint FilePoint;
  21. typedef struct FileChunk FileChunk;
  22. /* Space to hold the rollback journal is allocated in increments of
  23. ** this many bytes.
  24. **
  25. ** The size chosen is a little less than a power of two. That way,
  26. ** the FileChunk object will have a size that almost exactly fills
  27. ** a power-of-two allocation. This mimimizes wasted space in power-of-two
  28. ** memory allocators.
  29. */
  30. #define JOURNAL_CHUNKSIZE ((int)(1024-sizeof(FileChunk*)))
  31. /*
  32. ** The rollback journal is composed of a linked list of these structures.
  33. */
  34. struct FileChunk {
  35. FileChunk *pNext; /* Next chunk in the journal */
  36. u8 zChunk[JOURNAL_CHUNKSIZE]; /* Content of this chunk */
  37. };
  38. /*
  39. ** An instance of this object serves as a cursor into the rollback journal.
  40. ** The cursor can be either for reading or writing.
  41. */
  42. struct FilePoint {
  43. sqlite3_int64 iOffset; /* Offset from the beginning of the file */
  44. FileChunk *pChunk; /* Specific chunk into which cursor points */
  45. };
  46. /*
  47. ** This subclass is a subclass of sqlite3_file. Each open memory-journal
  48. ** is an instance of this class.
  49. */
  50. struct MemJournal {
  51. sqlite3_io_methods *pMethod; /* Parent class. MUST BE FIRST */
  52. FileChunk *pFirst; /* Head of in-memory chunk-list */
  53. FilePoint endpoint; /* Pointer to the end of the file */
  54. FilePoint readpoint; /* Pointer to the end of the last xRead() */
  55. };
  56. /*
  57. ** Read data from the in-memory journal file. This is the implementation
  58. ** of the sqlite3_vfs.xRead method.
  59. */
  60. static int memjrnlRead(
  61. sqlite3_file *pJfd, /* The journal file from which to read */
  62. void *zBuf, /* Put the results here */
  63. int iAmt, /* Number of bytes to read */
  64. sqlite_int64 iOfst /* Begin reading at this offset */
  65. ){
  66. MemJournal *p = (MemJournal *)pJfd;
  67. u8 *zOut = zBuf;
  68. int nRead = iAmt;
  69. int iChunkOffset;
  70. FileChunk *pChunk;
  71. /* SQLite never tries to read past the end of a rollback journal file */
  72. assert( iOfst+iAmt<=p->endpoint.iOffset );
  73. if( p->readpoint.iOffset!=iOfst || iOfst==0 ){
  74. sqlite3_int64 iOff = 0;
  75. for(pChunk=p->pFirst;
  76. ALWAYS(pChunk) && (iOff+JOURNAL_CHUNKSIZE)<=iOfst;
  77. pChunk=pChunk->pNext
  78. ){
  79. iOff += JOURNAL_CHUNKSIZE;
  80. }
  81. }else{
  82. pChunk = p->readpoint.pChunk;
  83. }
  84. iChunkOffset = (int)(iOfst%JOURNAL_CHUNKSIZE);
  85. do {
  86. int iSpace = JOURNAL_CHUNKSIZE - iChunkOffset;
  87. int nCopy = MIN(nRead, (JOURNAL_CHUNKSIZE - iChunkOffset));
  88. memcpy(zOut, &pChunk->zChunk[iChunkOffset], nCopy);
  89. zOut += nCopy;
  90. nRead -= iSpace;
  91. iChunkOffset = 0;
  92. } while( nRead>=0 && (pChunk=pChunk->pNext)!=0 && nRead>0 );
  93. p->readpoint.iOffset = iOfst+iAmt;
  94. p->readpoint.pChunk = pChunk;
  95. return SQLITE_OK;
  96. }
  97. /*
  98. ** Write data to the file.
  99. */
  100. static int memjrnlWrite(
  101. sqlite3_file *pJfd, /* The journal file into which to write */
  102. const void *zBuf, /* Take data to be written from here */
  103. int iAmt, /* Number of bytes to write */
  104. sqlite_int64 iOfst /* Begin writing at this offset into the file */
  105. ){
  106. MemJournal *p = (MemJournal *)pJfd;
  107. int nWrite = iAmt;
  108. u8 *zWrite = (u8 *)zBuf;
  109. /* An in-memory journal file should only ever be appended to. Random
  110. ** access writes are not required by sqlite.
  111. */
  112. assert( iOfst==p->endpoint.iOffset );
  113. UNUSED_PARAMETER(iOfst);
  114. while( nWrite>0 ){
  115. FileChunk *pChunk = p->endpoint.pChunk;
  116. int iChunkOffset = (int)(p->endpoint.iOffset%JOURNAL_CHUNKSIZE);
  117. int iSpace = MIN(nWrite, JOURNAL_CHUNKSIZE - iChunkOffset);
  118. if( iChunkOffset==0 ){
  119. /* New chunk is required to extend the file. */
  120. FileChunk *pNew = sqlite3_malloc(sizeof(FileChunk));
  121. if( !pNew ){
  122. return SQLITE_IOERR_NOMEM;
  123. }
  124. pNew->pNext = 0;
  125. if( pChunk ){
  126. assert( p->pFirst );
  127. pChunk->pNext = pNew;
  128. }else{
  129. assert( !p->pFirst );
  130. p->pFirst = pNew;
  131. }
  132. p->endpoint.pChunk = pNew;
  133. }
  134. memcpy(&p->endpoint.pChunk->zChunk[iChunkOffset], zWrite, iSpace);
  135. zWrite += iSpace;
  136. nWrite -= iSpace;
  137. p->endpoint.iOffset += iSpace;
  138. }
  139. return SQLITE_OK;
  140. }
  141. /*
  142. ** Truncate the file.
  143. */
  144. static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
  145. MemJournal *p = (MemJournal *)pJfd;
  146. FileChunk *pChunk;
  147. assert(size==0);
  148. UNUSED_PARAMETER(size);
  149. pChunk = p->pFirst;
  150. while( pChunk ){
  151. FileChunk *pTmp = pChunk;
  152. pChunk = pChunk->pNext;
  153. sqlite3_free(pTmp);
  154. }
  155. sqlite3MemJournalOpen(pJfd);
  156. return SQLITE_OK;
  157. }
  158. /*
  159. ** Close the file.
  160. */
  161. static int memjrnlClose(sqlite3_file *pJfd){
  162. memjrnlTruncate(pJfd, 0);
  163. return SQLITE_OK;
  164. }
  165. /*
  166. ** Sync the file.
  167. **
  168. ** Syncing an in-memory journal is a no-op. And, in fact, this routine
  169. ** is never called in a working implementation. This implementation
  170. ** exists purely as a contingency, in case some malfunction in some other
  171. ** part of SQLite causes Sync to be called by mistake.
  172. */
  173. static int memjrnlSync(sqlite3_file *NotUsed, int NotUsed2){
  174. UNUSED_PARAMETER2(NotUsed, NotUsed2);
  175. return SQLITE_OK;
  176. }
  177. /*
  178. ** Query the size of the file in bytes.
  179. */
  180. static int memjrnlFileSize(sqlite3_file *pJfd, sqlite_int64 *pSize){
  181. MemJournal *p = (MemJournal *)pJfd;
  182. *pSize = (sqlite_int64) p->endpoint.iOffset;
  183. return SQLITE_OK;
  184. }
  185. /*
  186. ** Table of methods for MemJournal sqlite3_file object.
  187. */
  188. static const struct sqlite3_io_methods MemJournalMethods = {
  189. 1, /* iVersion */
  190. memjrnlClose, /* xClose */
  191. memjrnlRead, /* xRead */
  192. memjrnlWrite, /* xWrite */
  193. memjrnlTruncate, /* xTruncate */
  194. memjrnlSync, /* xSync */
  195. memjrnlFileSize, /* xFileSize */
  196. 0, /* xLock */
  197. 0, /* xUnlock */
  198. 0, /* xCheckReservedLock */
  199. 0, /* xFileControl */
  200. 0, /* xSectorSize */
  201. 0, /* xDeviceCharacteristics */
  202. 0, /* xShmMap */
  203. 0, /* xShmLock */
  204. 0, /* xShmBarrier */
  205. 0, /* xShmUnmap */
  206. 0, /* xFetch */
  207. 0 /* xUnfetch */
  208. };
  209. /*
  210. ** Open a journal file.
  211. */
  212. void sqlite3MemJournalOpen(sqlite3_file *pJfd){
  213. MemJournal *p = (MemJournal *)pJfd;
  214. assert( EIGHT_BYTE_ALIGNMENT(p) );
  215. memset(p, 0, sqlite3MemJournalSize());
  216. p->pMethod = (sqlite3_io_methods*)&MemJournalMethods;
  217. }
  218. /*
  219. ** Return true if the file-handle passed as an argument is
  220. ** an in-memory journal
  221. */
  222. int sqlite3IsMemJournal(sqlite3_file *pJfd){
  223. return pJfd->pMethods==&MemJournalMethods;
  224. }
  225. /*
  226. ** Return the number of bytes required to store a MemJournal file descriptor.
  227. */
  228. int sqlite3MemJournalSize(void){
  229. return sizeof(MemJournal);
  230. }