/ Check-in [b8332aa8]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Enable async testing. Modify the OS layer interface. Add the sqlite3_aux.h include file. Add tests for boolean value representation in file format 4. (CVS 2866)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:b8332aa8b83142898779972b3dff13cbe3c78623
User & Date: drh 2006-01-06 03:29:57
Context
2006-01-06
06:33
Fix a bug that was emptying shared-schema tables during an ATTACH. (CVS 2867) check-in: 752a2754 user: danielk1977 tags: trunk
03:29
Enable async testing. Modify the OS layer interface. Add the sqlite3_aux.h include file. Add tests for boolean value representation in file format 4. (CVS 2866) check-in: b8332aa8 user: drh tags: trunk
01:42
Formatting changes in btree.c. (CVS 2865) check-in: f1922da2 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to Makefile.in.

187
188
189
190
191
192
193

194
195
196
197
198
199
200
...
203
204
205
206
207
208
209

210
211
212
213
214
215
216
  $(TOP)/src/printf.c \
  $(TOP)/src/test1.c \
  $(TOP)/src/test2.c \
  $(TOP)/src/test3.c \
  $(TOP)/src/test4.c \
  $(TOP)/src/test5.c \
  $(TOP)/src/test6.c \

  $(TOP)/src/utf.c \
  $(TOP)/src/util.c \
  $(TOP)/src/vdbe.c \
  $(TOP)/src/md5.c \
  $(TOP)/src/where.c

# Header files used by all library source files.
................................................................................
   sqlite3.h  \
   $(TOP)/src/btree.h \
   $(TOP)/src/hash.h \
   opcodes.h \
   $(TOP)/src/os.h \
   $(TOP)/src/os_common.h \
   $(TOP)/src/sqliteInt.h  \

   $(TOP)/src/vdbe.h \
   parse.h

# Header files used by the VDBE submodule
#
VDBEHDR = \
   $(HDR) \







>







 







>







187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
...
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
  $(TOP)/src/printf.c \
  $(TOP)/src/test1.c \
  $(TOP)/src/test2.c \
  $(TOP)/src/test3.c \
  $(TOP)/src/test4.c \
  $(TOP)/src/test5.c \
  $(TOP)/src/test6.c \
  $(TOP)/src/test_async.c \
  $(TOP)/src/utf.c \
  $(TOP)/src/util.c \
  $(TOP)/src/vdbe.c \
  $(TOP)/src/md5.c \
  $(TOP)/src/where.c

# Header files used by all library source files.
................................................................................
   sqlite3.h  \
   $(TOP)/src/btree.h \
   $(TOP)/src/hash.h \
   opcodes.h \
   $(TOP)/src/os.h \
   $(TOP)/src/os_common.h \
   $(TOP)/src/sqliteInt.h  \
   $(TOP)/src/sqlite3_aux.h \
   $(TOP)/src/vdbe.h \
   parse.h

# Header files used by the VDBE submodule
#
VDBEHDR = \
   $(HDR) \

Changes to main.mk.

129
130
131
132
133
134
135

136
137
138
139
140
141
142
...
147
148
149
150
151
152
153

154
155
156
157
158
159
160
  $(TOP)/src/printf.c \
  $(TOP)/src/test1.c \
  $(TOP)/src/test2.c \
  $(TOP)/src/test3.c \
  $(TOP)/src/test4.c \
  $(TOP)/src/test5.c \
  $(TOP)/src/test6.c \

  $(TOP)/src/utf.c \
  $(TOP)/src/util.c \
  $(TOP)/src/vdbe.c \
  $(TOP)/src/md5.c \
  $(TOP)/src/where.c

#  $(TOP)/src/test_async.c 
................................................................................
   sqlite3.h  \
   $(TOP)/src/btree.h \
   $(TOP)/src/hash.h \
   opcodes.h \
   $(TOP)/src/os.h \
   $(TOP)/src/os_common.h \
   $(TOP)/src/sqliteInt.h  \

   $(TOP)/src/vdbe.h \
   parse.h

# Header files used by the VDBE submodule
#
VDBEHDR = \
   $(HDR) \







>







 







>







129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
...
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
  $(TOP)/src/printf.c \
  $(TOP)/src/test1.c \
  $(TOP)/src/test2.c \
  $(TOP)/src/test3.c \
  $(TOP)/src/test4.c \
  $(TOP)/src/test5.c \
  $(TOP)/src/test6.c \
  $(TOP)/src/test_async.c \
  $(TOP)/src/utf.c \
  $(TOP)/src/util.c \
  $(TOP)/src/vdbe.c \
  $(TOP)/src/md5.c \
  $(TOP)/src/where.c

#  $(TOP)/src/test_async.c 
................................................................................
   sqlite3.h  \
   $(TOP)/src/btree.h \
   $(TOP)/src/hash.h \
   opcodes.h \
   $(TOP)/src/os.h \
   $(TOP)/src/os_common.h \
   $(TOP)/src/sqliteInt.h  \
   $(TOP)/src/sqlite3_aux.h \
   $(TOP)/src/vdbe.h \
   parse.h

# Header files used by the VDBE submodule
#
VDBEHDR = \
   $(HDR) \

Changes to src/os.c.

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
}
int sqlite3OsLockState(OsFile *id){
  return id->pMethod->xLockState(id);
}
int sqlite3OsCheckReservedLock(OsFile *id){
  return id->pMethod->xCheckReservedLock(id);
}

