1

I got an exception in my code.

10-10 22:05:33.866  5725  5725 E AndroidRuntime: Caused by: net.sqlcipher.database.SQLiteDiskIOException: error code 10: disk I/O error
10-10 22:05:33.866  5725  5725 E AndroidRuntime:    at net.sqlcipher.database.SQLiteStatement.native_execute(Native Method)
10-10 22:05:33.866  5725  5725 E AndroidRuntime:    at net.sqlcipher.database.SQLiteStatement.execute(SQLiteStatement.java:58)
10-10 22:05:33.866  5725  5725 E AndroidRuntime:    at net.sqlcipher.database.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:2074)

This has only happened once (so far) among thousands of successful inserts and selects, so I suspect there is some kind of race condition between different threads in the same process trying to access the same database.

The actual code is unimportant, this is just a plain insert of a new record, and the on conflict parameter is saying to ignore any conflict:

    ContentValues values = new ContentValues();
    // values.put(); calls go here, nothing strange about the data
    db.insertWithOnConflict("Sample", null, values, SQLiteDatabase.CONFLICT_IGNORE);

Architectually I have a singleton object in my Service encapsulating a single continuously open connection to the database with a cache sitting in front of it. Multiple threads call the object from different places in the Service to insert data, these are typically listeners which are logging things such as GPS position, battery state, etc. Reading typically comes from the cache and does not hit the database.

My first thought was that perhaps I need to synchronize the class through which database access flow (it smells like two different threads might be trying to insert at almost exactly the same time, which in practice would happen rarely), but this answer seems to be saying that I should be able to do this with no problem. "Inserts, updates, deletes and reads are generally OK from multiple threads" Of note the exception says "I/O error" not "database locked".

Update: I added logcat traces and exception catching around every database access. After that I got two more exceptions. In both cases only a single database access was in progress. Both were simple inserts. The first one threw an exception 1.2 seconds after the insertion began, which seems unbelievably high. The second only took 38ms which looks to be about average.

The issues is not running out of storage: I have 27GB free. I have a hard time believing it is an issue with the flash either, as I am not seeing any other errors with write to it. I have also not seen any issues like this with an older app that uses the same SQLCipher library but which closes the database after each insert.

Update 2: In the exception handler I added code to immediately retry the insert, and so far I have not received a second exception at this point:

    try {
        ret = db.insertWithOnConflict("Sample", null, values, SQLiteDatabase.CONFLICT_IGNORE);
    } catch (Exception e) {
        Log.d(logtag,"exception:"+e);
        try {
            ret = db.insertWithOnConflict("Sample", null, values, SQLiteDatabase.CONFLICT_IGNORE);
        } catch (Exception e1) {
            Log.d(logtag,"exception2:"+e1);
        }
        return 0;
    }
Michael
  • 9,060
  • 14
  • 61
  • 123

0 Answers0