@@ -28,12 +28,12 @@ primary keys in ``field[1]``:
28
28
29
29
UPDATE tester SET "field[2]" = 'size', "field[3]" = 0 WHERE "field[1]" = 3
30
30
31
- This query will be processed with three operating system **threads **:
31
+ Assuming this query is received by Tarantool via network,
32
+ it will be processed with three operating system **threads **:
32
33
33
- 1. If we issue the query on a remote client, then the **network thread ** on
34
- the server side receives the query, parses the statement and changes it
35
- to a server executable message which has already been checked, and which
36
- the server instance can understand without parsing everything again.
34
+ 1. The **network thread ** on the server side receives the query, parses
35
+ the statement, checks if it's correct, and then transforms it into a special
36
+ structure--a message containing an executable statement and its options.
37
37
38
38
2. The network thread ships this message to the instance's
39
39
**transaction processor thread ** using a lock-free message bus.
@@ -43,12 +43,13 @@ This query will be processed with three operating system **threads**:
43
43
The instance's transaction processor thread uses the primary-key index on
44
44
field[1] to find the location of the tuple. It determines that the tuple
45
45
can be updated (not much can go wrong when you're merely changing an
46
- unindexed field value to something shorter ).
46
+ unindexed field value).
47
47
48
48
3. The transaction processor thread sends a message to the
49
49
:ref: `write-ahead logging (WAL) thread <internals-wal >` to commit the
50
50
transaction. When done, the WAL thread replies with a COMMIT or ROLLBACK
51
- result, which is returned to the client.
51
+ result to the transaction processor which gives it back to the network thread,
52
+ and the network thread returns the result to the client.
52
53
53
54
Notice that there is only one transaction processor thread in Tarantool.
54
55
Some people are used to the idea that there can be multiple threads operating
@@ -91,7 +92,9 @@ ready-to-run fiber takes its place and becomes the new running fiber.
91
92
92
93
This model makes all programmatic locks unnecessary: cooperative multitasking
93
94
ensures that there will be no concurrency around a resource, no race conditions,
94
- and no memory consistency issues.
95
+ and no memory consistency issues. The way to achieve this is quite simple:
96
+ in critical sections, don't use yields, explicit or implicit, and no one
97
+ can interfere into the code execution.
95
98
96
99
When requests are small, for example simple UPDATE or INSERT or DELETE or SELECT,
97
100
fiber scheduling is fair: it takes only a little time to process the request,
@@ -119,7 +122,12 @@ Or, if needed, transaction changes can be rolled back --
119
122
:ref: `completely <box-rollback >` or to a specific
120
123
:ref: `savepoint <box-rollback_to_savepoint >`.
121
124
122
- To implement isolation, Tarantool uses a simple optimistic scheduler:
125
+ In Tarantool, `transaction isolation level <https://en.wikipedia.org/wiki/Isolation_(database_systems)#Isolation_levels >`_
126
+ is *serializable * with the clause "if no failure during writing to WAL". In
127
+ case of such a failure that can happen, for example, if the disk space
128
+ is over, the transaction isolation level becomes *read uncommitted *.
129
+
130
+ In :ref: `vynil <engines-chapter >`, to implement isolation Tarantool uses a simple optimistic scheduler:
123
131
the first transaction to commit wins. If a concurrent active transaction
124
132
has read a value modified by a committed transaction, it is aborted.
125
133
@@ -133,6 +141,10 @@ cause an abort as it should according to the description. This happens because
133
141
actually ``box.begin() `` does not start a transaction. It is a mark telling
134
142
Tarantool to start a transaction after some database request that follows.
135
143
144
+ In memtx, if an instruction that implies yields, explicit or implicit, is
145
+ executed during a transaction, the transaction is fully rolled back. In vynil,
146
+ we use more complex transactional manager that allows yields.
147
+
136
148
.. note ::
137
149
138
150
You can’t mix storage engines in a transaction today.
@@ -148,7 +160,7 @@ and :ref:`fiber.yield() <fiber-yield>`, but many other requests "imply" yields
148
160
because Tarantool is designed to avoid blocking.
149
161
150
162
Database requests imply yields if and only if there is disk I/O.
151
- For memtx, since all data is in memory, there is no disk I/O during the request.
163
+ For memtx, since all data is in memory, there is no disk I/O during a read request.
152
164
For vinyl, since some data may not be in memory, there may be disk I/O
153
165
for a read (to fetch data from disk) or for a write (because a stall
154
166
may occur while waiting for memory to be free).
@@ -171,12 +183,12 @@ due to implicit yield happening after each chunk of code is executed in the cons
171
183
**Example #1 **
172
184
173
185
* *Engine = memtx * |br |
174
- ``select() insert() `` has one yield, at the end of insertion, caused by
186
+ The sequence ``select() insert() `` has one yield, at the end of insertion, caused by
175
187
implicit commit; ``select() `` has nothing to write to the WAL and so does not
176
188
yield.
177
189
178
190
* *Engine = vinyl * |br |
179
- ``select() insert() `` has between one and three yields, since ``select() ``
191
+ The sequence ``select() insert() `` has one to three yields, since ``select() ``
180
192
may yield if the data is not in cache, ``insert() `` may yield waiting for
181
193
available memory, and there is an implicit yield at commit.
182
194
@@ -185,7 +197,7 @@ due to implicit yield happening after each chunk of code is executed in the cons
185
197
186
198
**Example #2 **
187
199
188
- Assume that in space ‘tester’ there are tuples in which the third field
200
+ Assume that in the memtx space ‘tester’ there are tuples in which the third field
189
201
represents a positive dollar amount. Let's start a transaction, withdraw
190
202
from tuple#1, deposit in tuple#2, and end the transaction, making its
191
203
effects permanent.
@@ -211,21 +223,22 @@ implicit yielding at commit time does not take place, because there are
211
223
no writes to the WAL.
212
224
213
225
If a task is interactive -- sending requests to the server and receiving responses --
214
- then it involves network IO , and therefore there is an implicit yield, even if the
226
+ then it involves network I/O , and therefore there is an implicit yield, even if the
215
227
request that is sent to the server is not itself an implicit yield request.
216
- Therefore, the sequence:
228
+ Therefore, the following sequence
217
229
218
230
.. cssclass :: highlight
219
231
.. parsed-literal ::
220
232
221
- select
222
- select
223
- select
233
+ conn.space.test: select{1}
234
+ conn.space.test: select{2}
235
+ conn.space.test: select{3}
224
236
225
- causes blocking (in memtx), if it is inside a function or Lua program being
226
- executed on the server instance, but causes yielding (in both memtx and vinyl)
227
- if it is done as a series of transmissions from a client, including a client which
228
- operates via telnet, via one of the connectors, or via the
237
+ causes yields three times sequentially when sending requests to the network
238
+ and awaiting the results. On the server side, the same requests are executed
239
+ in common order possibly mixing with other requests from the network and
240
+ local fibers. Something similar happens when using clients that operate
241
+ via telnet, via one of the connectors, or via the
229
242
:ref: `MySQL and PostgreSQL rocks <dbms_modules >`, or via the interactive mode when
230
243
:ref: `using Tarantool as a client <admin-using_tarantool_as_a_client >`.
231
244
0 commit comments