Almost positive what's happening is that Python shutdown process is
interacting badly with ServerProgress's __del__().

__del__() methods are not the best way to reclaim resources, especially
when you leave it to Python's shutdown process to implicitly free
objects, like what happens in update-apt-xapian-index.   Here's what
happens:

When Python shutdown, after it's run the atexit handlers, it then tries
to free up all objects that are still implicitly alive because of
reference counts.  It does this first by emptying the __dict__s of all
modules, which will decref any still referenced globals.  It actually
does this first by setting all keys in the module's globals to None.
Because Python can't know what's a safe order to do this, it will do it
randomly.

Notice a few things.  In update-a-x-i, indexer is a module global.  When
its .lock() method is called, it sets self.progress to a ServerProgress
instance and neither instance is explicitly freed, so they live until
Python shutdown.  Now, when Python gets around to clearing the module
dicts as described above, it will set u-a-x-i's indexer instance to
None, which will decref it to zero, and so freeing the indexer instance.

Because the ServerProgress instance is kept alive by the reference from
the indexer's self.progress attribute, once the indexer is freed, the
ServerProgress instance probably decrefs to zero and then *it* gets
freed.  This will call ServerProgress.__del__().  Line 306 is the
os.unlink() call and you'll notice that you get an exception that None
is not callable.  Why is that?

Well, because if the os module's dictionary got cleared *before* the
ServerProgress instance's __del__() got called, the os module is still
valid, and it still has a name bound in it called 'unlink' but that name
has been bound to None!  If you're lucky, the ServerProgress instance
gets decrefed away before os gets cleared, but as you've observed in
IRC, about every third time, you're unlucky, and os gets cleared first
(remember, the order is random).  In those cases... boom!

I don't like the design here, since relying on __del__ methods to free
resources isn't good Python style, especially when those resources can
be freed explicitly, but fixing that is probably more work than we want
to do for a package that is abandoned in Debian.  A bandaid might be
easy though: before the sys.exit() call in u-a-x-i, let's try to
explicitly `del indexer`.  That will cause all the cascading decrefs
before Python's shutdown machinery clears out the os module.  I'll
attach a diff to try.

-- 
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/1530518

Title:
  /etc/cron.weekly/apt-xapian-index reports TypeError

To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/apt-xapian-index/+bug/1530518/+subscriptions

-- 
ubuntu-bugs mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs

Reply via email to