forgotten commit. disabled until egl is adapted.
[AROS-Contrib.git] / sqlite3 / os_test.c
blob8199f5b18327af8eeac7008d344dacaf275d711d
1 /*
2 ** 2004 May 22
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.
11 ******************************************************************************
13 ** This file contains code that is specific to Unix systems. It is used
14 ** for testing SQLite only.
16 #if OS_TEST /* This file is used for the test backend only */
17 #include "sqliteInt.h"
18 #include "os.h" /* Must be first to enable large file support */
20 #define sqlite3OsOpenReadWrite sqlite3RealOpenReadWrite
21 #define sqlite3OsOpenExclusive sqlite3RealOpenExclusive
22 #define sqlite3OsOpenReadOnly sqlite3RealOpenReadOnly
23 #define sqlite3OsOpenDirectory sqlite3RealOpenDirectory
24 #define sqlite3OsClose sqlite3RealClose
25 #define sqlite3OsRead sqlite3RealRead
26 #define sqlite3OsWrite sqlite3RealWrite
27 #define sqlite3OsSeek sqlite3RealSeek
28 #define sqlite3OsSync sqlite3RealSync
29 #define sqlite3OsTruncate sqlite3RealTruncate
30 #define sqlite3OsFileSize sqlite3RealFileSize
31 #define sqlite3OsLock sqlite3RealLock
32 #define sqlite3OsUnlock sqlite3RealUnlock
33 #define sqlite3OsCheckReservedLock sqlite3RealCheckReservedLock
35 #define OsFile OsRealFile
36 #define OS_UNIX 1
37 #include "os_unix.c"
38 #undef OS_UNIX
39 #undef OsFile
41 #undef sqlite3OsOpenReadWrite
42 #undef sqlite3OsOpenExclusive
43 #undef sqlite3OsOpenReadOnly
44 #undef sqlite3OsOpenDirectory
45 #undef sqlite3OsClose
46 #undef sqlite3OsRead
47 #undef sqlite3OsWrite
48 #undef sqlite3OsSeek
49 #undef sqlite3OsSync
50 #undef sqlite3OsTruncate
51 #undef sqlite3OsFileSize
52 #undef sqlite3OsLock
53 #undef sqlite3OsUnlock
54 #undef sqlite3OsCheckReservedLock
56 #define BLOCKSIZE 512
57 #define BLOCK_OFFSET(x) ((x) * BLOCKSIZE)
61 ** The following variables control when a simulated crash occurs.
63 ** If iCrashDelay is non-zero, then zCrashFile contains (full path) name of
64 ** a file that SQLite will call sqlite3OsSync() on. Each time this happens
65 ** iCrashDelay is decremented. If iCrashDelay is zero after being
66 ** decremented, a "crash" occurs during the sync() operation.
68 ** In other words, a crash occurs the iCrashDelay'th time zCrashFile is
69 ** synced.
71 static int iCrashDelay = 0;
72 char zCrashFile[256];
75 ** Set the value of the two crash parameters.
77 void sqlite3SetCrashParams(int iDelay, char const *zFile){
78 sqlite3OsEnterMutex();
79 assert( strlen(zFile)<256 );
80 strcpy(zCrashFile, zFile);
81 iCrashDelay = iDelay;
82 sqlite3OsLeaveMutex();
86 ** File zPath is being sync()ed. Return non-zero if this should
87 ** cause a crash.
89 static int crashRequired(char const *zPath){
90 int r;
91 int n;
92 sqlite3OsEnterMutex();
93 n = strlen(zCrashFile);
94 if( zCrashFile[n-1]=='*' ){
95 n--;
96 }else if( strlen(zPath)>n ){
97 n = strlen(zPath);
99 r = 0;
100 if( iCrashDelay>0 && strncmp(zPath, zCrashFile, n)==0 ){
101 iCrashDelay--;
102 if( iCrashDelay<=0 ){
103 r = 1;
106 sqlite3OsLeaveMutex();
107 return r;
111 static OsTestFile *pAllFiles = 0;
114 ** Initialise the os_test.c specific fields of pFile.
116 static void initFile(OsFile *id, char const *zName){
117 OsTestFile *pFile = (OsTestFile *)
118 sqliteMalloc(sizeof(OsTestFile) + strlen(zName)+1);
119 pFile->nMaxWrite = 0;
120 pFile->nBlk = 0;
121 pFile->apBlk = 0;
122 pFile->zName = (char *)(&pFile[1]);
123 strcpy(pFile->zName, zName);
124 *id = pFile;
125 pFile->pNext = pAllFiles;
126 pAllFiles = pFile;
130 ** Undo the work done by initFile. Delete the OsTestFile structure
131 ** and unlink the structure from the pAllFiles list.
133 static void closeFile(OsFile *id){
134 OsTestFile *pFile = *id;
135 if( pFile==pAllFiles ){
136 pAllFiles = pFile->pNext;
137 }else{
138 OsTestFile *p;
139 for(p=pAllFiles; p->pNext!=pFile; p=p->pNext ){
140 assert( p );
142 p->pNext = pFile->pNext;
144 sqliteFree(pFile);
145 *id = 0;
149 ** Return the current seek offset from the start of the file. This
150 ** is unix-only code.
152 static i64 osTell(OsTestFile *pFile){
153 return lseek(pFile->fd.h, 0, SEEK_CUR);
157 ** Load block 'blk' into the cache of pFile.
159 static int cacheBlock(OsTestFile *pFile, int blk){
160 if( blk>=pFile->nBlk ){
161 int n = ((pFile->nBlk * 2) + 100 + blk);
162 /* if( pFile->nBlk==0 ){ printf("DIRTY %s\n", pFile->zName); } */
163 pFile->apBlk = (u8 **)sqliteRealloc(pFile->apBlk, n * sizeof(u8*));
164 if( !pFile->apBlk ) return SQLITE_NOMEM;
165 memset(&pFile->apBlk[pFile->nBlk], 0, (n - pFile->nBlk)*sizeof(u8*));
166 pFile->nBlk = n;
169 if( !pFile->apBlk[blk] ){
170 i64 filesize;
171 int rc;
173 u8 *p = sqliteMalloc(BLOCKSIZE);
174 if( !p ) return SQLITE_NOMEM;
175 pFile->apBlk[blk] = p;
177 rc = sqlite3RealFileSize(&pFile->fd, &filesize);
178 if( rc!=SQLITE_OK ) return rc;
180 if( BLOCK_OFFSET(blk)<filesize ){
181 int len = BLOCKSIZE;
182 rc = sqlite3RealSeek(&pFile->fd, blk*BLOCKSIZE);
183 if( BLOCK_OFFSET(blk+1)>filesize ){
184 len = filesize - BLOCK_OFFSET(blk);
186 if( rc!=SQLITE_OK ) return rc;
187 rc = sqlite3RealRead(&pFile->fd, p, len);
188 if( rc!=SQLITE_OK ) return rc;
192 return SQLITE_OK;
195 /* #define TRACE_WRITECACHE */
198 ** Write the cache of pFile to disk. If crash is non-zero, randomly
199 ** skip blocks when writing. The cache is deleted before returning.
201 static int writeCache2(OsTestFile *pFile, int crash){
202 int i;
203 int nMax = pFile->nMaxWrite;
204 i64 offset;
205 int rc = SQLITE_OK;
207 offset = osTell(pFile);
208 for(i=0; i<pFile->nBlk; i++){
209 u8 *p = pFile->apBlk[i];
210 if( p ){
211 int skip = 0;
212 int trash = 0;
213 if( crash ){
214 char random;
215 sqlite3Randomness(1, &random);
216 if( random & 0x01 ){
217 if( random & 0x02 ){
218 trash = 1;
219 #ifdef TRACE_WRITECACHE
220 printf("Trashing block %d of %s\n", i, pFile->zName);
221 #endif
222 }else{
223 skip = 1;
224 #ifdef TRACE_WRITECACHE
225 printf("Skiping block %d of %s\n", i, pFile->zName);
226 #endif
228 }else{
229 #ifdef TRACE_WRITECACHE
230 printf("Writing block %d of %s\n", i, pFile->zName);
231 #endif
234 if( rc==SQLITE_OK ){
235 rc = sqlite3RealSeek(&pFile->fd, BLOCK_OFFSET(i));
237 if( rc==SQLITE_OK && !skip ){
238 int len = BLOCKSIZE;
239 if( BLOCK_OFFSET(i+1)>nMax ){
240 len = nMax-BLOCK_OFFSET(i);
242 if( len>0 ){
243 if( trash ){
244 sqlite3Randomness(len, p);
246 rc = sqlite3RealWrite(&pFile->fd, p, len);
249 sqliteFree(p);
252 sqliteFree(pFile->apBlk);
253 pFile->nBlk = 0;
254 pFile->apBlk = 0;
255 pFile->nMaxWrite = 0;
257 if( rc==SQLITE_OK ){
258 rc = sqlite3RealSeek(&pFile->fd, offset);
260 return rc;
264 ** Write the cache to disk.
266 static int writeCache(OsTestFile *pFile){
267 if( pFile->apBlk ){
268 int c = crashRequired(pFile->zName);
269 if( c ){
270 OsTestFile *p;
271 #ifdef TRACE_WRITECACHE
272 printf("\nCrash during sync of %s\n", pFile->zName);
273 #endif
274 for(p=pAllFiles; p; p=p->pNext){
275 writeCache2(p, 1);
277 exit(-1);
278 }else{
279 return writeCache2(pFile, 0);
282 return SQLITE_OK;
286 ** Close the file.
288 int sqlite3OsClose(OsFile *id){
289 if( !(*id) ) return SQLITE_OK;
290 if( (*id)->fd.isOpen ){
291 /* printf("CLOSE %s (%d blocks)\n", (*id)->zName, (*id)->nBlk); */
292 writeCache(*id);
293 sqlite3RealClose(&(*id)->fd);
295 closeFile(id);
296 return SQLITE_OK;
299 int sqlite3OsRead(OsFile *id, void *pBuf, int amt){
300 i64 offset; /* The current offset from the start of the file */
301 i64 end; /* The byte just past the last byte read */
302 int blk; /* Block number the read starts on */
303 int i;
304 u8 *zCsr;
305 int rc = SQLITE_OK;
306 OsTestFile *pFile = *id;
308 offset = osTell(pFile);
309 end = offset+amt;
310 blk = (offset/BLOCKSIZE);
312 zCsr = (u8 *)pBuf;
313 for(i=blk; i*BLOCKSIZE<end; i++){
314 int off = 0;
315 int len = 0;
318 if( BLOCK_OFFSET(i) < offset ){
319 off = offset-BLOCK_OFFSET(i);
321 len = BLOCKSIZE - off;
322 if( BLOCK_OFFSET(i+1) > end ){
323 len = len - (BLOCK_OFFSET(i+1)-end);
326 if( i<pFile->nBlk && pFile->apBlk[i]){
327 u8 *pBlk = pFile->apBlk[i];
328 memcpy(zCsr, &pBlk[off], len);
329 }else{
330 rc = sqlite3RealSeek(&pFile->fd, BLOCK_OFFSET(i) + off);
331 if( rc!=SQLITE_OK ) return rc;
332 rc = sqlite3RealRead(&pFile->fd, zCsr, len);
333 if( rc!=SQLITE_OK ) return rc;
336 zCsr += len;
338 assert( zCsr==&((u8 *)pBuf)[amt] );
340 rc = sqlite3RealSeek(&pFile->fd, end);
341 return rc;
344 int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
345 i64 offset; /* The current offset from the start of the file */
346 i64 end; /* The byte just past the last byte written */
347 int blk; /* Block number the write starts on */
348 int i;
349 const u8 *zCsr;
350 int rc = SQLITE_OK;
351 OsTestFile *pFile = *id;
353 offset = osTell(pFile);
354 end = offset+amt;
355 blk = (offset/BLOCKSIZE);
357 zCsr = (u8 *)pBuf;
358 for(i=blk; i*BLOCKSIZE<end; i++){
359 u8 *pBlk;
360 int off = 0;
361 int len = 0;
363 /* Make sure the block is in the cache */
364 rc = cacheBlock(pFile, i);
365 if( rc!=SQLITE_OK ) return rc;
367 /* Write into the cache */
368 pBlk = pFile->apBlk[i];
369 assert( pBlk );
371 if( BLOCK_OFFSET(i) < offset ){
372 off = offset-BLOCK_OFFSET(i);
374 len = BLOCKSIZE - off;
375 if( BLOCK_OFFSET(i+1) > end ){
376 len = len - (BLOCK_OFFSET(i+1)-end);
378 memcpy(&pBlk[off], zCsr, len);
379 zCsr += len;
381 if( pFile->nMaxWrite<end ){
382 pFile->nMaxWrite = end;
384 assert( zCsr==&((u8 *)pBuf)[amt] );
386 rc = sqlite3RealSeek(&pFile->fd, end);
387 return rc;
391 ** Sync the file. First flush the write-cache to disk, then call the
392 ** real sync() function.
394 int sqlite3OsSync(OsFile *id){
395 int rc;
396 /* printf("SYNC %s (%d blocks)\n", (*id)->zName, (*id)->nBlk); */
397 rc = writeCache(*id);
398 if( rc!=SQLITE_OK ) return rc;
399 rc = sqlite3RealSync(&(*id)->fd);
400 return rc;
404 ** Truncate the file. Set the internal OsFile.nMaxWrite variable to the new
405 ** file size to ensure that nothing in the write-cache past this point
406 ** is written to disk.
408 int sqlite3OsTruncate(OsFile *id, i64 nByte){
409 (*id)->nMaxWrite = nByte;
410 return sqlite3RealTruncate(&(*id)->fd, nByte);
414 ** Return the size of the file. If the cache contains a write that extended
415 ** the file, then return this size instead of the on-disk size.
417 int sqlite3OsFileSize(OsFile *id, i64 *pSize){
418 int rc = sqlite3RealFileSize(&(*id)->fd, pSize);
419 if( rc==SQLITE_OK && pSize && *pSize<(*id)->nMaxWrite ){
420 *pSize = (*id)->nMaxWrite;
422 return rc;
426 ** The three functions used to open files. All that is required is to
427 ** initialise the os_test.c specific fields and then call the corresponding
428 ** os_unix.c function to really open the file.
430 int sqlite3OsOpenReadWrite(const char *zFilename, OsFile *id, int *pReadonly){
431 initFile(id, zFilename);
432 return sqlite3RealOpenReadWrite(zFilename, &(*id)->fd, pReadonly);
434 int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
435 initFile(id, zFilename);
436 return sqlite3RealOpenExclusive(zFilename, &(*id)->fd, delFlag);
438 int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
439 initFile(id, zFilename);
440 return sqlite3RealOpenReadOnly(zFilename, &(*id)->fd);
444 ** These six function calls are passed straight through to the os_unix.c
445 ** backend.
447 int sqlite3OsSeek(OsFile *id, i64 offset){
448 return sqlite3RealSeek(&(*id)->fd, offset);
450 int sqlite3OsCheckReservedLock(OsFile *id){
451 return sqlite3RealCheckReservedLock(&(*id)->fd);
453 int sqlite3OsLock(OsFile *id, int locktype){
454 return sqlite3RealLock(&(*id)->fd, locktype);
456 int sqlite3OsUnlock(OsFile *id, int locktype){
457 return sqlite3RealUnlock(&(*id)->fd, locktype);
459 int sqlite3OsOpenDirectory(const char *zDirname, OsFile *id){
460 return sqlite3RealOpenDirectory(zDirname, &(*id)->fd);
463 #endif /* OS_TEST */