Re: Transaction Set clean does not actually clean

Jeff Johnson <[email protected]> Fri, 14 Dec 2007 15:46:22 -0500
Newsgroups gmane.linux.redhat.rpm.python
Message-ID <[email protected]>
On Dec 14, 2007, at 2:08 PM, Mitko Haralanov wrote:

> On Fri, 7 Dec 2007 15:59:29 -0800
> Mitko Haralanov <[email protected]> wrote:
>
>> That's it! I can use the wrapper for thread safety, keep the ts
>> instance around and intercept the ts.clean() calls.
>
> The idea that you offered works perfectly when trying to clean the
> transaction set.

Good.

> However, now I am running against a different problem which I can't
> figure out how to solve without opening and closing the database:
> Since my application act like a daemon, waiting for rpm requests, the
> TransactionSet (when created) locks the database and does not allow  
> any
> other application to work with it.

Opening & closing an rpmdb is like killing mosquitoes with a bazooka.

> This, of course, is solvable with opening and closing the database but
> I remember you mentioning that this should not be done because there
> are other things that should be taken care of if done.
>

OTOH, if your goal is a dead mosquito, then just make sure that
you also have voided out any retrieved information, particularly
internal information like void keys.

Yum script kiddies are still waiting to learn that lesson afaik ...

> Would you mind elaborating on that?

You are likely dead locked in one of 3 ways:

1) The layer of single threading you've used in python on top
of (not thread safe) rpmlib. Presumably you can sort that problem  
pretty easily.

2) The fcntl lock used to protect transactions. That lock blocks
readers iff rpmtsRun() (or --rebuilddb) is called and the lock  
becomes exclusive.

Use lsof to verify whether the file path used by the transaction lock  
is open.

3) The Berkeley DB INIT_CDB cursor locks on rpmdb access itself.

INIT_CDB is used for concurrent access protection with a guarantee  
that there
is only a single write or multiple readers of a Berkeley DB at any  
point in time.

You're likely dead-locked because of the INIT_CDB locking, its the  
hardest to
diagnose problems with.

Display the current locks in a dbenv using db_stat from Berkeley DB  
utilities.
There's a copy of db_stat in /usr/lib/rpm, often renamed to rpmdb_stat.

E.g. here's a shared read lock from a paused "rpm -qa"

$ sudo /usr/lib/rpm/db_stat -Cl
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Lock REGINFO information:
Lock    Region type
4       Region ID
__db.004        Region name
0xb7c3d000      Original region address
0xb7c3d000      Region address
0xb7c3d044      Region primary address
0       Region maximum allocation
0       Region allocated
Region allocations: 3005 allocations, 0 failures, 0 frees, 1 longest
REGION_JOIN_OK  Region flags
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Locks grouped by lockers:
Locker   Mode      Count Status  ----------------- Object  
---------------
[jbj@wellfleet rpm]$ sudo /usr/lib/rpm/db_stat -Cl
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Lock REGINFO information:
Lock    Region type
4       Region ID
__db.004        Region name
0xb7c12000      Original region address
0xb7c12000      Region address
0xb7c12044      Region primary address
0       Region maximum allocation
0       Region allocated
Region allocations: 3005 allocations, 0 failures, 0 frees, 1 longest
REGION_JOIN_OK  Region flags
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Locks grouped by lockers:
Locker   Mode      Count Status  ----------------- Object  
---------------
        4 dd= 0 locks held 1    write locks 0    pid/thread  
497/3086265024
        4 READ          1 HELD    (30769 802 cdc6e56d 1056 0)  
handle        0
        5 dd= 0 locks held 1    write locks 0    pid/thread  
497/3086265024
        5 READ          1 HELD    0x3a134 len:  20 data:  
i0x070x03000x020x080000m0xe50xc60xcdV0x10000000000000
        6 dd= 0 locks held 1    write locks 0    pid/thread  
497/3086265024
        6 READ          1 HELD    (30783 802 e3d3478b 1b8796 0)  
handle        0

Note the process and thread id's that are displayed.

That's the starting point of the diagnosis. My guess is that one
of your threads has left an iterator open somewhere.

Note "guess" please ;-)

73 de jeff