Make database.getAll() not block the main thread on database access.
This commit is contained in:
parent
0423ed7fb4
commit
248b258413
@ -320,31 +320,90 @@ static JSValue _database_remove(JSContext* context, JSValueConst this_val, int a
|
|||||||
return JS_UNDEFINED;
|
return JS_UNDEFINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct _database_get_all_t
|
||||||
|
{
|
||||||
|
const char* id;
|
||||||
|
const char* key;
|
||||||
|
size_t key_length;
|
||||||
|
char** out_values;
|
||||||
|
size_t* out_lengths;
|
||||||
|
int out_values_length;
|
||||||
|
JSValue promise[2];
|
||||||
|
} database_get_all_t;
|
||||||
|
|
||||||
|
static void _database_get_all_work(tf_ssb_t* ssb, void* user_data)
|
||||||
|
{
|
||||||
|
database_get_all_t* work = user_data;
|
||||||
|
sqlite3_stmt* statement;
|
||||||
|
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
|
||||||
|
if (sqlite3_prepare(db, "SELECT key FROM properties WHERE id = ?", -1, &statement, NULL) == SQLITE_OK)
|
||||||
|
{
|
||||||
|
if (sqlite3_bind_text(statement, 1, work->id, -1, NULL) == SQLITE_OK)
|
||||||
|
{
|
||||||
|
while (sqlite3_step(statement) == SQLITE_ROW)
|
||||||
|
{
|
||||||
|
work->out_values = tf_resize_vec(work->out_values, sizeof(char*) * (work->out_values_length + 1));
|
||||||
|
work->out_lengths = tf_resize_vec(work->out_lengths, sizeof(size_t) * (work->out_values_length + 1));
|
||||||
|
size_t length = sqlite3_column_bytes(statement, 0);
|
||||||
|
char* data = tf_malloc(length + 1);
|
||||||
|
memcpy(data, sqlite3_column_text(statement, 0), length);
|
||||||
|
data[length] = '\0';
|
||||||
|
work->out_values[work->out_values_length] = data;
|
||||||
|
work->out_lengths[work->out_values_length] = length;
|
||||||
|
work->out_values_length++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sqlite3_finalize(statement);
|
||||||
|
}
|
||||||
|
tf_ssb_release_db_reader(ssb, db);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _database_get_all_after_work(tf_ssb_t* ssb, int status, void* user_data)
|
||||||
|
{
|
||||||
|
database_get_all_t* work = user_data;
|
||||||
|
JSContext* context = tf_ssb_get_context(ssb);
|
||||||
|
JSValue result = JS_NewArray(context);
|
||||||
|
;
|
||||||
|
for (int i = 0; i < work->out_values_length; i++)
|
||||||
|
{
|
||||||
|
JS_SetPropertyUint32(context, result, i, JS_NewStringLen(context, work->out_values[i], work->out_lengths[i]));
|
||||||
|
tf_free((void*)work->out_values[i]);
|
||||||
|
}
|
||||||
|
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]);
|
||||||
|
tf_free(work->out_values);
|
||||||
|
tf_free(work->out_lengths);
|
||||||
|
tf_free(work);
|
||||||
|
}
|
||||||
|
|
||||||
static JSValue _database_get_all(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
static JSValue _database_get_all(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
||||||
{
|
{
|
||||||
JSValue array = 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_reader(ssb);
|
|
||||||
if (sqlite3_prepare(db, "SELECT key, value FROM properties WHERE id = ?1", -1, &statement, NULL) == SQLITE_OK)
|
size_t length;
|
||||||
{
|
const char* key = JS_ToCStringLen(context, &length, argv[0]);
|
||||||
if (sqlite3_bind_text(statement, 1, database->id, -1, NULL) == SQLITE_OK)
|
database_get_all_t* work = tf_malloc(sizeof(database_get_all_t) + strlen(database->id) + 1 + length + 1);
|
||||||
{
|
*work = (database_get_all_t) {
|
||||||
array = JS_NewArray(context);
|
.id = (const char*)(work + 1),
|
||||||
uint32_t index = 0;
|
.key = (const char*)(work + 1) + strlen(database->id) + 1,
|
||||||
while (sqlite3_step(statement) == SQLITE_ROW)
|
.key_length = length,
|
||||||
{
|
};
|
||||||
JS_SetPropertyUint32(context, array, index++, JS_NewStringLen(context, (const char*)sqlite3_column_text(statement, 0), sqlite3_column_bytes(statement, 0)));
|
memcpy((char*)work->id, database->id, strlen(database->id) + 1);
|
||||||
}
|
memcpy((char*)work->key, key, length + 1);
|
||||||
}
|
JS_FreeCString(context, key);
|
||||||
sqlite3_finalize(statement);
|
|
||||||
}
|
tf_ssb_run_work(ssb, _database_get_all_work, _database_get_all_after_work, work);
|
||||||
tf_ssb_release_db_reader(ssb, db);
|
result = JS_NewPromiseCapability(context, work->promise);
|
||||||
}
|
}
|
||||||
return array;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSValue _database_get_like(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
static JSValue _database_get_like(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
||||||
|
@ -279,7 +279,7 @@ static void _test_database(const tf_test_options_t* options)
|
|||||||
" 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"
|
||||||
" var have = db.getAll();\n"
|
" var have = await db.getAll();\n"
|
||||||
" for (var i = 0; i < have.length; i++) {\n"
|
" for (var i = 0; i < have.length; i++) {\n"
|
||||||
" var item = have[i];\n"
|
" var item = have[i];\n"
|
||||||
" if (expected.indexOf(item) == -1) {\n"
|
" if (expected.indexOf(item) == -1) {\n"
|
||||||
|
Loading…
Reference in New Issue
Block a user