Sqlite error on Android : error code 11: database disk image is malformed

Asked

Viewed 1,364 times

10

I have a version of the App in production where it is allowed to mark a message as favorite, only that this totally random error happens provoking corruption of the database and resulting in application crash.

I know I realize operations a little risky according to Sqlite’s own staff.

The procedure is as follows:

  • starts the upgrade procedure
  • copies the user’s database to a temporary file
  • copies the new database to the device
  • attaches the old base with the new
  • necessary data (such as favorite messages)
  • detaches the temporary base
  • excludes the temporary basis

This procedure is done on thousands of devices, mostly everything goes well, but it started to become frequent cases like this.

Does anyone know how to minimize that?

ERROR:

java.lang.RuntimeException: Unable to start activity ComponentInfo{br.com.redrails.torpedos/br.com.redrails.torpedos.MainActivity}: android.database.sqlite.SQLiteDatabaseCorruptException: error code 11: database disk image is malformed
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1970)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1995)
    at android.app.ActivityThread.access$600(ActivityThread.java:128)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1161)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:137)
    at android.app.ActivityThread.main(ActivityThread.java:4514)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:511)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:790)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:557)
    at dalvik.system.NativeStart.main(Native Method)
Caused by: android.database.sqlite.SQLiteDatabaseCorruptException: error code 11: database disk image is malformed
    at android.database.sqlite.SQLiteStatement.native_1x1_long(Native Method)
    at android.database.sqlite.SQLiteStatement.simpleQueryForLong(SQLiteStatement.java:138)
    at android.database.DatabaseUtils.longForQuery(DatabaseUtils.java:791)
    at android.database.DatabaseUtils.longForQuery(DatabaseUtils.java:779)
    at br.com.redrails.torpedos.MensagemDAO.reloadQuantidadeTotal(MensagemDAO.java:144)
    at br.com.redrails.torpedos.MensagemDAO.getQuantidadeTotal(MensagemDAO.java:149)
    at br.com.redrails.torpedos.MainActivity.onCreate(MainActivity.java:85)
    at android.app.Activity.performCreate(Activity.java:4465)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1053)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1934)
    ... 11 more
  • 2

    Maybe block access to the database before doing these operations?

  • Do you think blocking the database will solve? and other I need to perform operations in the database during the process.

  • Maybe put operations in a queue, block during copying, then unlock and continue with the queue... write to a file that at this point is copied gives problems qq way, pq n is atomic.

  • By chance I still read code today that confirmed me that in Sqlite this is important... (and suggested further that sometimes blocking the program side may not even be enough...)

  • Know where I can get more explanations on how to do this @Lapingvino ??

  • 1

    http://www.mimec.org/node/306 this may help to block at the same sqlite level, otherwise you can also block in Java (see threading).

  • I’ll try it, thanks @Lapingvino :)

  • It would be great to have an example of the operations you are doing. Are you trying to mess with the base while copying? Handles different threads at the same time? ?

  • I modified to try to minimize everything, I will add the example of the code @Alexandrer.L.eMarcondes

  • 2

    One thing I notice developers forget about on Android devices is that these usually have solid state secondary memories like Flash, and that these have a number of restricted writing cycles (Windows Embbeded itself had option to reduce the number of scripts), so the more you can work on the primary memory (RAM) before writing on the secondary better.

Show 5 more comments

2 answers

1

I think it is worth studying the possibility of implementing a PUSH service to synchronize your databases, so everything would be done in a "invisible" way to the user and also in a safer way.

A good place to create free WS and also use free PUSH for both Android and iOS is http://parse.com

1


A few months ago we started receiving many reports from users complaining of failures in one of our applications. During the investigation of the problem, it became clear that the error was due to some corruption in the SQLite. I have observed that this problem also existed from a certain period until then. I also saw that this error occurred especially with newer devices that have more processing cores and more clock and that in older devices less powerful and especially with only one core this error occurred very little or simply did not occur. This made me conclude that the problem was related to competition. That here was linked to access by multiple Threads to SQLite.

After some research and testing I saw the following points:

For each database there should be only one SqliteOpenHelper. As it may seem, there are no multiple connections to the database. A SqliteOpenHelper has only one connection. Always. Even if the methods getWritableDatabase and getReadableDatabase make it look like there are two different connections, it just doesn’t happen: it’s the same connection.

This ensures no collisions, concurrent access to the database file.

In the case of the application in question, there were multiple SqliteOpenHelper and multiple Threads. The solution was a general re-factoring in persistence with the goal of having only one SqliteOpenHelper for each database (in this case there were three). There was a strong reduction in the occurrence of the problem, but there were still occurrences.

Finally, the methods of access to the database were synchronized in order to avoid concurrent access to the SqliteOpenHelper. This is a measure that did not affect the performance of the application, but should be analyzed for each case.

In short:

  1. Keep only one SqliteOpenHelper by database
  2. If necessary and feasible, access
  • Quite a complete answer, I have not yet tested, but the scenario seems a faithful description of mine. This way I believe is the solution I should implement. Thank you.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.