DBA Data[Home] [Help]

PACKAGE BODY: APPS.FND_DCP

Source


1 package body FND_DCP as
2 /* $Header: AFCPDCPB.pls 120.5.12020000.3 2012/10/11 22:31:51 ckclark ship $ */
3 
4   --
5   -- PRIVATE VARIABLES
6   --
7 
8   DAY	   constant number	:= 86400;	-- In secs
9   EON	   constant number	:= 86400000;	-- 1000 days in secs
10   NTRUE	   constant number	:= 1;
11   NFALSE   constant number	:= 0;
12   SYSADMIN constant number	:= 0;
13   MGRUSRID constant number	:= 4;
14   THRSHLD  constant number	:= 2;		-- PMON method
15   DEFSLEEP constant number	:= 60;		-- PMON method
16   TSTAMP   constant number	:= 1;		-- PMON method
17   FNDCPLK  constant varchar2(8) := 'FNDCPLK_';
18 
19   my_node        varchar2(30);
20   --
21   -- PRIVATE PROCEDURES, FUNCTIONS
22   --
23 
24   /* Private -- inserts info in FND_CONCURRENT_DEBUG_INFO */
25 
26   procedure debug_fnd_dcp (fn  in varchar2,
27                            msg in varchar2,
28                            txn in number default NULL) is
29   pragma AUTONOMOUS_TRANSACTION;
30   userid number;
31   begin
32    select user_id into userid from user_users;
33 
34    insert into fnd_concurrent_debug_info
35      (SESSION_ID, USER_ID, LOGIN_ID, FUNCTION, TIME, ACTION, MESSAGE)
36    values
37      (userenv('SESSIONID'), userid, fnd_global.login_id, fn,
38      sysdate, 'TXN NO '|| nvl(to_char(txn),'NULL'), msg);
39 
40    commit;
41 
42   end debug_fnd_dcp;
43 
44   function get_icm_info (logf in out nocopy varchar2,
45 			 node in out nocopy varchar2,
46 			 inst in out nocopy varchar2)
47 			 return number is
48 
49 	cpid	number(15) := null;
50 
51   begin
52 	select concurrent_process_id,
53                node_name,
54 	       logfile_name,
55 	       db_instance
56 	  into cpid,
57                node,
58 	       logf,
59 	       inst
60 	  from fnd_concurrent_processes
61 	 where concurrent_process_id in (
62 			select max (concurrent_process_id)
63 			  from fnd_concurrent_processes
64 			 where queue_application_id = 0
65 			   and concurrent_queue_id  = 1
66 			   and process_status_code in ('A', 'M', 'K'));
67 
68         if( FND_LOG.LEVEL_EVENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
69           fnd_log.string(FND_LOG.LEVEL_EVENT, 'fnd.plsql.FND_DCP.GET_ICM_INFO',
70                   'ICM info: cpid=' ||cpid||', node='||node||', inst=' ||inst);
71         end if;
72 
73 	return (cpid);
74 
75 	exception
76 	  when others then
77 	    return (null);
78   end get_icm_info;
79 
80 
81   function get_pid_time (ti   in out nocopy number,	-- PMON method
82 			 td   in out nocopy number,
83 			 apid in     number,
84 			 qid  in     number,
85 			 psc1 in     varchar2 default null,
86 			 psc2 in     varchar2 default null,
87 			 psc3 in     varchar2 default null,
88 			 psc4 in     varchar2 default null)
89 			 return number is
90 
91 	cpid	number(15) := null;
92 
93   begin
94 	select nvl (sleep_seconds, DEFSLEEP)
95 	  into ti
96 	  from fnd_concurrent_queues
97 	 where application_id      = apid
98 	   and concurrent_queue_id = qid;
99 
100 	select concurrent_process_id,
101 	       (sysdate - last_update_date) * DAY
102 	  into cpid,
103 	       td
104 	  from fnd_concurrent_processes
105 	 where concurrent_process_id in (
106 			select max (concurrent_process_id)
107 			  from fnd_concurrent_processes
108 			 where queue_application_id = apid
109 			   and concurrent_queue_id  = qid
110 			   and process_status_code in (
111 					psc1, psc2, psc3, psc4))
112 	   for update nowait;
113 
114 	return (cpid);
115 
116 	exception
117 	  when others then
118 	    return (null);
119   end get_pid_time;				-- PMON method
120 
121   -- ### OVERLOADED ###
122   /*------------------------------------------------------------------|
123    | Private: For use by ATG Only. Please use Check_Process_Status or |
124    |          Request_Session_Lock                                    |
125    |------------------------------------------------------------------|
126    | Bug 2093806: The purpose of this overload for Request_Lock is    |
127    | request a lock by a known handle and to offer more flexibility   |
128    | for the call to DBMS_LOCK.Request.  This procedure accepts a     |
129    | timeout value, and lock mode value.  Instead of interpreting the |
130    | return code from DBMS_LOCK.Request as the  parameter "e_code" set|
131    | to NTRUE (1) or NFALSE (0), the parameter "result" is set to the |
132    | return code for interpretation by the calling function.  If      |
133    | result = NULL, indicates when others exception was raised.       |
134    |------------------------------------------------------------------*/
135   procedure request_lock (hndl    in	 varchar2,
136                           lmode   in     number   default null, -- lock mode
137                           timeout in     number   default null,
138 			  result  in out nocopy number) is
139   begin
140 
141         result := NULL;
142 
143         if ((timeout IS NULL) and (lmode IS NULL )) then
144         /*-------------------------------------------------------+
145          | When caller does not specify, use dbms_lock defaults, |
146          | currently MAXWAIT (32767 secs) X_MODE (6-Exclusive)   |
147          +-------------------------------------------------------*/
148 	  result := dbms_lock.request ( lockhandle => hndl );
149         elsif (timeout IS NULL) then
150           result := dbms_lock.request ( lockhandle => hndl,
151                                         lockmode   => lmode );    -- MAXWAIT
152         elsif (lmode IS NULL) then
153           result := dbms_lock.request ( lockhandle  => hndl,
154                                         timeout     => timeout ); -- ULX lock
155         else
156 	  result := dbms_lock.request ( lockhandle  => hndl,
157                                         lockmode    => lmode,
158                                         timeout     => timeout);
159         end if;
160 
161         /*-------------------------------------------------------+
162          | DBMS_LOCK.Request Result codes:                       |
163          | 0 - Success                                           |
164          | 1 - Timeout                                           |
165          | 2 - Deadlock                                          |
166          | 3 - Parameter error                                   |
167          | 4 - Already own lock specified by lockhandle          |
168          | 5 - Illegal lock handle                               |
169          +-------------------------------------------------------*/
170 
171   exception
172      when others then
173        fnd_message.set_name ('FND', 'CP-Generic oracle error');
174        fnd_message.set_token ('ERROR', substr (sqlerrm, 1, 30), FALSE);
175        fnd_message.set_token ('ROUTINE', 'REQUEST_LOCK (hndl)', FALSE);
176   end request_lock;
177 
178   --
179   -- PUBLIC PROCEDURES, FUNCTIONS
180   --
181 
182   procedure get_lk_handle (apid	  in     number,
183 			   qid	  in     number,
184 			   pid	  in     number,
185 			   hndl	  in out nocopy varchar2,
186 			   e_code in out nocopy number,
187 			   exp_sec in number default 86400000) is
188 
189 	result	number;
190 	lk	varchar2(128);
191 
192   begin
193 	e_code := NTRUE;
194 
195 	hndl := NULL;
196 
197 	if (apid = 0 and qid = 1 and pid = 0) then
198 	  lk := FNDCPLK || 'ICM';
199 	else
200 	  lk := FNDCPLK || apid || '_' || qid || '_' || pid;
201 	end if;
202 
203 	dbms_lock.allocate_unique (lk, hndl, exp_sec);
204 
205 	exception
206 	  when others then
207 	    e_code := NFALSE;
208 	    fnd_message.set_name ('FND', 'CP-Generic oracle error');
209 	    fnd_message.set_token ('ERROR', substr (sqlerrm, 1, 30), FALSE);
210 	    fnd_message.set_token ('ROUTINE', 'get_lk_handle', FALSE);
211   end get_lk_handle;
212 
213   /*------------------------------------------------------------------|
214    | Bug 2093806: The purpose of Request_Session_Lock is to provide   |
215    | an API which can be used for a manager process (ICM, CM, IM, CRM,|
216    | TM) to request it's own lock for the session.  This procedure    |
217    | is not meant to be used for a process (such as an Apps form, OAM |
218    | procedure or ICM in PMON cycle) to check the lock of another     |
219    | process.  This procedure will wait for the default of  MAXWAIT   |
220    | for the RDBMS to grant the requested lock. If the parameters "lk"|
221    | and "hndl" are returned as NULL, then there was a problem. The   |
222    | calling process can analyze the "result" parameter to determine  |
223    | why the request was not granted.                                 |
224    |------------------------------------------------------------------*/
225   procedure request_session_lock (apid	 in     number,
226 			          qid    in     number,
227 			          pid    in     number,
228 			          lk     in out nocopy varchar2,
229 			          hndl   in out nocopy varchar2,
230 			          result in out nocopy number) is
231 	ecode     number;
232 	timeout   number;
233   begin
234         if( FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
235     	    fnd_log.string(FND_LOG.LEVEL_STATEMENT,
236                   'fnd.plsql.FND_DCP.REQUEST_SESSION_LOCK',
237                   'request_session_lock called for apid='||to_char(apid)||
238                   ', qid='||to_char(qid)||', pid='||to_char(pid));
239         end if;
240 
241         result := null;
242 
243         /*-------------------------------------------------------+
244          | Construct the lock name for out parameter "lk" and    |
245          | set timeout for Request_Lock.                         |
246          +-------------------------------------------------------*/
247 	if (apid = 0 and qid = 1 and pid = 0) then
248 	  lk      := FNDCPLK || 'ICM';
249           timeout := 5;     -- ICM only waits 5 secs for lock request.
250 	else
251 	  lk      := FNDCPLK || apid || '_' || qid || '_' || pid;
252           timeout := null;  -- Others wait MAXWAIT for lock request.
253 	end if;
254 	if( FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
255 	    fnd_log.string(FND_LOG.LEVEL_STATEMENT,
256                   'fnd.plsql.FND_DCP.REQUEST_SESSION_LOCK',
257                   'lock name='||lk);
258         end if;
259 
260         /*-------------------------------------------------------+
261          | Get handle for the request.                           |
262          +-------------------------------------------------------*/
263         get_lk_handle (apid      => apid,
264                        qid       => qid,
265                        pid       => pid,
266                        hndl      => hndl,
267                        e_code    => ecode);
268         if (ecode = NFALSE) then
269         /*-------------------------------------------------------+
270          | Message available in dictionary set by Get_Lk_Handle  |
271          +-------------------------------------------------------*/
272           lk   := null;
273           hndl := null;
274           return;
275         else
276           if( FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
277               fnd_log.string(FND_LOG.LEVEL_STATEMENT,
278                   'fnd.plsql.FND_DCP.REQUEST_SESSION_LOCK',
279                   'for lock name='||lk||' hndl='||hndl);
280           end if;
281         end if;
282 
283         /*-------------------------------------------------------+
284          | Request with mode of exclusive (ULX), with timeout    |
285          +-------------------------------------------------------*/
286         request_lock (hndl    =>     hndl,
287                       lmode   =>     6,
288                       timeout =>     timeout,
289                       result  =>     result);
290         if( FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
291             fnd_log.string(FND_LOG.LEVEL_STATEMENT,
292                   'fnd.plsql.FND_DCP.REQUEST_SESSION_LOCK',
293                   'result of request_lock: '||to_char(result));
294         end if;
295 
296         if (result in (0, 4)) then
297           return;
298         else
299           fnd_message.set_name ('FND', 'CONC-DBMS_LOCK.Request result');
300           fnd_message.set_token ('ROUTINE',
301                                  'FND_DCP.REQUEST_SESSION_LOCK', FALSE);
302           fnd_message.set_token ('RESULT',
303                                  nvl(to_char(result),'NULL'), FALSE);
304           lk   := null;
305           hndl := null;
306           return;
307         end if;
308 
309   end request_session_lock;
310 
311   /*------------------------------------------------------------------|
312    | Bug 2093806: The purpose of Check_Process_Status_By_Handle is to |
313    | provide an API which can be used for a process (such as an Apps  |
314    | form, OAM procedure or ICM in PMON cycle) to check the lock of   |
315    | another process (such as ICM, CM, IM, CRM, TM).  This procedure  |
316    | will immediately time out if the RDBMS does not grant the lock.  |
317    | If process is alive, alive = NTRUE(1). Otherwise, alive =        |
318    | NFALSE(0).  Calling process can analyze the "result" parameter to|
319    | determine  why/why not the lock was granted, if desired.         |
320    |------------------------------------------------------------------*/
321   procedure check_process_status_by_handle (hndl   in   varchar2,
322                                             result out  nocopy number,
323                                             alive  out  nocopy number) is
324 
325 	dummy	    number;
326 
327   begin
328         if( FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
332         end if;
329             fnd_log.string(FND_LOG.LEVEL_STATEMENT,
330                   'fnd.plsql.FND_DCP.CHECK_PROCESS_STATUS_BY_HANDLE',
331                   'check_process_status_by_handle called for hndl='||hndl);
333 
334         /*-------------------------------------------------------+
335          | Request with mode of row share (ULRS), timeout of 0   |
336          +-------------------------------------------------------*/
337         request_lock (hndl    =>     hndl,
338                       lmode   =>     2,
339                       timeout =>     0,
340                       result  =>     result);
341         if( FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
342             fnd_log.string(FND_LOG.LEVEL_STATEMENT,
343                   'fnd.plsql.FND_DCP.CHECK_PROCESS_STATUS_BY_HANDLE',
344                   'result of request_lock: '||to_char(result));
345         end if;
346 
347         if (result = 0) then
348             /*-------------------------------------------------------+
349              | Lock for handle was granted                           |
350              +-------------------------------------------------------*/
351              alive := NFALSE;            -- manager not alive
352              release_lock(hndl, dummy);
353              return;
354         elsif (result = 4) then
355             /*-------------------------------------------------------+
356              | This process owns the lock, it must be alive!         |
357              +-------------------------------------------------------*/
358              alive := NTRUE;
359              release_lock(hndl, dummy);
360              return;
361         elsif (result in (1, 2)) then
362             /*-------------------------------------------------------+
363              | Lock for handle not granted (2 should never occur)    |
364              +-------------------------------------------------------*/
365              alive := NTRUE;             -- manager alive
366              return;
367         else
368             /*-------------------------------------------------------+
369              | Lock for handle not granted:                          |
370              | result = (3 or 5 from DBMS_LOCK.Request or            |
371              |          still NULL from Request_Lock                 |
372              +-------------------------------------------------------*/
373              alive := NTRUE;             -- assume manager alive
374              fnd_message.set_name ('FND', 'CONC-DBMS_LOCK.Request result');
375          fnd_message.set_token ('ROUTINE',
376                                     'FND_DCP.CHECK_PROCESS_STATUS_BY_HANDLE',
377                                     FALSE);
378          fnd_message.set_token ('RESULT',
379                                     nvl(to_char(result), 'NULL'), FALSE);
380 
381         end if;
382 
383   end check_process_status_by_handle;
384 
385   /*------------------------------------------------------------------|
386    | Bug 2093806: The purpose of Check_Process_Status_By_Ids is to    |
387    | provide an API which can be used for a process (such as an Apps  |
388    | form, OAM procedure or ICM in PMON cycle) to check the lock of   |
389    | another process (such as ICM, CM, IM, CRM, TM).  This procedure  |
390    | uses the Application Id, Queue Id, and O/S Pid to construct the  |
391    | named lock for the request. The procedure  will immediately time |
392    | out if the RDBMS does not grant the lock.  If process is alive,  |
393    | alive = NTRUE(1). Otherwise, alive = NFALSE(0). Calling process  |
394    | can analyze the "result" parameter to determine why/why not the  |
395    | lock was granted, if desired.                                    |
396    |------------------------------------------------------------------*/
397   procedure check_process_status_by_ids (apid    in     number,
398                                          qid     in     number,
399                                          pid     in     number,
400                                          result  out    nocopy number,
401                                          alive   out    nocopy number) is
402 
403         hndl        varchar2(128) := NULL;
404 	dummy	    number;
405 
406   begin
407 
408         /*-------------------------------------------------------+
409          | Get handle for the request                            |
410          +-------------------------------------------------------*/
411         get_lk_handle (apid      => apid,
412                        qid       => qid,
413                        pid       => pid,
414                        hndl      => hndl,
415                        e_code    => dummy);
416 
417         /*-------------------------------------------------------+
418          | Check the process' status by the handle               |
419          +-------------------------------------------------------*/
420         check_process_status_by_handle (hndl   => hndl,
421                                         result => result,
422                                         alive  => alive);
423 
424   end check_process_status_by_ids;
425 
426 
427   -- ### OVERLOADED ###
428   /*------------------------------------------------------------------|
429    | Obsolete: Please use Request_Session_Lock, Check_Process_Status  |
430    |           or Check_Process_Status_By_Handle                      |
431    +------------------------------------------------------------------*/
432   procedure request_lock (apid	in     number,
433 			  qid	in     number,
434 			  pid	in     number,
435 			  lk	in out nocopy varchar2,
436 			  hndl	in out nocopy varchar2,
437 			  e_code in out nocopy number) is
438 
439 	result	number;
440         count   number;
441 
442   begin
443 	e_code := NTRUE;
444 
445 	if (apid = 0 and qid = 1 and pid = 0) then
446 	  lk := FNDCPLK || 'ICM';
447 	else
451 	dbms_lock.allocate_unique (lk, hndl, EON);
448 	  lk := FNDCPLK || apid || '_' || qid || '_' || pid;
449 	end if;
450 
452 	result := dbms_lock.request (hndl, 6, 0);  -- ULX lock
453 
454 	if (result in (0, 4)) then	-- Success or own lock
455 	  return;
456 	elsif (result in (1, 2)) then	-- Timeout or deadlock
457 
458           /* ------------------------------------------------------- */
459           /* Bug 1967288: Timout occasionally returned when manager  */
460           /* log backs into database with afpcsq(). So, try up to 2  */
461           /* more times with 5 second timeout.                       */
462           /* We cannot wait much longer since Forms and OAM use this */
463           /* version of Request_Lock to check each manager's status  */
464           /* This is a short-term fix until more robust restructuring*/
465           /* can be done with lock management procedures, functions. */
466           /* ------------------------------------------------------- */
467 
468 	  for count in 1..2 loop
469 	    result := dbms_lock.request (hndl, 6, 5);
470 	    exit when result in (0, 4);
471 	  end loop;
472 
473 	  if (result in (0, 4)) then	-- Success or own lock
474 	    return;
475 	  elsif (result in (1, 2)) then	-- Timeout or deadlock
476 	      lk := null;
477 	      hndl := null;
478 	  else                          -- Bad lock handle or bad param
479 	      lk   := null;
480 	      hndl := null;
481 	      e_code := NFALSE;
482 	  end if;
483 
484 	else				-- Bad lock handle or bad param
485 	  lk   := null;
486 	  hndl := null;
487 	  e_code := NFALSE;
488 	end if;
489 
490 	exception
491 	  when others then
492 	    e_code := NFALSE;
493 	    fnd_message.set_name ('FND', 'CP-Generic oracle error');
494 	    fnd_message.set_token ('ERROR', substr (sqlerrm, 1, 30), FALSE);
495 	    fnd_message.set_token ('ROUTINE', 'REQUEST_LOCK', FALSE);
496   end request_lock;
497 
498   -- ### OVERLOADED ###
499   /*------------------------------------------------------------------|
500    | Obsolete: Please use Request_Session_Lock, Check_Process_Status  |
501    |           or Check_Process_Status_By_Handle                      |
502    +------------------------------------------------------------------*/
503   procedure request_lock (hndl   in	varchar2,
504 			  status in out nocopy number,
505 			  e_code in out nocopy number) is
506 
507 	result	number;
508 
509   begin
510 	e_code := NTRUE;
511 
512 	result := dbms_lock.request (hndl, 6, 0);  -- ULX lock
513 
514 	if (result in (0, 4)) then	-- Success or own lock
515 	  status := NTRUE;
516 	elsif (result in (1, 2)) then	-- Timeout or deadlock
517 	  status := NFALSE;
518 	else				-- Bad lock handle or bad param
519 	  e_code := NFALSE;
520 	end if;
521 
522 	exception
523 	  when others then
524 	    e_code := NFALSE;
525 	    fnd_message.set_name ('FND', 'CP-Generic oracle error');
526 	    fnd_message.set_token ('ERROR', substr (sqlerrm, 1, 30), FALSE);
527 	    fnd_message.set_token ('ROUTINE', 'REQUEST_LOCK (hndl)', FALSE);
528   end request_lock;
529 
530 
531   procedure release_lock (hndl	 in     varchar2,
532 			  e_code in out nocopy number) is
533 
534 	result	number;
535 
536   begin
537         if( FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
538             fnd_log.string(FND_LOG.LEVEL_STATEMENT,
539                   'fnd.plsql.FND_DCP.RELEASE_LOCK',
540                   'release_lock called for hndl='||hndl);
541         end if;
542 	result := dbms_lock.release (hndl);
543 
544 	if ((result = 0) or (result = 4)) then
545 	  e_code := NTRUE;
546 	else
547 	  e_code := NFALSE;
548 	end if;
549 	if( FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
550             fnd_log.string(FND_LOG.LEVEL_STATEMENT,
551                   'fnd.plsql.FND_DCP.RELEASE_LOCK',
552                   'release result='||to_char(result));
553         end if;
554 	exception
555 	  when others then
556 	    e_code := NFALSE;
557 	    fnd_message.set_name ('FND', 'CP-Generic oracle error');
558 	    fnd_message.set_token ('ERROR', substr (sqlerrm, 1, 30), FALSE);
559 	    fnd_message.set_token ('ROUTINE', 'release_lock', FALSE);
560   end release_lock;
561 
562 
563   procedure clean_mgrs (e_code in out nocopy number) is
564 
565   begin
566 	null;
567   end clean_mgrs;
568 
569 
570   procedure monitor_icm (hndl   in out nocopy varchar2,
571 			 up	in out nocopy number,
572 			 logf	in out nocopy varchar2,
573 			 node	in out nocopy varchar2,
574 			 inst	in out nocopy varchar2,
575 			 cpid	in out nocopy number,
576 			 mthd	in     number,	-- PMON method
577 			 e_code in out nocopy number) is
578 
579 	lk		varchar2(50);
580 	result		number;
581 	bad_lock	exception;
582 	time_interval	number;			-- PMON method = TSTAMP
583 	time_difference	number;			-- PMON method = TSTAMP
584 	dummy		number;
585 
586   begin
587 	e_code := NTRUE;
588 
589 	if (mthd = TSTAMP) then			-- PMON method = TSTAMP
590 	  cpid := get_pid_time (time_interval,
591 				time_difference,
592 				0, 1, 'A', 'C', 'M', 'K');
593 
594 	  if (time_difference < THRSHLD * time_interval) then
595 	    up := NTRUE;
596 	    rollback;
597 	    return;
598 	  end if;
599 
600 	else					-- PMON method = DBLOCK
601 	  cpid := get_icm_info (logf, node, inst);
602 
603 	  if (hndl is not null) then
604 	    result := dbms_lock.request (hndl, 6, 0);  -- ULX lock
605 
606             if( FND_LOG.LEVEL_EVENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
610             end if;
607               fnd_log.string(FND_LOG.LEVEL_EVENT,
608                   'fnd.plsql.FND_DCP.MONITOR_ICM',
609                   'lock request result='||to_char(result)||' for hndl='||hndl);
611 
612 
613 	    if (result in (1, 2)) then	-- Timeout or deadlock
614 	      up := NTRUE;
615 	      return;
616 	    end if;
617 
618 	  end if;
619 
620 	end if;					-- PMON method TSTAMP/DBLOCK
621 
622 	if (cpid is null) then
623           if( FND_LOG.LEVEL_EVENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
624             fnd_log.string(FND_LOG.LEVEL_EVENT, 'fnd.plsql.FND_DCP.MONITOR_ICM',
625                     'get_icm_info returned cpid NULL');
626           end if;
627 
628 	  up := NTRUE;
629 	  hndl := null;
630           rollback;
631 	  return;
632 
633 	else
634           if( FND_LOG.LEVEL_EVENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
635             fnd_log.string(FND_LOG.LEVEL_EVENT, 'fnd.plsql.FND_DCP.MONITOR_ICM',
636                     'get_icm_info returned cpid='||to_char(cpid));
637           end if;
638 
639 	  lk := FNDCPLK || '0_1_' || cpid;
640 	  dbms_lock.allocate_unique (lk, hndl, EON);
641 	  result := dbms_lock.request (hndl, 6, 0);  -- ULX lock
642 
643           if( FND_LOG.LEVEL_EVENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
644             fnd_log.string(FND_LOG.LEVEL_EVENT, 'fnd.plsql.FND_DCP.MONITOR_ICM',
645                   'new lock name = '||lk);
646             fnd_log.string(FND_LOG.LEVEL_EVENT, 'fnd.plsql.FND_DCP.MONITOR_ICM',
647                   'lock request result='||to_char(result)||' for hndl='||hndl);
648           end if;
649 
650 	  if (result = 0) then		-- Success
651 	    select 1 into dummy
652             from fnd_concurrent_processes
653 	    where concurrent_process_id = cpid
654 	    for update nowait;
655 
656 	    update fnd_concurrent_processes
657 	       set process_status_code = decode (process_status_code,
658 						 'A', 'K',
659 						 'M', 'S',
660 						       process_status_code)
661 	     where concurrent_process_id = cpid;
662 	    up := NFALSE;
663 	    commit;
664 	  elsif (result in (1, 2)) then	-- Timeout or deadlock
665 	    up := NTRUE;
666 	  elsif (result = 4) then	-- Own the lock (shouldn't happen)
667 	    up := NFALSE;
668 	  else				-- Bad lock handle or bad param
669 	    raise bad_lock;
670 	  end if;
671 
672 	end if;
673 
674 	exception
675 	  when others then
676 	    e_code := NFALSE;
677 	    rollback;
678 	    fnd_message.set_name ('FND', 'CP-Generic oracle error');
679 	    fnd_message.set_token ('ERROR', substr (sqlerrm, 1, 30), FALSE);
680 	    fnd_message.set_token ('ROUTINE', 'monitor_icm', FALSE);
681   end monitor_icm;
682 
683 
684   procedure monitor_im (apid   in     number,
685 			qid    in     number,
686 			pid    in     number,
687 			cnode  in     varchar2,
688 			status in out nocopy number,
689 			e_code in out nocopy number) is
690 
691 	max_procs	number;
692 	run_procs	number;
693 	ccode		varchar2(1);	-- Control code
694 	tnode		varchar2(30);	-- Target node
695 
696   begin
697 	e_code := NTRUE;
698 
699 	select max_processes,
700 	       running_processes,
701 	       control_code,
702 	       target_node
703 	  into max_procs,
704 	       run_procs,
705 	       ccode,
706 	       tnode
707 	  from fnd_concurrent_queues
708 	 where application_id = apid
709 	   and concurrent_queue_id = qid;
710 
711 	if ((max_procs < run_procs) or
712 	    (cnode <> tnode)) then	-- Migrate
713 	  status := NFALSE;			-- Exit
714 	else
715 	  status := NTRUE;			-- Stay up
716 	end if;
717 
718 	exception
719 	  when others then
720 	    e_code := NFALSE;
721 	    fnd_message.set_name ('FND', 'CP-Generic oracle error');
722 	    fnd_message.set_token ('ERROR', substr (sqlerrm, 1, 30), FALSE);
723 	    fnd_message.set_token ('ROUTINE', 'monitor_im', FALSE);
724   end monitor_im;
725 
726 
727   procedure reassign_lkh (e_code in out nocopy number) is
728 
729 	cursor 	c1 is
730 		   select queue_application_id,
731 			  concurrent_queue_id,
732 			  concurrent_process_id,
733 			  rowid
734 		     from fnd_concurrent_processes
735 		    where manager_type between 1 and 5
736 		      and process_status_code in ('A', 'C')
737 		 order by concurrent_process_id;
738 
739 	apid	number(15);
740 	qid	number(15);
741 	pid	number(15);
742 	rid	ROWID;
743 	hndl	varchar2(128);
744 
745   begin
746 	e_code := NTRUE;
747 
748 	open c1;
749 
750 	loop
751 	  fetch c1 into apid, qid, pid, rid;
752 	  exit when c1%notfound;
753 
754 	  dbms_lock.allocate_unique (FNDCPLK ||
755 				     apid || '_' || qid || '_' || pid,
756 				     hndl, EON);
757 
758 	  update fnd_concurrent_processes
759 	     set lk_handle = hndl
760 	   where rowid = rid;
761 
762 	end loop;
763 
764 	close c1;
765 	commit;
766 
767 	exception
768 	  when others then
769 	    e_code := NFALSE;
770 	    fnd_message.set_name ('FND', 'CP-Generic oracle error');
771 	    fnd_message.set_token ('ERROR', substr (sqlerrm, 1, 30), FALSE);
772 	    fnd_message.set_token ('ROUTINE', 'reassign_lkh', FALSE);
773   end reassign_lkh;
774 
775 
776   /* function get_inst_num
777    *
778    * This function is used to determine the OPS instance
779    * to which a manager should "specialize".  For Parallel
780    * Concurrent Processing, we want the a manager to
784    * If the manager was started on its primary node, then
781    * service requests only for the instance associated with
782    * its primary node.
783    *
785    * the current instance number is retrieved from v$instance,
786    * stored in fnd_concurrent_queues, and returned to the caller.
787    *
788    * If the manager was started on its secondary node, then
789    * the instance number is retrieved from fnd_concurrent_queues
790    *
791    * Parameters:
792    *   queue_appl_id - Concurrent queue application ID.
793    *   queue_id      - Concurrent queue ID.
794    *   current_node  - Node where manager is running.
795    *
796    * Returns:
797    *   An OPS instance number.
798    *
799    * Alters:
800    *   The table fnd_concurrent_queues may be updated.
801    *
802    * Assumptions:
803    *   This function assumes that the node names stored in
804    *   fnd_concurrent_queues exactly match those in the manager's
805    *   sysinfo structure.  (i.e. Both fully qualified, or both not
806    *   fully qualified)
807    *
808    * Error conditions:
809    *
810    *   All other exceptions are unhandled.
811    */
812 
813   function get_inst_num	(queue_appl_id	in	number,
814 			 queue_id	in	number,
815 			 current_node	in	varchar2)
816 			return number is
817     primary_node   fnd_concurrent_queues.node_name%type;
818     secondary_node fnd_concurrent_queues.node_name2%type;
819     inst_num number; /* OPS Instance Number */
820   begin
821     /* Are we on the primary node?*/
822     select upper(node_name), upper(node_name2)
823       into primary_node, secondary_node
824       from fnd_concurrent_queues
825       where concurrent_queue_id = queue_id
826         and application_id = queue_appl_id;
827 
828 
829     if (upper(current_node) = primary_node) then /* PCP Primary node */
830       /* Get inst number from v$instance */
831       select instance_number
832         into inst_num
833         from v$instance;
834 
835       /* Store it into fnd_concurrent_queues. */
836 
837       update fnd_concurrent_queues
838 		set instance_number = inst_num
839 		where application_id = queue_appl_id
840 		and concurrent_queue_id = queue_id;
841 
842       /* Update the global */
843       FND_CONC_GLOBAL.Override_OPS_INST_NUM(inst_num);
844 
845     else /* we aren't on the primary node...maybe we still know the inst num*/
846       select INSTANCE_NUMBER
847       into inst_num
848       from fnd_concurrent_queues
849       where application_id = queue_appl_id
850       and concurrent_queue_id = queue_id;
851 
852       /* Update the global...if not null */
853       if (inst_num is not null) then
854 	  FND_CONC_GLOBAL.Override_OPS_INST_NUM(inst_num);
855       end if;
856     end if;
857 
858     return inst_num;
859   end;
860 
861   /* function target_node_mgr_chk
862    * If a request is targeted to a specific node, the concurrent
863    * manager will use this function in his request query (afpgrq)
864    * to filter it out if it doesn't meet any of the following conditions:
865    * a) request's target node is the same as manager's current node
866    * b)	request's target node is different from manager's current node, but the
867    *    FND_NODES status is 'N' or node_mode is not 'O' (online).
868    * c)	There are no managers specialized to run this request on request's
869    *    target node
870    *
871    * Parameters:
872    *   request_id - id of request that is targeted to a secific node
873    *
874    * Returns:
875    *   NTRUE/TRUE/1   if this request can appear in query results
876    *   NFALSE/FALSE/0 if this request should be filtered from query results
877    *
878    * Assumptions:
879    *   The manager's target_node in fnd_concurrent_queues is it's current
880    *   node.  This should always be true for active managers in afpgrq.
881    *
882    * Error conditions:
883    *
884    *   All other exceptions are unhandled.
885    */
886 
887    function target_node_mgr_chk (req_id  in number) return number is
888 
889       cursor mgr_cursor (rid number, qappid number, qid number) is
890         select queue_application_id, concurrent_queue_id,
891              running_processes, max_processes,
892              decode(control_code,
893                     'T','N',       -- Abort
894                     'X','N',       -- Aborted
895                     'D','N',       -- Deactivate
896                     'E','N',       -- Deactivated
897                         'Y') active,
898              target_node
899           from fnd_concurrent_worker_requests
900           where request_id = rid
901             and not((queue_application_id = 0)
902                   and (concurrent_queue_id in (1,4)))
903             and not((queue_application_id = qappid)
904                   and (concurrent_queue_id = qid ));
905 
906       my_q_appl_id    number := FND_GLOBAL.queue_appl_id ;
907       my_q_id         number := FND_GLOBAL.conc_queue_id;
908       req_node        varchar2(30) := null;
909       dummy           number := 0;
910       retval          number := NFALSE;
911 
912    begin
913 
914       if( FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
915           fnd_log.string(FND_LOG.LEVEL_STATEMENT,
916                'fnd.plsql.FND_DCP.TARGET_NODE_MGR_CHK',
917                'Enter TARGET_NODE_MGR_CHK for manager ('||
918                to_char(my_q_appl_id)|| '/'||my_q_id||
919                ') and request_id '|| to_char(req_id));
920       end if;
921 
922       /* Retrieve the request's target node */
923       select node_name1
924         into req_node
925         from fnd_concurrent_requests
929           fnd_log.string(FND_LOG.LEVEL_STATEMENT,
926        where request_id = req_id;
927 
928       if( FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
930                'fnd.plsql.FND_DCP.TARGET_NODE_MGR_CHK',
931                'Target node for request '||to_char(req_id)||' is '||
932                NVL(req_node,'NULL'));
933       end if;
934 
935       /* If request has no target node, okay to run it */
936       if (req_node is null) then
937          retval := NTRUE;
938       end if;
939 
940       /* Check if the request node matches my node */
941       if (retval = NFALSE) then
942         if (my_node is NULL) then
943           select target_node
944             into my_node
945             from fnd_concurrent_queues
946            where application_id = my_q_appl_id
947              and concurrent_queue_id = my_q_id;
948         end if;
949 
950         if( FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
951             fnd_log.string(FND_LOG.LEVEL_STATEMENT,
952                  'fnd.plsql.FND_DCP.TARGET_NODE_MGR_CHK',
953                  'Manager node is '||NVL(my_node,'NULL'));
954         end if;
955 
956         /* If request target node matches my node, okay to run it */
957         if (req_node = my_node) then
958            retval := NTRUE;
959         end if;
960       end if;
961 
962       /* Check if the request node is down */
963       if (retval = NFALSE) then
964         select count(*)
965           into dummy
966           from fnd_nodes
967          where node_name = req_node
968            and (node_mode <> 'O'
969             or status <> 'Y');
970 
971         if( FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
972           if dummy >= 1 then
973             fnd_log.string(FND_LOG.LEVEL_STATEMENT,
974                'fnd.plsql.FND_DCP.TARGET_NODE_MGR_CHK',
975                'Request target node '||req_node||' is DOWN');
976           else
977             fnd_log.string(FND_LOG.LEVEL_STATEMENT,
978                'fnd.plsql.FND_DCP.TARGET_NODE_MGR_CHK',
979                'Request target node '||req_node||' is UP');
980           end if;
981         end if;
982 
983          /* If request target node is down, okay to run it */
984          if (dummy >= 1) then
985             retval := NTRUE;
986 	    fnd_message.set_name ('FND', 'CONC-REQ NODE NOT HONORED');
987 	    fnd_message.set_token ('REQID', to_char(req_id), FALSE);
988 	    fnd_message.set_token ('NODE', req_node, FALSE);
989             if( FND_LOG.LEVEL_EVENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
990               fnd_log.message(FND_LOG.LEVEL_EVENT,
991                               'fnd.plsql.FND_DCP.TARGET_NODE_MGR_CHK',
992                               FALSE);
993             end if;
994          end if;
995       end if;
996 
997       /* Check if a manager is available to run this request on target node */
998       /* The first available manager we find, exit and return NFALSE        */
999       if (retval = NFALSE) then
1000         if( FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
1001            fnd_log.string(FND_LOG.LEVEL_STATEMENT,
1002               'fnd.plsql.FND_DCP.TARGET_NODE_MGR_CHK',
1003               'Enter loop to determine if another manager can run');
1004         end if;
1005         for mgr_rec in mgr_cursor(req_id, my_q_appl_id, my_q_id) loop
1006           if ((mgr_rec.active = 'Y')
1007               and (mgr_rec.max_processes > 0)
1008               and (mgr_rec.running_processes > 0)
1009               and mgr_rec.target_node = req_node) then
1010                  /* Here is an available manager, no need to continue. */
1011                  if( FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
1012                      fnd_log.string(FND_LOG.LEVEL_STATEMENT,
1013                           'fnd.plsql.FND_DCP.TARGET_NODE_MGR_CHK',
1014                           'Another manager ('||
1015                            to_char(mgr_rec.queue_application_id )||'/'||
1016                            to_char(mgr_rec.concurrent_queue_id)||
1017                           ') can run this request');
1018                  end if;
1019                  retval := NFALSE;
1020                  exit;
1021           else
1022               retval := NTRUE;
1023 	      fnd_message.set_name ('FND', 'CONC-REQ NODE NOT HONORED');
1024 	      fnd_message.set_token ('REQID', to_char(req_id), FALSE);
1025 	      fnd_message.set_token ('NODE', req_node, FALSE);
1026               if( FND_LOG.LEVEL_EVENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
1027                 fnd_log.message(FND_LOG.LEVEL_EVENT,
1028                                 'fnd.plsql.FND_DCP.TARGET_NODE_MGR_CHK',
1029                                 FALSE);
1030               end if;
1031           end if;
1032         end loop;
1033       end if;
1034 
1035       if( FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
1036        if retval = NTRUE then
1037          fnd_log.string(FND_LOG.LEVEL_STATEMENT,
1038                'fnd.plsql.FND_DCP.TARGET_NODE_MGR_CHK',
1039                'Returning retval= NTRUE');
1040        else
1041          fnd_log.string(FND_LOG.LEVEL_STATEMENT,
1042                'fnd.plsql.FND_DCP.TARGET_NODE_MGR_CHK',
1043                'Returning retval= NFALSE');
1044        end if;
1045       end if;
1046       return retval;
1047 
1048    end target_node_mgr_chk;
1049 
1050   --
1051   -- Name
1052   --   is_dcp
1053   -- Purpose
1054   --   Returns TRUE if the environment has multiple CP nodes,
1055   --   FALSE if not.
1056   --
1057   -- Parameters:
1058   -- None
1059   --
1060   -- Returns:
1061   --   NTRUE/TRUE/1   - environment is DCP
1062   --   NFALSE/FALSE/0 - environment is non-DCP
1063   --
1064   function is_dcp return number is
1065 
1066     node_count number := 0;
1067   begin
1068 
1069     select count(*)
1070       into node_count
1071       from fnd_nodes
1072      where node_name <> 'AUTHENTICATION'
1073        and support_cp = 'Y';
1074 
1075     if (node_count > 1) then
1076       return NTRUE;
1077     else
1078       return NFALSE;
1079     end if;
1080 
1081   end is_dcp;
1082 
1083 
1084 end FND_DCP;