SQLiteDiskIOException в Android

Мы получаем большое количество ошибок SQLiteDiskIOException в нашем приложении для Android, со стековыми следами, подобными следующим:

E/AndroidRuntime( 2252): Caused by: android.database.sqlite.SQLiteDiskIOException: disk I/O error
E/AndroidRuntime( 2252): at android.database.sqlite.SQLiteQuery.native_fill_window(Native Method)
E/AndroidRuntime( 2252): at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:75)
E/AndroidRuntime( 2252): at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:288)
E/AndroidRuntime( 2252): at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:269)
E/AndroidRuntime( 2252): at android.database.AbstractCursor.moveToPosition(AbstractCursor.java:171)
E/AndroidRuntime( 2252): at android.database.AbstractCursor.moveToFirst(AbstractCursor.java:248)
E/AndroidRuntime( 2252): at com.company.android.CActivity$QueryTask.doInBackground(CActivity.java:1660)

Это недавно началось несколько недель назад, но существенных изменений в базе данных не произошло в точной версии, в которой началась отчетность об этой проблеме. Несмотря на наличие (я считаю,) соответствующих индексов, об этом исключении сообщалось больше, чем нам было удобно в случае вызовов cursor.moveToFirst() после завершения запроса, как вы можете видеть из трассировки стека. До сих пор мы полностью не могли воспроизвести.

Запрос несколько сложный, с тремя левыми соединениями. Ниже представлен репрезентативный запрос, в котором некоторые идентифицирующие столбцы изменены для защиты невинных.

select distinct c._id as _id,c.type as type,c.name as name,c.slug as slug,c.description as description,c.extra1 as extra1,c.extra2 as extra2,c.extra3 as extra3,c.extra4 as extra4,c.extra5,c.extra6 as extra6,c.extra7 as extra7,c.extra8 as extra8, c.extra9 as extra9,c.sslug as sslug,
  c2.name as sname,
  p.type as prel,
  em.dS as dS,em.eS as eS 
from cse as c 
left join cse as c2 on c.sslug=c2.slug 
left join emed as em on c.slug=em.slug 
left join pre as p on c.sslug=p.slug 
where c.pslug='slug' AND c.user='user' AND c.csource='csource' 
order by c.type asc, c.extra6 desc, c.sortorder asc

Другие источники предположили, что мы пытаемся вытащить слишком много данных, но это просто не так. Три пользовательских случая, в которых нам удалось получить полную базу данных rowcounts, показывают: cse с < 2000 записей, с использованием 150 слов и pre с 0 или 7 записями. Кроме того, "объяснить план запроса" в запросе указывает, что все соединения выполняются с индексированными столбцами.

В каждом случае мы это видели, пользователь запускал Android 2.1 на различных устройствах (DROID, Hero, EVO и, возможно, другие). Примечательно, что мы не видели этого на нескольких устройствах G1, которые у нас есть, даже когда они загружаются другими приложениями.

Наконец, удаление и повторная установка оказались успешными в устранении проблемы, хотя, возможно, только временно.

Я боюсь, что эта проблема связана с повреждением данных в Android 2.1. Есть ли у кого-нибудь возможные предложения о том, что посмотреть? Может ли это быть связано с этой ошибкой Android на SQLiteDatabaseCorruptException

Руководство и решения высоко ценятся.

Ответ 1

Кажется, что у вас многопоточная проблема, один поток пытается получить данные, а другой один или несколько пытается вставить некоторые данные в ваши таблицы, потому что исключение выбрано из метода (getCount).

И не забывайте; Курс SQLite не синхронизирован внутри страны, поэтому, если вы используете этот курсор из нескольких потоков, вы должны выполнить собственный механизм синхронизации.

Ответ 2

Аналогичная проблема имеет место. Когда начинается наше приложение, происходит ошибка. В методе onCreate мы проверяем, есть ли какая-либо база данных в пути приложения. Если какая-либо база данных происходит, мы вызываем такой код

public boolean createDataBase() throws IOException
    { 
        boolean dbExist = checkDataBase();

        if(dbExist)
        {
            //do nothing - database already exist
        }
        else
        { 
            //By calling this method and empty database will be created into the default system path
            //of your application so we are gonna be able to overwrite that database with our database.
            this.getReadableDatabase();
        }

        return dbExist;
    }



    private boolean checkDataBase()
    {
        SQLiteDatabase checkDB = null;

        try
        {
            String myPath = DATABASE_PATH + DATABASE_NAME;
            checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);

        }
        catch(SQLiteException e)
        {

        }

        if(checkDB != null)
        { 
            checkDB.close(); 
        }

        return checkDB != null ? true : false;
    }

И если нет базы данных (первый запуск приложения), мы скопируем ее из ресурсов. Но иногда возникает SQLiteDiskIOException и вызовы базы данных из ресурсов.

Ответ 3

Одна из причин заключается в том, что Bassel Kh заявила, что многопроцессорный вопрос, другой - db, недоступен, т.е. db удаляется или sdcard недоступен.