static void**getOsRoutinePtr(int eRoutine){
  switch( eRoutine ){
    case SQLITE_OS_ROUTINE_OPENREADWRITE:
      return (void **)(&sqlite3Os.xOpenReadWrite);
    case SQLITE_OS_ROUTINE_OPENREADONLY:
      return (void **)(&sqlite3Os.xOpenReadOnly);
    case SQLITE_OS_ROUTINE_OPENEXCLUSIVE:
      return (void **)(&sqlite3Os.xOpenExclusive);
    case SQLITE_OS_ROUTINE_DELETE:
      return (void **)(&sqlite3Os.xDelete);
    case SQLITE_OS_ROUTINE_FILEEXISTS:
      return (void **)(&sqlite3Os.xFileExists);
    case SQLITE_OS_ROUTINE_SYNCDIRECTORY:
      return (void **)(&sqlite3Os.xSyncDirectory);
    default:
      assert(!"Illegal eRoutine value");
  }

  return 0;
}

void *sqlite3_os_routine_get(int eRoutine){
  return *getOsRoutinePtr(eRoutine);
}

void *sqlite3_os_routine_set(int eRoutine, void *pRoutine){
  void **ppRet = getOsRoutinePtr(eRoutine);
  void *pRet = *ppRet;
  *ppRet = pRoutine;
  return pRet;
}

void sqlite3_os_enter_mutex(){
  sqlite3Os.xEnterMutex();
}
void sqlite3_os_leave_mutex(){
  sqlite3Os.xLeaveMutex();
}








<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
>
|

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
65
66
67
68
69
70
71


















72
73
74



















}
int sqlite3OsLockState(OsFile *id){
  return id->pMethod->xLockState(id);
}
int sqlite3OsCheckReservedLock(OsFile *id){
  return id->pMethod->xCheckReservedLock(id);
}


















struct sqlite3OsVtbl *sqlite3_os_switch(void){
  return &sqlite3Os;
}



















Changes to src/os.h.

12
13
14
15
16
17
18

19
20
21
22
23
24
25
..
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
...
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
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
**
** This header file (together with is companion C source-code file
** "os.c") attempt to abstract the underlying operating system so that
** the SQLite library will work on both POSIX and windows systems.
*/
#ifndef _SQLITE_OS_H_
#define _SQLITE_OS_H_


/*
** Figure out if we are dealing with Unix, Windows or MacOS.
**
** N.B. MacOS means Mac Classic (or Carbon). Treat Darwin (OS X) as Unix.
**      The MacOS build is designed to use CodeWarrior (tested with v8)
*/
................................................................................
#else
# ifndef OS_WIN
#  define OS_WIN 0
# endif
#endif


/*
** Forward declarations
*/
typedef struct OsFile OsFile;
typedef struct IoMethod IoMethod;

/*
** An instance of the following structure contains pointers to all
** methods on an OsFile object.
*/
struct IoMethod {
  int (*xClose)(OsFile**);
  int (*xOpenDirectory)(OsFile*, const char*);
  int (*xRead)(OsFile*, void*, int amt);
  int (*xWrite)(OsFile*, const void*, int amt);
  int (*xSeek)(OsFile*, i64 offset);
  int (*xTruncate)(OsFile*, i64 size);
  int (*xSync)(OsFile*, int);
  void (*xSetFullSync)(OsFile *id, int setting);
  int (*xFileHandle)(OsFile *id);
  int (*xFileSize)(OsFile*, i64 *pSize);
  int (*xLock)(OsFile*, int);
  int (*xUnlock)(OsFile*, int);
  int (*xLockState)(OsFile *id);
  int (*xCheckReservedLock)(OsFile *id);
};

/*
** The OsFile object describes an open disk file in an OS-dependent way.
** The version of OsFile defined here is a generic version.  Each OS
** implementation defines its own subclass of this structure that contains
** additional information needed to handle file I/O.  But the pMethod
** entry (pointing to the virtual function table) always occurs first
** so that we can always find the appropriate methods.
*/
struct OsFile {
  IoMethod const *pMethod;
};

/*
** Define the maximum size of a temporary filename
*/
#if OS_WIN
# include <windows.h>
# define SQLITE_TEMPNAME_SIZE (MAX_PATH+50)
#else
................................................................................
** prematurely, old temporary files can be easily identified. This can be done
** using -DTEMP_FILE_PREFIX=myprefix_ on the compiler command line.
*/
#ifndef TEMP_FILE_PREFIX
# define TEMP_FILE_PREFIX "sqlite_"
#endif

/*
** The following values may be passed as the second argument to
** sqlite3OsLock(). The various locks exhibit the following semantics:
**
** SHARED:    Any number of processes may hold a SHARED lock simultaneously.
** RESERVED:  A single process may hold a RESERVED lock on a file at
**            any time. Other processes may hold and obtain new SHARED locks.
** PENDING:   A single process may hold a PENDING lock on a file at
**            any one time. Existing SHARED locks may persist, but no new
**            SHARED locks may be obtained by other processes.
** EXCLUSIVE: An EXCLUSIVE lock precludes all other locks.
**
** PENDING_LOCK may not be passed directly to sqlite3OsLock(). Instead, a
** process that requests an EXCLUSIVE lock may actually obtain a PENDING
** lock. This can be upgraded to an EXCLUSIVE lock by a subsequent call to
** sqlite3OsLock().
*/
#define NO_LOCK         0
#define SHARED_LOCK     1
#define RESERVED_LOCK   2
#define PENDING_LOCK    3
#define EXCLUSIVE_LOCK  4

