Forest DB throws exception from native call

Env
Android API 22
compile 'com.couchbase.lite:couchbase-lite-android:1.2.0’
compile ‘com.couchbase.lite:couchbase-lite-android-forestdb:1.2.0’

While performing one of the query in my app, ForestDB throws exception. The result is non-deterministic - the exception was thrown sometime but not always for the same query. See the following stack trace. Can you please provide some information/help on what would potentially cause this exception and how to fix the issue.

Caused by: com.couchbase.lite.CouchbaseLiteException: ForestException{domain=2, code=-39}, Status: -39 (HTTP 500 Internal error)
    at com.couchbase.lite.store.ForestDBViewStore.updateIndexes(ForestDBViewStore.java:283)
    at com.couchbase.lite.View.updateIndexes(View.java:321)
    at com.couchbase.lite.View.updateIndex(View.java:294)
    at com.couchbase.lite.Database.queryViewNamed(Database.java:2092)
    at com.couchbase.lite.Query.run(Query.java:433)
    ....    
    at android.os.AsyncTask$2.call(AsyncTask.java:295) 
    at java.util.concurrent.FutureTask.run(FutureTask.java:237) 
    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) 
    at java.lang.Thread.run(Thread.java:818) 

Caused by: ForestException{domain=2, code=-39}
    at com.couchbase.cbforest.Indexer.iterateDocuments(Native Method)
    at com.couchbase.cbforest.Indexer.iterateDocuments(Indexer.java:18)
    at com.couchbase.lite.store.ForestDBViewStore.updateIndexes(ForestDBViewStore.java:250)
    at com.couchbase.lite.View.updateIndexes(View.java:321) 
    at com.couchbase.lite.View.updateIndex(View.java:294) 
    at com.couchbase.lite.Database.queryViewNamed(Database.java:2092) 
    at com.couchbase.lite.Query.run(Query.java:433)

Could you provide a sample of code that is causing the exception (not just the query, but that could be helpful too)?

Hi @cheng.ustc,

Could you please try 1.2.1 instead of 1.2.0. We fixed some forestdb related issues with 1.2.1 release.

Thanks!

Hi @hideki,

I have tried 1.2.1 and the issue still occurs.

@matthew.groves
The code which cause the exception is the following:

    QueryRunner<List<X>> query = mView.<List<X>>createQuery()
            .setKeys(Lists.newArrayList((Object) id))
            .setIndexUpdateMode(QueryRunner.IndexUpdateMode.BEFORE)
            .setMapOnly(true);
    try {
        return query.run().get(new QueryEnumerator.ResultMapper<List<X>>() {

            @Override
            public List<X> map(QueryEnumerator<List<X>> rows) {
                List<X> list = new LinkedList<>();

                for (QueryRow row : rows) {
                    String id = row.getDocumentId();
                    Map<String, Object> props = row.getDocument().getUserProperties();
                    X x = new X(id, props);
                    x.getPropertyChanges();
                    list.add(x);
                }
                return list;
            }
        });
    } catch (DBException e) {
        Log.E("error loading document id=%s", id, e);
        throw e;
    }

Hi @cheng.ustc,

Thank you for your response.

I filed the ticket for this issue.

I need two more information from you.

  • Beside the query operation, what operations are running simultaneously? The app inserting docs? or pull replication is running?
  • Can you describe QueryRunner implementation? does this create another thread?

@hideki

  • Pull replication isn’t running but there might be an updating on the doc running simultaneously. More specifically, I have two doc types, let’s say A and B, and from OO perspective A contains a non-id property p and a list of B (A.id as the foreign key on B). The query thrown exception is fetching the list of B but there is a possibility at the time of query, p is updated asynchronously.

  • QueryRunner is nothing but a wrapper of Query and there is no thread (running on UI thread) involved. The QueryRunner.run() returns our wrapper of QueryEnumerator.

@cheng.ustc thank you very much for your additional information!! It helps a lot.