[
https://issues.apache.org/jira/browse/SENTRY-1486?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15678068#comment-15678068
]
Alexander Kolbasov edited comment on SENTRY-1486 at 11/18/16 11:13 PM:
-----------------------------------------------------------------------
Here is a bit more explanation for the problem with read-committed transaction
isolation level.
I wrote a little test that demonstrates the problem.
Here is the description of the test:
test creates 10 persistent instances of class Product each having a price of
$10.
It also creates two threads running in parallel.
The first thread simulates a typical Sentry workflow. It walks all rows one by
one and adds the price together, printing each product as it goes and the final
total price (which should be $100)
The second thread simulates updates. It walks all products and for each even
one it increases its price by $5 and for each odd one it decreases it by $5.
This doesn't change the total price, of course.
As expected, running this program produces different results from one run to
another. Sometimes I get total of 100 and sometimes 95. So the behavior is
non-deterministic. The problem is that "read-committed" transactions do not
prevent any changes happening between statements within transaction.
This means that in the presence of writes Sentry may produce non-deterministic
results which is rather bad.
Here are code snippets:
{code}
public double total(PersistenceManager pm) {
double result = 0.0;
Transaction tx = pm.currentTransaction();
tx.begin();
for (int i = 0; i < nobjects; i++) {
Query<Product> query = pm.newQuery(Product.class);
query.setFilter("this.pid == :pid");
query.setUnique(true);
Product p = (Product)query.execute(i);
result += p.getPrice();
System.out.println(p);
}
tx.commit();
return result;
}
{code}
{code}
public void updatePrice(PersistenceManager pm) {
Transaction tx = pm.currentTransaction();
tx.begin();
// for (int i = 0; i < nobjects; i++) {
for (int i = 0; i < nobjects; i++) {
Product p = (Product) pm.getObjectById(prodIds[i]);
if (i % 2 == 0) {
p.updatePrice(5.0);
} else {
p.updatePrice(-5.0);
}
}
tx.commit();
}
{code}
And here are a some test runs:
Run 1:
{code}
Product(11) name=Product0 [Some product] pid = 0 price 10.0
Product(12) name=Product1 [Some product] pid = 1 price 5.0
Product(13) name=Product2 [Some product] pid = 2 price 15.0
Product(14) name=Product3 [Some product] pid = 3 price 5.0
Product(15) name=Product4 [Some product] pid = 4 price 15.0
Product(16) name=Product5 [Some product] pid = 5 price 5.0
Product(17) name=Product6 [Some product] pid = 6 price 15.0
Product(18) name=Product7 [Some product] pid = 7 price 5.0
Product(19) name=Product8 [Some product] pid = 8 price 15.0
Product(20) name=Product9 [Some product] pid = 9 price 5.0
-> 1_1: 95.0000
{code}
Run 2:
{code}
Product(21) name=Product0 [Some product] pid = 0 price 10.0
Product(22) name=Product1 [Some product] pid = 1 price 10.0
Product(23) name=Product2 [Some product] pid = 2 price 15.0
Product(24) name=Product3 [Some product] pid = 3 price 5.0
Product(25) name=Product4 [Some product] pid = 4 price 15.0
Product(26) name=Product5 [Some product] pid = 5 price 5.0
Product(27) name=Product6 [Some product] pid = 6 price 15.0
Product(28) name=Product7 [Some product] pid = 7 price 5.0
Product(29) name=Product8 [Some product] pid = 8 price 15.0
Product(30) name=Product9 [Some product] pid = 9 price 5.0
-> 1_1: 100.000
{code}
was (Author: akolb):
Here is a bit more explanation for the problem with read-committed transaction
isolation level.
I wrote a little test that demonstrates the problem.
Here is the description of the test:
test creates 10 persistent instances of class Product each having a price of
$10.
It also creates two threads running in parallel.
The first thread simulates a typical Sentry workflow. It walks all rows one by
one and adds the price together, printing each product as it goes and the final
total price (which should be $100)
The second thread simulates updates. It walks all products and for each even
one it increases its price by $5 and for each odd one it decreases it by $5.
This doesn't change the total price, of course.
As expected, running this program produces different results from one run to
another. Sometimes I get total of 100 and sometimes 95. So the behavior is
non-deterministic. The problem is that "read-committed" transactions do not
prevent any changes happening between statements within transaction.
This means that in the presence of writes Sentry may produce non-deterministic
results which is rather bad.
Here are code snippets:
{code}
public double total(PersistenceManager pm) {
double result = 0.0;
Transaction tx = pm.currentTransaction();
tx.begin();
for (int i = 0; i < nobjects; i++) {
Query<Product> query = pm.newQuery(Product.class);
query.setFilter("this.pid == :pid");
query.setUnique(true);
Product p = (Product)query.execute(i);
result += p.getPrice();
System.out.println(p);
}
tx.commit();
return result;
}
{code}
public void updatePrice(PersistenceManager pm) {
Transaction tx = pm.currentTransaction();
tx.begin();
// for (int i = 0; i < nobjects; i++) {
for (int i = 0; i < nobjects; i++) {
Product p = (Product) pm.getObjectById(prodIds[i]);
if (i % 2 == 0) {
p.updatePrice(5.0);
} else {
p.updatePrice(-5.0);
}
}
tx.commit();
}
{code}
And here are a some test runs:
Run 1:
{code}
Product(11) name=Product0 [Some product] pid = 0 price 10.0
Product(12) name=Product1 [Some product] pid = 1 price 5.0
Product(13) name=Product2 [Some product] pid = 2 price 15.0
Product(14) name=Product3 [Some product] pid = 3 price 5.0
Product(15) name=Product4 [Some product] pid = 4 price 15.0
Product(16) name=Product5 [Some product] pid = 5 price 5.0
Product(17) name=Product6 [Some product] pid = 6 price 15.0
Product(18) name=Product7 [Some product] pid = 7 price 5.0
Product(19) name=Product8 [Some product] pid = 8 price 15.0
Product(20) name=Product9 [Some product] pid = 9 price 5.0
-> 1_1: 95.0000
{code}
Run 2:
{code}
Product(21) name=Product0 [Some product] pid = 0 price 10.0
Product(22) name=Product1 [Some product] pid = 1 price 10.0
Product(23) name=Product2 [Some product] pid = 2 price 15.0
Product(24) name=Product3 [Some product] pid = 3 price 5.0
Product(25) name=Product4 [Some product] pid = 4 price 15.0
Product(26) name=Product5 [Some product] pid = 5 price 5.0
Product(27) name=Product6 [Some product] pid = 6 price 15.0
Product(28) name=Product7 [Some product] pid = 7 price 5.0
Product(29) name=Product8 [Some product] pid = 8 price 15.0
Product(30) name=Product9 [Some product] pid = 9 price 5.0
-> 1_1: 100.000
{code}
> Sentry should use repeatable-read consistency level
> ---------------------------------------------------
>
> Key: SENTRY-1486
> URL: https://issues.apache.org/jira/browse/SENTRY-1486
> Project: Sentry
> Issue Type: Bug
> Components: Sentry
> Affects Versions: 1.7.0, sentry-ha-redesign
> Reporter: Alexander Kolbasov
> Assignee: Alexander Kolbasov
> Fix For: 1.8.0
>
> Attachments: SENTRY-1486.001.patch, SENTRY-1486.002.patch
>
>
> Currently Sentry uses the "read-committed" consistency level which is the
> default for the Datanucleus JDO library. This causes potential problems since
> the state visible to each transaction can actually see updates from another
> transactions, so it is very difficult to reason about any code that reads
> multiple pieces of data.
> Instead it should use repeatable read" consistency which guarantees that any
> transaction only sees the state at the beginning of a transaction plus any
> updates done within a transaction.
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)