Re: [Spacewalk-devel] [PATCH] Avoid a possible concurrency issue on RhnSet update

2013-09-06 Thread Tomas Lestach
Hello Silvio,

 I investigated that: we get ConstraintViolationException with Oracle
 and
 WrappedSQLException in Postgres. That depends on
 SqlExceptionTranslator.sqlException(), which can translate
 Oracle-specific errors but not Postgres ones.

This is not good. We actually shall fix the code to catch WrappedSQLException 
on Oracle as well.
For the time being I committed your patch (with an extra comment) as: 
3cf0c8132c8fa4c9b79b41478b7d6679457196c2


Thank you,
--
Tomas Lestach
Red Hat Satellite Engineering, Red Hat

___
Spacewalk-devel mailing list
Spacewalk-devel@redhat.com
https://www.redhat.com/mailman/listinfo/spacewalk-devel


Re: [Spacewalk-devel] [PATCH] Avoid a possible concurrency issue on RhnSet update

2013-09-05 Thread Silvio Moioli
On 09/05/2013 02:26 AM, Jan Pazdziora wrote:
 Please note that this will not work -- the fact that you check content
 of some table in your session and your transaction and based on that
 run the insert operation does not mean that the other session cannot
 do exactly the same, both will find the record not there, and you will
 get the ORA-1 anyway.

Good point: actually I was thinking about that statement being the only
one in its transaction, but that's actually not the case.

I think I will do as Thomas suggested, handling exceptions better in
order to be as safe as possible when ignoring them, yet accepting
failures in this specific case. I will be back with a patch as soon as I
have tested it.

Thanks for the discussion by the way, as problems in this topic are
traditionally difficult to handle!

Regards,
-- 
Silvio Moioli
SUSE LINUX Products GmbH
Maxfeldstraße 5, 90409 Nürnberg Germany

___
Spacewalk-devel mailing list
Spacewalk-devel@redhat.com
https://www.redhat.com/mailman/listinfo/spacewalk-devel


Re: [Spacewalk-devel] [PATCH] Avoid a possible concurrency issue on RhnSet update

2013-09-04 Thread Silvio Moioli
On 09/03/2013 02:33 PM, Tomas Lestach wrote:
 to be honest, I personally do not like seeing DB index names in
 the application code.

I agree that it is not really an elegant solution, but I could not find
another way of ignoring such specific exceptions. Ideas welcome :-)

 (Btw. does it work on PG, when the index name is stated uppercase?)

Actually, we could not reproduce the problem in Postgres at all. If the
proposed solution turns out to be acceptable, I will research that.

 Isn't it possible to use 'SELECT FOR UPDATE' in these cases?

I do not really think so, because AFAIU there is actually no SELECT
involved. Failing statements are INSERTs that add tuples like (user, label,
system, id), all built from HTTP request parameters, so there is no need
to fetch data from the database in order to build them.

In order not to add duplicates those INSERTs are preceded by DELETEs rather
than SELECTs, so I guess write locks are acquired anyway.

 No, if both transactions start at the same time and one of them commits,
 the other transaction does not see those changes.

Maybe I am missing something here but this is not what I observe. On
Postgres, you can easily prove this using pgAdmin III and two Query
windows. In the first window input:

BEGIN;
INSERT INTO rhnset (user_id, label, element, element_two, element_three)
VALUES (
  (SELECT id FROM web_contact LIMIT 1),
  'test',
   1,
   1,
   1
);
F5 (this leaves the transaction pending uncommitted [1])

And in the second one:

BEGIN;
SELECT * FROM rhnset WHERE label = 'test';
F5

You should not see the above test row. Now switch back to the first
window and input:

COMMIT;
F5 (this commits the pending transaction)

Finally switch back to the second window and repeat the query:

SELECT * FROM rhnset WHERE label = 'test';
F5

You should see the added row. Note that the second transaction did see
the update while not being committed. In fact if you run COMMIT;
Postgres will close it (running COMMIT a second time will emit a warning
that no transactions were pending).

As I wrote, this is the expected behavior since the default READ
COMMITTED isolation level is used [2]:

[...] two successive SELECT commands can see different data, even
though they are within a single transaction, if other transactions
commit changes during execution [...] 

The same proof can be done with Oracle SQL Developer with minor syntax
fixes.
Note that you will have to open two connections to the same database
because,
by default, all SQL Worksheets there will refer to the same transaction.