/*
** File Locking Notes:  (Mostly about windows but also some info for Unix)
**
** We cannot use LockFileEx() or UnlockFileEx() on Win95/98/ME because
** those functions are not available.  So we use only LockFile() and
** UnlockFile().
**
** LockFile() prevents not just writing but also reading by other processes.
** A SHARED_LOCK is obtained by locking a single randomly-chosen 
** byte out of a specific range of bytes. The lock byte is obtained at 
** random so two separate readers can probably access the file at the 
** same time, unless they are unlucky and choose the same lock byte.
** An EXCLUSIVE_LOCK is obtained by locking all bytes in the range.
** There can only be one writer.  A RESERVED_LOCK is obtained by locking
** a single byte of the file that is designated as the reserved lock byte.
** A PENDING_LOCK is obtained by locking a designated byte different from
** the RESERVED_LOCK byte.
**
** On WinNT/2K/XP systems, LockFileEx() and UnlockFileEx() are available,
** which means we can use reader/writer locks.  When reader/writer locks
** are used, the lock is placed on the same range of bytes that is used
** for probabilistic locking in Win95/98/ME.  Hence, the locking scheme
** will support two or more Win95 readers or two or more WinNT readers.
** But a single Win95 reader will lock out all WinNT readers and a single
** WinNT reader will lock out all other Win95 readers.
**
** The following #defines specify the range of bytes used for locking.
** SHARED_SIZE is the number of bytes available in the pool from which
** a random byte is selected for a shared lock.  The pool of bytes for
** shared locks begins at SHARED_FIRST. 
**
** These #defines are available in os.h so that Unix can use the same
** byte ranges for locking.  This leaves open the possiblity of having
** clients on win95, winNT, and unix all talking to the same shared file
** and all locking correctly.  To do so would require that samba (or whatever
** tool is being used for file sharing) implements locks correctly between
** windows and unix.  I'm guessing that isn't likely to happen, but by
** using the same locking range we are at least open to the possibility.
**
** Locking in windows is manditory.  For this reason, we cannot store
** actual data in the bytes used for locking.  The pager never allocates
** the pages involved in locking therefore.  SHARED_SIZE is selected so
** that all locks will fit on a single page even at the minimum page size.
** PENDING_BYTE defines the beginning of the locks.  By default PENDING_BYTE
** is set high so that we don't have to allocate an unused page except
** for very large databases.  But one should test the page skipping logic 
** by setting PENDING_BYTE low and running the entire regression suite.
**
** Changing the value of PENDING_BYTE results in a subtly incompatible
** file format.  Depending on how it is changed, you might not notice
** the incompatibility right away, even running a full regression test.
** The default location of PENDING_BYTE is the first byte past the
** 1GB boundary.
**
*/
#ifndef SQLITE_TEST
#define PENDING_BYTE      0x40000000  /* First byte past the 1GB boundary */
#else
extern unsigned int sqlite3_pending_byte;
#define PENDING_BYTE sqlite3_pending_byte
#endif

#define RESERVED_BYTE     (PENDING_BYTE+1)
#define SHARED_FIRST      (PENDING_BYTE+2)
#define SHARED_SIZE       510

/*
** A single global instance of the following structure holds pointers to the
** various system-specific interface routines.
*/
extern struct sqlite3OsVtbl {
  int (*xOpenReadWrite)(const char*, OsFile**, int*);
  int (*xOpenExclusive)(const char*, OsFile**, int);
  int (*xOpenReadOnly)(const char*, OsFile**);

  int (*xDelete)(const char*);
  int (*xFileExists)(const char*);
  char *(*xFullPathname)(const char*);
  int (*xIsDirWritable)(char*);
  int (*xSyncDirectory)(const char*);
  int (*xTempFileName)(char*);

  int (*xRandomSeed)(char*);
  int (*xSleep)(int ms);
  int (*xCurrentTime)(double*);

  void (*xEnterMutex)(void);
  void (*xLeaveMutex)(void);
  int (*xInMutex)(void);
  void *(*xThreadSpecificData)(int);

  void *(*xMalloc)(int);
  void *(*xRealloc)(void *, int);
  void (*xFree)(void *);
  int (*xAllocationSize)(void *);
} sqlite3Os;


/*
** The semi-published API for setting and getting methods from the 
** global sqlite3OsVtbl structure. Neither sqlite3_os_routine_XXX() function
** is intriniscally thread-safe.
**
** External get/set access is only provided to the routines identified 
** by the following SQLITE_OS_ROUTINE symbols:
*/
#define SQLITE_OS_ROUTINE_OPENREADWRITE   1
#define SQLITE_OS_ROUTINE_OPENREADONLY    2
#define SQLITE_OS_ROUTINE_OPENEXCLUSIVE   3
#define SQLITE_OS_ROUTINE_DELETE          4
#define SQLITE_OS_ROUTINE_FILEEXISTS      5
#define SQLITE_OS_ROUTINE_SYNCDIRECTORY   6
void *sqlite3_os_routine_get(int);
void *sqlite3_os_routine_set(int, void *);

void sqlite3_os_enter_mutex();
void sqlite3_os_leave_mutex();

/*
** Prototypes for routines found in os.c
*/
int sqlite3OsClose(OsFile**);
int sqlite3OsOpenDirectory(OsFile*, const char*);
int sqlite3OsRead(OsFile*, void*, int amt);
int sqlite3OsWrite(OsFile*, const void*, int amt);
int sqlite3OsSeek(OsFile*, i64 offset);
int sqlite3OsTruncate(OsFile*, i64 size);
int sqlite3OsSync(OsFile*, int);
void sqlite3OsSetFullSync(OsFile *id, int setting);
int sqlite3OsFileHandle(OsFile *id);
int sqlite3OsFileSize(OsFile*, i64 *pSize);
int sqlite3OsLock(OsFile*, int);
int sqlite3OsUnlock(OsFile*, int);
int sqlite3OsLockState(OsFile *id);
int sqlite3OsCheckReservedLock(OsFile *id);


#endif /* _SQLITE_OS_H_ */







>







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
..
40
41
42
43
44
45
46







































47
48
49
50
51
52
53
..
70
71
72
73
74
75
76






















77





























































78











































































79
**
** This header file (together with is companion C source-code file
** "os.c") attempt to abstract the underlying operating system so that
** the SQLite library will work on both POSIX and windows systems.
*/
#ifndef _SQLITE_OS_H_
#define _SQLITE_OS_H_
#include "sqlite3_aux.h"

