Skip to content

Commit ae36fd6

Browse files
Simplify transaction starting constraints to match reality (#319)
All implementations have a strict ordering of transactions with overlapping scopes; read-only transactions can run in parallel but block a later read/write transaction from starting, and the read/write transactions similarly block later read/write and read-only transactions. Tighten up the constraints definition to something precise, and move the wordy implications into a non-normative aside. Also, define "overlapping scopes" as a term. Closes #253
1 parent 093afa4 commit ae36fd6

File tree

1 file changed

+29
-74
lines changed

1 file changed

+29
-74
lines changed

index.bs

Lines changed: 29 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -892,10 +892,9 @@ and data mutation operations.
892892
All transactions are created through a [=/connection=], which is the
893893
transaction's <dfn>connection</dfn>.
894894

895-
A [=/transaction=] has a <dfn>scope</dfn> that determines the
896-
[=/object stores=] with which the transaction may interact. A
897-
transaction's scope remains fixed for the lifetime of that
898-
transaction.
895+
A [=/transaction=] has a <dfn>scope</dfn> which is a [=/set=] of [=/object stores=] that the transaction may interact with. A transaction's scope remains fixed for the lifetime of that transaction.
896+
897+
Two [=/transactions=] have <dfn lt="overlap|overlapping scope">overlapping scope</dfn> if any [=/object store=] is in both transactions' [=transaction/scope=].
899898

900899
A [=/transaction=] has a <dfn>mode</dfn> that determines which types
901900
of interactions can be performed upon that transaction. The [=transaction/mode=]
@@ -908,7 +907,7 @@ following:
908907
The transaction is only allowed to read data. No modifications can
909908
be done by this type of transaction. This has the advantage that
910909
several [=read-only transactions=] can run at the same time even
911-
if their [=transaction/scopes=] are overlapping, i.e. if they are using the
910+
if their [=transaction/scopes=] are [=overlapping=], i.e. if they are using the
912911
same object stores. This type of transaction can be created any
913912
time once a database has been opened.
914913

@@ -917,7 +916,7 @@ following:
917916
The transaction is allowed to read, modify and delete data from
918917
existing object stores. However object stores and indexes can't be
919918
added or removed. Multiple {{"readwrite"}} transactions
920-
can't run at the same time if their [=transaction/scopes=] are overlapping
919+
can't run at the same time if their [=transaction/scopes=] are [=overlapping=]
921920
since that would mean that they can modify each other's data in
922921
the middle of the transaction. This type of transaction can be
923922
created any time once a database has been opened.
@@ -1115,87 +1114,42 @@ They will return true if any transactions were cleaned up, or false otherwise.
11151114
each [=/transaction=].
11161115
</aside>
11171116

1118-
<!-- ============================================================ -->
1119-
### Transaction scheduling ### {#transaction-scheduling}
1120-
<!-- ============================================================ -->
1121-
11221117
An event with type <dfn event>`complete`</dfn> is fired at
11231118
a [=/transaction=] that has successfully [=transaction/committed=].
11241119

11251120
An event with type <dfn event>`abort`</dfn> is fired at
11261121
a [=/transaction=] that has [=transaction/aborted=].
11271122

1128-
The following constraints define when a [=/transaction=] can be
1129-
[=transaction/started=]:
1123+
<!-- ============================================================ -->
1124+
### Transaction scheduling ### {#transaction-scheduling}
1125+
<!-- ============================================================ -->
11301126

1131-
* Any number of [=read-only transactions=] are allowed to run
1132-
concurrently, even if the transaction's [=transaction/scope=] overlap and
1133-
include the same [=/object stores=]. As long as a [=read-only
1134-
transaction=] is running, the data that the implementation returns
1135-
through [=/requests=] created with that transaction must remain
1136-
constant. That is, two requests to read the same piece of data
1137-
must yield the same result both for the case when data is found
1138-
and the result is that data, and for the case when data is not
1139-
found and a lack of data is indicated.
1127+
The following constraints define when a [=/transaction=] can be [=transaction/started=]:
11401128

1141-
<aside class=note>
1142-
There are a number of ways that an implementation can ensure
1143-
this. The implementation could prevent any <a>read/write
1144-
transaction</a>, whose scope overlaps the scope of the
1145-
[=read-only transaction=], from starting until the
1146-
[=read-only transaction=] finishes. Or the implementation
1147-
could allow the [=read-only transaction=] to see a snapshot
1148-
of the contents of the [=/object stores=] which is taken when
1149-
the [=read-only transaction=] started.
1150-
</aside>
1129+
* A [=read-only transactions=] |tx| can [=transaction/start=] when there are no <a>read/write transactions</a> which:
1130+
* Were [=transaction/created=] before |tx|; and
1131+
* have [=overlapping scopes=] with |tx|; and
1132+
* are not [=transaction/finished=].
1133+
* A <a>read/write transaction</a> |tx| can [=transaction/start=] when there are no [=/transactions=] which:
1134+
* Were [=transaction/created=] before |tx|; and
1135+
* have [=overlapping scopes=] with |tx|; and
1136+
* are not [=transaction/finished=].
11511137

1152-
* Similarly, implementations must ensure that a <a>read/write
1153-
transaction</a> is only affected by changes to [=/object
1154-
stores=] that are made using the transaction itself. For
1155-
example, the implementation must ensure that another transaction
1156-
does not modify the contents of [=/object stores=] in the
1157-
<a>read/write transaction</a>'s [=transaction/scope=]. The implementation
1158-
must also ensure that if the <a>read/write transaction</a>
1159-
completes successfully, the changes written to [=/object
1160-
stores=] using the transaction can be committed to the
1161-
[=database=] without merge conflicts. An implementation must
1162-
not abort a transaction due to merge conflicts.
1163-
1164-
* If multiple <a>read/write transactions</a> are attempting to access
1165-
the same object store (i.e. if they have overlapping [=transaction/scope=]),
1166-
the transaction that was [=transaction/created=] first must be the transaction
1167-
which gets access to the object store first. Due to the
1168-
requirements in the previous paragraph, this also means that it is
1169-
the only transaction which has access to the object store until
1170-
the transaction is [=transaction/finished=].
1171-
1172-
* Any transaction [=transaction/created=] after a <a>read/write transaction</a>
1173-
must see the changes written by the <a>read/write transaction</a>.
1174-
So if a <a>read/write transaction</a>, A, is created, and later
1175-
another transaction B, is created, and the two transactions have
1176-
overlapping [=transaction/scopes=], then B must see any changes made to any
1177-
[=/object stores=] that are part of that overlapping [=transaction/scope=].
1178-
Due to the requirements in the previous paragraph, this also means
1179-
that the B transaction does not have access to any [=/object
1180-
stores=] in that overlapping [=transaction/scope=] until the A transaction is
1181-
[=transaction/finished=].
1138+
Implementations may impose additional constraints. For example, implementations are not required to run non-[=overlapping=] <a>read/write transactions</a> in parallel, or may impose limits on the number of running transactions.
11821139

1183-
<aside class=note>
1184-
Generally speaking, the above requirements mean that any
1185-
transaction which has an overlapping scope with a <a>read/write
1186-
transaction</a> and which was created after that <a>read/write
1187-
transaction</a>, can't run in parallel with that <a>read/write
1188-
transaction</a>.
1189-
</aside>
1140+
<aside class=note>
11901141

1191-
* User agents must ensure a reasonable level of fairness across
1192-
transactions to prevent starvation. For example, if multiple
1193-
[=read-only transactions=] are started one after another the
1194-
implementation must not indefinitely prevent a pending
1195-
<a>read/write transaction</a> from [=transaction/starting=].
1142+
These constraints imply the following:
11961143

1197-
</div>
1144+
* Any number of [=read-only transactions=] are allowed to run concurrently, even if they have [=overlapping scopes=].
1145+
* As long as a [=read-only transaction=] is running, the data that the implementation returns through [=/requests=] created with that transaction remains constant. That is, two requests to read the same piece of data yield the same result both for the case when data is found and the result is that data, and for the case when data is not found and a lack of data is indicated.
1146+
* A <a>read/write transaction</a> is only affected by changes to [=/object stores=] that are made using the transaction itself. The implementation ensures that another transaction does not modify the contents of [=/object stores=] in the <a>read/write transaction</a>'s [=transaction/scope=]. The implementation also ensures that if the <a>read/write transaction</a> completes successfully, the changes written to [=/object stores=] using the transaction can be committed to the [=database=] without merge conflicts.
1147+
* If multiple <a>read/write transactions</a> are attempting to access the same object store (i.e. if they have [=overlapping scopes=]), the transaction that was [=transaction/created=] first is the transaction which gets access to the object store first, and it is the only transaction which has access to the object store until the transaction is [=transaction/finished=].
1148+
* Any transaction [=transaction/created=] after a <a>read/write transaction</a> sees the changes written by the <a>read/write transaction</a>. For example, if a <a>read/write transaction</a> A, is created, and later another transaction B, is created, and the two transactions have [=overlapping scopes=], then transaction B sees any changes made to any [=/object stores=] that are part of that [=overlapping scope=]. This also means that transaction B does not have access to any [=/object stores=] in that overlapping [=transaction/scope=] until transaction A is [=transaction/finished=].
1149+
1150+
</aside>
11981151

1152+
</div>
11991153

12001154
<!-- ============================================================ -->
12011155
### Upgrade transactions ### {#upgrade-transaction-construct}
@@ -6864,6 +6818,7 @@ For the revision history of the second edition, see [that document's Revision Hi
68646818
* Restrict array keys to [=/Array exotic objects=] (i.e. disallow proxies). ([Issue #309](https://github.com/w3c/IndexedDB/issues/309))
68656819
* Transactions are now temporarily made inactive during clone operations.
68666820
* Added {{IDBTransactionOptions/durability}} option and {{IDBTransaction/durability}} attribute. ([Issue #50](https://github.com/w3c/IndexedDB/issues/50))
6821+
* Specified [[#transaction-scheduling]] more precisely and disallow starting read/write transactions while read-only transactions with overlapping scope are running. ([Issue #253](https://github.com/w3c/IndexedDB/issues/253))
68676822

68686823
<!-- ============================================================ -->
68696824
# Acknowledgements # {#acknowledgements}

0 commit comments

Comments
 (0)