mirror of
https://github.com/moparisthebest/k-9
synced 2024-11-27 19:52:17 -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,
|
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() {
|
threadPool.execute(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
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) {
|
final Flag flag, final boolean newState, final boolean threadedList) {
|
||||||
|
|
||||||
LocalStore localStore;
|
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
|
// Update affected messages in the database. This should be as fast as possible so the UI
|
||||||
// can be updated with the new state.
|
// can be updated with the new state.
|
||||||
try {
|
try {
|
||||||
localStore.setFlag(messageIds, flag, newState, threadedList);
|
if (threadedList) {
|
||||||
|
localStore.setFlagForThreads(ids, flag, newState);
|
||||||
|
} else {
|
||||||
|
localStore.setFlag(ids, flag, newState);
|
||||||
|
}
|
||||||
} catch (MessagingException e) {
|
} catch (MessagingException e) {
|
||||||
Log.e(K9.LOG_TAG, "Couldn't set flags in local database", 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
|
// Read folder name and UID of messages from the database
|
||||||
Map<String, List<String>> folderMap;
|
Map<String, List<String>> folderMap;
|
||||||
try {
|
try {
|
||||||
folderMap = localStore.getFoldersAndUids(messageIds, threadedList);
|
folderMap = localStore.getFoldersAndUids(ids, threadedList);
|
||||||
} catch (MessagingException e) {
|
} catch (MessagingException e) {
|
||||||
Log.e(K9.LOG_TAG, "Couldn't get folder name and UID of messages", e);
|
Log.e(K9.LOG_TAG, "Couldn't get folder name and UID of messages", e);
|
||||||
return;
|
return;
|
||||||
|
@ -2056,10 +2056,16 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick
|
|||||||
|
|
||||||
Cursor cursor = (Cursor) mAdapter.getItem(adapterPosition);
|
Cursor cursor = (Cursor) mAdapter.getItem(adapterPosition);
|
||||||
Account account = mPreferences.getAccount(cursor.getString(ACCOUNT_UUID_COLUMN));
|
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,
|
if (mThreadedList && cursor.getInt(THREAD_COUNT_COLUMN) > 1) {
|
||||||
mThreadedList);
|
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();
|
computeBatchDirection();
|
||||||
}
|
}
|
||||||
@ -2069,7 +2075,8 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick
|
|||||||
return;
|
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>();
|
Set<Account> accounts = new HashSet<Account>();
|
||||||
|
|
||||||
for (int position = 0, end = mAdapter.getCount(); position < end; position++) {
|
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)) {
|
if (mSelected.contains(uniqueId)) {
|
||||||
String uuid = cursor.getString(ACCOUNT_UUID_COLUMN);
|
String uuid = cursor.getString(ACCOUNT_UUID_COLUMN);
|
||||||
Account account = mPreferences.getAccount(uuid);
|
Account account = mPreferences.getAccount(uuid);
|
||||||
|
|
||||||
accounts.add(account);
|
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) {
|
for (Account account : accounts) {
|
||||||
List<Long> messageIds = accountMapping.get(account);
|
List<Long> messageIds = messageMap.get(account);
|
||||||
mController.setFlag(account, messageIds, flag, newState, mThreadedList);
|
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();
|
computeBatchDirection();
|
||||||
|
@ -118,6 +118,13 @@ public class LocalStore extends Store implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private static final int FLAG_UPDATE_BATCH_SIZE = 500;
|
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;
|
public static final int DB_VERSION = 47;
|
||||||
|
|
||||||
protected String uUid = null;
|
protected String uUid = null;
|
||||||
@ -4169,10 +4176,7 @@ public class LocalStore extends Store implements Serializable {
|
|||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* The goal of this method is to be fast. Currently this means using as few SQL UPDATE
|
* The goal of this method is to be fast. Currently this means using as few SQL UPDATE
|
||||||
* statements as possible.<br>
|
* statements as possible.
|
||||||
* Current benchmarks show that updating 1000 messages takes about 8 seconds on a Nexus 7. So
|
|
||||||
* there should be room for further improvement.
|
|
||||||
* </p>
|
|
||||||
*
|
*
|
||||||
* @param messageIds
|
* @param messageIds
|
||||||
* A list of primary keys in the "messages" table.
|
* 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.
|
* The flag to change. This must be a flag with a separate column in the database.
|
||||||
* @param newState
|
* @param newState
|
||||||
* {@code true}, if the flag should be set. {@code false}, otherwise.
|
* {@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
|
* @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)
|
public void setFlag(final List<Long> messageIds, final Flag flag, final boolean newState)
|
||||||
throws MessagingException {
|
throws MessagingException {
|
||||||
|
|
||||||
@ -4251,7 +4241,23 @@ public class LocalStore extends Store implements Serializable {
|
|||||||
}, FLAG_UPDATE_BATCH_SIZE);
|
}, 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 {
|
throws MessagingException {
|
||||||
|
|
||||||
final String flagColumn;
|
final String flagColumn;
|
||||||
@ -4281,35 +4287,37 @@ public class LocalStore extends Store implements Serializable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getListSize() {
|
public int getListSize() {
|
||||||
return messageIds.size();
|
return threadRootIds.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getListItem(int index) {
|
public String getListItem(int index) {
|
||||||
return Long.toString(messageIds.get(index));
|
return Long.toString(threadRootIds.get(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doDbWork(SQLiteDatabase db, String selectionSet, String[] selectionArgs)
|
public void doDbWork(SQLiteDatabase db, String selectionSet, String[] selectionArgs)
|
||||||
throws UnavailableStorageException {
|
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") +
|
db.execSQL("UPDATE messages SET " + flagColumn + " = " + ((newState) ? "1" : "0") +
|
||||||
" WHERE id IN (" +
|
" WHERE id IN (" +
|
||||||
"SELECT m.id FROM messages h " +
|
"SELECT m.id FROM threads t " +
|
||||||
"JOIN threads t1 ON (t1.message_id = h.id) " +
|
"LEFT JOIN messages m ON (t.message_id = m.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) " +
|
|
||||||
"WHERE (m.empty IS NULL OR m.empty != 1) AND m.deleted = 0 " +
|
"WHERE (m.empty IS NULL OR m.empty != 1) AND m.deleted = 0 " +
|
||||||
"AND h.id" + selectionSet + ")",
|
"AND (t.id" + selectionSet + " OR t.root" + selectionSet + "))",
|
||||||
selectionArgs);
|
args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void postDbWork() {
|
public void postDbWork() {
|
||||||
notifyChange();
|
notifyChange();
|
||||||
}
|
}
|
||||||
}, FLAG_UPDATE_BATCH_SIZE);
|
}, THREAD_FLAG_UPDATE_BATCH_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user