/*
** Figure out if we are dealing with Unix, Windows or MacOS.
**
** N.B. MacOS means Mac Classic (or Carbon). Treat Darwin (OS X) as Unix.
**      The MacOS build is designed to use CodeWarrior (tested with v8)
*/
................................................................................
#else
# ifndef OS_WIN
#  define OS_WIN 0
# endif
#endif









































/*
** Define the maximum size of a temporary filename
*/
#if OS_WIN
# include <windows.h>
# define SQLITE_TEMPNAME_SIZE (MAX_PATH+50)
#else
................................................................................
** prematurely, old temporary files can be easily identified. This can be done
** using -DTEMP_FILE_PREFIX=myprefix_ on the compiler command line.
*/
#ifndef TEMP_FILE_PREFIX
# define TEMP_FILE_PREFIX "sqlite_"
#endif

































































































































































#endif /* _SQLITE_OS_H_ */

Added src/sqlite3_aux.h.











































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
/*
** 2006 January 05
**
** 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 header file defines auxiliary interfaces to the SQLite library.
** This header file is a companion to the official "sqlite.h" interface
** file.  The difference is that the extraordinary efforts are made to
** insure that the interface defined in "sqlite.h" is always backwards
** compatible.  No such guarantees are made for the auxiliary interfaces
** defined in this header file.  The interfaces defined here are subject
** to change in future releases of SQLite.
**
** We justify the volitility of the interfaces defined here by noting that
** these interfaces are designed not for users of the SQLite library but
** by code that wishes to expand and extend the SQLite library.  Some
** knowledge of what SQLite is doing internally is necessary to use these
** interfaces.  
**
** We have no intention of changing the interfaces defined in this file
** gratuitously.  No interfaces will be changed without good reason.  But
** on the other hand, if the quality and functionality of SQLite can be
** enhanced by modifying the interfaces found here, then we will do so.
**
** Since these interfaces are variable, it is suggested that they not
** be accessed as a shared library.  Users of these interfaces should
** statically link.
**
** @(#) $Id: sqlite3_aux.h,v 1.1 2006/01/06 03:29:58 drh Exp $
*/
/*
** Forward declarations
*/
typedef struct OsFile OsFile;
typedef struct IoMethod IoMethod;

/*
** An instance of the following structure contains pointers to all
** methods on an OsFile object.
*/
struct IoMethod {
  int (*xClose)(OsFile**);
  int (*xOpenDirectory)(OsFile*, const char*);
  int (*xRead)(OsFile*, void*, int amt);
  int (*xWrite)(OsFile*, const void*, int amt);
  int (*xSeek)(OsFile*, i64 offset);
  int (*xTruncate)(OsFile*, i64 size);
  int (*xSync)(OsFile*, int);
  void (*xSetFullSync)(OsFile *id, int setting);
  int (*xFileHandle)(OsFile *id);
  int (*xFileSize)(OsFile*, i64 *pSize);
  int (*xLock)(OsFile*, int);
  int (*xUnlock)(OsFile*, int);
  int (*xLockState)(OsFile *id);
  int (*xCheckReservedLock)(OsFile *id);
};

/*
** The OsFile object describes an open disk file in an OS-dependent way.
** The version of OsFile defined here is a generic version.  Each OS
** implementation defines its own subclass of this structure that contains
** additional information needed to handle file I/O.  But the pMethod
** entry (pointing to the virtual function table) always occurs first
** so that we can always find the appropriate methods.
*/
struct OsFile {
  IoMethod const *pMethod;
};

/*
** The following values may be passed as the second argument to
** sqlite3OsLock(). The various locks exhibit the following semantics:
**
** SHARED:    Any number of processes may hold a SHARED lock simultaneously.
** RESERVED:  A single process may hold a RESERVED lock on a file at
**            any time. Other processes may hold and obtain new SHARED locks.
** PENDING:   A single process may hold a PENDING lock on a file at
**            any one time. Existing SHARED locks may persist, but no new
**            SHARED locks may be obtained by other processes.
** EXCLUSIVE: An EXCLUSIVE lock precludes all other locks.
**
** PENDING_LOCK may not be passed directly to sqlite3OsLock(). Instead, a
** process that requests an EXCLUSIVE lock may actually obtain a PENDING
** lock. This can be upgraded to an EXCLUSIVE lock by a subsequent call to
** sqlite3OsLock().
*/
#define NO_LOCK         0
#define SHARED_LOCK     1
#define RESERVED_LOCK   2
#define PENDING_LOCK    3
#define EXCLUSIVE_LOCK  4

