Even in the new world of stateless web applications, from time to time we still come across the “lunch break locking” problem. That is, someone or something, commences a transaction which locks some rows, and then their session goes idle, without committing or rolling back the transaction. The metaphor commonly used was the “someone locks a row in a table and then goes out for lunch”, with them being totally oblivious to the havoc they have caused until they return.
With modern applications being generally stateless (or transactionally stateless) you would think the problem would have disappeared, but if anything, whilst the frequency of the problem has dropped, the diagnosis of the problem when it occurs is harder than ever. The anonymity of application server sessions, and the scale of web-based customers means when a session does “lose track” of what it was doing and leaves a transaction active, it is very hard to detect until we have a major problem or outage on our hands.
But here’s a mitigation strategy you might want to consider. Resource Manager can do some of the heavy lifting for you. It can kill sessions that are idle but are blocking other sessions from completing their work.
Here’s a simple demo of how to put a resource manager plan in place to do that
SQL> begin 2 dbms_resource_manager.create_pending_area(); 3 -- 4 5 dbms_resource_manager.create_consumer_group( 6 CONSUMER_GROUP=>'CG_STOP_BLOCKERS', 7 COMMENT=>'CG for stop blocking' 8 ); 9 10 dbms_resource_manager.create_plan( 11 PLAN=> 'STOP_BLOCKERS', 12 COMMENT=>'Plan for stop blocking' 13 ); 14 15 dbms_resource_manager.create_plan_directive( 16 PLAN=> 'STOP_BLOCKERS', 17 GROUP_OR_SUBPLAN=>'CG_STOP_BLOCKERS', 18 COMMENT=>'Directive', 19 MAX_IDLE_BLOCKER_TIME => 60 20 ); 21 22 23 dbms_resource_manager.create_plan_directive( 24 PLAN=> 'STOP_BLOCKERS', 25 GROUP_OR_SUBPLAN=>'OTHER_GROUPS', 26 COMMENT=>'leave others alone' 27 ); 28 29 DBMS_RESOURCE_MANAGER.VALIDATE_PENDING_AREA; 30 31 DBMS_RESOURCE_MANAGER.SUBMIT_PENDING_AREA(); 32 33 end; 34 / PL/SQL procedure successfully completed.
The key element here is the plan directive, which sets MAX_IDLE_BLOCKER_TIME to 60 seconds. So if an idle session is blocking another for that duration, resource manage will kill the session. Let’s assign the the appropriate consumer group to SCOTT, enable the plan and see it in action
SQL> exec dbms_resource_manager_privs.grant_switch_consumer_group('SCOTT','CG_STOP_BLOCKERS',false); PL/SQL procedure successfully completed. SQL> exec dbms_resource_manager.set_initial_consumer_group('SCOTT','CG_STOP_BLOCKERS'); PL/SQL procedure successfully completed. SQL> ALTER SYSTEM SET RESOURCE_MANAGER_PLAN = STOP_BLOCKERS; System altered. SQL> conn scott/tiger Connected. SQL> create table t as select 1 x from dual; Table created. SQL> delete from t; 1 row deleted.
So this session now has a lock on the row, but is now idle…Now we fire up another session who will get blocked
SQL> set timing on SQL> delete from t; [waiting]
After approximately 60 seconds, the second session did in fact respond
SQL> set timing on SQL> delete from t; 1 row deleted. Elapsed: 00:00:58.09
So presumably the lock from session 1 has been released. If we return to session 1, we can see how the lock get released
SQL> select * from dual; select * from dual * ERROR at line 1: ORA-03113: end-of-file on communication channel Process ID: 24708 Session ID: 593 Serial number: 59128
They got killed ! So they can take their time at lunch, and come back with their double-choc muffins, chai latte and watercress salad…We don’t care, because our application is protected