Merge "Remove DictionaryUpdateController."

main
Keisuke Kuroyanagi 2014-04-28 08:29:02 +00:00 committed by Android (Google) Code Review
commit 5c1416e426
3 changed files with 21 additions and 107 deletions

View File

@ -89,8 +89,8 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
registerObserver(context); registerObserver(context);
// Load the current binary dictionary from internal storage. If no binary dictionary exists, // Load the current binary dictionary from internal storage. If no binary dictionary exists,
// loadDictionary will start a new thread to generate one asynchronously. // reloadDictionaryIfRequired will start a new thread to generate one asynchronously.
loadDictionary(); reloadDictionaryIfRequired();
} }
private synchronized void registerObserver(final Context context) { private synchronized void registerObserver(final Context context) {
@ -100,7 +100,7 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
new ContentObserver(null) { new ContentObserver(null) {
@Override @Override
public void onChange(boolean self) { public void onChange(boolean self) {
setRequiresReload(true); setNeedsToReload();
} }
}); });
} }

View File

@ -27,7 +27,6 @@ import com.android.inputmethod.latin.makedict.UnsupportedFormatException;
import com.android.inputmethod.latin.makedict.WordProperty; import com.android.inputmethod.latin.makedict.WordProperty;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import com.android.inputmethod.latin.utils.AsyncResultHolder; import com.android.inputmethod.latin.utils.AsyncResultHolder;
import com.android.inputmethod.latin.utils.CollectionUtils;
import com.android.inputmethod.latin.utils.CombinedFormatUtils; import com.android.inputmethod.latin.utils.CombinedFormatUtils;
import com.android.inputmethod.latin.utils.ExecutorUtils; import com.android.inputmethod.latin.utils.ExecutorUtils;
import com.android.inputmethod.latin.utils.FileUtils; import com.android.inputmethod.latin.utils.FileUtils;
@ -38,7 +37,6 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
@ -74,15 +72,6 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
private static final int DICTIONARY_FORMAT_VERSION = FormatSpec.VERSION4; private static final int DICTIONARY_FORMAT_VERSION = FormatSpec.VERSION4;
/**
* A static map of update controllers, each of which records the time of accesses to a single
* binary dictionary file and tracks whether the file is regenerating. The key for this map is
* the dictionary name and the value is the shared dictionary time recorder associated with
* that dictionary name.
*/
private static final ConcurrentHashMap<String, DictionaryUpdateController>
sDictNameDictionaryUpdateControllerMap = CollectionUtils.newConcurrentHashMap();
/** The application context. */ /** The application context. */
protected final Context mContext; protected final Context mContext;
@ -105,14 +94,9 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
/** Dictionary file */ /** Dictionary file */
private final File mDictFile; private final File mDictFile;
// TODO: remove, once dynamic operations is serialized private final AtomicBoolean mProcessingLargeTask;
/** Controls updating the shared binary dictionary file across multiple instances. */ private boolean mNeedsToReload;
private final DictionaryUpdateController mDictNameDictionaryUpdateController;
// TODO: remove, once dynamic operations is serialized
/** Controls updating the local binary dictionary for this instance. */
private final DictionaryUpdateController mPerInstanceDictionaryUpdateController =
new DictionaryUpdateController();
/* A extension for a binary dictionary file. */ /* A extension for a binary dictionary file. */
protected static final String DICT_FILE_EXTENSION = ".dict"; protected static final String DICT_FILE_EXTENSION = ".dict";
@ -145,21 +129,6 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
return mBinaryDictionary.isValidDictionary(); return mBinaryDictionary.isValidDictionary();
} }
/**
* Gets the dictionary update controller for the given dictionary name.
*/
private static DictionaryUpdateController getDictionaryUpdateController(
final String dictName) {
DictionaryUpdateController recorder = sDictNameDictionaryUpdateControllerMap.get(dictName);
if (recorder == null) {
synchronized(sDictNameDictionaryUpdateControllerMap) {
recorder = new DictionaryUpdateController();
sDictNameDictionaryUpdateControllerMap.put(dictName, recorder);
}
}
return recorder;
}
/** /**
* Creates a new expandable binary dictionary. * Creates a new expandable binary dictionary.
* *
@ -179,7 +148,8 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
mLocale = locale; mLocale = locale;
mDictFile = getDictFile(context, dictName, dictFile); mDictFile = getDictFile(context, dictName, dictFile);
mBinaryDictionary = null; mBinaryDictionary = null;
mDictNameDictionaryUpdateController = getDictionaryUpdateController(dictName); mProcessingLargeTask = new AtomicBoolean();
mNeedsToReload = false;
} }
public static File getDictFile(final Context context, final String dictName, public static File getDictFile(final Context context, final String dictName,
@ -286,7 +256,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
try { try {
mBinaryDictionary.flushWithGC(); mBinaryDictionary.flushWithGC();
} finally { } finally {
mDictNameDictionaryUpdateController.mProcessingLargeTask.set(false); mProcessingLargeTask.set(false);
} }
} }
}); });
@ -388,7 +358,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
callback.onFinished(); callback.onFinished();
} }
if (locked) { if (locked) {
mDictNameDictionaryUpdateController.mProcessingLargeTask.set(false); mProcessingLargeTask.set(false);
} }
} }
} }
@ -461,25 +431,11 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
return mBinaryDictionary.isValidBigram(word1, word2); return mBinaryDictionary.isValidBigram(word1, word2);
} }
/**
* Load the current binary dictionary from internal storage in a background thread. If no binary
* dictionary exists, this method will generate one.
*/
protected void loadDictionary() {
mPerInstanceDictionaryUpdateController.mLastUpdateRequestTime = System.currentTimeMillis();
reloadDictionaryIfRequired();
}
/** /**
* Loads the current binary dictionary from internal storage. Assumes the dictionary file * Loads the current binary dictionary from internal storage. Assumes the dictionary file
* exists. * exists.
*/ */
private void loadBinaryDictionaryLocked() { private void loadBinaryDictionaryLocked() {
if (DEBUG) {
Log.d(TAG, "Loading binary dictionary: " + mDictName + " request="
+ mDictNameDictionaryUpdateController.mLastUpdateRequestTime + " update="
+ mDictNameDictionaryUpdateController.mLastUpdateTime);
}
if (DBG_STRESS_TEST) { if (DBG_STRESS_TEST) {
// Test if this class does not cause problems when it takes long time to load binary // Test if this class does not cause problems when it takes long time to load binary
// dictionary. // dictionary.
@ -505,11 +461,6 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
* Create a new binary dictionary and load initial contents. * Create a new binary dictionary and load initial contents.
*/ */
private void createNewDictionaryLocked() { private void createNewDictionaryLocked() {
if (DEBUG) {
Log.d(TAG, "Generating binary dictionary: " + mDictName + " request="
+ mDictNameDictionaryUpdateController.mLastUpdateRequestTime + " update="
+ mDictNameDictionaryUpdateController.mLastUpdateTime);
}
removeBinaryDictionaryLocked(); removeBinaryDictionaryLocked();
createOnMemoryBinaryDictionaryLocked(); createOnMemoryBinaryDictionaryLocked();
loadInitialContentsLocked(); loadInitialContentsLocked();
@ -529,20 +480,11 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
} }
/** /**
* Marks that the dictionary is out of date and requires a reload. * Marks that the dictionary needs to be reloaded.
* *
* @param requiresRebuild Indicates that the source dictionary content has changed and a rebuild
* of the binary file is required. If not true, the next reload process will only read
* the current binary dictionary from file.
*/ */
protected void setRequiresReload(final boolean requiresRebuild) { protected void setNeedsToReload() {
final long time = System.currentTimeMillis(); mNeedsToReload = true;
mPerInstanceDictionaryUpdateController.mLastUpdateRequestTime = time;
mDictNameDictionaryUpdateController.mLastUpdateRequestTime = time;
if (DEBUG) {
Log.d(TAG, "Reload request: " + mDictName + ": request=" + time + " update="
+ mDictNameDictionaryUpdateController.mLastUpdateTime);
}
} }
/** /**
@ -559,18 +501,17 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
* Returns whether a dictionary reload is required. * Returns whether a dictionary reload is required.
*/ */
private boolean isReloadRequired() { private boolean isReloadRequired() {
return mBinaryDictionary == null || mPerInstanceDictionaryUpdateController.isOutOfDate(); return mBinaryDictionary == null || mNeedsToReload;
} }
private boolean processingLargeTask() { private boolean processingLargeTask() {
return mDictNameDictionaryUpdateController.mProcessingLargeTask.get(); return mProcessingLargeTask.get();
} }
// Returns whether the dictionary is being used for a large task. If true, we should not use // Returns whether the dictionary is being used for a large task. If true, we should not use
// this dictionary for latency sensitive operations. // this dictionary for latency sensitive operations.
private boolean setProcessingLargeTaskIfNot() { private boolean setProcessingLargeTaskIfNot() {
return mDictNameDictionaryUpdateController.mProcessingLargeTask.compareAndSet( return mProcessingLargeTask.compareAndSet(false /* expect */ , true /* update */);
false /* expect */ , true /* update */);
} }
/** /**
@ -584,28 +525,17 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
@Override @Override
public void run() { public void run() {
try { try {
final long time = System.currentTimeMillis(); if (!dictionaryFileExists() || haveContentsChanged()) {
final boolean openedDictIsOutOfDate =
mDictNameDictionaryUpdateController.isOutOfDate();
if (!dictionaryFileExists()
|| (openedDictIsOutOfDate && haveContentsChanged())) {
// If the shared dictionary file does not exist or is out of date and // If the shared dictionary file does not exist or is out of date and
// contents have been updated, the first instance that acquires the lock // contents have been updated, the first instance that acquires the lock
// will generate a new one // will generate a new one
mDictNameDictionaryUpdateController.mLastUpdateTime = time;
createNewDictionaryLocked(); createNewDictionaryLocked();
} else if (openedDictIsOutOfDate) { } else if (mBinaryDictionary == null) {
// If not, the reload request was unnecessary so revert
// LastUpdateRequestTime to LastUpdateTime.
mDictNameDictionaryUpdateController.mLastUpdateRequestTime =
mDictNameDictionaryUpdateController.mLastUpdateTime;
} else if (mBinaryDictionary == null ||
mPerInstanceDictionaryUpdateController.mLastUpdateTime
< mDictNameDictionaryUpdateController.mLastUpdateTime) {
// Otherwise, if the local dictionary is older than the shared dictionary, // Otherwise, if the local dictionary is older than the shared dictionary,
// load the shared dictionary. // load the shared dictionary.
loadBinaryDictionaryLocked(); loadBinaryDictionaryLocked();
} }
mNeedsToReload = false;
if (mBinaryDictionary != null && !(isValidDictionaryLocked() if (mBinaryDictionary != null && !(isValidDictionaryLocked()
// TODO: remove the check below // TODO: remove the check below
&& matchesExpectedBinaryDictFormatVersionForThisType( && matchesExpectedBinaryDictFormatVersionForThisType(
@ -613,12 +543,10 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
// Binary dictionary or its format version is not valid. Regenerate // Binary dictionary or its format version is not valid. Regenerate
// the dictionary file. writeBinaryDictionary will remove the // the dictionary file. writeBinaryDictionary will remove the
// existing files if appropriate. // existing files if appropriate.
mDictNameDictionaryUpdateController.mLastUpdateTime = time;
createNewDictionaryLocked(); createNewDictionaryLocked();
} }
mPerInstanceDictionaryUpdateController.mLastUpdateTime = time;
} finally { } finally {
mDictNameDictionaryUpdateController.mProcessingLargeTask.set(false); mProcessingLargeTask.set(false);
} }
} }
}); });
@ -643,20 +571,6 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
ExecutorUtils.getExecutor(mDictName).replaceAndExecute(oldTask, newTask); ExecutorUtils.getExecutor(mDictName).replaceAndExecute(oldTask, newTask);
} }
/**
* For tracking whether the dictionary is out of date and the dictionary is used in a large
* task. Can be shared across multiple dictionary instances that access the same filename.
*/
private static class DictionaryUpdateController {
public volatile long mLastUpdateTime = 0;
public volatile long mLastUpdateRequestTime = 0;
public volatile AtomicBoolean mProcessingLargeTask = new AtomicBoolean();
public boolean isOutOfDate() {
return (mLastUpdateRequestTime > mLastUpdateTime);
}
}
// TODO: Implement BinaryDictionary.isInDictionary(). // TODO: Implement BinaryDictionary.isInDictionary().
@UsedForTesting @UsedForTesting
public boolean isInUnderlyingBinaryDictionaryForTests(final String word) { public boolean isInUnderlyingBinaryDictionaryForTests(final String word) {

View File

@ -116,12 +116,12 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary {
// devices. On older versions of the platform, the hook above will be called instead. // devices. On older versions of the platform, the hook above will be called instead.
@Override @Override
public void onChange(final boolean self, final Uri uri) { public void onChange(final boolean self, final Uri uri) {
setRequiresReload(true); setNeedsToReload();
} }
}; };
cres.registerContentObserver(Words.CONTENT_URI, true, mObserver); cres.registerContentObserver(Words.CONTENT_URI, true, mObserver);
mEnabled = readIsEnabled(); mEnabled = readIsEnabled();
loadDictionary(); reloadDictionaryIfRequired();
} }
@Override @Override