/*
** File Locking Notes:  (Mostly about windows but also some info for Unix)
**
** We cannot use LockFileEx() or UnlockFileEx() on Win95/98/ME because
** those functions are not available.  So we use only LockFile() and
** UnlockFile().
**
** LockFile() prevents not just writing but also reading by other processes.
** A SHARED_LOCK is obtained by locking a single randomly-chosen 
** byte out of a specific range of bytes. The lock byte is obtained at 
** random so two separate readers can probably access the file at the 
** same time, unless they are unlucky and choose the same lock byte.
** An EXCLUSIVE_LOCK is obtained by locking all bytes in the range.
** There can only be one writer.  A RESERVED_LOCK is obtained by locking
** a single byte of the file that is designated as the reserved lock byte.
** A PENDING_LOCK is obtained by locking a designated byte different from
** the RESERVED_LOCK byte.
**
** On WinNT/2K/XP systems, LockFileEx() and UnlockFileEx() are available,
** which means we can use reader/writer locks.  When reader/writer locks
** are used, the lock is placed on the same range of bytes that is used
** for probabilistic locking in Win95/98/ME.  Hence, the locking scheme
** will support two or more Win95 readers or two or more WinNT readers.
** But a single Win95 reader will lock out all WinNT readers and a single
** WinNT reader will lock out all other Win95 readers.
**
** The following #defines specify the range of bytes used for locking.
** SHARED_SIZE is the number of bytes available in the pool from which
** a random byte is selected for a shared lock.  The pool of bytes for
** shared locks begins at SHARED_FIRST. 
**
** These #defines are available in sqlite_aux.h so that adaptors for
** connecting SQLite to other operating systems can use the same byte
** ranges for locking.  In particular, the same locking strategy and
** byte ranges are used for Unix.  This leaves open the possiblity of having
** clients on win95, winNT, and unix all talking to the same shared file
** and all locking correctly.  To do so would require that samba (or whatever
** tool is being used for file sharing) implements locks correctly between
** windows and unix.  I'm guessing that isn't likely to happen, but by
** using the same locking range we are at least open to the possibility.
**
** Locking in windows is manditory.  For this reason, we cannot store
** actual data in the bytes used for locking.  The pager never allocates
** the pages involved in locking therefore.  SHARED_SIZE is selected so
** that all locks will fit on a single page even at the minimum page size.
** PENDING_BYTE defines the beginning of the locks.  By default PENDING_BYTE
** is set high so that we don't have to allocate an unused page except
** for very large databases.  But one should test the page skipping logic 
** by setting PENDING_BYTE low and running the entire regression suite.
**
** Changing the value of PENDING_BYTE results in a subtly incompatible
** file format.  Depending on how it is changed, you might not notice
** the incompatibility right away, even running a full regression test.
** The default location of PENDING_BYTE is the first byte past the
** 1GB boundary.
**
*/
#ifndef SQLITE_TEST
#define PENDING_BYTE      0x40000000  /* First byte past the 1GB boundary */
#else
extern unsigned int sqlite3_pending_byte;
#define PENDING_BYTE sqlite3_pending_byte
#endif

#define RESERVED_BYTE     (PENDING_BYTE+1)
#define SHARED_FIRST      (PENDING_BYTE+2)
#define SHARED_SIZE       510

/*
** A single global instance of the following structure holds pointers to 
** the routines that SQLite uses to talk with the underlying operating
** system.  Clever programmers can substitute alternative implementations
** of these routine (prior to using any SQLite API!) in order to modify
** the way SQLite interacts with its environment.  For example, modifications
** could be supplied that allow SQLite to talk to a virtual file system.
*/
extern struct sqlite3OsVtbl {
  int (*xOpenReadWrite)(const char*, OsFile**, int*);
  int (*xOpenExclusive)(const char*, OsFile**, int);
  int (*xOpenReadOnly)(const char*, OsFile**);

  int (*xDelete)(const char*);
  int (*xFileExists)(const char*);
  char *(*xFullPathname)(const char*);
  int (*xIsDirWritable)(char*);
  int (*xSyncDirectory)(const char*);
  int (*xTempFileName)(char*);

  int (*xRandomSeed)(char*);
  int (*xSleep)(int ms);
  int (*xCurrentTime)(double*);

  void (*xEnterMutex)(void);
  void (*xLeaveMutex)(void);
  int (*xInMutex)(void);
  void *(*xThreadSpecificData)(int);

  void *(*xMalloc)(int);
  void *(*xRealloc)(void *, int);
  void (*xFree)(void *);
  int (*xAllocationSize)(void *);
} sqlite3Os;

/*
** The following API routine returns a pointer to the sqlite3Os global
** variable.  It is probably easier just to reference the global variable
** directly.  This routine is provided for backwards compatibility with
** an older interface design.
*/
struct sqlite3OsVtbl *sqlite3_os_switch(void);


/*
** The following are prototypes of convenience routines that simply
** call the corresponding routines in the OsFile.pMethod virtual
** function table.
*/
int sqlite3OsClose(OsFile**);
int sqlite3OsOpenDirectory(OsFile*, const char*);
int sqlite3OsRead(OsFile*, void*, int amt);
int sqlite3OsWrite(OsFile*, const void*, int amt);
int sqlite3OsSeek(OsFile*, i64 offset);
int sqlite3OsTruncate(OsFile*, i64 size);
int sqlite3OsSync(OsFile*, int);
void sqlite3OsSetFullSync(OsFile *id, int setting);
int sqlite3OsFileHandle(OsFile *id);
int sqlite3OsFileSize(OsFile*, i64 *pSize);
int sqlite3OsLock(OsFile*, int);
int sqlite3OsUnlock(OsFile*, int);
int sqlite3OsLockState(OsFile *id);
int sqlite3OsCheckReservedLock(OsFile *id);

Changes to src/tclsqlite.c.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
....
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
**    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.
**
*************************************************************************
** A TCL Interface to SQLite
**
** $Id: tclsqlite.c,v 1.145 2006/01/05 15:50:07 drh Exp $
*/
#ifndef NO_TCL     /* Omit this whole file if TCL is unavailable */

#include "sqliteInt.h"
#include "hash.h"
#include "tcl.h"
#include <stdlib.h>
................................................................................

    Sqlitetest1_Init(interp);
    Sqlitetest2_Init(interp);
    Sqlitetest3_Init(interp);
    Sqlitetest4_Init(interp);
    Sqlitetest5_Init(interp);
    Sqlitetest6_Init(interp);
    /* Sqlitetestasync_Init(interp); */
    Md5_Init(interp);
#ifdef SQLITE_SSE
    Sqlitetestsse_Init(interp);
#endif
  }
#endif
  if( argc>=2 || TCLSH==2 ){







|







 







|







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
....
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
**    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.
**
*************************************************************************
** A TCL Interface to SQLite
**
** $Id: tclsqlite.c,v 1.146 2006/01/06 03:29:58 drh Exp $
*/
#ifndef NO_TCL     /* Omit this whole file if TCL is unavailable */

#include "sqliteInt.h"
#include "hash.h"
#include "tcl.h"
#include <stdlib.h>
................................................................................

    Sqlitetest1_Init(interp);
    Sqlitetest2_Init(interp);
    Sqlitetest3_Init(interp);
    Sqlitetest4_Init(interp);
    Sqlitetest5_Init(interp);
    Sqlitetest6_Init(interp);
    Sqlitetestasync_Init(interp);
    Md5_Init(interp);
#ifdef SQLITE_SSE
    Sqlitetestsse_Init(interp);
#endif
  }
