summaryrefslogtreecommitdiffstats
path: root/www/c3ref/unlock_notify.html
blob: 53694d124b4865ad97fb6d0da560bc32aa069306 (plain)
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
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
<!DOCTYPE html>
<html><head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<link href="../sqlite.css" rel="stylesheet">
<title>Unlock Notification</title>
<!-- path=../ -->
</head>
<body>
<div class=nosearch>
<a href="../index.html">
<img class="logo" src="../images/sqlite370_banner.gif" alt="SQLite" border="0">
</a>
<div><!-- IE hack to prevent disappearing logo --></div>
<div class="tagline desktoponly">
Small. Fast. Reliable.<br>Choose any three.
</div>
<div class="menu mainmenu">
<ul>
<li><a href="../index.html">Home</a>
<li class='mobileonly'><a href="javascript:void(0)" onclick='toggle_div("submenu")'>Menu</a>
<li class='wideonly'><a href='../about.html'>About</a>
<li class='desktoponly'><a href="../docs.html">Documentation</a>
<li class='desktoponly'><a href="../download.html">Download</a>
<li class='wideonly'><a href='../copyright.html'>License</a>
<li class='desktoponly'><a href="../support.html">Support</a>
<li class='desktoponly'><a href="../prosupport.html">Purchase</a>
<li class='search' id='search_menubutton'>
<a href="javascript:void(0)" onclick='toggle_search()'>Search</a>
</ul>
</div>
<div class="menu submenu" id="submenu">
<ul>
<li><a href='../about.html'>About</a>
<li><a href='../docs.html'>Documentation</a>
<li><a href='../download.html'>Download</a>
<li><a href='../support.html'>Support</a>
<li><a href='../prosupport.html'>Purchase</a>
</ul>
</div>
<div class="searchmenu" id="searchmenu">
<form method="GET" action="../search">
<select name="s" id="searchtype">
<option value="d">Search Documentation</option>
<option value="c">Search Changelog</option>
</select>
<input type="text" name="q" id="searchbox" value="">
<input type="submit" value="Go">
</form>
</div>
</div>
<script>
function toggle_div(nm) {
var w = document.getElementById(nm);
if( w.style.display=="block" ){
w.style.display = "none";
}else{
w.style.display = "block";
}
}
function toggle_search() {
var w = document.getElementById("searchmenu");
if( w.style.display=="block" ){
w.style.display = "none";
} else {
w.style.display = "block";
setTimeout(function(){
document.getElementById("searchbox").focus()
}, 30);
}
}
function div_off(nm){document.getElementById(nm).style.display="none";}
window.onbeforeunload = function(e){div_off("submenu");}
/* Disable the Search feature if we are not operating from CGI, since */
/* Search is accomplished using CGI and will not work without it. */
if( !location.origin || !location.origin.match || !location.origin.match(/http/) ){
document.getElementById("search_menubutton").style.display = "none";
}
/* Used by the Hide/Show button beside syntax diagrams, to toggle the */
function hideorshow(btn,obj){
var x = document.getElementById(obj);
var b = document.getElementById(btn);
if( x.style.display!='none' ){
x.style.display = 'none';
b.innerHTML='show';
}else{
x.style.display = '';
b.innerHTML='hide';
}
return false;
}
var antiRobot = 0;
function antiRobotGo(){
if( antiRobot!=3 ) return;
antiRobot = 7;
var j = document.getElementById("mtimelink");
if(j && j.hasAttribute("data-href")) j.href=j.getAttribute("data-href");
}
function antiRobotDefense(){
document.body.onmousedown=function(){
antiRobot |= 2;
antiRobotGo();
document.body.onmousedown=null;
}
document.body.onmousemove=function(){
antiRobot |= 2;
antiRobotGo();
document.body.onmousemove=null;
}
setTimeout(function(){
antiRobot |= 1;
antiRobotGo();
}, 100)
antiRobotGo();
}
antiRobotDefense();
</script>
<!-- keywords: sqlite3_unlock_notify -->
<div class=nosearch>
<a href="../c3ref/intro.html"><h2>SQLite C Interface</h2></a>
<h2>Unlock Notification</h2>
</div>
<blockquote><pre>
int sqlite3_unlock_notify(
  sqlite3 *pBlocked,                          /* Waiting connection */
  void (*xNotify)(void **apArg, int nArg),    /* Callback function to invoke */
  void *pNotifyArg                            /* Argument to pass to xNotify */
);
</pre></blockquote>
<p>
When running in shared-cache mode, a database operation may fail with
an <a href="../rescode.html#locked">SQLITE_LOCKED</a> error if the required locks on the shared-cache or
individual tables within the shared-cache cannot be obtained. See
<a href="../sharedcache.html">SQLite Shared-Cache Mode</a> for a description of shared-cache locking.
This API may be used to register a callback that SQLite will invoke
when the connection currently holding the required lock relinquishes it.
This API is only available if the library was compiled with the
<a href="../compile.html#enable_unlock_notify">SQLITE_ENABLE_UNLOCK_NOTIFY</a> C-preprocessor symbol defined.</p>

<p>See Also: <a href="../unlock_notify.html">Using the SQLite Unlock Notification Feature</a>.</p>