On 09/03/2013 04:14 PM, Paul Robert Marino wrote:
 I'm a little rusty on my Oracle but in PostgreSQL I think this could
 be resolved using the Isolation level within the transaction

That could be done, but since a transaction is opened and closed at the
beginning and end of an HTTP request (at least most of the time), that
would mean to either change isolation level for all requests or
introducing a mechanism to flag certain actions/URLs to get a different
isolation level. Also, code using any transaction at an isolation level
above READ COMMITTED should be modified to handle transaction
serialization errors and be prepared to retry failed transactions, which
AFAIK is never done now.

 possibly snapshots within the transaction

That would mean saving snapshot IDs between HTTP requests. Again,
doable, but sounds quite difficult at least to me!

Yet another possibility would be to INSERT only tuples not already
present by set difference, something like this query:

INSERT INTO rhnset (user_id, label, element, element_two, element_three)
  SELECT :user_id, :label, :element, :element_two, :element_three
FROM dual
WHERE (:user_id, :label, :element, :element_two, :element_three) NOT
IN (
  SELECT * FROM rhnset
)

Is that better in your opinion?

[1]
http://www.postgresql.org/message-id/937d27e10810020633k164e7f4bsb5213d86d2bfb...@mail.gmail.com
[2]
http://www.postgresql.org/docs/9.2/static/transaction-iso.html#XACT-READ-COMMITTED

Regards,
-- 
Silvio Moioli
SUSE LINUX Products GmbH
Maxfeldstraße 5, 90409 Nürnberg Germany

___
Spacewalk-devel mailing list
Spacewalk-devel@redhat.com
https://www.redhat.com/mailman/listinfo/spacewalk-devel

Re: [Spacewalk-devel] [PATCH] Avoid a possible concurrency issue on RhnSet update

2013-09-04 Thread Tomas Lestach
  (Btw. does it work on PG, when the index name is stated uppercase?)
 
 Actually, we could not reproduce the problem in Postgres at all.

This is interesting.

  Isn't it possible to use 'SELECT FOR UPDATE' in these cases?
 
 I do not really think so, because AFAIU there is actually no SELECT
 involved. Failing statements are INSERTs that add tuples like (user,
 label,
 system, id), all built from HTTP request parameters, so there is no
 need
 to fetch data from the database in order to build them.

I see.

  No, if both transactions start at the same time and one of them
  commits,
  the other transaction does not see those changes.
 
 Maybe I am missing something here but this is not what I observe.

Right. I am sorry, I was wrong.

 Yet another possibility would be to INSERT only tuples not already
 present by set difference, something like this query:
 
 INSERT INTO rhnset (user_id, label, element, element_two,
 element_three)
   SELECT :user_id, :label, :element, :element_two, :element_three
 FROM dual
 WHERE (:user_id, :label, :element, :element_two, :element_three)
 NOT
 IN (
   SELECT * FROM rhnset
 )
 
 Is that better in your opinion?

Options:
* We will accept this solution (the last one).

* We'll accept also your first exception solution, just remove the index name, 
please.
Actually I would expect WrappedSQLException gets thrown (not 
ConstraintViolationException).
In case you would catch WrappedSQLException, just check it contains some 
information about
constraint violation. In case you catch directly ConstraintViolationException, 
it's ok.

* I am not sure, if we can explicitly tell hibernate to lock the table for us, 
what could be another option.


So, just choose the one you like the most and I'll accept it. :-)

Thank you,
--
Tomas Lestach
Red Hat Satellite Engineering, Red Hat

___
Spacewalk-devel mailing list
Spacewalk-devel@redhat.com
https://www.redhat.com/mailman/listinfo/spacewalk-devel


Re: [Spacewalk-devel] [PATCH] Avoid a possible concurrency issue on RhnSet update

2013-09-04 Thread Jan Pazdziora
On Wed, Sep 04, 2013 at 08:35:27AM +0200, Silvio Moioli wrote:
 On 09/03/2013 02:33 PM, Tomas Lestach wrote:
  to be honest, I personally do not like seeing DB index names in
  the application code.
 
 I agree that it is not really an elegant solution, but I could not find
 another way of ignoring such specific exceptions. Ideas welcome :-)