#endif
  if( argc>=2 || TCLSH==2 ){

Changes to src/test_async.c.

231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
...
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
...
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
...
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
...
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
...
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
...
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
...
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
...
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
...
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
...
922
923
924
925
926
927
928
929
** to sqlite3_async_flush() is responsible for calling sqliteFree().
**
** Once an AsyncWrite structure has been added to the list, it must not be
** read or modified by the caller (in case another thread calls
** sqlite3_async_flush() ).
*/
static void addAsyncWrite(AsyncWrite *pWrite){
  sqlite3_os_enter_mutex();
  assert( !pWrite->pNext );
  if( sqlite3_asyncListLast ){
    assert( sqlite3_asyncListFirst );
    sqlite3_asyncListLast->pNext = pWrite;
  }else{
    sqlite3_asyncListFirst = pWrite;
  }
  sqlite3_asyncListLast = pWrite;
  sqlite3_os_leave_mutex();
}

/*
** The caller should already hold the mutex when this is called.
*/
static void removeAsyncWrite(AsyncWrite *p){
  assert( p==sqlite3_asyncListFirst );
................................................................................
static int asyncRead(OsFile *id, void *obuf, int amt){
  int rc = SQLITE_OK;
  i64 filesize;
  int nRead;
  AsyncFile *pFile = (AsyncFile *)id;

  /* Grab the mutex for the duration of the call */
  sqlite3_os_enter_mutex();

  if( pFile->pBaseRead ){
    rc = sqlite3OsFileSize(pFile->pBaseRead, &filesize);
    if( rc!=SQLITE_OK ){
      goto asyncread_out;
    }
    rc = sqlite3OsSeek(pFile->pBaseRead, pFile->iOffset);
................................................................................
      }
    }

    pFile->iOffset += (i64)amt;
  }

asyncread_out:
  sqlite3_os_leave_mutex();
  return rc;
}

/*
** Seek to the specified offset. This just adjusts the AsyncFile.iOffset 
** variable - calling seek() on the underlying file is defered until the 
** next read() or write() operation. 
................................................................................
**
** This method holds the mutex from start to finish.
*/
int asyncFileSize(OsFile *id, i64 *pSize){
  int rc = SQLITE_OK;
  i64 s = 0;
  OsFile *pBase;
  sqlite3_os_enter_mutex();

  /* Read the filesystem size from the base file. If pBaseRead is NULL, this
  ** means the file hasn't been opened yet. In this case all relevant data 
  ** must be in the write-op queue anyway, so we can omit reading from the
  ** file-system.
  */
  pBase = ((AsyncFile *)id)->pBaseRead;
................................................................................
            s = MIN(s, p->nByte);
            break;
        }
      }
    }
    *pSize = s;
  }
  sqlite3_os_leave_mutex();
  return rc;
}

/*
** Return the operating system file handle. This is only used for debugging 
** at the moment anyway.
*/
................................................................................
** in the file system. 
**
** This method holds the mutex from start to finish.
*/
static int asyncFileExists(const char *z){
  int ret;
  AsyncWrite *p;
  sqlite3_os_enter_mutex();

  /* See if the real file system contains the specified file.  */
  ret = xOrigFileExists(z);
  
  for(p=sqlite3_asyncListFirst; p; p = p->pNext){
    if( p->op==ASYNC_DELETE && 0==strcmp(p->zBuf, z) ){
      ret = 0;
    }else if( p->op==ASYNC_OPENEXCLUSIVE && 0==strcmp(p->zBuf, z) ){
      ret = 1;
    }
  }

  sqlite3_os_leave_mutex();
  return ret;
}

/*
** The following routine is one of two exported symbols in this module (along
** with sqlite3_async_flush(), see below). This routine should be called
** once to enable the asynchronous IO features implemented in this file. If 
** the features are successfully enabled (or if they have already been 
** enabled) then SQLITE_OK is returned. Otherwise, SQLITE_MISUSE.
*/
int sqlite3_async_enable(void){
  if( xOrigOpenReadWrite==0 ){
#define ROUTINE(a,b,c) {(void**)&a,SQLITE_OS_ROUTINE_ ## b,(void *)c}
    struct ReplacementOp {
      void ** pOldRoutine;
      int eRoutine;
      void * pNewRoutine;
    } aRoutines[] = {
      ROUTINE(xOrigOpenReadWrite, OPENREADWRITE, asyncOpenReadWrite),
      ROUTINE(xOrigOpenReadOnly, OPENREADONLY, asyncOpenReadOnly), 
      ROUTINE(xOrigOpenExclusive, OPENEXCLUSIVE, asyncOpenExclusive), 
      ROUTINE(xOrigDelete, DELETE, asyncDelete), 
      ROUTINE(xOrigFileExists, FILEEXISTS, asyncFileExists), 
      ROUTINE(xOrigSyncDirectory, SYNCDIRECTORY, asyncSyncDirectory)
    };
#undef ROUTINE
    int i;

    sqlite3_os_enter_mutex();
    for(i=0; i<sizeof(aRoutines)/sizeof(aRoutines[0]); i++){
      struct ReplacementOp *p = &aRoutines[i];
      *(p->pOldRoutine) = sqlite3_os_routine_set(p->eRoutine, p->pNewRoutine);
    }
    sqlite3_os_leave_mutex();
  }
  return SQLITE_OK;
}

