SQLite

Check-in [a4470313]
Login

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

Overview
Comment:Fix a problem with rolling back hot journals using the unix-dotfile VFS.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: a44703135e8dd3cc67e548e1aa3c42e71df127fb7b593ccfc06025ec42a501fd
User & Date: dan 2024-06-12 15:50:35
Context
2024-06-12
21:01
Remove some JS docs which no longer apply. No code changes. (check-in: f253cab3 user: stephan tags: trunk)
15:50
Fix a problem with rolling back hot journals using the unix-dotfile VFS. (check-in: a4470313 user: dan tags: trunk)
15:29
Omit tests that depend on sqlite3_release_memory() in lock5.test when running the memsubsys1 or memsubsys2 permutations. (Closed-Leaf check-in: 9d63033b user: dan tags: unix-dotfile-fix)
12:36
Fix a potential db corruption case triggered by the OPFS VFS's xCheckReservedLock() implementation, as discussed in forum thread a2f573b00cda1372. (check-in: c298b8ba user: stephan tags: trunk)
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/os_unix.c.

2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297


2298

2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
** The file suffix added to the data base filename in order to create the
** lock directory.
*/
#define DOTLOCK_SUFFIX ".lock"

/*
** This routine checks if there is a RESERVED lock held on the specified
** file by this or any other process. If such a lock is held, set *pResOut
** to a non-zero value otherwise *pResOut is set to zero.  The return value
** is set to SQLITE_OK unless an I/O error occurs during lock checking.
**
** In dotfile locking, either a lock exists or it does not.  So in this
** variation of CheckReservedLock(), *pResOut is set to true if any lock
** is held on the file and false if the file is unlocked.
*/
static int dotlockCheckReservedLock(sqlite3_file *id, int *pResOut) {
  int rc = SQLITE_OK;
  int reserved = 0;
  unixFile *pFile = (unixFile*)id;

  SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );

  assert( pFile );


  reserved = osAccess((const char*)pFile->lockingContext, 0)==0;

  OSTRACE(("TEST WR-LOCK %d %d %d (dotlock)\n", pFile->h, rc, reserved));
  *pResOut = reserved;
  return rc;
}

/*
** Lock the file with the lock specified by parameter eFileLock - one
** of the following:
**
**     (1) SHARED_LOCK







|
|
|
<
<
<
|


<
<

<


|
>
>
|
>
|
<
|







2275
2276
2277
2278
2279
2280
2281
2282
2283
2284



2285
2286
2287


2288

2289
2290
2291
2292
2293
2294
2295
2296

2297
2298
2299
2300
2301
2302
2303
2304
** The file suffix added to the data base filename in order to create the
** lock directory.
*/
#define DOTLOCK_SUFFIX ".lock"

/*
** This routine checks if there is a RESERVED lock held on the specified
** file by this or any other process. If the caller holds a SHARED
** or greater lock when it is called, then it is assumed that no other
** client may hold RESERVED. Or, if the caller holds no lock, then it



** is assumed another client holds RESERVED if the lock-file exists.
*/
static int dotlockCheckReservedLock(sqlite3_file *id, int *pResOut) {


  unixFile *pFile = (unixFile*)id;

  SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );

  if( pFile->eFileLock>=SHARED_LOCK ){
    *pResOut = 0;
  }else{
    *pResOut = osAccess((const char*)pFile->lockingContext, 0)==0;
  }
  OSTRACE(("TEST WR-LOCK %d %d %d (dotlock)\n", pFile->h, 0, *pResOut));

  return SQLITE_OK;
}

