Avoid race conditions between queries and closing of the auto_dict database.

Keep a reference to the openhelper around across locale and input language
changes. Also, share the openhelper between the queries and updates. Creating
a new one in a separate thread could cause it to be closed at the wrong time.

Monkey bugs, probably dupes.

Bug: 2560471
Bug: 2544169
Change-Id: I6eb39145de7191732ddde455728bf147a2d1ba31
main
Amith Yamasani 2010-03-31 14:01:59 -07:00
parent 06933183c8
commit fbd1866424
1 changed files with 33 additions and 29 deletions

View File

@ -83,13 +83,15 @@ public class AutoDictionary extends ExpandableDictionary {
sDictProjectionMap.put(COLUMN_LOCALE, COLUMN_LOCALE); sDictProjectionMap.put(COLUMN_LOCALE, COLUMN_LOCALE);
} }
private DatabaseHelper mOpenHelper; private static DatabaseHelper mOpenHelper = null;
public AutoDictionary(Context context, LatinIME ime, String locale) { public AutoDictionary(Context context, LatinIME ime, String locale) {
super(context); super(context);
mIme = ime; mIme = ime;
mLocale = locale; mLocale = locale;
mOpenHelper = new DatabaseHelper(getContext()); if (mOpenHelper == null) {
mOpenHelper = new DatabaseHelper(getContext());
}
if (mLocale != null && mLocale.length() > 1) { if (mLocale != null && mLocale.length() > 1) {
loadDictionary(); loadDictionary();
} }
@ -104,7 +106,10 @@ public class AutoDictionary extends ExpandableDictionary {
@Override @Override
public void close() { public void close() {
flushPendingWrites(); flushPendingWrites();
mOpenHelper.close(); // Don't close the database as locale changes will require it to be reopened anyway
// Also, the database is written to somewhat frequently, so it needs to be kept alive
// throughout the life of the process.
// mOpenHelper.close();
super.close(); super.close();
} }
@ -112,21 +117,24 @@ public class AutoDictionary extends ExpandableDictionary {
public void loadDictionaryAsync() { public void loadDictionaryAsync() {
// Load the words that correspond to the current input locale // Load the words that correspond to the current input locale
Cursor cursor = query(COLUMN_LOCALE + "=?", new String[] { mLocale }); Cursor cursor = query(COLUMN_LOCALE + "=?", new String[] { mLocale });
if (cursor.moveToFirst()) { try {
int wordIndex = cursor.getColumnIndex(COLUMN_WORD); if (cursor.moveToFirst()) {
int frequencyIndex = cursor.getColumnIndex(COLUMN_FREQUENCY); int wordIndex = cursor.getColumnIndex(COLUMN_WORD);
while (!cursor.isAfterLast()) { int frequencyIndex = cursor.getColumnIndex(COLUMN_FREQUENCY);
String word = cursor.getString(wordIndex); while (!cursor.isAfterLast()) {
int frequency = cursor.getInt(frequencyIndex); String word = cursor.getString(wordIndex);
// Safeguard against adding really long words. Stack may overflow due int frequency = cursor.getInt(frequencyIndex);
// to recursive lookup // Safeguard against adding really long words. Stack may overflow due
if (word.length() < getMaxWordLength()) { // to recursive lookup
super.addWord(word, frequency); if (word.length() < getMaxWordLength()) {
super.addWord(word, frequency);
}
cursor.moveToNext();
} }
cursor.moveToNext();
} }
} finally {
cursor.close();
} }
cursor.close();
} }
@Override @Override
@ -161,7 +169,7 @@ public class AutoDictionary extends ExpandableDictionary {
// Nothing pending? Return // Nothing pending? Return
if (mPendingWrites.isEmpty()) return; if (mPendingWrites.isEmpty()) return;
// Create a background thread to write the pending entries // Create a background thread to write the pending entries
new UpdateDbTask(getContext(), mPendingWrites, mLocale).execute(); new UpdateDbTask(getContext(), mOpenHelper, mPendingWrites, mLocale).execute();
// Create a new map for writing new entries into while the old one is written to db // Create a new map for writing new entries into while the old one is written to db
mPendingWrites = new HashMap<String, Integer>(); mPendingWrites = new HashMap<String, Integer>();
} }
@ -216,11 +224,11 @@ public class AutoDictionary extends ExpandableDictionary {
private final DatabaseHelper mDbHelper; private final DatabaseHelper mDbHelper;
private final String mLocale; private final String mLocale;
public UpdateDbTask(Context context, public UpdateDbTask(Context context, DatabaseHelper openHelper,
HashMap<String, Integer> pendingWrites, String locale) { HashMap<String, Integer> pendingWrites, String locale) {
mMap = pendingWrites; mMap = pendingWrites;
mLocale = locale; mLocale = locale;
mDbHelper = new DatabaseHelper(context); mDbHelper = openHelper;
} }
@Override @Override
@ -228,18 +236,14 @@ public class AutoDictionary extends ExpandableDictionary {
SQLiteDatabase db = mDbHelper.getWritableDatabase(); SQLiteDatabase db = mDbHelper.getWritableDatabase();
// Write all the entries to the db // Write all the entries to the db
Set<Entry<String,Integer>> mEntries = mMap.entrySet(); Set<Entry<String,Integer>> mEntries = mMap.entrySet();
try { for (Entry<String,Integer> entry : mEntries) {
for (Entry<String,Integer> entry : mEntries) { Integer freq = entry.getValue();
Integer freq = entry.getValue(); db.delete(AUTODICT_TABLE_NAME, COLUMN_WORD + "=? AND " + COLUMN_LOCALE + "=?",
db.delete(AUTODICT_TABLE_NAME, COLUMN_WORD + "=? AND " + COLUMN_LOCALE + "=?", new String[] { entry.getKey(), mLocale });
new String[] { entry.getKey(), mLocale }); if (freq != null) {
if (freq != null) { db.insert(AUTODICT_TABLE_NAME, null,
db.insert(AUTODICT_TABLE_NAME, null, getContentValues(entry.getKey(), freq, mLocale));
getContentValues(entry.getKey(), freq, mLocale));
}
} }
} finally {
mDbHelper.close();
} }
return null; return null;
} }