[Date Prev][Date Next][Thread Prev][Thread Next]
- Subject: Re: Error handling (was Re: [ANN] Lua 5.3.0 (final) now available)
- From: William Ahern <william@...>
- Date: Mon, 19 Jan 2015 17:46:56 -0800
On Sun, Jan 18, 2015 at 02:17:02AM +0700, David Favro wrote:
> On 01/17/2015 04:15 AM, Sean Conner wrote:
> >It was thus said that the Great Andrew Starks once stated:
> >>If you always error, you can
> >>pretend that errors never happen, until you can't. In a garbage
> >>collected language, the places where you need to clean the state up
> >>are pretty limited, so this may be more true of Lua than of C, or
> > But you can still leak resources if you don't clear your references. I
> >just found such a bug at work at one place, and now I'm afraid of all the
> >paths I neglected to clean up references leading up to that point.
> Indeed, I recently ran into a bug in which a database transaction was
> 'leaked', i.e. a transaction was started, an error raised in the code
> between the start and commit, and it was pcall-caught higher up the call
> stack, without rolling back the transaction. The higher-level code then
> continued using the database connection with the pending partial
> transaction (and subsequent updates to the DB) never getting committed
> until the process terminated and the subsequent updates were rolled back.
> In C++ this kind of thing often can be conveniently avoided by using the
> Resource Acquisition Is Initialization paradigm, or if not, less
> conveniently with try-catch blocks. In Lua, I find it a bit of a PITA
> to try to release resources using xpcall. But frankly I prefer it to
> "return nil,msg".
Maybe you already do this, but in Lua 5.2 and 5.3 you can catch the leak by
using the object to index a weak table, where you store a table with a __gc
metamethod hook to trigger your cleanup logic. (In Lua 5.1 you can use the
undocumented newproxy in lieu of table __gc metamethods.)
I use this as a fail-safe in several of my applications. It's basically
operates as a destructor that you can attach to objects without having to
hack their implementation (e.g. attach a __gc handler to the object itself).
Because you never know when the GC will run, I usually have a task with runs
every N seconds to step through the GC. That way leaked object recyling will
happen within bounded wallclock time, rather than based on memory pressure.
This helps to reduce GC jitter, anyhow.