<p>Shared-cache locks are released when a database connection concludes
its current transaction, either by committing it or rolling it back.</p>

<p>When a connection (known as the blocked connection) fails to obtain a
shared-cache lock and SQLITE_LOCKED is returned to the caller, the
identity of the database connection (the blocking connection) that
has locked the required resource is stored internally. After an
application receives an SQLITE_LOCKED error, it may call the
sqlite3_unlock_notify() method with the blocked connection handle as
the first argument to register for a callback that will be invoked
when the blocking connections current transaction is concluded. The
callback is invoked from within the <a href="../c3ref/step.html">sqlite3_step</a> or <a href="../c3ref/close.html">sqlite3_close</a>
call that concludes the blocking connection's transaction.</p>

<p>If sqlite3_unlock_notify() is called in a multi-threaded application,
there is a chance that the blocking connection will have already
concluded its transaction by the time sqlite3_unlock_notify() is invoked.
If this happens, then the specified callback is invoked immediately,
from within the call to sqlite3_unlock_notify().</p>

<p>If the blocked connection is attempting to obtain a write-lock on a
shared-cache table, and more than one other connection currently holds
a read-lock on the same table, then SQLite arbitrarily selects one of
the other connections to use as the blocking connection.</p>

<p>There may be at most one unlock-notify callback registered by a
blocked connection. If sqlite3_unlock_notify() is called when the
blocked connection already has a registered unlock-notify callback,
then the new callback replaces the old. If sqlite3_unlock_notify() is
called with a NULL pointer as its second argument, then any existing
unlock-notify callback is canceled. The blocked connections
unlock-notify callback may also be canceled by closing the blocked
connection using <a href="../c3ref/close.html">sqlite3_close()</a>.</p>

<p>The unlock-notify callback is not reentrant. If an application invokes
any sqlite3_xxx API functions from within an unlock-notify callback, a
crash or deadlock may be the result.</p>

<p>Unless deadlock is detected (see below), sqlite3_unlock_notify() always
returns SQLITE_OK.</p>

<p><b>Callback Invocation Details</b></p>

<p>When an unlock-notify callback is registered, the application provides a
single void* pointer that is passed to the callback when it is invoked.
However, the signature of the callback function allows SQLite to pass
it an array of void* context pointers. The first argument passed to
an unlock-notify callback is a pointer to an array of void* pointers,
and the second is the number of entries in the array.</p>

<p>When a blocking connection's transaction is concluded, there may be
more than one blocked connection that has registered for an unlock-notify
callback. If two or more such blocked connections have specified the
same callback function, then instead of invoking the callback function
multiple times, it is invoked once with the set of void* context pointers
specified by the blocked connections bundled together into an array.
This gives the application an opportunity to prioritize any actions
related to the set of unblocked database connections.</p>

<p><b>Deadlock Detection</b></p>

<p>Assuming that after registering for an unlock-notify callback a
database waits for the callback to be issued before taking any further
action (a reasonable assumption), then using this API may cause the
application to deadlock. For example, if connection X is waiting for
connection Y's transaction to be concluded, and similarly connection
Y is waiting on connection X's transaction, then neither connection
will proceed and the system may remain deadlocked indefinitely.</p>

<p>To avoid this scenario, the sqlite3_unlock_notify() performs deadlock
detection. If a given call to sqlite3_unlock_notify() would put the
system in a deadlocked state, then SQLITE_LOCKED is returned and no
unlock-notify callback is registered. The system is said to be in
a deadlocked state if connection A has registered for an unlock-notify
callback on the conclusion of connection B's transaction, and connection
B has itself registered for an unlock-notify callback when connection
A's transaction is concluded. Indirect deadlock is also detected, so
the system is also considered to be deadlocked if connection B has
registered for an unlock-notify callback on the conclusion of connection
C's transaction, where connection C is waiting on connection A. Any
number of levels of indirection are allowed.</p>

<p><b>The "DROP TABLE" Exception</b></p>

<p>When a call to <a href="../c3ref/step.html">sqlite3_step()</a> returns SQLITE_LOCKED, it is almost
always appropriate to call sqlite3_unlock_notify(). There is however,
one exception. When executing a "DROP TABLE" or "DROP INDEX" statement,
SQLite checks if there are any currently executing SELECT statements
that belong to the same connection. If there are, SQLITE_LOCKED is
returned. In this case there is no "blocking connection", so invoking
sqlite3_unlock_notify() results in the unlock-notify callback being
invoked immediately. If the application then re-attempts the "DROP TABLE"
or "DROP INDEX" query, an infinite loop might be the result.</p>

<p>One way around this problem is to check the extended error code returned
by an sqlite3_step() call. If there is a blocking connection, then the
extended error code is set to SQLITE_LOCKED_SHAREDCACHE. Otherwise, in
the special "DROP TABLE/INDEX" case, the extended error code is just
SQLITE_LOCKED.
</p><p>See also lists of
  <a href="../c3ref/objlist.html">Objects</a>,
  <a href="../c3ref/constlist.html">Constants</a>, and
  <a href="../c3ref/funclist.html">Functions</a>.</p>