You can do a select after that exception to see if the record in the
database is what you intended it to be. If it is (and you got an
exception in your session), you can assume it was the other session
which set it up. You don't really care if the operation in your
session suceeded -- you care about the result.

Of course, whether and how this will work with some application
sessions (hibernate?), I can't really say.

-- 
Jan Pazdziora
Principal Software Engineer, Identity Management Engineering, Red Hat

___
Spacewalk-devel mailing list
Spacewalk-devel@redhat.com
https://www.redhat.com/mailman/listinfo/spacewalk-devel


Re: [Spacewalk-devel] [PATCH] Avoid a possible concurrency issue on RhnSet update

2013-09-04 Thread Jan Pazdziora
On Wed, Sep 04, 2013 at 08:35:27AM +0200, Silvio Moioli wrote:
 
 That would mean saving snapshot IDs between HTTP requests. Again,
 doable, but sounds quite difficult at least to me!
 
 Yet another possibility would be to INSERT only tuples not already
 present by set difference, something like this query:
 
 INSERT INTO rhnset (user_id, label, element, element_two, element_three)
   SELECT :user_id, :label, :element, :element_two, :element_three
 FROM dual
 WHERE (:user_id, :label, :element, :element_two, :element_three) NOT
 IN (
   SELECT * FROM rhnset
 )
 
 Is that better in your opinion?

Please note that this will not work -- the fact that you check content
of some table in your session and your transaction and based on that
run the insert operation does not mean that the other session cannot
do exactly the same, both will find the record not there, and you will
get the ORA-1 anyway.

The only viable approach is to accept that the same operations will
happen, and either losen the unique constraint requirement, or handle
the exceptions which will from time to time happen. Or just live with
the fact that in some scenarios, the failures will occur.

-- 
Jan Pazdziora
Principal Software Engineer, Identity Management Engineering, Red Hat

___
Spacewalk-devel mailing list
Spacewalk-devel@redhat.com
https://www.redhat.com/mailman/listinfo/spacewalk-devel


Re: [Spacewalk-devel] [PATCH] Avoid a possible concurrency issue on RhnSet update

2013-09-03 Thread Tomas Lestach
Hello Silvio,

to be honest, I personally do not like seeing DB index names in
the application code.
(Btw. does it work on PG, when the index name is stated uppercase?)

Isn't it possible to use 'SELECT FOR UPDATE' in these cases?
(The other transaction would need to wait till the first one commits.)

 Hi,
 
 The attached patch attempts to fix an issue we found while running
 some
 Selenium-based automated UI tests. Basically multiple requests that
 involve an RhnSet can overlap if the user is clicking very quickly
 and
 that might result in an ISE because
 RHNSET.RHN_SET_USER_LABEL_ELEM_UNQ
 is violated.
 
 We verified that using a system's Errata page, specifically in code
 that
 gets executed from ErrataList.do to ErrataConfirm.do. In particular,
 if
 you check a box selecting an errata in ErrataList.do then an AJAX
 call
 is fired to DWRItemSelector.select(), which among other things
 updates
 the underlying rhnset by adding a row. Then, if you very quickly
 click
 on Apply Errata, ListRhnSetHelper will also try to add the same row
 because DWRItemSelector hasn't finished yet and, in case of
 particularly
 bad luck, the RDBMS will complain that the unique constraint has been
 violated.
 
 AFAIU this is possible from an RDBMS point of view since, both in the
 Oracle and in Postgres, the READ COMMITTED transaction isolation
 level
 is used. This means that a transaction can see data changing if
 other
 transactions COMMIT during its lifetime [2].

No, if both transactions start at the same time and one of them commits,
the other transaction does not see those changes.
If the other transaction makes the same changes, it fails first at commit
time on the mentioned index.

Regards,
--
Tomas Lestach
Red Hat Satellite Engineering, Red Hat

 
 Reproducing this issue is not very easy, since it is RDBMS, network
 and
 server-load dependent. We succeeded in reliably repeat it in SUSE
 Manager on Oracle using Selenium IDE for Firefox[1] to automate the
 clicks. Of course, this can also happen at more human time scales
 if,
 for example, server is under heavy load.
 
 The attached patch just ignores constraint violations in this
 specific
 case, as I see no point in throwing an exception when the row to
 INSERT
 is simply already there. AFAIU that does not have unwanted
 side-effects,
 but review is nevertheless very welcome.
 
 Regards,
 
 [1] http://docs.seleniumhq.org/download/
 [2] http://www.postgresql.org/docs/9.2/static/transaction-iso.html
 --
 Silvio Moioli
 SUSE LINUX Products GmbH
 Maxfeldstraße 5, 90409 Nürnberg Germany
 
 
 ___
 Spacewalk-devel mailing list
 Spacewalk-devel@redhat.com
 https://www.redhat.com/mailman/listinfo/spacewalk-devel

