views:

77

answers:

3

Hi, Firstly I'm an engineer, not a computer scientist, so please be gentle. I currently have a C++ program which uses MySQL++. The program also incorporates the NI Visa runtime. One of the interrupt handlers receives data (1 byte) from a USB device about 200 times a second. I would like to store this data with a time stamp on each sample on a remote server. Is this feasible? Can anyone recommend a good approach? Regards, Michael

+3  A: 

I think that performing 200 transactions/second against a remote server is asking a lot, especially when you consider that these transactions would be occurring in the context of an interrupt handler which has to do its job and get done quickly. I think it would be better to decouple your interrupt handler from your database access - perhaps have the interrupt handler store the incoming data and timestamp into some sort of in-memory data structure (array, circular linked list, or whatever, with appropriate synchronization) and have a separate thread that waits until data is available in the data structure and then pumps it to the database. I'd want to keep that interrupt handler as lean and deterministic as possible, and I'm concerned that database access across the network to a remote server would be too slow - or worse, would be OK most of the time, but sometimes would go to h*ll for no obvious reason.

This, of course, raises the question/problem of data overrun, where data comes in faster than it can be pumped to the database and the in-memory storage structure fills up. This could cause data loss. How bad a thing is it if you drop some samples?

Bob Jarvis
A: 

I don't think you'll be able to maintain that speed with 1 separate insert per value, but if you batched them up into large enough batches you could send it all as one query and it should be fine.

INSERT INTO records(timestamp, value)
  VALUES(1, 2), (3, 4), (5, 6), [...], (399, 400);

Just push the timestamp and value onto a buffer, and when the buffer hits 200 in size (or some other arbitrary figure), generate the SQL and send the whole lot off. Building this string up with sprintf shouldn't be too slow. Just beware of reading from a data structure that your interrupt routine might be writing to at the same time.

If you find that this SQL generation is too slow for some reason, and there's no quicker method using the API (eg. stored procedures), then you might want to run this concurrently with the data collection. Simplest is probably to stream the data across a socket or pipe to another process that performs the SQL generation. There are also multithreading approaches but they are more complex and error-prone.

Kylotan
I agree about the time stamp issue. I will buffer the samples and only add one timestamp for every 200 values. What storage mechanism would you suggest to store these values and read from them so as to avoid issues with the interrupt accessing it?
Michael
I would need to be familiar with the hardware and operating system in question to provide an authoritative answer to the interrupt issue. Often there is a way to prevent interrupts from happening for a short period of time which would be long enough to transfer data out of the structure that your interrupt uses. Alternatively there might be an atomic instruction which can switch which of two buffers you are referring to, but again this is platform specific. I would hope that whatever provides this interrupt routine also provides a way to manage its execution.
Kylotan
I will attempt to switch between 2 buffers. Thanks for the advice.
Michael
A: 

In my opinion, you should do two things: 1. buffer the data and 2. one time stamp per buffer. The USB protocol is not byte based and more message based. If you are tracking messages, then time stamp the messages.

Also, databases would rather receive blocks or chunks of data than one byte at a time. There is overhead in the database with each transaction. To measure the efficiency, divide the overhead by the number of bytes in the transaction. You'll see that large blocks are more efficient than lots of little transactions.

Another option is to store the data into a file, then use the MySQL LOADFILE function to load the data into the the database. Also, there is storing the data into a buffer then using the MySQL C++ connector stream to load the data into the database.

Thomas Matthews
I will do both 1 and 2 as you suggest. Regarding storing values locally in a file what do you suggest? SQlite?
Michael
As for the format for storing values in a file, read up on MySQL *LOADFILE* function. It will tell the format of the file that it requires. For storing variables outside a program, on Windows you can use the Registry. Another method is storing in a file. You can use XML, INI or your own formats. I have not used SQLite, so I cannot comment on it.
Thomas Matthews