~ubuntu-branches/ubuntu/vivid/db/vivid-proposed

« back to all changes in this revision

Viewing changes to sql/sqlite/src/memjournal.c

  • Committer: Bazaar Package Importer
  • Author(s): Clint Adams
  • Date: 2010-04-04 09:37:47 UTC
  • mto: This revision was merged to the branch mainline in revision 20.
  • Revision ID: james.westby@ubuntu.com-20100404093747-7x3j05svjdoy8tdi
Tags: upstream-5.0.21
ImportĀ upstreamĀ versionĀ 5.0.21

Show diffs side-by-side

added added

removed removed

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