[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Error handling (was Re: [ANN] Lua 5.3.0 (final) now available)
- From: Andrew Starks <andrew.starks@...>
- Date: Mon, 19 Jan 2015 23:34:50 -0600
On Monday, January 19, 2015, William Ahern <william@25thandclement.com> wrote:
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
> >>whathaveyou.
> > 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.
Wow. This is a great idea, if I'm following it.
Do I have this correct: when you are doing something that may need to be rolled back, you attach the roll back to a table with weak keys. If failure happens, the key is collected because the other references die with the failure. This releases the value associated with the key, which is a table that has a __gc method; the cleanup function.
You could wrap pcall to take the clean up function as an argument and it would create the fail safe and also dissarm it, should the call succeed.
Is that along the lines of what you were saying?