Any body can explain it detail? When we use transaction and when we use thread?
Thank you, Reinhart
Any body can explain it detail? When we use transaction and when we use thread?
Thank you, Reinhart
Any body can explain it detail? When we use transaction and when we use thread?
That's a slightly meaningless question since the 2 are not really related, it's like saying when should I use a toothbrush and should I take a bus. The point of a transaction is to ensure that a set of changes are either all committed or none of them (no matter what happens). The classic example is a money transfer. there are 2 changes (debit alice's account, credit bob's account) and we want either both to fail or both to succeed. We don't alice to be debited but bob not credited. Threads are when you need parallel units of execution. (you won't see them a lot in rails though since large chunks of rails are not threadsafe)
Fred
Here what I want to ask.
I have some questions regarding my topic in this forum and here they are:
[1] When and why we should use Thread as good implementation for our application ? and the same question for Transaction.
[2] What are differences Thread and Transaction?
Like I said before, threads and transactions are just completely different things. What's the difference between a cucumber and a capitalism ?
Fred
Rails Terrorist wrote:
Here what I want to ask.
I have some questions regarding my topic in this forum and here they are:
[1] When and why we should use Thread as good implementation for our application ? and the same question for Transaction.
Transactions are related to state, threads to process. Transactions are used to force logical atomicity when the data store implementation breaks the state transformation into multiple discrete parts. The common example is that of a funds transfer between accounts as given above.
Threads are used when activity can be safety detached and allowed to complete without the parent process having to wait. An example would be starting a file upload, detaching that process as a thread and immediately returning the focus to the UI allowing the user to perform a different action without waiting until the upload completes.
As mentioned above, the current implementation of Rails makes the use of threads inherently unsafe and problematic.
[2] What are differences Thread and Transaction?
Thread is for processes, transactions are for data.
[3] How we can prevent DeadLock in ActiveRecord?
By default, ActiveRecord does not perform any locking so the issue does not arise. If you implement row locking by adding the magic attribute lock_version then you get optimistic locking based on version tracking and again, a deadlock is not possible.
[4] How I can put Time Record for my Log, specially in test.log for each its line?
See:http://wiki.rubyonrails.org/rails/pages/HowtoConfigureLogging
specifically:
class Logger def format_message(severity, timestamp, progname, msg) "#{timestamp} (#{$$}) #{msg}\n" end end
Google is your friend.
James Byrne wrote:
See:http://wiki.rubyonrails.org/rails/pages/HowtoConfigureLogging
specifically:
class Logger def format_message(severity, timestamp, progname, msg) "#{timestamp} (#{$$}) #{msg}\n" end end
Be sure to read the entire article and determine which parts are applicable to the version of Rails that you are using.
That's not entirely true (see MySQL :: MySQL 8.0 Reference Manual :: 15.7.5 Deadlocks in InnoDB). The database itself clearly requires a lock of some sort of place while running an update for example, 2 things trying to update the same thing under the right conditions can give rise to a deadlock.
Fred
James Byrne wrote:
By default, ActiveRecord does not perform any locking so the issue does not arise. If you implement row locking by adding the magic attribute lock_version then you get optimistic locking based on version tracking and again, a deadlock is not possible.
What is the meaning of attribute lock_version? I was no problem when i used lock like :
ModelName.find(params[:id], :lock=>true),
But when i change to be :
ModelName.find(:all, :lock=>true, :conditions["expired_at > ?", Time.now])
The DeadLock is always happened.
Google is your friend.
Only small articles explained detail about Transaction and Lock in Theory. By The way, thanks for your cooling answer in all my questions.
Looking for your next respond
Reinhart http://teapoci.blogspot.com
I am not sure where exactly you are coming from, but if you are reading a lot about threads when dealing with database deadlocks, a thread is short hand for "some process that asks the DB for data". For example, two Rails servers hitting the same database would be termed as "two threads" even though they are really entirely different programs on different machines. What they mean by "threads" is internal to the database program... each connection to a MySQL server has it's own internal thread inside MySQL (confusing, huh?). Others have explained transactions, so I won't go into that here.
In general, my advice on locking is don't. 9/10 of the time you don't need it. Why are you locking on find in the first place? You do realize this probably locks the entire table in the second case, right? You should only lock when you are worried specifically about *bad* (not incomplete or the latest and greatest... they can run the query again if they want to get the last 30 seconds of data) data coming back to the user, or an inconsistent state. The reason deadlocks happen on the latter query is because you are scanning the entire table (effectively building up a temporary table in memory out of the condition in the where clause). This takes longer, making deadlocks more likely. All this is besides the fact that you should almost never use table locks with InnoDB, since table locks and row locks are handled by two different systems internally (and thus they don't always know about each other's locking... see the documentation for details).
1) Make sure you are using InnoDB tables (Rails does this by default. If you aren't using MySQL, check your documentation). They are much better at managing locks. 2) Don't issue lock statements unless you are running into problems. 99% of the time, the database knows when and when not to lock (especially with InnoDB). 3) Don't lock on select unless you are *absolutely* sure you need it, since selects are usually 90% of your application. If you need to lock the returned records (i.e. you are going to update them and you don't want anyone else messing with them), use FOR UPDATE or an equivalent lock that locks records and not tables. You may also look into LOCK IN SHARE MODE if you are looking for consistent reads in a transaction. 4) If you use transactions, order your table accesses in the same order in every transaction (I use alphabetical order myself for simplicity). Deadlocks usually occur under this condition:
Query A locks table A Query B locks table B Query A tries to lock table B and fails Query B tries to lock table A and fails Both queries deadlock. If they tried to access these same tables, except in the same order as the other query, the deadlock does not occur.
5) Always check the debug output from rails and the internal DB logs to ensure you are running the queries you think you are running. Since there is no one-to-one mapping between AR's semantics and (My|MS| Postgre)SQL's, the actual query text for advanced queries may not be what you expect. For example, what kind of lock does AR use in this case, assuming MySQL backend? Who knows? Caveat emptor.
6) SHOW ENGINE INNODB STATUS - the #1 tool for solving deadlock issues.
The MySQL documentation should help you find out where you are going wrong (RTFM baby!).
http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html http://dev.mysql.com/doc/refman/5.0/en/innodb-deadlocks.html
I implement it :
class BarangTerpesan < ActiveRecord::Base
def self.hitung_item_dikotak(kode_barang, hari_h, hari_out) if hari_out != nil barang = find(:all, :conditions => ["barang_id = ? AND hari_out > ? AND hari_h <= ?",kode_barang, hari_h, hari_out], :lock=>true)
else barang = find(:all, :conditions => ["barang_id = ? AND hari_h =? AND hari_out IS NULL", kode_barang, hari_h], :lock=> true)
end
barang.inject(0){|x,y| x + y.jumlah}
end
... end
And here is my test.log about dead lock :
And here's the code for pesimistic :lock => true http://pastie.org/195869
I tried implementing optimistic lock by adding 'magic' column lock_version in barang_terpesans table. but still not work (inconsistent data is always happened.)
Thank yOu
Reinhart
Calls to the database driver block until results are available. You can easily deadlock Ruby threads if you request & obtain a mysql lock in one thread then request the same lock in another thread: the database driver in the second thread will block until the mysql lock is released, but the first thread will be blocked by the second thread, unable to complete its work and release the mysql lock.
This can be solved by using multiple processes instead of multiple threads, by serializing database access across all threads, by using a pure-Ruby database driver, or by using the native postgresql or oracle drivers which support nonblocking db calls when you enable ActiveRecord::Base.allow_concurrency.
Best, jeremy
Clever Neologism, thank you for your references theory. but those references are teaching the way transaction in store procedure. But i need the way rails handle deadlock.
Rails has 2 key types, they are optimistic lock and pesimistic lock. I used pesimistic lock such as a ':lock=>true' to handle inconsistency data into focus table (barang_terpesans). But if i trid .find(:all, :lock=>true, :conditions=>[...]) it is always DeadLock.
I was trying an optimistic lock by adding lock_version column in barang_terpesans table but still can't handle inconsistency data. I tried like it :
I hope some one can help me in handle deadlock in rails way.
Thank you again very much, Reinhart
Clever Neologism wrote:
The reason deadlocks happen on the latter query is because you are scanning the entire table (effectively building up a temporary table in memory out of the condition in the where clause). This takes longer, making deadlocks more likely. All this is besides the fact that you should almost never use table locks with InnoDB, since table locks and row locks are handled by two different systems internally (and thus they don't always know about each other's locking).
The MySQL documentation should help you find out where you are going wrong (RTFM baby!).
http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html http://dev.mysql.com/doc/refman/5.0/en/innodb-deadlocks.html
I am interested with your statement above, because that is exactly happened to me. Ok let's forget about deadlock first. I do experiment for 2 transaction with same code in rails way here is my code : http://pastie.org/195869
And here is my ActiveRecord Which is containing LOCK. http://pastie.org/195875
And the problem now when 2 concurrent process run, each transactions take exclusive lock and execute it, the theory said that if one exclusive lock is taken another transaction which is wanting exclusive lock should wait till the previous lock is released.
Here is my record of log : http://pastie.org/195865
at lines 16 - 21 in Log : Transaksi 1 grant exclusive lock
at lines 50 - 55 in Log : Transaksi 2 grant Exclusive too, whereas Transaksi 1 is not released it.
at lines 83 - 89 in Log : Transaksi 2 gets DeadLock
My question now : "Why Transaction 2 can grant exclusive lock while Transaction 1 still not release the exclusive lock.?"
Thank you.
I've never seen a deadlock on a single table like that, and I am not positive why it's doing that either. But I am wondering why you are locking at all when you aren't updating the very records you are locking. Something tells me you really don't need those locks. But it's your code, so if you want to fix the issue, in that rescue clause, simply re-call the method it's in again, and retry the transaction (for, say, 3 times or so). If you get deadlocks all the time, you need to rethink your locking scheme, and maybe loosen your restrictions on just how accurate the data needs to be. If you are trying to keep "jumlah" , that sum you are finding in one of your queries, consistent, maybe make another table that keeps track of that variable, and simply use decrement and increment statements (i.e. SET value = value + 1), then you don't have to worry about locking on that value, since it's never actually manually written to (just increased or decreased).
Those are the only two solutions I can think of at the moment, and without knowing exactly what these table names mean, I am kind of stabbing in the dark as to what you are trying to accomplish.