DictionaryPool.java revision e30c05800fa463ef622132b0df466f5455281fc1
1/* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 17package com.android.inputmethod.latin.spellcheck; 18 19import android.util.Log; 20 21import java.util.Locale; 22import java.util.concurrent.LinkedBlockingQueue; 23import java.util.concurrent.TimeUnit; 24 25/** 26 * A blocking queue that creates dictionaries up to a certain limit as necessary. 27 * As a deadlock-detecting device, if waiting for more than TIMEOUT = 3 seconds, we 28 * will clear the queue and generate its contents again. This is transparent for 29 * the client code, but may help with sloppy clients. 30 */ 31@SuppressWarnings("serial") 32public class DictionaryPool extends LinkedBlockingQueue<DictAndProximity> { 33 private final static String TAG = DictionaryPool.class.getSimpleName(); 34 // How many seconds we wait for a dictionary to become available. Past this delay, we give up in 35 // fear some bug caused a deadlock, and reset the whole pool. 36 private final static int TIMEOUT = 3; 37 private final AndroidSpellCheckerService mService; 38 private final int mMaxSize; 39 private final Locale mLocale; 40 private int mSize; 41 private volatile boolean mClosed; 42 43 public DictionaryPool(final int maxSize, final AndroidSpellCheckerService service, 44 final Locale locale) { 45 super(); 46 mMaxSize = maxSize; 47 mService = service; 48 mLocale = locale; 49 mSize = 0; 50 mClosed = false; 51 } 52 53 @Override 54 public DictAndProximity poll(final long timeout, final TimeUnit unit) 55 throws InterruptedException { 56 final DictAndProximity dict = poll(); 57 if (null != dict) return dict; 58 synchronized(this) { 59 if (mSize >= mMaxSize) { 60 // Our pool is already full. Wait until some dictionary is ready, or TIMEOUT 61 // expires to avoid a deadlock. 62 final DictAndProximity result = super.poll(timeout, unit); 63 if (null == result) { 64 Log.e(TAG, "Deadlock detected ! Resetting dictionary pool"); 65 clear(); 66 mSize = 1; 67 return mService.createDictAndProximity(mLocale); 68 } else { 69 return result; 70 } 71 } else { 72 ++mSize; 73 return mService.createDictAndProximity(mLocale); 74 } 75 } 76 } 77 78 // Convenience method 79 public DictAndProximity pollWithDefaultTimeout() { 80 try { 81 return poll(TIMEOUT, TimeUnit.SECONDS); 82 } catch (InterruptedException e) { 83 return null; 84 } 85 } 86 87 public void close() { 88 synchronized(this) { 89 mClosed = true; 90 for (DictAndProximity dict : this) { 91 dict.mDictionary.close(); 92 } 93 clear(); 94 } 95 } 96 97 @Override 98 public boolean offer(final DictAndProximity dict) { 99 if (mClosed) { 100 dict.mDictionary.close(); 101 return false; 102 } else { 103 return super.offer(dict); 104 } 105 } 106} 107