CBLLiveQuery doesn't update when db not on main thread

143 views
Skip to first unread message

Chris Fuentes

unread,
Jun 17, 2014, 12:52:37 PM6/17/14
to mobile-c...@googlegroups.com
We recently put every CBL transaction on it's own queue, by setting the `dispatchQueue` property of CBLManager to

dispatch_queue_t couchbase_queue = dispatch_queue_create("COUCHBASE_TRANSACTION_QUEUE", DISPATCH_QUEUE_SERIAL);
[CBLManager sharedInstance].dispatchQueue = couchbase_queue;

We create a live query like so:


dispatch_async
(couchbase_queue, ^{
   
CBLView         *view   = [[self get].database viewNamed:@"commentsByReport"];

   CBLLiveQuery    *query  = [[view createQuery] asLiveQuery];
      query.keys              = @[ report_id ];
      dispatch_async(dispatch_get_main_queue(), ^{ 
           [_commentsQuery addObserver:self forKeyPath:@"rows" options:0 context:0];
     });
});


So KVO is fired once and returns the correct result initially. However, as more documents are added, the CBLLiveQuery does not update. The documents are added on the couchbase_queue as well. 

We have tried registering the _commentsQuery for KVO on the couchbase_queue, but then it doesn't even return the initial set. We have tried restarting the _commentsQuery after it grabs the initial set, but this leads to EXC_BAD_ACCESS on the Couchbase Server thread. 

The only time it works correctly is if we set the couchbase_queue to be dispatch_get_main_queue(). However, that's not what we want due to performance hits. 

Any help would be appreciated, we've been scratching our heads for a few days on it. 

PS the map reduce function looks like this:

[[_database viewNamed:@"commentsByReport"] setMapBlock: MAPBLOCK({
        if ([doc[@"type"] isEqualToString: @"comment"]) {
            if (doc[@"_deleted"]) { return; }
            emit(doc[@"report_id"], doc);
        }
 }) reduceBlock: nil version: @"1.13"];



Jens Alfke

unread,
Jun 17, 2014, 2:20:03 PM6/17/14
to mobile-c...@googlegroups.com

On Jun 17, 2014, at 9:52 AM, Chris Fuentes <ch...@crowdcomfort.com> wrote:

dispatch_async(couchbase_queue, ^{
   
CBLView         *view   = [[self get].database viewNamed:@"commentsByReport"];

   CBLLiveQuery    *query  = [[view createQuery] asLiveQuery];
      query.keys              = @[ report_id ];
      dispatch_async(dispatch_get_main_queue(), ^{ 
           [_commentsQuery addObserver:self forKeyPath:@"rows" options:0 context:0];
     });
});



The addObserver: call should be made on the couchbase_queue, not back on the main thread; the rule is that all calls to a CBL object should be made on its owning thread/queue.

We have tried registering the _commentsQuery for KVO on the couchbase_queue, but then it doesn't even return the initial set.

OK, you already tried that … It looks like there’s a bug in the code that runs a query in the background, which is part of what the LiveQuery does. When the background query finishes and notifies the caller, it assumes a thread-based model, i.e. it dispatches the callback on the calling thread’s runloop. Unfortunately if this is being invoked from a dispatch queue this is the wrong thing to do — the queue is running on some anonymous thread managed by GCD which won’t have a runloop. That explains why your observer isn’t being called.

Sorry about that! There must be an oversight in our unit tests — I think we’re testing multi-threaded operation but not GCD-based.

The fix looks pretty simple. I’m not in a good state right now to test it out and commit it, but you could check out the repo and make the change yourself, and let me know if it fixes your problem. Rather than spell it out here, I’ve created a new Github issue. I’ll post the fix there.

—Jens

Chris Fuentes

unread,
Jun 17, 2014, 3:57:20 PM6/17/14
to mobile-c...@googlegroups.com
Ah, I see. I actually thought at one point it might be related to the impermanent nature of dispatch_queues - but I couldn't find a good way to persist the dispatch queue on a particular thread. 
  
 Is there a way to associate a particular NSThread object with the CBLManager instance instead of a GCD queue? If not, I'll probably checkout the latest commits an attempt the change myself, just for expediency. Thanks for your help!

Jens Alfke

unread,
Jun 17, 2014, 7:19:30 PM6/17/14
to mobile-c...@googlegroups.com

On Jun 17, 2014, at 12:57 PM, Chris Fuentes <ch...@crowdcomfort.com> wrote:

> Is there a way to associate a particular NSThread object with the CBLManager instance instead of a GCD queue?

Yes, just create the CBLManager on that thread and it will implicitly be associated with it.

—Jens

Reply all
Reply to author
Forward
0 new messages