[Announce] libzdb 2.1

Jan-Henrik Haukeland hauk at tildeslash.com
Mon Mar 3 11:58:26 CET 2008


On 3. mars. 2008, at 09.44, Paul J Stevens wrote:

> Jan-Henrik Haukeland wrote:
>> On 2. mars. 2008, at 22.09, Paul J Stevens wrote:
>>
>>> I've been thinking about this. This implies that you can't use
>>> multiple
>>> statements within a single transaction (at least with sqlite). Is  
>>> that
>>> correct? Because that would make code like below invalid, right?
>>
>> Not necessarily, though a fair chance that it will not work. The
>> indicator is this SQLite error message "SQL statements in progress".
>
> I am aware of that caveat in the docs. Is that a limitation of  
> sqlite per se? Or
> rather how libzdb talks to sqlite?

I believe it is a combination. Using PreparedStatement_executeQuery()  
the prepared statement is reused in the ResultSet and not closed. One  
place where this is a problem is in an explicit transaction. Upon a  
commit or rollback, at least SQLite check for open statements and  
issue a "SQL statements in progress" error, unless Connection_clear()  
is called to explicit close the statement.

For Connection_execute() and Connection_executeQuery() which also use  
a statement internally, the statement is closed upon the next call to  
any of these methods and therefor does not have this problem. But for  
PreparedStatement_executeQuery() the same internal statement is  
reused, and since a prepared statement is longer lived [1] than a  
ResultSet it may be a problem. A better option than to reuse, is  
probably to create a new statement for the ResultSet when  
PreparedStatement_executeQuery() is called, though this need more  
research which I haven't had time to prioritize. Until then, a  
workaround is available by calling Connection_clear() at appropriate  
places to close prepared statements explicit.

> The reason I'm asking is because I'm still trying to get a feel for  
> libzdb's
> behaviour and implicit expectations. A few things I've noticed:
>
> - I can't use Connection_PreparedStatement on a postgresql  
> connection until I've
> issued a Connection_executeQuery. Doing so segfaults in libzdb. I've  
> reported
> this one already, and I can easily work around this.

Its on my TODO list and I hope to have it moved over to Martin's TODO  
list :)

> - I'm getting stack corruption and segfaults in certain hotspots in  
> my code that
> use glib's GObject interface throught the GMime code. Now is GObject  
> a known
> not-threadsafe interface, and putting mutexes around my calls solves  
> the
> segfaults. But thing is: my code is (still) single-threaded (apart  
> from the
> reaper thread). So apparently thread semantics apply even to single- 
> threaded
> apps when using libzdb. If that is true, I need to start studying on  
> threads
> pronto because I havent a clue as to how thread(un)safe my code is  
> at the moment.

Linking with pthread makes your application threaded, per def, *but*  
as long as you only use one thread, i.e. the application main-thread  
you should not need to consider yourself with tread-safeness nor  
synchronizing shared resources. This is also the case if you run  
libzdb with a reaper thread since it does not affect any of your  
application data structures.

Thread-safe is one thing, reentrant is another and since I know you  
are using libevent, you may also want to check your event handlers.  
Even a single threaded application may have reentrancy problems -  
think signal handlers, and using libevent may introduce reentrancy  
problems in your code which may look like a thread bug. Maybe linking  
with pthread/libzdb exposed these bugs, but I don't think its the root  
cause.


> - Valgrind is generating massive amounts of 'invalid read' warnings  
> in the
> ResultSet_getXXX code. Whether this results in segfaults is  
> dependent on the
> backend. The mysql driver appears to segfault where the postgresql  
> driver simply
> returns null values. I havent yet tested sqlite. I'm left wondering  
> if this too
> is thread related.

Well, this is unexpected. Not that valgrind issues lots of warnings,  
but that you get SIGSEGV from using ResultSet_getXXX. Sounds like a  
Heisenbug (http://en.wikipedia.org/wiki/Heisenbug) someplace.  
Hopefully not in libzdb. One thing to check is  
PreparedStatement_setXXX. String or blob values set in a  
PreparedStatement_setXXX method are set by *reference* and if those  
references has disappeared somehow before doing a  
PreparedStatement_execute.. there will be Heisenbugs.

> However, since I only just finished the code changes that de- 
> globalize the
> result and connection pointers (leaving only the pool pointer as a  
> global) I
> havent had enough time yet to do some thorough backtracking.
>
> keep you posted.


Appreciated!

[1] A prepared statement is closed when its parent Connection is  
returned to the pool. Though for efficiency it should live longer.  
libzdb should/may in the future internalize and cache them. I have not  
verified this, but I hope the database backends already does this.


More information about the libzdb-general mailing list