/* 
** This function is called externally to perform queued write and sync
** operations. It returns when an IO error occurs or there are no more queued
................................................................................
  int rc = SQLITE_OK;

  /* Grab the mutex and set the sqlite3_asyncIoBusy flag to make sure this
  ** is the only thread performing an sqlite3_async_flush() at this time.
  ** Or, if some other thread is already inside this function, return 
  ** SQLITE_BUSY to the caller.
  */
  sqlite3_os_enter_mutex();
  if( sqlite3_asyncIoBusy ){
    sqlite3_os_leave_mutex();
    return SQLITE_BUSY;
  }
  sqlite3_asyncIoBusy = 1;

  while( (p = sqlite3_asyncListFirst) && rc==SQLITE_OK ){
    int isInsideMutex = 1;

................................................................................
    if( p->pFile ){
      pBase = p->pFile->pBaseWrite;
      if( 
        p->op==ASYNC_CLOSE || 
        p->op==ASYNC_OPENEXCLUSIVE ||
        (pBase && (p->op==ASYNC_SYNC || p->op==ASYNC_WRITE) ) 
      ){
        sqlite3_os_leave_mutex();
        isInsideMutex = 0;
      }
      if( !pBase ){
        pBase = p->pFile->pBaseRead;
      }
    }

................................................................................

      case ASYNC_OPENEXCLUSIVE: {
        AsyncFile *pFile = p->pFile;
        int delFlag = ((p->iOffset)?1:0);
        OsFile *pBase = 0;
        rc = xOrigOpenExclusive(p->zBuf, &pBase, delFlag);

        sqlite3_os_enter_mutex();
        isInsideMutex = 1;
        if( rc==SQLITE_OK ){
          pFile->pBaseRead = pBase;
        }
        break;
      }

................................................................................
    }

    /* If we didn't hang on to the mutex during the IO op, obtain it now
    ** so that the AsyncWrite structure can be safely removed from the 
    ** global write-op queue.
    */
    if( !isInsideMutex ){
      sqlite3_os_enter_mutex();
    }
    if( rc==SQLITE_OK ){
      removeAsyncWrite(p);
      sqlite3Os.xFree(p);
    }
  }

  /* Clear the io-busy flag and exit the mutex */
  assert( sqlite3_asyncIoBusy );
  sqlite3_asyncIoBusy = 0;
  sqlite3_os_leave_mutex();

  return rc;
}

/*
** The following code defines a Tcl interface for testing the asynchronous 
** IO implementation in this file.
................................................................................
int Sqlitetestasync_Init(Tcl_Interp *interp){
  Tcl_CreateObjCommand(interp,"sqlite3_async_enable",testAsyncEnable,0,0);
  Tcl_CreateObjCommand(interp,"sqlite3_async_flush",testAsyncFlush,0,0);
  return TCL_OK;
}

#endif








|








|







 







|







 







|







 







|







 







|







 







|












|












|
|
|
|
|
|
|
|
|
|
|
|
|
<
<
<
<
<
<
<
<
<







 







|

|







 







|







 







|







 







|










|







 







<
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
...
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
...
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
...
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
...
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
...
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663









664
665
666
667
668
669
670
...
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
...
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
...
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
...
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
...
913
914
915
916
917
918
919

** to sqlite3_async_flush() is responsible for calling sqliteFree().
**
** Once an AsyncWrite structure has been added to the list, it must not be
** read or modified by the caller (in case another thread calls
** sqlite3_async_flush() ).
*/
static void addAsyncWrite(AsyncWrite *pWrite){
  sqlite3Os.xEnterMutex();
  assert( !pWrite->pNext );
  if( sqlite3_asyncListLast ){
    assert( sqlite3_asyncListFirst );
    sqlite3_asyncListLast->pNext = pWrite;
  }else{
    sqlite3_asyncListFirst = pWrite;
  }
  sqlite3_asyncListLast = pWrite;
  sqlite3Os.xLeaveMutex();
}

/*
** The caller should already hold the mutex when this is called.
*/
static void removeAsyncWrite(AsyncWrite *p){
  assert( p==sqlite3_asyncListFirst );
................................................................................
static int asyncRead(OsFile *id, void *obuf, int amt){
  int rc = SQLITE_OK;
  i64 filesize;
  int nRead;
  AsyncFile *pFile = (AsyncFile *)id;

  /* Grab the mutex for the duration of the call */
  sqlite3Os.xEnterMutex();

  if( pFile->pBaseRead ){
    rc = sqlite3OsFileSize(pFile->pBaseRead, &filesize);
    if( rc!=SQLITE_OK ){
      goto asyncread_out;
    }
    rc = sqlite3OsSeek(pFile->pBaseRead, pFile->iOffset);
................................................................................
      }
    }

    pFile->iOffset += (i64)amt;
  }

asyncread_out:
  sqlite3Os.xLeaveMutex();
  return rc;
}

/*
** Seek to the specified offset. This just adjusts the AsyncFile.iOffset 
** variable - calling seek() on the underlying file is defered until the 
** next read() or write() operation. 
................................................................................
**
** This method holds the mutex from start to finish.
*/
int asyncFileSize(OsFile *id, i64 *pSize){
  int rc = SQLITE_OK;
  i64 s = 0;
  OsFile *pBase;
  sqlite3Os.xEnterMutex();

  /* Read the filesystem size from the base file. If pBaseRead is NULL, this
  ** means the file hasn't been opened yet. In this case all relevant data 
  ** must be in the write-op queue anyway, so we can omit reading from the
  ** file-system.
  */
  pBase = ((AsyncFile *)id)->pBaseRead;
................................................................................
            s = MIN(s, p->nByte);
            break;
        }
      }
    }
    *pSize = s;
  }
  sqlite3Os.xLeaveMutex();
  return rc;
}

/*
** Return the operating system file handle. This is only used for debugging 
** at the moment anyway.
*/
................................................................................
** in the file system. 
**
** This method holds the mutex from start to finish.
*/
static int asyncFileExists(const char *z){
  int ret;
  AsyncWrite *p;
  sqlite3Os.xEnterMutex();

  /* See if the real file system contains the specified file.  */
  ret = xOrigFileExists(z);
  
  for(p=sqlite3_asyncListFirst; p; p = p->pNext){
    if( p->op==ASYNC_DELETE && 0==strcmp(p->zBuf, z) ){
      ret = 0;
    }else if( p->op==ASYNC_OPENEXCLUSIVE && 0==strcmp(p->zBuf, z) ){
      ret = 1;
    }
  }

  sqlite3Os.xLeaveMutex();
  return ret;
}