/*
** Lock the file with the lock specified by parameter eFileLock - one
** of the following:
**
**     (1) SHARED_LOCK

Changes to test/lock5.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
# 2008 June 28
#
# 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.  The
# focus of this script is database locks.
#
# $Id: lock5.test,v 1.6 2008/12/04 12:34:16 drh Exp $

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


# This file is only run if using the unix backend compiled with the
# SQLITE_ENABLE_LOCKING_STYLE macro.
db close
if {[catch {sqlite3 db test.db -vfs unix-none} msg]} {
  finish_test
  return













<



>







1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
21
22
23
24
# 2008 June 28
#
# 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.  The
# focus of this script is database locks.
#


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

# This file is only run if using the unix backend compiled with the
# SQLITE_ENABLE_LOCKING_STYLE macro.
db close
if {[catch {sqlite3 db test.db -vfs unix-none} msg]} {
  finish_test
  return
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
  db close
  file exists test.db.lock
} {0}

#####################################################################

forcedelete test.db
if {[catch {sqlite3 db test.db -vfs unix-flock} msg]} {
  finish_test
  return
}

do_test lock5-flock.1 {
  sqlite3 db test.db -vfs unix-flock
  execsql {
    CREATE TABLE t1(a, b);
    BEGIN;
    INSERT INTO t1 VALUES(1, 2);







|
<
<
<







97
98
99
100
101
102
103
104



105
106
107
108
109
110
111
  db close
  file exists test.db.lock
} {0}

#####################################################################

forcedelete test.db
if {0==[catch {sqlite3 db test.db -vfs unix-flock} msg]} {




do_test lock5-flock.1 {
  sqlite3 db test.db -vfs unix-flock
  execsql {
    CREATE TABLE t1(a, b);
    BEGIN;
    INSERT INTO t1 VALUES(1, 2);
144
145
146
147
148
149
150
151


152


153
154
155
156
157
158


159
160
161
162
163
164
165
  db close
  catchsql { SELECT * FROM t1 } db2
} {0 {1 2}}

do_test lock5-flock.8 {
  db2 close
} {}



#####################################################################



do_test lock5-none.1 {
  sqlite3 db test.db -vfs unix-none
  sqlite3 db2 test.db -vfs unix-none
  execsql { PRAGMA mmap_size = 0 } db2
  execsql {


    BEGIN;
    INSERT INTO t1 VALUES(3, 4);
  }
} {}
do_test lock5-none.2 {
  execsql { SELECT * FROM t1 }
} {1 2 3 4}








>
>

>
>






>
>







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
  db close
  catchsql { SELECT * FROM t1 } db2
} {0 {1 2}}

do_test lock5-flock.8 {
  db2 close
} {}

}

#####################################################################

reset_db

do_test lock5-none.1 {
  sqlite3 db test.db -vfs unix-none
  sqlite3 db2 test.db -vfs unix-none
  execsql { PRAGMA mmap_size = 0 } db2
  execsql {
    CREATE TABLE t1(a, b);
    INSERT INTO t1 VALUES(1, 2);
    BEGIN;
    INSERT INTO t1 VALUES(3, 4);
  }
} {}
do_test lock5-none.2 {
  execsql { SELECT * FROM t1 }
} {1 2 3 4}
174
175
176
177
178
179
180

181
182
183
184
185
186

187
188
189
190
191
192
193
194






































































195
196


} {1 2}
do_test lock5-none.5 {
  execsql COMMIT
  execsql {SELECT * FROM t1} db2
} {1 2}

ifcapable memorymanage {

  do_test lock5-none.6 {
    sqlite3_release_memory 1000000
    execsql {SELECT * FROM t1} db2
  } {1 2 3 4}
}


do_test lock5-none.X {
  db close
  db2 close
} {}

ifcapable lock_proxy_pragmas {
  set env(SQLITE_FORCE_PROXY_LOCKING) $::using_proxy
}







































































finish_test









>
|
|
|
|
|
|
>








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


>
>
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
} {1 2}
do_test lock5-none.5 {
  execsql COMMIT
  execsql {SELECT * FROM t1} db2
} {1 2}

ifcapable memorymanage {
  if {[permutation]!="memsubsys1" && [permutation]!="memsubsys2"} { 
    do_test lock5-none.6 {
      sqlite3_release_memory 1000000
      execsql {SELECT * FROM t1} db2
    } {1 2 3 4}
  }
}

do_test lock5-none.X {
  db close
  db2 close
} {}

ifcapable lock_proxy_pragmas {
  set env(SQLITE_FORCE_PROXY_LOCKING) $::using_proxy
}

#####################################################################
reset_db
if {[permutation]!="inmemory_journal"} {
  
  # 1. Create a large database using the unix-dotfile VFS
  # 2. Write a large transaction to the db, so that the cache spills, but do
  #    not commit it.
  # 3. Make a copy of the database files on disk.
  # 4. Try to read from the copy using unix-dotfile VFS. This fails because
  #    the dotfile still exists, so SQLite things the database is locked.
  # 5. Remove the dotfile.
  # 6. Try to read the db again. This time, the old transaction is rolled
  #    back and the read permitted.
  #
  do_test 2.dotfile.1 {
    sqlite3 db test.db -vfs unix-dotfile
    execsql {
      PRAGMA cache_size = 10;
      CREATE TABLE t1(x, y, z);
      CREATE INDEX t1x ON t1(x);
      WITH s(i) AS (
        SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<1000
      )
      INSERT INTO t1 SELECT hex(randomblob(20)), hex(randomblob(500)), i FROM s;
    }
  } {}
  
  do_execsql_test 2.dotfile.2 {
    BEGIN;
      UPDATE t1 SET z=z+1, x=hex(randomblob(20));
  }
  
  do_test 2.dotfile.3 {
    list                            \
      [file exists test.db]         \
      [file exists test.db-journal] \
      [file exists test.db.lock]
  } {1 1 1}
  
  do_test 2.dotfile.4 {
    forcecopy test.db test.db2
    forcecopy test.db-journal test.db2-journal
    file mkdir test.db2.lock
  
    sqlite3 db2 test.db2 -vfs unix-dotfile
    catchsql {
      SELECT count(*) FROM t1;
    } db2
  } {1 {database is locked}}
  
  do_test 2.dotfile.5 {
    file delete test.db2.lock
    execsql {
      PRAGMA integrity_check
    } db2
  } {ok}
  
  db2 close
  
  do_test 2.dotfile.6 {
    forcecopy test.db test.db2
    forcecopy test.db-journal test.db2-journal
  
    sqlite3 db2 file:test.db2?nolock=1 -vfs unix-dotfile -uri 1
    catchsql {
      SELECT count(*) FROM t1;
    } db2
  } {0 1000}
}

finish_test