views:

70

answers:

2

I'm using SQLite3 in a Windows application. I have the source code (so-called SQLite amalgamation).

Sometimes I have to execute heavy queries. That is, I call sqlite3_step on a prepared statement, and it takes a lot of time to complete (due to the heavy I/O load).

I wonder if there's a possibility to abort such a call. I would also be glad if there was an ability to do some background processing in the middle of the call within the same thread (since most of the time is spent in waiting for the I/O to complete).

I thought about modifying the SQLite code myself. In the simplest scenario I could check some condition (like an abort event handle for instance) before every invocation of either ReadFile/WriteFile, and return an error code appropriately. And in order to allow the background processing the file should be opened in the overlapped mode (this enables asynchronous ReadFile/WriteFile).

Is there a chance that interruption of WriteFile may in some circumstances leave the database in the inconsistent state, even with the journal enabled? I guess not, since the whole idea of the journal file is to be prepared for any error of any kind. But I'd like to hear more opinions about this.

Also, did someone tried something similar?

Thanks in advance.

EDIT:

Thanks to ereOn. I wasn't aware of the existence of sqlite3_interrupt. This probably answers my question.

Now, for all of you who wonders how (and why) one expects to do some background processing during the I/O within the same thread.

Unfortunately not many people are familiar with so-called "Overlapped I/O".

http://en.wikipedia.org/wiki/Overlapped_I/O

Using it one issues an I/O operation asynchronously, and the calling thread is not blocked. Then one receives the I/O completion status using one of the completion mechanisms: waitable event, new routine queued into the APC, or the completion port.

Using this technique one doesn't have to create extra threads. Actually the only real legitimation for creating threads is when your bottleneck is the computation time (i.e. CPU load), and the machine has several CPUs (or cores).

And creating a thread just to let it be blocked by the OS most of the time - this doesn't make sense. This leads to the unjustified waste of the OS resources, complicates the program (need for synchronization and etc.).

Unfortunately not all the libraries/APIs allow asynchronous mode of operation, thus making creating extra threads the necessarily evil.

EDIT2:

I've already found the solution, thansk to ereOn.

For all those who nevertheless insist that it's not worth doing things "in background" while "waiting" for the I/O to complete using overlapped I/O. I disagree, and I think there's no point to argue about this. At least this is not related to the subject.

I'm a Windows programmer (as you may noticed), and I have a very extensive experience in all kinds of multitasking. Plus I'm also a driver writer, so that I also know how things work "behind the scenes".

I know that it's a "common practice" to create several threads to do several things "in parallel". But this doesn't mean that this is a good practice. Please allow me not to follow the "common practice".

+1  A: 

I don't understand why you want the interruption to come from the same thread and I even don't understand how that would be possible: if the current thread is blocked, waiting for some IO, you can't execute any other code. (Yeah, that's what "blocked" means)

Perhaps if you give us more hints about why you want this, we might help further.

Usually, I use sqlite3_interrupt() to cancel calls. But this, obviously, involves that the call is made from another thread.

ereOn
Yeah: to do two things simultaneously there will be two threads involved at some level.
Eamon Nerbonne
I've edited the question. Please read the change, I explain what I mean
valdo
@valdo: I'm quite familiar with overlapped IO and if it allows you not to create another thread, it uses a thread underneath: there is no magic, you just don't have to care about it. Anyway, if your thread is "blocked" because it writes something, it is not **idle** and there is no waste of resource. As a general rule, don't second-guess performance issues. If your code really has a performance problem, profile it. But often the issue is not where you'd expect it to be.
ereOn
@ereOn: No offenses, but I think you have no idea about how overlapped I/O actually works, how the job is passed to the driver, IRP handling, system DPCs and etc. As a Windows programmer for over 10 years, both kernel and user sides, I know those things pretty well. Yes, there's a magic here. It's just **by design** WDM drivers in Windows know to handle IRP (I/O requests) asynchronously on the hardware level. The truth is exactly **opposite** of what you think: When you do a "blocked" I/O - the system actually issues an asynchronous I/O, and then immediately blocks till it's completes
valdo
@valdo: however, SQLite doesn't use this - right? So it's kind of a moot point; you'll need a second thread.
Eamon Nerbonne
@valdo: I was indeed simplifying things, perhaps using a wrong wording. You seem to know well the implementation details so: fair enough. Anyway, the point still remains: **something** has to wait (whether this "something" is a thread or something else doesn't really matter) and so you need parallel execution. On another hand, modifying SQLite is the better way to get a maintainance nightmare: whenever SQLite is updated (security fixes), you'd have to reapply all the changes.
ereOn
I accept the argument about all the drawbacks of modifying the official SQLite code. However I disagree about the argument that doing things in "parallel" requires multiple threads. If all you do is wait - a single thread can wait for a lot of different events/completions, and do whatever is necessary to handle them.
valdo
+1  A: 

By default, SQLite is threadsafe. It sounds to me like the easiest thing to do would be to start the Sqlite command on a background thread, and let SQLite to the necessary locking to have that work.

From your perspective then, the sqlite call looks like an asynchronous bit of I/O, and you can continue normal processing on this thread, such as e.g. using a loop including interruptible sleep and a bit of occasional background processing (e.g. to update a liveness indicator). When the SQLite statement completes, the background thread should set a state variable to indicate this, wake the main thread (if necessary), and terminate.

Eamon Nerbonne
Thanks for the answer. But my point was: what if I don't want to wait until the SQLite completes? I want to interrupt it ASAP. How do I do this?
valdo