Move db.exchange DB work off of the main thread.
This commit is contained in:
parent
63776d40bd
commit
b6a937c954
@ -245,55 +245,86 @@ static JSValue _database_set(JSContext* context, JSValueConst this_val, int argc
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct _database_exchange_t
|
||||||
|
{
|
||||||
|
const char* id;
|
||||||
|
const char* key;
|
||||||
|
size_t key_length;
|
||||||
|
const char* expected;
|
||||||
|
size_t expected_length;
|
||||||
|
const char* value;
|
||||||
|
size_t value_length;
|
||||||
|
bool result;
|
||||||
|
JSValue promise[2];
|
||||||
|
} database_exchange_t;
|
||||||
|
|
||||||
|
static void _database_exchange_work(tf_ssb_t* ssb, void* user_data)
|
||||||
|
{
|
||||||
|
database_exchange_t* work = user_data;
|
||||||
|
sqlite3* db = tf_ssb_acquire_db_writer(ssb);
|
||||||
|
sqlite3_stmt* statement;
|
||||||
|
if (!work->expected)
|
||||||
|
{
|
||||||
|
if (sqlite3_prepare(db, "INSERT INTO properties (id, key, value) VALUES (?1, ?2, ?3) ON CONFLICT DO NOTHING", -1, &statement, NULL) == SQLITE_OK)
|
||||||
|
{
|
||||||
|
if (sqlite3_bind_text(statement, 1, work->id, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 2, work->key, work->key_length, NULL) == SQLITE_OK &&
|
||||||
|
sqlite3_bind_text(statement, 3, work->value, work->value_length, NULL) == SQLITE_OK && sqlite3_step(statement) == SQLITE_DONE)
|
||||||
|
{
|
||||||
|
work->result = sqlite3_changes(db) != 0;
|
||||||
|
}
|
||||||
|
sqlite3_finalize(statement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (sqlite3_prepare(db, "UPDATE properties SET value = ?1 WHERE id = ?2 AND key = ?3 AND value = ?4", -1, &statement, NULL) == SQLITE_OK)
|
||||||
|
{
|
||||||
|
if (sqlite3_bind_text(statement, 1, work->value, work->value_length, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 2, work->id, -1, NULL) == SQLITE_OK &&
|
||||||
|
sqlite3_bind_text(statement, 3, work->key, work->key_length, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 4, work->expected, work->expected_length, NULL) == SQLITE_OK &&
|
||||||
|
sqlite3_step(statement) == SQLITE_DONE)
|
||||||
|
{
|
||||||
|
work->result = sqlite3_changes(db) != 0;
|
||||||
|
}
|
||||||
|
sqlite3_finalize(statement);
|
||||||
|
}
|
||||||
|
tf_ssb_release_db_writer(ssb, db);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _database_exchange_after_work(tf_ssb_t* ssb, int status, void* user_data)
|
||||||
|
{
|
||||||
|
database_exchange_t* work = user_data;
|
||||||
|
JSContext* context = tf_ssb_get_context(ssb);
|
||||||
|
JSValue result = work->result ? JS_TRUE : JS_UNDEFINED;
|
||||||
|
JSValue error = JS_Call(context, work->promise[0], JS_UNDEFINED, 1, &result);
|
||||||
|
tf_util_report_error(context, error);
|
||||||
|
JS_FreeValue(context, error);
|
||||||
|
JS_FreeValue(context, result);
|
||||||
|
JS_FreeValue(context, work->promise[0]);
|
||||||
|
JS_FreeValue(context, work->promise[1]);
|
||||||
|
JS_FreeCString(context, work->key);
|
||||||
|
JS_FreeCString(context, work->expected);
|
||||||
|
JS_FreeCString(context, work->value);
|
||||||
|
tf_free((char*)work->id);
|
||||||
|
tf_free(work);
|
||||||
|
}
|
||||||
|
|
||||||
static JSValue _database_exchange(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
static JSValue _database_exchange(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
||||||
{
|
{
|
||||||
JSValue exchanged = JS_UNDEFINED;
|
JSValue result = JS_UNDEFINED;
|
||||||
database_t* database = JS_GetOpaque(this_val, _database_class_id);
|
database_t* database = JS_GetOpaque(this_val, _database_class_id);
|
||||||
if (database)
|
if (database)
|
||||||
{
|
{
|
||||||
sqlite3_stmt* statement;
|
|
||||||
tf_ssb_t* ssb = tf_task_get_ssb(database->task);
|
tf_ssb_t* ssb = tf_task_get_ssb(database->task);
|
||||||
sqlite3* db = tf_ssb_acquire_db_writer(ssb);
|
database_exchange_t* work = tf_malloc(sizeof(database_exchange_t));
|
||||||
if (JS_IsNull(argv[1]) || JS_IsUndefined(argv[1]))
|
*work = (database_exchange_t)
|
||||||
{
|
{
|
||||||
if (sqlite3_prepare(db, "INSERT INTO properties (id, key, value) VALUES (?1, ?2, ?3) ON CONFLICT DO NOTHING", -1, &statement, NULL) == SQLITE_OK)
|
.id = tf_strdup(database->id),
|
||||||
{
|
};
|
||||||
size_t key_length;
|
work->key = JS_ToCStringLen(context, &work->key_length, argv[0]);
|
||||||
size_t set_length;
|
work->expected = (JS_IsNull(argv[1]) || JS_IsUndefined(argv[1])) ? NULL : JS_ToCStringLen(context, &work->expected_length, argv[1]);
|
||||||
const char* key = JS_ToCStringLen(context, &key_length, argv[0]);
|
work->value = JS_ToCStringLen(context, &work->value_length, argv[2]);
|
||||||
const char* set = JS_ToCStringLen(context, &set_length, argv[2]);
|
result = JS_NewPromiseCapability(context, work->promise);
|
||||||
if (sqlite3_bind_text(statement, 1, database->id, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 2, key, key_length, NULL) == SQLITE_OK &&
|
tf_ssb_run_work(ssb, _database_exchange_work, _database_exchange_after_work, work);
|
||||||
sqlite3_bind_text(statement, 3, set, set_length, NULL) == SQLITE_OK && sqlite3_step(statement) == SQLITE_DONE)
|
|
||||||
{
|
|
||||||
exchanged = sqlite3_changes(db) != 0 ? JS_TRUE : JS_FALSE;
|
|
||||||
}
|
|
||||||
JS_FreeCString(context, key);
|
|
||||||
JS_FreeCString(context, set);
|
|
||||||
sqlite3_finalize(statement);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (sqlite3_prepare(db, "UPDATE properties SET value = ?1 WHERE id = ?2 AND key = ?3 AND value = ?4", -1, &statement, NULL) == SQLITE_OK)
|
|
||||||
{
|
|
||||||
size_t key_length;
|
|
||||||
size_t expected_length;
|
|
||||||
size_t set_length;
|
|
||||||
const char* key = JS_ToCStringLen(context, &key_length, argv[0]);
|
|
||||||
const char* expected = JS_ToCStringLen(context, &expected_length, argv[1]);
|
|
||||||
const char* set = JS_ToCStringLen(context, &set_length, argv[2]);
|
|
||||||
if (sqlite3_bind_text(statement, 1, set, set_length, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 2, database->id, -1, NULL) == SQLITE_OK &&
|
|
||||||
sqlite3_bind_text(statement, 3, key, key_length, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 4, expected, expected_length, NULL) == SQLITE_OK &&
|
|
||||||
sqlite3_step(statement) == SQLITE_DONE)
|
|
||||||
{
|
|
||||||
exchanged = sqlite3_changes(db) != 0 ? JS_TRUE : JS_FALSE;
|
|
||||||
}
|
|
||||||
JS_FreeCString(context, key);
|
|
||||||
JS_FreeCString(context, expected);
|
|
||||||
JS_FreeCString(context, set);
|
|
||||||
sqlite3_finalize(statement);
|
|
||||||
}
|
|
||||||
tf_ssb_release_db_writer(ssb, db);
|
|
||||||
}
|
}
|
||||||
return exchanged;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSValue _database_remove(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
static JSValue _database_remove(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
||||||
|
@ -275,7 +275,11 @@ static void _test_database(const tf_test_options_t* options)
|
|||||||
" if (await db.get('a') != 1) {\n"
|
" if (await db.get('a') != 1) {\n"
|
||||||
" exit(2);\n"
|
" exit(2);\n"
|
||||||
" }\n"
|
" }\n"
|
||||||
" await db.set('b', 2);\n"
|
" await db.exchange('b', null, 1);\n"
|
||||||
|
" await db.exchange('b', 1, 2);\n"
|
||||||
|
" if (await db.get('b') != 2) {\n"
|
||||||
|
" exit(5);\n"
|
||||||
|
" }\n"
|
||||||
" await db.set('c', 3);\n"
|
" await db.set('c', 3);\n"
|
||||||
"\n"
|
"\n"
|
||||||
" var expected = ['a', 'b', 'c'];\n"
|
" var expected = ['a', 'b', 'c'];\n"
|
||||||
|
Loading…
Reference in New Issue
Block a user