/*
** The following routine is one of two exported symbols in this module (along
** with sqlite3_async_flush(), see below). This routine should be called
** once to enable the asynchronous IO features implemented in this file. If 
** the features are successfully enabled (or if they have already been 
** enabled) then SQLITE_OK is returned. Otherwise, SQLITE_MISUSE.
*/
int sqlite3_async_enable(void){
  if( xOrigOpenReadWrite==0 ){
    xOrigOpenReadWrite = sqlite3Os.xOpenReadWrite;
    xOrigOpenReadOnly = sqlite3Os.xOpenReadOnly;
    xOrigOpenExclusive = sqlite3Os.xOpenExclusive;
    xOrigDelete = sqlite3Os.xDelete;
    xOrigFileExists = sqlite3Os.xFileExists;
    xOrigSyncDirectory = sqlite3Os.xSyncDirectory;

    sqlite3Os.xOpenReadWrite = asyncOpenReadWrite;
    sqlite3Os.xOpenReadOnly = asyncOpenReadOnly;
    sqlite3Os.xOpenExclusive = asyncOpenExclusive;
    sqlite3Os.xDelete = asyncDelete;
    sqlite3Os.xFileExists = asyncFileExists;
    sqlite3Os.xSyncDirectory = asyncSyncDirectory;









  }
  return SQLITE_OK;
}

/* 
** This function is called externally to perform queued write and sync
** operations. It returns when an IO error occurs or there are no more queued
................................................................................
  int rc = SQLITE_OK;

  /* Grab the mutex and set the sqlite3_asyncIoBusy flag to make sure this
  ** is the only thread performing an sqlite3_async_flush() at this time.
  ** Or, if some other thread is already inside this function, return 
  ** SQLITE_BUSY to the caller.
  */
  sqlite3Os.xEnterMutex();
  if( sqlite3_asyncIoBusy ){
    sqlite3Os.xLeaveMutex();
    return SQLITE_BUSY;
  }
  sqlite3_asyncIoBusy = 1;

  while( (p = sqlite3_asyncListFirst) && rc==SQLITE_OK ){
    int isInsideMutex = 1;

................................................................................
    if( p->pFile ){
      pBase = p->pFile->pBaseWrite;
      if( 
        p->op==ASYNC_CLOSE || 
        p->op==ASYNC_OPENEXCLUSIVE ||
        (pBase && (p->op==ASYNC_SYNC || p->op==ASYNC_WRITE) ) 
      ){
        sqlite3Os.xLeaveMutex();
        isInsideMutex = 0;
      }
      if( !pBase ){
        pBase = p->pFile->pBaseRead;
      }
    }

................................................................................

      case ASYNC_OPENEXCLUSIVE: {
        AsyncFile *pFile = p->pFile;
        int delFlag = ((p->iOffset)?1:0);
        OsFile *pBase = 0;
        rc = xOrigOpenExclusive(p->zBuf, &pBase, delFlag);

        sqlite3Os.xEnterMutex();
        isInsideMutex = 1;
        if( rc==SQLITE_OK ){
          pFile->pBaseRead = pBase;
        }
        break;
      }

................................................................................
    }

    /* If we didn't hang on to the mutex during the IO op, obtain it now
    ** so that the AsyncWrite structure can be safely removed from the 
    ** global write-op queue.
    */
    if( !isInsideMutex ){
      sqlite3Os.xEnterMutex();
    }
    if( rc==SQLITE_OK ){
      removeAsyncWrite(p);
      sqlite3Os.xFree(p);
    }
  }

  /* Clear the io-busy flag and exit the mutex */
  assert( sqlite3_asyncIoBusy );
  sqlite3_asyncIoBusy = 0;
  sqlite3Os.xLeaveMutex();

  return rc;
}

/*
** The following code defines a Tcl interface for testing the asynchronous 
** IO implementation in this file.
................................................................................
int Sqlitetestasync_Init(Tcl_Interp *interp){
  Tcl_CreateObjCommand(interp,"sqlite3_async_enable",testAsyncEnable,0,0);
  Tcl_CreateObjCommand(interp,"sqlite3_async_flush",testAsyncFlush,0,0);
  return TCL_OK;
}

#endif

Added test/format4.test.































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
# 2005 December 29
#
# 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 implements regression tests for SQLite library.
#
# This file implements tests to verify that the new serial_type
# values of 8 (integer 0) and 9 (integer 1) work correctly.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl

do_test format4-1.1 {
  execsql {
    CREATE TABLE t1(x0,x1,x2,x3,x4,x5,x6,x7,x8,x9);
    INSERT INTO t1 VALUES(0,0,0,0,0,0,0,0,0,0);
    INSERT INTO t1 SELECT * FROM t1;
    INSERT INTO t1 SELECT * FROM t1;
    INSERT INTO t1 SELECT * FROM t1;
    INSERT INTO t1 SELECT * FROM t1;
    INSERT INTO t1 SELECT * FROM t1;
    INSERT INTO t1 SELECT * FROM t1;
  }
  file size test.db
} {2048}
do_test format4-1.2 {
  execsql {
    UPDATE t1 SET x0=1, x1=1, x2=1, x3=1, x4=1, x5=1, x6=1, x7=1, x8=1, x9=1
  }
  file size test.db
} {2048}
do_test format4-1.3 {
  execsql {
    UPDATE t1 SET x0=2, x1=2, x2=2, x3=2, x4=2, x5=2, x6=2, x7=2, x8=2, x9=2
  }
  file size test.db
} {4096}


finish_test