Tracing Library Cache Locks

While working on a recent problem, I missed a possibility of tracing library cache locks. In contrast, row cache locks can be traced with the event 10222:

...
kqrpre: optimistic lookup: success
kqrpre: done po=7fffbd990200 cid=8 flg=0 eq=0 pso=99184ec8 dur=CALL
kqrpre: keyIndex=0 hash=162240d8 d53980ff 0
kqrpre: obobn=690 obname=OPTSTAT_HIST_CONTROL$ obtyp=2 obsta=1 obflg=4194304
kqrpre: returnVal: TRUE
...

As far as I know, there isn’t anything similar for library cache locks. If you were thinking of querying x$kgllk or dumping the library cache, they provide just a momentary snapshot of the current state. But sometimes, it’s useful to observe the library cache locks over time. SQL trace shows that information, but only for blocked requests.

In order to close this gap I, first, examined the following two Oracle C functions on the release 19.6.0.0.200114: kgllkal and kglGetSO.

kgllkal allocates a library cache lock. It receives the following arguments:

  • rdx: handle address
  • rcx: lock mode

Further, it calls kglGetSO to allocate the library cache state object. kglGetSO returns the lock address.

That being said, it’s easy to come up with the DTrace script which assembles the useful information:

#pragma D option quiet

pid$target:oracle:kgllkal:entry
{
  printf("%Y\n", walltimestamp);
  ustack();
  self->kgllkhdl = arg2;
  self->kgllkmod = arg3;
}

pid$target:oracle:kglGetSO:entry
/ self->kgllkhdl /
{
  self->kglGetSO = 1;
}

pid$target:oracle:kglGetSO:return
/ self->kglGetSO /
{
  printf("\n");
  printf("KGLLKHDL KGLLKMOD KGLLKADR\n");
  printf("-------- -------- --------\n");
  printf("%X %8d %X\n" , self->kgllkhdl, self->kgllkmod, arg1 );
  printf("\n");
  printf("==========================\n");
  printf("\n");
  self->kglGetSO = 0;
}

pid$target:oracle:kgllkal:return
{
  self->kgllkhdl = 0;
  self->kgllkmod = 0;
}

Here’s a sample output:


...
==========================

2020 May  8 22:02:18

              oracle`kgllkal
              oracle`kglLockCursor+0x83c
              oracle`kkspbd0+0x161
              oracle`kksParseCursory+0x1a5
              oracle`opiosq0+0xb72
              oracle`opipls+0x1a52
              oracle`opiodr+0x439
              oracle`rpidrus+0xdc
              oracle`skgmstack+0x59
              oracle`rpidru+0x9f
              oracle`rpiswu2+0x22e
              oracle`rpidrv+0x551
              oracle`psddr0+0x22f
              oracle`psdnal+0x31a
              oracle`pevm_EXECC+0x14a
              oracle`pfrinstr_EXECC+0x41
              oracle`pfrrun_no_tool+0x3c
              oracle`pfrrun+0x54a
              oracle`plsql_run+0x2c0
              oracle`peicnt+0x16c

KGLLKHDL KGLLKMOD KGLLKADR
-------- -------- --------
9E4C2908        1 99B2BFA8

==========================

2020 May  8 22:02:18

              oracle`kgllkal
              oracle`kglLockCursor+0x83c
              oracle`kxsGetLookupLock+0x67
              oracle`kkscsCheckCursor+0x1b2
              oracle`kkscsSearchChildList+0x398
              oracle`kksfbc+0xabd
              oracle`kkspbd0+0x39f
              oracle`kksParseCursor+0x1a5
              oracle`opiosq0+0xb72
              oracle`opipls+0x1a52
              oracle`opiodr+0x439
              oracle`rpidrus+0xdc
              oracle`skgmstack+0x59
              oracle`rpidru+0x9f
              oracle`rpiswu2+0x22e
              oracle`rpidrv+0x551
              oracle`psddr0+0x22f
              oracle`psdnal+0x31a
              oracle`pevm_EXECC+0x14a
              oracle`pfrinstr_EXECC+0x41

KGLLKHDL KGLLKMOD KGLLKADR
-------- -------- --------
9C7093A8        1 99B2BDD8

==========================

The script shows the call stacks, thus, providing the context of each lock allocation. In the example above, the first entry is for parsing a parent cursor, the second for a child cursor.

The script also shows the columns from x$kgllk, which is, by the way, the SQL interface to the shared memory structure underpinning library cache locks:

  • KGLLKHDL: handle address (parameter 1 of library cache lock wait event)
  • KGLLKADR: lock address (parameter 2 of library cache lock wait event)
  • KGLLKMOD: lock mode (contained in the parameter 3 of library cache lock wait event)

You can use these values for querying the database:

select kgllkhdl,kglhdpar,kgllkmod,kglnaobj,kgllkuse from x$kgllk 
  where kgllkadr in ('0000000099B2BFA8','0000000099B2BDD8') ;

KGLLKHDL         KGLHDPAR           KGLLKMOD KGLNAOBJ                                                     KGLLKUSE
---------------- ---------------- ---------- ------------------------------------------------------------ ----------------
000000009C7093A8 000000009E4C2908          1 UPDATE /*+ OPT_PARAM('_parallel_syspls_obey_force' 'false')  00000000BA662B50
000000009E4C2908 000000009E4C2908          1 UPDATE /*+ OPT_PARAM('_parallel_syspls_obey_force' 'false')  00000000BA662B50

Note that the output above confirms the relationship between the parent and the child cursor that we deduced by observing the call stacks.

Once more, DTrace proved invaluable for extending the observability in the Oracle database.

Thanks for sharing

Nenad Noveljic

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.