Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I lock a set of objects for an operation?

In my rails application, I have some code like this:

def foo
  if object_bar_exists
    raise "can't create bar twice!"
  end

  Bar.create
end

Which could be invoked by two different requests coming into the application server. If this code is run by two requests simultaneously, and they both run the if check at the same time, neither will find the other's bar, and 2 bars will be created.

What's the best way to create a "mutex" for "the collection of bars"? A special purpose mutex table in the DB?

update

I should emphasize that I cannot use a memory mutex here, because the concurrency is across requests/processes and not threads.

like image 713
John Bachir Avatar asked Mar 24 '11 19:03

John Bachir


People also ask

What is Object Lock?

Object Lock can help prevent objects from being deleted or overwritten for a fixed amount of time or indefinitely. You can use Object Lock to help meet regulatory requirements that require WORM storage, or to simply add another layer of protection against object changes and deletion.

How do I lock an item in place?

Lock an object in placeSelect the Inspector from the toolbar. In the Inspector, select the Lock tab. Select an object (or objects) on the canvas that you would like to lock. Choose Lock.

Which of the following options will you use to lock an object?

Press Ctrl+Alt+L.


2 Answers

The best thing to do is perform your operations in a DB transaction. Because you will probably eventually have multiple applications running and they very possibly won't share memory, you won't be able to create a Mutex lock on the application level, especially if those two application services are running on entirely different physical boxes. Here's how to accomplish the DB transaction:

ActiveRecord::Base.transaction do
  # Transaction code goes here.
end

If you want to ensure a rollback on the DB transaction then you'll have to have validation enabled on the Bar class so that an invalid save request will cause a rollback:

ActiveRecord::Base.transaction do
  bar = Bar.new(params[:bar])
  bar.save!
end

If you already have a bar object in the DB, you can lock that object pessimistically like this:

ActiveRecord::Base.transaction do
  bar = Bar.find(1, :lock => true)
  # perform operations on bar
end
like image 87
Pan Thomakos Avatar answered Oct 17 '22 11:10

Pan Thomakos


If they all the requests are coming into the same machine, and the same ruby virtual machine, you could use Ruby's built in Mutex class: Mutex Docs.

If there are multiple machines or rvms, you will have to use a database transaction to create / get the Bar object, assuming it's stored in the db somehow.

like image 31
Alex Moore Avatar answered Oct 17 '22 10:10

Alex Moore