I have a table in MySQL database that holds some "prepared" jobs.
CREATE TABLE `ww_jobs_for_update` (
`id` bigint(11) NOT NULL AUTO_INCREMENT,
`status` int(11) NOT NULL,
`inc` int(11) NOT NULL,
PRIMARY KEY (`id`)
)
Now I have a C++1y multithreaded application, where each thread goes to the table and selects a job where status=0 (Not completed), does some computation and sets the status=1 upon completion.
The problem is that many threads will acquire a "job row" concurrently so some locking in the database has to take place.
The C++ method that locks/updates/commit is the following
connection = "borrow a connection from the pool"
std::unique_ptr<sql::Statement> statement(connection->sql_connection_->createStatement());
connection->sql_connection_->setAutoCommit(false);
//statement->execute("START TRANSACTION");
std::unique_ptr<sql::ResultSet> rs(statement->executeQuery("select id from ww_jobs_for_update where status=0 ORDER BY id LIMIT 1 FOR UPDATE"));
if (rs->next()) {
db_id = rs->getInt64(1);
DEBUG << "Unlock Fetched: " << db_id;
}
rs->close();
std::stringstream ss;
ss << "update ww_jobs_for_update set status=1 where id=" << db_id;
statement->execute(ss.str());
//statement->execute("COMMIT;");
connection->sql_connection_->commit();
"release the connection to the pool();"
But this approach seems not be efficient. I always get back
ErrorCode: 1205,SQLState: HY000. Details:
from a lot of threads, especially when there load is increasing.
Why I am getting this back? What is the most efficient way to do this, hard consistency is a requirement.
The best way for this task in my experience is using redis queues.
Locking tables SELECT ... FOR UPDATE is hanging the database when you have some multi-thread application running etc.
I would advice you to install a redis, and write some scripts to create queues according to the data in tables and rewrite your program to use redis queues for the task.
redis queues will not give the same value for different threads, so you get the uniqueness and there are no locks in the database - so your scripts will work fast.
Can you make your transaction durations shorter? Here's what I mean.
You have status values of 0 for "waiting" and 1 for "complete". Use the status value 2 (or -1, or whatever you choose) to mean "working".
Then when a worker thread grabs a job to do from the table, it will do this (pseudo-SQL).
BEGIN TRANSACTION
SELECT id FROM ww_jobs_for_update WHERE status=0 ORDER BY id LIMIT 1 FOR UPDATE
UPDATE ww_jobs_for_update SET status=2 WHERE id = << db_id
COMMIT
Now, your thread has taken a job and released the transaction lock. When the job is done you simply do this to mark it done, with no transaction needed.
UPDATE ww_jobs_for_update SET status=1 WHERE id=" << db_id;
There's an even simpler way to do this if you can guarantee each worker thread has a unique identifer threadId . Put a thread column in the table with a default NULL value. Then to start processing a job.
UPDATE ww_jobs_for_update
SET thread = threadId, status = 2
WHERE status = 0 AND threadId IS NULL
ORDER BY id LIMIT 1;
SELECT id FROM ww_jobs_for_update WHERE thread = threadId AND status=2
When done
UPDATE ww_jobs_for_update
SET thread = NULL, status = 1
WHERE thread = threadId;
Because each thread has a unique threadId, and because individual SQL UPDATE statements are themselves little transactions, you can do this without using any transactions or commits at all.
Both these approaches have the added benefit that you can use a SELECT query to find out which jobs are active. This may allow you to deal with jobs that never completed for whatever reason.
Related
I am doing an experiment that concurrently insert data into a MySQL table by multi-thread.
Here is partial code in C++.
bool query_thread(const char* cmd, MYSQL* con) {
if( !query( cmd, con ) ) {
return 0;
}
return 1;
}
int main() {
........
if(mysql_query(m_con, "CREATE TABLE tb1 (model INT(32), handle INT(32))") != 0) {
return 0;
}
thread thread1(query_thread, "INSERT INTO tb1 VALUES (1,1)", m_con);
thread thread2(query_thread, "INSERT INTO tb1 VALUES (2,2)", m_con);
thread thread3(query_thread, "INSERT INTO tb1 VALUES (3,3)", m_con);
thread1.join();
thread2.join();
thread3.join();
}
But the MySQL error message is issued.
error cmd: INSERT INTO tb1 VALUES (1,1)
Lost connection to MySQL server during query
Segmentation fault
My questions are as following.
Is it because the MySQL cannot accept concurrently insertion? Or bad use of multi-thread.
By multi-thread insertion as above, does it help to speed up the program? I understand the best way are multiple insert per query and LOAD DATA INFILE. But I just want to know if this way can help.
Each thread must have:
own database connection
own transaction
own cursor
This, however will not make your inserts much faster. In short, the innodb log (journal) is essentially serial which limits server total insert rate. Read mysql performance blog (percona / mariadb) for details. Certainly there are parameters to tweak and there seem to have been advances with recently.
I have to perform some calculations with data stored in an MSSQL Server database and then save the results in the same database.
I need to load (part of) a table into C++ data structures, perform a calculation (that can take substantial time), and finally add some rows to the same table.
The problem is that several users can access the database concurrently, and I want the table to be locked since the data is loaded in memory until the results of the calculation are written to the table.
Using the ODBC SDK, is it possible to explicitly lock and unlock part of a table?
I have tried the following test program, but unfortunately the INSERT statement succeeds before StmtHandle1 is freed:
SQLDriverConnect(ConHandle1, NULL, (SQLCHAR *)"DRIVER={ODBC Driver 13 for SQL Server};"
"SERVER=MyServer;"
"DATABASE=MyDatabase;"/*, ... */);
SQLSetStmtAttr(StmtHandle1,SQL_ATTR_CONCURRENCY,(SQLPOINTER)SQL_CONCUR_LOCK,SQL_IS_INTEGER);
SQLExecDirect(StmtHandle1, (SQLCHAR *)"SELECT * FROM [MyTable] WITH (TABLOCKX, HOLDLOCK)", SQL_NTS);
SQLDriverConnect(ConHandle2, NULL, (SQLCHAR *)"DRIVER={ODBC Driver 13 for SQL Server};"
"SERVER=MyServer;"
"DATABASE=MyDatabase;"/*, ... */);
SQLSetStmtAttr(StmtHandle2,SQL_ATTR_CONCURRENCY,(SQLPOINTER)SQL_CONCUR_LOCK,SQL_IS_INTEGER);
SQLExecDirect(StmtHandle2, (SQLCHAR *)"INSERT INTO [MyTable] VALUES (...)", SQL_NTS);
unfortunately the INSERT statement succeeds before StmtHandle1 is
freed
By default SQL Server opereates in autocommit mode, i.e. opens a tarnsaction and commits it for you.
You requested TABLOCKX and the table was locked for the duration of your transaction, but what you want instead is to explicitely open a transaction and don't commit/rollback it until you'll done with your calculations, i.e. you should use
begin tran; SELECT top 1 * FROM [MyTable] WITH (TABLOCKX, HOLDLOCK);
And you don't need to read the whole table, top 1 * is sufficient.
int iReturn = sqlite3_wal_checkpoint_v2(m_poDB, NULL, SQLITE_CHECKPOINT_FULL, &iSizeOfWalLog, &iNumOfCheckpointedFrames);
returns with iReturn = 5 (SQLITE_BUSY). The writer wakes up now and then, adds or deletes a number of rows to the database, does a checkpoint and goes to sleep again.
Question 1: How is that possible if I use WAL mode and have 4 readers and one writer?
Question 2: In the log messages I have seen that the checkpointing often works but only sometimes reports SQLITE_BUSY. Should I be concerned if it works sometimes but not always? Can this corrupt the database?
Question 3: Should I not use sqlite3_wal_checkpoint_v2 or SQLITE_CHECKPOINT_FULL?
A full checkpoint requires that there are no concurrent readers or writers.
You could try to increase your busy timeout, but if you try to do the checkpoint regularly, you could get away with ignoring single failures.
We are using the sqlite 3.7.14.1 code in our application. Lately we are seeing a dead lock kind of state while deleting records from a table. The deletion is done from two different threads and acting upon the same table.
Sqlite is configured in WAL mode. All threads open their own shared connection to the database. The application is complied with SQLITE_THREADSAFE=1 and SQLITE_ENABLE_MEMORY_MANAGEMENT.
m_init = sqlite3_open_v2(
m_dbfilename.toUtf8().data(), /* Database filename (UTF-8) */
&m_dbHandler, /* OUT: SQLite db handle */
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX | SQLITE_OPEN_SHAREDCACHE, /* Flags */
NULL /* Name of VFS module to use */
);
All update,insert and deletion of records in multiple threads happen in transactions. The update/insert statement works absolutely fine with out any dead lock. But when two or more threads try to remove an entry in the same table, then they go into a dead lock state where sqlite3_step keeps on returning SQLITE_LOCKED. When we did debug the code
10:00.234 Thread 1 BEGIN
10:00.235 Thread 1 select * from <table1>
10:00.234 Thread 1 select * from <table x>
10:00.456 Thread 1 delete from <table1>
10:00.456 Thread 2 BEGIN
10:00.456 Thread 2 select * from <table1>
10:00.906 Thread 2 select * from <table x>
10:01.156 Thread 2 delete from <table1>
Thread 1 SQLITE_LOCKED(6) Error <Table1> is locked
Thread 2 SQLITE_LOCKED(6) Error database table is locked
Thread 1 which is the first one to enter BEGIN and do modifications to the table, and it should have gained the WRITE lock on the table. Even If we consider Thread 2 was performing the select on the same table at the same time, then Thread 2 should have locked table in its delete call. In this case none of the threads are getting lock on the table and are waiting for ever. In each of the thread we are waiting for a random amount of time re-executing(sqlite3_step) the same prepared statement after calling reset on the prepared statement.
In any of the scenario one of the thread should be the winner in getting the lock on this table.
My question is how can I find who is locking the table. Is there any way I can get this info ? why is this happening for delete when concurrent update and inserts are happening properly ?
I need to check context switches for thread. I'm writing function, that return context switches from thread id. I'm computing context switch counts using the PDH library. I can get the thread context switch count for all threads using this construction:
Status = PdhAddCounter(Query, resultBuffer, NULL, &Counter);
where resultBuffer is "Thread(_Total/_Total)\\Context Switches/sec"
What do I have to change (_Total/_Total)?
Some playing around with perfmon suggests that the format should be
Thread(<process name>/<thread id>)\\Context Switches/sec
The thread ID you already have; you can get the process name from the process ID using the answers to this question.