am 8be44a2d: am f28ca53b: am 864ee881: Merge "Fix UserHistoryDictionaryTests."

* commit '8be44a2d8751357b1413105a195b59a165749263':
  Fix UserHistoryDictionaryTests.
This commit is contained in:
Keisuke Kuroyanagi 2013-10-09 19:33:36 -07:00 committed by Android Git Automerger
commit 96a7654072
4 changed files with 70 additions and 54 deletions

View file

@ -249,6 +249,9 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
final File file = new File(mContext.getFilesDir(), mFilename); final File file = new File(mContext.getFilesDir(), mFilename);
BinaryDictionary.createEmptyDictFile(file.getAbsolutePath(), BinaryDictionary.createEmptyDictFile(file.getAbsolutePath(),
DICTIONARY_FORMAT_VERSION, getHeaderAttributeMap()); DICTIONARY_FORMAT_VERSION, getHeaderAttributeMap());
mBinaryDictionary = new BinaryDictionary(
file.getAbsolutePath(), 0 /* offset */, file.length(),
true /* useFullEditDistance */, null, mDictType, mIsUpdatable);
} else { } else {
mDictionaryWriter.clear(); mDictionaryWriter.clear();
} }
@ -273,11 +276,26 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
lastModifiedTime); lastModifiedTime);
} }
/**
* Check whether GC is needed and run GC if required.
*/
protected void runGCIfRequired(final boolean mindsBlockByGC) { protected void runGCIfRequired(final boolean mindsBlockByGC) {
if (!ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE) return; if (!ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE) return;
getExecutor(mFilename).execute(new Runnable() {
@Override
public void run() {
runGCIfRequiredInternalLocked(mindsBlockByGC);
}
});
}
private void runGCIfRequiredInternalLocked(final boolean mindsBlockByGC) {
if (!ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE) return;
// Calls to needsToRunGC() need to be serialized.
if (mBinaryDictionary.needsToRunGC(mindsBlockByGC)) { if (mBinaryDictionary.needsToRunGC(mindsBlockByGC)) {
if (setIsRegeneratingIfNotRegenerating()) { if (setIsRegeneratingIfNotRegenerating()) {
getExecutor(mFilename).execute(new Runnable() { // Run GC after currently existing time sensitive operations.
getExecutor(mFilename).executePrioritized(new Runnable() {
@Override @Override
public void run() { public void run() {
try { try {
@ -300,11 +318,11 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
Log.w(TAG, "addWordDynamically is called for non-updatable dictionary: " + mFilename); Log.w(TAG, "addWordDynamically is called for non-updatable dictionary: " + mFilename);
return; return;
} }
runGCIfRequired(true /* mindsBlockByGC */);
getExecutor(mFilename).execute(new Runnable() { getExecutor(mFilename).execute(new Runnable() {
@Override @Override
public void run() { public void run() {
if (ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE) { if (ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE) {
runGCIfRequiredInternalLocked(true /* mindsBlockByGC */);
mBinaryDictionary.addUnigramWord(word, frequency); mBinaryDictionary.addUnigramWord(word, frequency);
} else { } else {
// TODO: Remove. // TODO: Remove.
@ -324,11 +342,11 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
+ mFilename); + mFilename);
return; return;
} }
runGCIfRequired(true /* mindsBlockByGC */);
getExecutor(mFilename).execute(new Runnable() { getExecutor(mFilename).execute(new Runnable() {
@Override @Override
public void run() { public void run() {
if (ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE) { if (ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE) {
runGCIfRequiredInternalLocked(true /* mindsBlockByGC */);
mBinaryDictionary.addBigramWords(word0, word1, frequency); mBinaryDictionary.addBigramWords(word0, word1, frequency);
} else { } else {
// TODO: Remove. // TODO: Remove.
@ -348,11 +366,11 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
+ mFilename); + mFilename);
return; return;
} }
runGCIfRequired(true /* mindsBlockByGC */);
getExecutor(mFilename).execute(new Runnable() { getExecutor(mFilename).execute(new Runnable() {
@Override @Override
public void run() { public void run() {
if (ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE) { if (ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE) {
runGCIfRequiredInternalLocked(true /* mindsBlockByGC */);
mBinaryDictionary.removeBigramWords(word0, word1); mBinaryDictionary.removeBigramWords(word0, word1);
} else { } else {
// TODO: Remove. // TODO: Remove.
@ -479,8 +497,8 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
final long length = file.length(); final long length = file.length();
// Build the new binary dictionary // Build the new binary dictionary
final BinaryDictionary newBinaryDictionary = new BinaryDictionary(filename, 0, length, final BinaryDictionary newBinaryDictionary = new BinaryDictionary(filename, 0 /* offset */,
true /* useFullEditDistance */, null, mDictType, mIsUpdatable); length, true /* useFullEditDistance */, null, mDictType, mIsUpdatable);
// Ensure all threads accessing the current dictionary have finished before // Ensure all threads accessing the current dictionary have finished before
// swapping in the new one. // swapping in the new one.

View file

@ -230,6 +230,7 @@ public abstract class DecayingExpandableBinaryDictionaryBase extends ExpandableB
mSessions.remove(session); mSessions.remove(session);
} }
@UsedForTesting
public void clearAndFlushDictionary() { public void clearAndFlushDictionary() {
// Clear the node structure on memory // Clear the node structure on memory
clear(); clear();

View file

@ -67,7 +67,6 @@ static jboolean latinime_BinaryDictionary_createEmptyDictFile(JNIEnv *env, jclas
valueChars[valueUtf8Length] = '\0'; valueChars[valueUtf8Length] = '\0';
HeaderReadWriteUtils::AttributeMap::mapped_type value; HeaderReadWriteUtils::AttributeMap::mapped_type value;
HeaderReadWriteUtils::insertCharactersIntoVector(valueChars, &value); HeaderReadWriteUtils::insertCharactersIntoVector(valueChars, &value);
attributeMap[key] = value; attributeMap[key] = value;
} }

View file

@ -109,35 +109,54 @@ public class UserHistoryDictionaryTests extends AndroidTestCase {
dict.close(); dict.close();
} }
public void testRandomWords() { /**
File dictFile = null; * Clear all entries in the user history dictionary.
Log.d(TAG, "This test can be used for profiling."); * @param testFilenameSuffix file name suffix used for testing.
Log.d(TAG, "Usage: please set UserHistoryDictionary.PROFILE_SAVE_RESTORE to true."); */
final String testFilenameSuffix = "testRandomWords" + System.currentTimeMillis(); private void clearHistory(final String testFilenameSuffix) {
final int numberOfWords = 1000; final UserHistoryDictionary dict =
final Random random = new Random(123456); PersonalizationHelper.getUserHistoryDictionary(getContext(),
testFilenameSuffix /* locale */, mPrefs);
dict.clearAndFlushDictionary();
dict.close();
}
try { /**
addAndWriteRandomWords(testFilenameSuffix, numberOfWords, random, * Shut down executer and wait until all operations of user history are done.
true /* checksContents */); * @param testFilenameSuffix file name suffix used for testing.
} finally { */
private void waitForWriting(final String testFilenameSuffix) {
try { try {
final UserHistoryDictionary dict = final UserHistoryDictionary dict =
PersonalizationHelper.getUserHistoryDictionary(getContext(), PersonalizationHelper.getUserHistoryDictionary(getContext(),
testFilenameSuffix, mPrefs); testFilenameSuffix, mPrefs);
Log.d(TAG, "waiting for writing ...");
dict.shutdownExecutorForTests(); dict.shutdownExecutorForTests();
while (!dict.isTerminatedForTests()) { while (!dict.isTerminatedForTests()) {
Thread.sleep(WAIT_TERMINATING_IN_MILLISECONDS); Thread.sleep(WAIT_TERMINATING_IN_MILLISECONDS);
} }
} catch (InterruptedException e) { } catch (InterruptedException e) {
Log.d(TAG, "InterruptedException: " + e); Log.d(TAG, "InterruptedException: ", e);
}
} }
public void testRandomWords() {
Log.d(TAG, "This test can be used for profiling.");
Log.d(TAG, "Usage: please set UserHistoryDictionary.PROFILE_SAVE_RESTORE to true.");
final String testFilenameSuffix = "testRandomWords" + System.currentTimeMillis();
final String fileName = UserHistoryDictionary.NAME + "." + testFilenameSuffix final String fileName = UserHistoryDictionary.NAME + "." + testFilenameSuffix
+ ExpandableBinaryDictionary.DICT_FILE_EXTENSION; + ExpandableBinaryDictionary.DICT_FILE_EXTENSION;
dictFile = new File(getContext().getFilesDir(), fileName);
final int numberOfWords = 1000;
final Random random = new Random(123456);
try {
clearHistory(testFilenameSuffix);
addAndWriteRandomWords(testFilenameSuffix, numberOfWords, random,
true /* checksContents */);
} finally {
Log.d(TAG, "waiting for writing ...");
waitForWriting(testFilenameSuffix);
final File dictFile = new File(getContext().getFilesDir(), fileName);
if (dictFile != null) { if (dictFile != null) {
assertTrue(dictFile.exists()); assertTrue(dictFile.exists());
assertTrue(dictFile.length() >= MIN_USER_HISTORY_DICTIONARY_FILE_SIZE); assertTrue(dictFile.length() >= MIN_USER_HISTORY_DICTIONARY_FILE_SIZE);
@ -162,6 +181,7 @@ public class UserHistoryDictionaryTests extends AndroidTestCase {
final String fileName = UserHistoryDictionary.NAME + "." + final String fileName = UserHistoryDictionary.NAME + "." +
testFilenameSuffixes[i] + ExpandableBinaryDictionary.DICT_FILE_EXTENSION; testFilenameSuffixes[i] + ExpandableBinaryDictionary.DICT_FILE_EXTENSION;
dictFiles[i] = new File(getContext().getFilesDir(), fileName); dictFiles[i] = new File(getContext().getFilesDir(), fileName);
clearHistory(testFilenameSuffixes[i]);
} }
final long start = System.currentTimeMillis(); final long start = System.currentTimeMillis();
@ -178,19 +198,9 @@ public class UserHistoryDictionaryTests extends AndroidTestCase {
Log.d(TAG, "testStressTestForSwitchingLanguageAndAddingWords took " Log.d(TAG, "testStressTestForSwitchingLanguageAndAddingWords took "
+ (end - start) + " ms"); + (end - start) + " ms");
} finally { } finally {
try {
Log.d(TAG, "waiting for writing ..."); Log.d(TAG, "waiting for writing ...");
for (int i = 0; i < numberOfLanguages; i++) { for (int i = 0; i < numberOfLanguages; i++) {
final UserHistoryDictionary dict = waitForWriting(testFilenameSuffixes[i]);
PersonalizationHelper.getUserHistoryDictionary(getContext(),
testFilenameSuffixes[i], mPrefs);
dict.shutdownExecutorForTests();
while (!dict.isTerminatedForTests()) {
Thread.sleep(WAIT_TERMINATING_IN_MILLISECONDS);
}
}
} catch (InterruptedException e) {
Log.d(TAG, "InterruptedException: " + e);
} }
for (final File file : dictFiles) { for (final File file : dictFiles) {
if (file != null) { if (file != null) {
@ -203,33 +213,21 @@ public class UserHistoryDictionaryTests extends AndroidTestCase {
} }
public void testAddManyWords() { public void testAddManyWords() {
File dictFile = null;
final String testFilenameSuffix = "testRandomWords" + System.currentTimeMillis(); final String testFilenameSuffix = "testRandomWords" + System.currentTimeMillis();
final int numberOfWords = final int numberOfWords =
ExpandableBinaryDictionary.ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE ? ExpandableBinaryDictionary.ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE ?
10000 : 1000; 10000 : 1000;
final Random random = new Random(123456); final Random random = new Random(123456);
clearHistory(testFilenameSuffix);
UserHistoryDictionary dict =
PersonalizationHelper.getUserHistoryDictionary(getContext(),
testFilenameSuffix, mPrefs);
try { try {
addAndWriteRandomWords(testFilenameSuffix, numberOfWords, random, addAndWriteRandomWords(testFilenameSuffix, numberOfWords, random,
true /* checksContents */); true /* checksContents */);
dict.close();
} finally { } finally {
try {
Log.d(TAG, "waiting for writing ..."); Log.d(TAG, "waiting for writing ...");
dict.shutdownExecutorForTests(); waitForWriting(testFilenameSuffix);
while (!dict.isTerminatedForTests()) {
Thread.sleep(WAIT_TERMINATING_IN_MILLISECONDS);
}
} catch (InterruptedException e) {
Log.d(TAG, "InterruptedException: ", e);
}
final String fileName = UserHistoryDictionary.NAME + "." + testFilenameSuffix final String fileName = UserHistoryDictionary.NAME + "." + testFilenameSuffix
+ ExpandableBinaryDictionary.DICT_FILE_EXTENSION; + ExpandableBinaryDictionary.DICT_FILE_EXTENSION;
dictFile = new File(getContext().getFilesDir(), fileName); final File dictFile = new File(getContext().getFilesDir(), fileName);
if (dictFile != null) { if (dictFile != null) {
assertTrue(dictFile.exists()); assertTrue(dictFile.exists());
assertTrue(dictFile.length() >= MIN_USER_HISTORY_DICTIONARY_FILE_SIZE); assertTrue(dictFile.length() >= MIN_USER_HISTORY_DICTIONARY_FILE_SIZE);