___
Spacewalk-devel mailing list
Spacewalk-devel@redhat.com
https://www.redhat.com/mailman/listinfo/spacewalk-devel

Re: [Spacewalk-devel] [PATCH] Avoid a possible concurrency issue on RhnSet update

2013-09-03 Thread Paul Robert Marino
I'm a little rusty on my Oracle but in PostgreSQL I think this could
be resolved using the Isolation level within the transaction, and
possibly snapshots within the transaction
http://www.postgresql.org/docs/9.2/interactive/sql-set-transaction.html

An other possibility is to request an exclusive lock could be
requested for queries which have this potential but that method should
be avoided if possible.

On Tue, Sep 3, 2013 at 8:33 AM, Tomas Lestach tlest...@redhat.com wrote:
 Hello Silvio,

 to be honest, I personally do not like seeing DB index names in
 the application code.
 (Btw. does it work on PG, when the index name is stated uppercase?)

 Isn't it possible to use 'SELECT FOR UPDATE' in these cases?
 (The other transaction would need to wait till the first one commits.)

 Hi,

 The attached patch attempts to fix an issue we found while running
 some
 Selenium-based automated UI tests. Basically multiple requests that
 involve an RhnSet can overlap if the user is clicking very quickly
 and
 that might result in an ISE because
 RHNSET.RHN_SET_USER_LABEL_ELEM_UNQ
 is violated.

 We verified that using a system's Errata page, specifically in code
 that
 gets executed from ErrataList.do to ErrataConfirm.do. In particular,
 if
 you check a box selecting an errata in ErrataList.do then an AJAX
 call
 is fired to DWRItemSelector.select(), which among other things
 updates
 the underlying rhnset by adding a row. Then, if you very quickly
 click
 on Apply Errata, ListRhnSetHelper will also try to add the same row
 because DWRItemSelector hasn't finished yet and, in case of
 particularly
 bad luck, the RDBMS will complain that the unique constraint has been
 violated.

 AFAIU this is possible from an RDBMS point of view since, both in the
 Oracle and in Postgres, the READ COMMITTED transaction isolation
 level
 is used. This means that a transaction can see data changing if
 other
 transactions COMMIT during its lifetime [2].

 No, if both transactions start at the same time and one of them commits,
 the other transaction does not see those changes.
 If the other transaction makes the same changes, it fails first at commit
 time on the mentioned index.

 Regards,
 --
 Tomas Lestach
 Red Hat Satellite Engineering, Red Hat


 Reproducing this issue is not very easy, since it is RDBMS, network
 and
 server-load dependent. We succeeded in reliably repeat it in SUSE
 Manager on Oracle using Selenium IDE for Firefox[1] to automate the
 clicks. Of course, this can also happen at more human time scales
 if,
 for example, server is under heavy load.

 The attached patch just ignores constraint violations in this
 specific
 case, as I see no point in throwing an exception when the row to
 INSERT
 is simply already there. AFAIU that does not have unwanted
 side-effects,
 but review is nevertheless very welcome.

 Regards,

 [1] http://docs.seleniumhq.org/download/
 [2] http://www.postgresql.org/docs/9.2/static/transaction-iso.html
 --
 Silvio Moioli
 SUSE LINUX Products GmbH
 Maxfeldstraße 5, 90409 Nürnberg Germany


 ___
 Spacewalk-devel mailing list
 Spacewalk-devel@redhat.com
 https://www.redhat.com/mailman/listinfo/spacewalk-devel

 ___
 Spacewalk-devel mailing list
 Spacewalk-devel@redhat.com
 https://www.redhat.com/mailman/listinfo/spacewalk-devel

___
Spacewalk-devel mailing list
Spacewalk-devel@redhat.com
https://www.redhat.com/mailman/listinfo/spacewalk-devel