/ Check-in [d33771a3]
Login

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

Overview
Comment:Do not invoke the busy callback when trying to promote a lock from SHARED to RESERVED. This avoids a deadlock. (CVS 1879)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:d33771a303d9c20dd477b1a973024ff763203211
User & Date: drh 2004-08-07 23:54:48
Context
2004-08-08
19:43
Attempting to open a locked table for writing should fail immediately. Ticket #842. (CVS 1880) check-in: fc879a9b user: drh tags: trunk
2004-08-07
23:54
Do not invoke the busy callback when trying to promote a lock from SHARED to RESERVED. This avoids a deadlock. (CVS 1879) check-in: d33771a3 user: drh tags: trunk
2004-08-06
17:00
Fix a bug in the logic that converts numbers into strings inside the VM. Ticket #844 (CVS 1878) check-in: 863540be user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/pager.c.

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
....
2410
2411
2412
2413
2414
2415
2416

2417
2418
2419
2420
2421
2422
2423
2424


2425







2426
2427
2428
2429
2430
2431
2432
** The pager is used to access a database disk file.  It implements
** atomic commit and rollback through the use of a journal file that
** is separate from the database file.  The pager also implements file
** locking to prevent two processes from writing the same database
** file simultaneously, or one process from reading the database while
** another is writing.
**
** @(#) $Id: pager.c,v 1.153 2004/07/22 15:02:25 drh Exp $
*/
#include "os.h"         /* Must be first to enable large file support */
#include "sqliteInt.h"
#include "pager.h"
#include <assert.h>
#include <string.h>

................................................................................
  assert( pPager->state!=PAGER_UNLOCK );
  if( pPager->state==PAGER_SHARED ){
    assert( pPager->aInJournal==0 );
    if( pPager->memDb ){
      pPager->state = PAGER_EXCLUSIVE;
      pPager->origDbSize = pPager->dbSize;
    }else{

      int busy = 1;
      do {
        rc = sqlite3OsLock(&pPager->fd, RESERVED_LOCK);
      }while( rc==SQLITE_BUSY && 
          pPager->pBusyHandler && 
          pPager->pBusyHandler->xFunc && 
          pPager->pBusyHandler->xFunc(pPager->pBusyHandler->pArg, busy++)
      );


      if( rc!=SQLITE_OK ){







        return rc;
      }
      pPager->state = PAGER_RESERVED;
      pPager->dirtyCache = 0;
      TRACE2("TRANSACTION %d\n", pPager->fd.h);
      if( pPager->useJournal && !pPager->tempFile ){
        rc = pager_open_journal(pPager);







|







 







>








>
>

>
>
>
>
>
>
>







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
....
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
** The pager is used to access a database disk file.  It implements
** atomic commit and rollback through the use of a journal file that
** is separate from the database file.  The pager also implements file
** locking to prevent two processes from writing the same database
** file simultaneously, or one process from reading the database while
** another is writing.
**
** @(#) $Id: pager.c,v 1.154 2004/08/07 23:54:48 drh Exp $
*/
#include "os.h"         /* Must be first to enable large file support */
#include "sqliteInt.h"
#include "pager.h"
#include <assert.h>
#include <string.h>

................................................................................
  assert( pPager->state!=PAGER_UNLOCK );
  if( pPager->state==PAGER_SHARED ){
    assert( pPager->aInJournal==0 );
    if( pPager->memDb ){
      pPager->state = PAGER_EXCLUSIVE;
      pPager->origDbSize = pPager->dbSize;
    }else{
#if 0
      int busy = 1;
      do {
        rc = sqlite3OsLock(&pPager->fd, RESERVED_LOCK);
      }while( rc==SQLITE_BUSY && 
          pPager->pBusyHandler && 
          pPager->pBusyHandler->xFunc && 
          pPager->pBusyHandler->xFunc(pPager->pBusyHandler->pArg, busy++)
      );
#endif
      rc = sqlite3OsLock(&pPager->fd, RESERVED_LOCK);
      if( rc!=SQLITE_OK ){
        /* We do not call the busy handler when we fail to get a reserved lock.
        ** The only reason we might fail is because another process is holding
        ** the reserved lock.  But the other process will not be able to
        ** release its reserved lock until this process releases its shared
        ** lock.  So we might as well fail in this process, let it release
        ** its shared lock so that the other process can commit.
        */
        return rc;
      }
      pPager->state = PAGER_RESERVED;
      pPager->dirtyCache = 0;
      TRACE2("TRANSACTION %d\n", pPager->fd.h);
      if( pPager->useJournal && !pPager->tempFile ){
        rc = pager_open_journal(pPager);

Changes to src/sqliteInt.h.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
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
**    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.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.313 2004/08/04 14:29:23 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_

#include "config.h"
#include "sqlite3.h"
#include "hash.h"
................................................................................

/*
** This macro casts a pointer to an integer.  Useful for doing
** pointer arithmetic.
*/
#define Addr(X)  ((uptr)X)

/*
** The maximum number of bytes of data that can be put into a single
** row of a single table.  The upper bound on this limit is
** 9223372036854775808 bytes (or 2**63).  We have arbitrarily set the
** limit to just 1MB here because the overflow page chain is inefficient
** for really big records and we want to discourage people from thinking that 
** multi-megabyte records are OK.  If your needs are different, you can
** change this define and recompile to increase or decrease the record
** size.
*/
#define MAX_BYTES_PER_ROW  1048576

/*
** If memory allocation problems are found, recompile with
**
**      -DSQLITE_DEBUG=1
**
** to enable some sanity checking on malloc() and free().  To
** check for memory leaks, recompile with







|







 







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







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
169
170
171
172
173
174
175












176
177
178
179
180
181
182
**    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.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.314 2004/08/07 23:54:48 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_

#include "config.h"
#include "sqlite3.h"
#include "hash.h"
................................................................................

/*
** This macro casts a pointer to an integer.  Useful for doing
** pointer arithmetic.
*/
#define Addr(X)  ((uptr)X)













/*
** If memory allocation problems are found, recompile with
**
**      -DSQLITE_DEBUG=1
**
** to enable some sanity checking on malloc() and free().  To
** check for memory leaks, recompile with

Changes to src/vdbe.c.

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
....
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.406 2004/07/24 17:38:29 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include "vdbeInt.h"

/*
................................................................................
    nHdr += sqlite3VarintLen(serial_type);
  }

  /* Add the initial header varint and total the size */
  nHdr += sqlite3VarintLen(nHdr);
  nByte = nHdr+nData;

  if( nByte>MAX_BYTES_PER_ROW ){
    rc = SQLITE_TOOBIG;
    goto abort_due_to_error;
  }

  /* Allocate space for the new record. */
  if( nByte>sizeof(zTemp) ){
    zNewRecord = sqliteMallocRaw(nByte);
    if( !zNewRecord ){
      goto no_mem;
    }
  }else{







|







 







<
<
<
<
<







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
....
2076
2077
2078
2079
2080
2081
2082





2083
2084
2085
2086
2087
2088
2089
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.407 2004/08/07 23:54:48 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include "vdbeInt.h"

/*
................................................................................
    nHdr += sqlite3VarintLen(serial_type);
  }

  /* Add the initial header varint and total the size */
  nHdr += sqlite3VarintLen(nHdr);
  nByte = nHdr+nData;






  /* Allocate space for the new record. */
  if( nByte>sizeof(zTemp) ){
    zNewRecord = sqliteMallocRaw(nByte);
    if( !zNewRecord ){
      goto no_mem;
    }
  }else{

Changes to test/bigrow.test.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
201
202
203
204
205
206
207
208
209
210
211









212
213
214
215
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is stressing the library by putting large amounts
# of data in a single row of a table.
#
# $Id: bigrow.test,v 1.4 2001/11/24 00:31:47 drh Exp $

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

# Make a big string that we can use for test data
#
do_test bigrow-1.0 {
................................................................................
      UPDATE t1 SET b=b||b;
      SELECT a,length(b),c FROM t1;
    }
  } "one $sz hi"
  incr i
}
do_test bigrow-5.3 {
  set r [catch {execsql {UPDATE t1 SET b=b||b}} msg]
  lappend r $msg
} {1 {too much data for one table row}}
do_test bigrow-5.4 {









  execsql {DROP TABLE t1}
} {}

finish_test







|







 







|
|
<

>
>
>
>
>
>
>
>
>




8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
201
202
203
204
205
206
207
208
209

210
211
212
213
214
215
216
217
218
219
220
221
222
223
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is stressing the library by putting large amounts
# of data in a single row of a table.
#
# $Id: bigrow.test,v 1.5 2004/08/07 23:54:48 drh Exp $

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

# Make a big string that we can use for test data
#
do_test bigrow-1.0 {
................................................................................
      UPDATE t1 SET b=b||b;
      SELECT a,length(b),c FROM t1;
    }
  } "one $sz hi"
  incr i
}
do_test bigrow-5.3 {
  catchsql {UPDATE t1 SET b=b||b}
} {0 {}}

do_test bigrow-5.4 {
  execsql {SELECT length(b) FROM t1}
} 1966080
do_test bigrow-5.5 {
  catchsql {UPDATE t1 SET b=b||b}
} {0 {}}
do_test bigrow-5.6 {
  execsql {SELECT length(b) FROM t1}
} 3932160
do_test bigrow-5.99 {
  execsql {DROP TABLE t1}
} {}

finish_test

Changes to test/lock.test.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
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
...
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
#    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: lock.test,v 1.26 2004/06/19 00:16:31 drh Exp $


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

# Create an alternative connection to the database
#
................................................................................
# A thread can read when another has a RESERVED lock.
#
do_test lock-2.2 {
  catchsql {SELECT * FROM t2} db2
} {0 {9 8}}

# If the other thread (the one that does not hold the transaction with
# a RESERVED lock) tries to get a RESERVED lock, we get a busy callback.
#
do_test lock-2.3 {
  proc callback {count} {
    set ::callback_value $count
    break
  }
  set ::callback_value {}
  db2 busy callback
  set r [catch {execsql {UPDATE t1 SET a=b, b=a} db2} msg]
  lappend r $msg
  lappend r $::callback_value
} {1 {database is locked} 1}
do_test lock-2.4 {
  proc callback {count} {
    lappend ::callback_value $count
    if {$count>4} break
  }
  set ::callback_value {}
  db2 busy callback
  set r [catch {execsql {UPDATE t1 SET a=b, b=a} db2} msg]
  lappend r $msg
  lappend r $::callback_value
} {1 {database is locked} {1 2 3 4 5}}
do_test lock-2.5 {
  proc callback {count} {
    lappend ::callback_value $count
    if {$count>4} break
  }
  set ::callback_value {}
  db2 busy callback
  set r [catch {execsql {SELECT * FROM t1} db2} msg]
  lappend r $msg
  lappend r $::callback_value
} {0 {2 1} {}}

# In this test, the 3rd invocation of the busy callback causes
# the first thread to release its transaction.  That allows the
# second thread to continue.
#
do_test lock-2.6 {
  proc callback {count} {
    lappend ::callback_value $count
    if {$count>2} {
      execsql {ROLLBACK}
    }
  }
  set ::callback_value {}
  db2 busy callback
  set r [catch {execsql {SELECT * FROM t2} db2} msg]
  lappend r $msg
  lappend r $::callback_value
} {0 {9 8} {}}
do_test lock-2.7 {
  proc callback {count} {
    lappend ::callback_value $count
    if {$count>2} {
      execsql {ROLLBACK}
    }
  }
  set ::callback_value {}
  db2 busy callback
  execsql {BEGIN TRANSACTION} db2
  set r [catch {execsql {UPDATE t1 SET a = 0 WHERE 0} db2} msg]
  execsql {ROLLBACK} db2
  lappend r $msg
  lappend r $::callback_value
} {0 {} {1 2 3}}

# Test the built-in busy timeout handler
#
do_test lock-2.8 {
  db2 timeout 400
  execsql BEGIN
  execsql {UPDATE t1 SET a = 0 WHERE 0}
  catchsql BEGIN db2
  catchsql {UPDATE t1 SET a = 0 WHERE 0} db2
} {1 {database is locked}}
do_test lock-2.9 {
  db2 timeout 0
  execsql COMMIT
} {}
integrity_check lock-2.10
................................................................................
  proc callback {count} {
    lappend ::callback_value $count
    if {$count>4} break
  }
  db2 busy callback
  set rc [catch {db2 eval {UPDATE t1 SET a=0}} msg]
  lappend rc $msg $::callback_value
} {1 {database is locked} {1 2 3 4 5}}
execsql {ROLLBACK}

# When one thread is writing, other threads cannot read.  Except if the
# writing thread is writing to its temporary tables, the other threads
# can still read.  -> Not so in 3.0.  One thread can read while another
# holds a RESERVED lock.
#







|







 







|











|










|











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







|







 







|







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
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
...
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
#    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: lock.test,v 1.27 2004/08/07 23:54:48 drh Exp $


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

# Create an alternative connection to the database
#
................................................................................
# A thread can read when another has a RESERVED lock.
#
do_test lock-2.2 {
  catchsql {SELECT * FROM t2} db2
} {0 {9 8}}

# If the other thread (the one that does not hold the transaction with
# a RESERVED lock) tries to get a RESERVED lock, we do not get a busy callback.
#
do_test lock-2.3 {
  proc callback {count} {
    set ::callback_value $count
    break
  }
  set ::callback_value {}
  db2 busy callback
  set r [catch {execsql {UPDATE t1 SET a=b, b=a} db2} msg]
  lappend r $msg
  lappend r $::callback_value
} {1 {database is locked} {}}
do_test lock-2.4 {
  proc callback {count} {
    lappend ::callback_value $count
    if {$count>4} break
  }
  set ::callback_value {}
  db2 busy callback
  set r [catch {execsql {UPDATE t1 SET a=b, b=a} db2} msg]
  lappend r $msg
  lappend r $::callback_value
} {1 {database is locked} {}}
do_test lock-2.5 {
  proc callback {count} {
    lappend ::callback_value $count
    if {$count>4} break
  }
  set ::callback_value {}
  db2 busy callback
  set r [catch {execsql {SELECT * FROM t1} db2} msg]
  lappend r $msg
  lappend r $::callback_value
} {0 {2 1} {}}









execsql {ROLLBACK}
























# Test the built-in busy timeout handler
#
do_test lock-2.8 {
  db2 timeout 400
  execsql BEGIN
  execsql {UPDATE t1 SET a = 0 WHERE 0}
  # catchsql BEGIN db2
  catchsql {UPDATE t1 SET a = 0 WHERE 0} db2
} {1 {database is locked}}
do_test lock-2.9 {
  db2 timeout 0
  execsql COMMIT
} {}
integrity_check lock-2.10
................................................................................
  proc callback {count} {
    lappend ::callback_value $count
    if {$count>4} break
  }
  db2 busy callback
  set rc [catch {db2 eval {UPDATE t1 SET a=0}} msg]
  lappend rc $msg $::callback_value
} {1 {database is locked} {}}
execsql {ROLLBACK}

# When one thread is writing, other threads cannot read.  Except if the
# writing thread is writing to its temporary tables, the other threads
# can still read.  -> Not so in 3.0.  One thread can read while another
# holds a RESERVED lock.
#