couchbaselabs / TouchDB-Android

CouchDB-compatible mobile database; Android version

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

TouchDB does not work on Android 4.1

mschoch opened this issue · comments

java.lang.NoSuchFieldError: no field with name='mNativeHandle' signature='I' in class Landroid/database/sqlite/SQLiteDatabase;
at com.couchbase.touchdb.TDCollateJSON.nativeRegisterCustomCollators(Native Method)
at com.couchbase.touchdb.TDCollateJSON.registerCustomCollators(TDCollateJSON.java:10)
at com.couchbase.touchdb.TDDatabase.open(TDDatabase.java:222)
at com.couchbase.touchdb.TDDatabase.createEmptyDBAtPath(TDDatabase.java:161)
at com.couchbase.touchdb.testapp.tests.CRUDOperations.testCRUDOperations(CRUDOperations.java:46)
at java.lang.reflect.Method.invokeNative(Native Method)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:190)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:175)
at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:555)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1584)

TouchDB relies on some low-level implementation details to manually install our own collators using native code. On the surface it looks like those low-level details changed and broke our implementation. Unfortunately, source code for Android 4.1 is not available yet, making it hard to diagnose further.

Damn, running into this too.

I'ts kind of important for us to be able to deploy on 4.1 - can you maybe give an estimation when you'll be able to work on this one?

maybe time to move the whole thing to H2 anyways, see here and here

I've put in a fix that works in some cases (not convinced it works in all cases because of the way Android changed things)

ade012c

The unit tests pass and AndroidGrocerySync works as expected in the 4.1 emulator now, so its clearly an improvement worth sharing.

Could you elaborate on where you think we might run into trouble with this fix? Does it seem that the new hook may be device-dependent?

The issue is that SQLiteDatabase no longer has a 1-1 mapping to the underlying sqlite handle (at the c library layer). Ideally, whenever a new sqlite handle is opened, we need to register our custom collation functions there. Now, SQLiteDatabase has a ThreadLocal reference to a SQLiteSession, which has reference to a SQLiteConnectionPool which has a pool of SQLiteConnections's. Each of these has their own sqlite handle (at the c library layer).

All of this means its a lot harder (maybe impossible) to reliably ensure our custom collation functions are always registered. I coded up what we needed to make sure it gets registered on the "primary" connection, which is the one that it uses when you first call openDatabase().

I actually didn't expect AndroidGrocerySync to work with this patch because I was pretty sure we have multiple threads accessing the SQLiteDatabase (in a coordinated manner). But, for some reason it does work. I have not had the time to go back and get a better understanding of why this is.

I think you're taking the wrong approach here. Both native code and custom collators were KISS violations anyway and now this mess. So instead of registering a custom collator, compute an artificial collation key from the JSON that is e.g. a string and that has the quality that a comparison on that string with the built-in collator matches comparison on the corresponding JSON. Then store that key in the key column of your table. If you look at java.text.spi.CollatorProvider that comes with Open/Sun JDK (not Android) then you see it does the same thing (computing an artificial key) for performance reasons, only it is a binary blob.

Thanks for the input, can you point me to any sample code doing this?

Sorry no. I had the artificial collation key mostly figured out in my mind when I did the research into porting TouchDB to H2/JDBC but I'd yet have to type it in.

Maybe it is better to include SQLite code in TouchDB? That way TouchDB is independent from the underneath changes?

I've been testing extensively on Android 4.2 with no observed issues. Just now tried 4.1 and didn't see any problems.