I''m using postgresql and using the following method for creating a lock in my application to prevent two requests of the same type from proceeding. There is also a method to release the lock, but for now I''m just starting with an entry already created in the locks table, so it will always return with locked = 1. What''s happening is that when I send 10 or so simultaneous requests, invariably the application locks up after a few requests. Postgresql shows 2 transactions, one in SELECT FOR UPDATE and the other idle. What I think is happening is that while one request already has an exclusive lock but has not yet issued the commit, another request issues another SELECT FOR UPDATE, which blocks ruby and prevents the previous request from issuing the commit and releasing the lock. What I''m thinking might be a solution is to also use a global variable as a lock in front of the database locking. That way the above scenario would never happen as the application would return a busy response to the client if any simultaneous requests happen within that instance of the application, and it would also take care of locking across multiple instances. It would still block if another instance held a database lock, but it wouldn''t deadlock like it does now because all instances would be guaranteed to release the database locks at some point, probably within a second or so. def getlock locked = 0 begin conn = @dbh.get_connection conn.do("BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE") sth = conn.prepare("SELECT merchant_id from locks where merchant_id = ? FOR UPDATE") sth.execute(@mconf.merchant_id) if row = sth.fetch locked = 1 else sth2 = conn.prepare("INSERT INTO locks (merchant_id) VALUES (?)") sth2.execute(@mconf.merchant_id) end conn.do("COMMIT TRANSACTION") @dbh.release conn @logger.debug("Locked=#{locked}") rescue Exception => e conn.do("ROLLBACK TRANSACTION") @dbh.release conn end return locked end
Francis Cianfrocca
2006-Aug-27 07:33 UTC
[Eventmachine-talk] using select for update in postgresql
On 8/27/06, snacktime <snacktime at gmail.com> wrote:> > I''m using postgresql and using the following method for creating a > lock in my application to prevent two requests of the same type from > proceeding. There is also a method to release the lock, but for now > I''m just starting with an entry already created in the locks table, so > it will always return with locked = 1. What''s happening is that when > I send 10 or so simultaneous requests, invariably the application > locks up after a few requests. Postgresql shows 2 transactions, one > in SELECT FOR UPDATE and the other idle. What I think is happening is > that while one request already has an exclusive lock but has not yet > issued the commit, another request issues another SELECT FOR UPDATE, > which blocks ruby and prevents the previous request from issuing the > commit and releasing the lock.Have you considered using an advisory file-lock? -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/eventmachine-talk/attachments/20060827/ae32141a/attachment.html
> Have you considered using an advisory file-lock?Different instances would be running on different servers. I got it working using a global variable to create a lock before calling getlock.
Francis Cianfrocca
2006-Aug-27 10:56 UTC
[Eventmachine-talk] using select for update in postgresql
On 8/27/06, snacktime <snacktime at gmail.com> wrote:> > > Have you considered using an advisory file-lock? > > Different instances would be running on different servers. I got it > working using a global variable to create a lock before calling > getlock. > _______________________________________________Ok, good that you have a solution. As a conceptual exercise, would it have helped you if you had a way to send the database requests asynchronously through a queueing system, that would apply them all in sequence? -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/eventmachine-talk/attachments/20060827/aee865ec/attachment.html
> > Ok, good that you have a solution. As a conceptual exercise, would it have > helped you if you had a way to send the database requests asynchronously > through a queueing system, that would apply them all in sequence?Probably not in this case. Just seems like too much added complexity for what is basically a workaround. If I didn''t have a solution, I''d probably sooner pay someone to write a non blocking postgresql adapter.