Use dos queues de FMDB (lectura / escritura) en la misma database

Creo que mi caso de uso es bastante común, pero no pude encontrar una respuesta autorizada para esto.

Tengo un mecanismo de synchronization que se ejecuta en segundo plano y escribe datos en mi database. Esta synchronization puede llevar mucho time (uso FTS). Para esto utilizo un FMDatabaseQueue . Cuando quiero leer en la database, uso la misma queue para hacer una consulta.

Ahora, cuando el process de synchronization ya puso en queue muchas transactions, la aplicación quiere hacer una lectura, tiene que esperar a que todas las transactions de escritura terminen antes de poder hacer una consulta, ya que se trata de una queue en serie. El código podría verse así:

 FMDatabaseQueue *queue = [self getDatabaseQueue]; [queue inTransaction:^(FMDatabase *db, BOOL *rollback) { // Very slow process [db executeUpdate:@"UPDATE docs SET name = ?", "value..."]; }]; [queue inTransaction:^(FMDatabase *db, BOOL *rollback) { // Very slow process [db executeUpdate:@"UPDATE docs SET name = ?", "value..."]; }]; [queue inTransaction:^(FMDatabase *db, BOOL *rollback) { // Very slow process [db executeUpdate:@"UPDATE docs SET name = ?", "value..."]; }]; [queue inDatabase:^(FMDatabase *db) { FMResultSet *resultSet = [db executeQuery:@"SELECT name..."]; }]; 

Quiero tener los resultados de la consulta instantáneamente (incluso si la synchronization no se hace) y no esperar a que se UPDATE la UPDATE .

¿Puedo crear dos FMDatabaseQueue s, uno para las consultas de escritura y otro para las consultas de lectura? ¿Qué sucederá si una consulta de lectura comienza justo en el medio de una transacción de escritura?

El código podría verse así:

 FMDatabaseQueue *writeQueue = [self getWriteDatabaseQueue]; FMDatabaseQueue *readQueue = [self getReadDatabaseQueue]; [writeQueue inTransaction:^(FMDatabase *db, BOOL *rollback) { // Very slow process [db executeUpdate:@"UPDATE docs SET name = ?", "value..."]; }]; [writeQueue inTransaction:^(FMDatabase *db, BOOL *rollback) { // Very slow process [db executeUpdate:@"UPDATE docs SET name = ?", "value..."]; }]; [writeQueue inTransaction:^(FMDatabase *db, BOOL *rollback) { // Very slow process [db executeUpdate:@"UPDATE docs SET name = ?", "value..."]; }]; [readQueue inDatabase:^(FMDatabase *db) { FMResultSet *resultSet = [db executeQuery:@"SELECT name..."]; }]; 

Editar:

Además, lo que me confunde es la documentation que dice:

Siempre ha sido correcto crear un object FMDatabase por subprocess. Simplemente no comparta una sola instancia a través de subprocesss.

Entonces, lo que yo entiendo es que puedo crear dos isntances con la misma database pero que solo necesito mantenerlo en su propio hilo.

No, no desea que dos FMDatabaseQueue interactúen con la misma database. El propósito completo de FMDatabaseQueue es proporcionar una sola queue para coordinar las llamadas de la database desde diferentes subprocesss a través de una sola queue de serie compartida.

Sin embargo, me pregunto sobre su código en los bloques de "processs muy lentos". Si eso no es algo específico de la database, entonces no debería estar dentro de las inTransaction y / o inDatabase .

 NSOperationQueue *backgroundQueue = [[NSOperationQueue alloc] init]; FMDatabaseQueue *databaseQueue = [FMDatabaseQueue databaseWithPath:path]; [backgroundQueue addOperationWithBlock:^{ // very slow process [databaseQueue inTransaction:^(FMDatabase *db, BOOL *rollback) { [db executeUpdate:@"UPDATE docs SET name = ?", "value..."]; }]; }]; [backgroundQueue addOperationWithBlock:^{ // very slow process [databaseQueue inTransaction:^(FMDatabase *db, BOOL *rollback) { [db executeUpdate:@"UPDATE docs SET name = ?", "value..."]; }]; }]; 

Y mientras que los que están en queue y en ejecución, la queue principal puede hacer sus propias llamadas a databaseQueue , utilizando el FMDatabaseQueue para asegurar que esto esté coordinado de tal manera que no ocurra simultáneamente con los bloques inTransaction anteriores:

 [databaseQueue inDatabase:^(FMDatabase *db) { FMResultSet *resultSet = [db executeQuery:@"SELECT name..."]; while (![resultSet next]) { .... } }]; 

Claramente, debe administrar sus tareas en segundo plano; sin embargo, es adecuado para su aplicación (usé una queue de operaciones simultáneas, pero puede usar queues en serie o queues de envío o lo que quiera). No se deje atrapar por los detalles del backgroundQueue anterior, ya que su implementación variará.

La observación key es que no debe usar el databaseQueue para administrar sus tareas de "process muy lento", así como la interacción de la database. Tome cualquier cosa que no esté relacionada con la database fuera de las llamadas inTransaction y inDatabase . Use sus propias queues para administrar su propio código no relacionado con bases de datos. Siempre FMDatabaseQueue y salga de la databaseQueue FMDatabaseQueue más rápido posible y deje que el FMDatabaseQueue , único y compartido, coordine la interacción con la database pasando de varios subprocesss.