BatchingNamedTaskExecutor.java revision a48af083ff81555261f334a1e050eae3b02a746c
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of 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,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.quicksearchbox.util;
18
19
20import android.util.Log;
21
22import java.util.ArrayList;
23import java.util.List;
24
25/**
26 * Executes NamedTasks in batches of a predefined size.  Tasks in excess of
27 * the batch size are queued until the caller indicates that more results
28 * are required.
29 */
30public class BatchingNamedTaskExecutor implements NamedTaskExecutor {
31
32    private static final boolean DBG = true;
33    private static final String TAG = "QSB.BatchingNamedTaskExecutor";
34
35    private final NamedTaskExecutor mExecutor;
36
37    private final int mBatchSize;
38
39    /** Queue of tasks waiting to be dispatched to mExecutor **/
40    private final ArrayList<NamedTask> mQueuedTasks = new ArrayList<NamedTask>();
41
42    /** Count of tasks already dispatched to mExecutor in this batch **/
43    private int mDispatchedCount;
44
45    /**
46     * Creates a new BatchingSourceTaskExecutor.
47     *
48     * @param executor A SourceTaskExecutor for actually executing the tasks.
49     * @param batchSize The number of tasks to submit in each batch.
50     */
51    public BatchingNamedTaskExecutor(NamedTaskExecutor executor, int batchSize) {
52        mExecutor = executor;
53        mBatchSize = batchSize;
54    }
55
56    public void execute(NamedTask task) {
57        synchronized (mQueuedTasks) {
58            if (mDispatchedCount == mBatchSize) {
59                if (DBG) Log.d(TAG, "Queueing " + task);
60                mQueuedTasks.add(task);
61                return;
62            }
63            mDispatchedCount++;
64        }
65        // Avoid holding the lock when dispatching the task.
66        dispatch(task);
67    }
68
69    private void dispatch(NamedTask task) {
70        if (DBG) Log.d(TAG, "Dispatching " + task);
71        mExecutor.execute(task);
72    }
73
74    /**
75     * Instructs the executor to submit the next batch of results.
76     */
77    public void executeNextBatch() {
78        NamedTask[] batch = new NamedTask[0];
79        synchronized (mQueuedTasks) {
80            int count = Math.min(mQueuedTasks.size(), mBatchSize);
81            List<NamedTask> nextTasks = mQueuedTasks.subList(0, count);
82            batch = nextTasks.toArray(batch);
83            nextTasks.clear();
84            mDispatchedCount = count;
85            if (DBG) Log.d(TAG, "Dispatching batch of " + count);
86        }
87
88        for (NamedTask task : batch) {
89            dispatch(task);
90        }
91    }
92
93    /**
94     * Cancel any unstarted tasks running in this executor.  This instance
95     * should not be re-used after calling this method.
96     */
97    public void cancelPendingTasks() {
98        synchronized (mQueuedTasks) {
99            mQueuedTasks.clear();
100            mDispatchedCount = 0;
101        }
102        mExecutor.cancelPendingTasks();
103    }
104
105    public void close() {
106        cancelPendingTasks();
107        mExecutor.close();
108    }
109}
110