mirror of
https://github.com/moparisthebest/k-9
synced 2024-12-25 00:58:50 -05:00
Optimize setting flags for whole threads
This commit is contained in:
parent
3ec623c174
commit
421558c148
@ -2533,17 +2533,28 @@ public class MessagingController implements Runnable {
|
||||
}
|
||||
|
||||
public void setFlag(final Account account, final List<Long> messageIds, final Flag flag,
|
||||
final boolean newState, final boolean threadedList) {
|
||||
final boolean newState) {
|
||||
|
||||
threadPool.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
setFlagSynchronous(account, messageIds, flag, newState, threadedList);
|
||||
setFlagSynchronous(account, messageIds, flag, newState, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setFlagSynchronous(final Account account, final List<Long> messageIds,
|
||||
public void setFlagForThreads(final Account account, final List<Long> threadRootIds,
|
||||
final Flag flag, final boolean newState) {
|
||||
|
||||
threadPool.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
setFlagSynchronous(account, threadRootIds, flag, newState, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setFlagSynchronous(final Account account, final List<Long> ids,
|
||||
final Flag flag, final boolean newState, final boolean threadedList) {
|
||||
|
||||
LocalStore localStore;
|
||||
@ -2557,7 +2568,11 @@ public class MessagingController implements Runnable {
|
||||
// Update affected messages in the database. This should be as fast as possible so the UI
|
||||
// can be updated with the new state.
|
||||
try {
|
||||
localStore.setFlag(messageIds, flag, newState, threadedList);
|
||||
if (threadedList) {
|
||||
localStore.setFlagForThreads(ids, flag, newState);
|
||||
} else {
|
||||
localStore.setFlag(ids, flag, newState);
|
||||
}
|
||||
} catch (MessagingException e) {
|
||||
Log.e(K9.LOG_TAG, "Couldn't set flags in local database", e);
|
||||
}
|
||||
@ -2565,7 +2580,7 @@ public class MessagingController implements Runnable {
|
||||
// Read folder name and UID of messages from the database
|
||||
Map<String, List<String>> folderMap;
|
||||
try {
|
||||
folderMap = localStore.getFoldersAndUids(messageIds, threadedList);
|
||||
folderMap = localStore.getFoldersAndUids(ids, threadedList);
|
||||
} catch (MessagingException e) {
|
||||
Log.e(K9.LOG_TAG, "Couldn't get folder name and UID of messages", e);
|
||||
return;
|
||||
|
@ -2056,10 +2056,16 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick
|
||||
|
||||
Cursor cursor = (Cursor) mAdapter.getItem(adapterPosition);
|
||||
Account account = mPreferences.getAccount(cursor.getString(ACCOUNT_UUID_COLUMN));
|
||||
long id = cursor.getLong(ID_COLUMN);
|
||||
|
||||
mController.setFlag(account, Collections.singletonList(Long.valueOf(id)), flag, newState,
|
||||
mThreadedList);
|
||||
if (mThreadedList && cursor.getInt(THREAD_COUNT_COLUMN) > 1) {
|
||||
long threadRootId = cursor.getLong(THREAD_ROOT_COLUMN);
|
||||
mController.setFlagForThreads(account,
|
||||
Collections.singletonList(Long.valueOf(threadRootId)), flag, newState);
|
||||
} else {
|
||||
long id = cursor.getLong(ID_COLUMN);
|
||||
mController.setFlag(account, Collections.singletonList(Long.valueOf(id)), flag,
|
||||
newState);
|
||||
}
|
||||
|
||||
computeBatchDirection();
|
||||
}
|
||||
@ -2069,7 +2075,8 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick
|
||||
return;
|
||||
}
|
||||
|
||||
Map<Account, List<Long>> accountMapping = new HashMap<Account, List<Long>>();
|
||||
Map<Account, List<Long>> messageMap = new HashMap<Account, List<Long>>();
|
||||
Map<Account, List<Long>> threadMap = new HashMap<Account, List<Long>>();
|
||||
Set<Account> accounts = new HashSet<Account>();
|
||||
|
||||
for (int position = 0, end = mAdapter.getCount(); position < end; position++) {
|
||||
@ -2079,21 +2086,39 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick
|
||||
if (mSelected.contains(uniqueId)) {
|
||||
String uuid = cursor.getString(ACCOUNT_UUID_COLUMN);
|
||||
Account account = mPreferences.getAccount(uuid);
|
||||
|
||||
accounts.add(account);
|
||||
List<Long> messageIdList = accountMapping.get(account);
|
||||
if (messageIdList == null) {
|
||||
messageIdList = new ArrayList<Long>();
|
||||
accountMapping.put(account, messageIdList);
|
||||
}
|
||||
|
||||
messageIdList.add(cursor.getLong(ID_COLUMN));
|
||||
if (mThreadedList && cursor.getInt(THREAD_COUNT_COLUMN) > 1) {
|
||||
List<Long> threadRootIdList = threadMap.get(account);
|
||||
if (threadRootIdList == null) {
|
||||
threadRootIdList = new ArrayList<Long>();
|
||||
threadMap.put(account, threadRootIdList);
|
||||
}
|
||||
|
||||
threadRootIdList.add(cursor.getLong(THREAD_ROOT_COLUMN));
|
||||
} else {
|
||||
List<Long> messageIdList = messageMap.get(account);
|
||||
if (messageIdList == null) {
|
||||
messageIdList = new ArrayList<Long>();
|
||||
messageMap.put(account, messageIdList);
|
||||
}
|
||||
|
||||
messageIdList.add(cursor.getLong(ID_COLUMN));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Account account : accounts) {
|
||||
List<Long> messageIds = accountMapping.get(account);
|
||||
mController.setFlag(account, messageIds, flag, newState, mThreadedList);
|
||||
List<Long> messageIds = messageMap.get(account);
|
||||
List<Long> threadRootIds = threadMap.get(account);
|
||||
|
||||
if (messageIds != null) {
|
||||
mController.setFlag(account, messageIds, flag, newState);
|
||||
}
|
||||
|
||||
if (threadRootIds != null) {
|
||||
mController.setFlagForThreads(account, threadRootIds, flag, newState);
|
||||
}
|
||||
}
|
||||
|
||||
computeBatchDirection();
|
||||
|
@ -118,6 +118,13 @@ public class LocalStore extends Store implements Serializable {
|
||||
*/
|
||||
private static final int FLAG_UPDATE_BATCH_SIZE = 500;
|
||||
|
||||
/**
|
||||
* Number of threads to perform flag updates on at once.
|
||||
*
|
||||
* @see #setFlagForThreads(List, Flag, boolean)
|
||||
*/
|
||||
private static final int THREAD_FLAG_UPDATE_BATCH_SIZE = 400;
|
||||
|
||||
public static final int DB_VERSION = 47;
|
||||
|
||||
protected String uUid = null;
|
||||
@ -4169,10 +4176,7 @@ public class LocalStore extends Store implements Serializable {
|
||||
*
|
||||
* <p>
|
||||
* The goal of this method is to be fast. Currently this means using as few SQL UPDATE
|
||||
* statements as possible.<br>
|
||||
* Current benchmarks show that updating 1000 messages takes about 8 seconds on a Nexus 7. So
|
||||
* there should be room for further improvement.
|
||||
* </p>
|
||||
* statements as possible.
|
||||
*
|
||||
* @param messageIds
|
||||
* A list of primary keys in the "messages" table.
|
||||
@ -4180,23 +4184,9 @@ public class LocalStore extends Store implements Serializable {
|
||||
* The flag to change. This must be a flag with a separate column in the database.
|
||||
* @param newState
|
||||
* {@code true}, if the flag should be set. {@code false}, otherwise.
|
||||
* @param threadRootIds
|
||||
* If this is {@code true}, {@code messageIds} contains the IDs of the messages at the
|
||||
* root of a thread. In that case the flag is changed for all messages in these threads.
|
||||
* If this is {@code false} only the messages in {@code messageIds} are changed.
|
||||
*
|
||||
* @throws MessagingException
|
||||
*/
|
||||
public void setFlag(List<Long> messageIds, Flag flag, boolean newState, boolean threadRootIds)
|
||||
throws MessagingException {
|
||||
|
||||
if (threadRootIds) {
|
||||
setFlagForThreads(messageIds, flag, newState);
|
||||
} else {
|
||||
setFlag(messageIds, flag, newState);
|
||||
}
|
||||
}
|
||||
|
||||
public void setFlag(final List<Long> messageIds, final Flag flag, final boolean newState)
|
||||
throws MessagingException {
|
||||
|
||||
@ -4251,7 +4241,23 @@ public class LocalStore extends Store implements Serializable {
|
||||
}, FLAG_UPDATE_BATCH_SIZE);
|
||||
}
|
||||
|
||||
public void setFlagForThreads(final List<Long> messageIds, Flag flag, final boolean newState)
|
||||
/**
|
||||
* Change the state of a flag for a list of threads.
|
||||
*
|
||||
* <p>
|
||||
* The goal of this method is to be fast. Currently this means using as few SQL UPDATE
|
||||
* statements as possible.
|
||||
*
|
||||
* @param threadRootIds
|
||||
* A list of root thread IDs.
|
||||
* @param flag
|
||||
* The flag to change. This must be a flag with a separate column in the database.
|
||||
* @param newState
|
||||
* {@code true}, if the flag should be set. {@code false}, otherwise.
|
||||
*
|
||||
* @throws MessagingException
|
||||
*/
|
||||
public void setFlagForThreads(final List<Long> threadRootIds, Flag flag, final boolean newState)
|
||||
throws MessagingException {
|
||||
|
||||
final String flagColumn;
|
||||
@ -4281,35 +4287,37 @@ public class LocalStore extends Store implements Serializable {
|
||||
|
||||
@Override
|
||||
public int getListSize() {
|
||||
return messageIds.size();
|
||||
return threadRootIds.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getListItem(int index) {
|
||||
return Long.toString(messageIds.get(index));
|
||||
return Long.toString(threadRootIds.get(index));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doDbWork(SQLiteDatabase db, String selectionSet, String[] selectionArgs)
|
||||
throws UnavailableStorageException {
|
||||
|
||||
int len = selectionArgs.length;
|
||||
String[] args = new String[len * 2];
|
||||
System.arraycopy(selectionArgs, 0, args, 0, len);
|
||||
System.arraycopy(selectionArgs, 0, args, len, len);
|
||||
|
||||
db.execSQL("UPDATE messages SET " + flagColumn + " = " + ((newState) ? "1" : "0") +
|
||||
" WHERE id IN (" +
|
||||
"SELECT m.id FROM messages h " +
|
||||
"JOIN threads t1 ON (t1.message_id = h.id) " +
|
||||
"JOIN threads t2 ON " +
|
||||
"(t1.root IN (t2.id, t2.root) OR t1.id IN (t2.id, t2.root)) " +
|
||||
"JOIN messages m ON (t2.message_id = m.id) " +
|
||||
"SELECT m.id FROM threads t " +
|
||||
"LEFT JOIN messages m ON (t.message_id = m.id) " +
|
||||
"WHERE (m.empty IS NULL OR m.empty != 1) AND m.deleted = 0 " +
|
||||
"AND h.id" + selectionSet + ")",
|
||||
selectionArgs);
|
||||
"AND (t.id" + selectionSet + " OR t.root" + selectionSet + "))",
|
||||
args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postDbWork() {
|
||||
notifyChange();
|
||||
}
|
||||
}, FLAG_UPDATE_BATCH_SIZE);
|
||||
}, THREAD_FLAG_UPDATE_BATCH_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user