Simplify store keep alive

pull/145/head
M66B 6 years ago
parent 0bf88fcf9e
commit ee4339a971

@ -337,10 +337,61 @@ public class FragmentFolder extends FragmentEx {
pbWait.setVisibility(View.GONE); pbWait.setVisibility(View.GONE);
Helper.setViewsEnabled(view, true); Helper.setViewsEnabled(view, true);
etRename.setEnabled(folder == null || EntityFolder.USER.equals(folder.type)); etRename.setEnabled(folder == null || EntityFolder.USER.equals(folder.type));
grpInterval.setVisibility(folder == null || EntityFolder.USER.equals(folder.type) ? View.VISIBLE : View.GONE);
btnSave.setEnabled(true); btnSave.setEnabled(true);
ibDelete.setVisibility(folder == null || !EntityFolder.USER.equals(folder.type) ? View.GONE : View.VISIBLE); ibDelete.setVisibility(folder == null || !EntityFolder.USER.equals(folder.type) ? View.GONE : View.VISIBLE);
} }
}); });
Bundle args = new Bundle();
args.putLong("id", id);
args.putLong("account", account);
new SimpleTask<Boolean>() {
@Override
protected Boolean onLoad(Context context, Bundle args) throws Throwable {
long fid = args.getLong("id");
long aid = args.getLong("account");
IMAPStore istore = null;
DB db = DB.getInstance(getContext());
try {
db.beginTransaction();
EntityAccount account;
if (fid < 0)
account = db.account().getAccount(aid);
else {
EntityFolder folder = db.folder().getFolder(fid);
account = db.account().getAccount(folder.account);
}
db.setTransactionSuccessful();
Properties props = MessageHelper.getSessionProperties(account.auth_type);
Session isession = Session.getInstance(props, null);
istore = (IMAPStore) isession.getStore("imaps");
istore.connect(account.host, account.port, account.user, account.password);
return istore.hasCapability("IDLE");
} finally {
db.endTransaction();
if (istore != null)
istore.close();
}
}
@Override
protected void onLoaded(Bundle args, Boolean capIdle) {
grpInterval.setVisibility(capIdle ? View.GONE : View.VISIBLE);
}
@Override
protected void onException(Bundle args, Throwable ex) {
grpInterval.setVisibility(View.VISIBLE);
if (BuildConfig.DEBUG)
Helper.unexpectedError(getContext(), ex);
}
}.load(this, args);
} }
} }

@ -50,12 +50,10 @@ import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import com.sun.mail.iap.ConnectionException; import com.sun.mail.iap.ConnectionException;
import com.sun.mail.iap.ProtocolException;
import com.sun.mail.imap.AppendUID; import com.sun.mail.imap.AppendUID;
import com.sun.mail.imap.IMAPFolder; import com.sun.mail.imap.IMAPFolder;
import com.sun.mail.imap.IMAPMessage; import com.sun.mail.imap.IMAPMessage;
import com.sun.mail.imap.IMAPStore; import com.sun.mail.imap.IMAPStore;
import com.sun.mail.imap.protocol.IMAPProtocol;
import com.sun.mail.util.FolderClosedIOException; import com.sun.mail.util.FolderClosedIOException;
import com.sun.mail.util.MailConnectException; import com.sun.mail.util.MailConnectException;
@ -129,7 +127,6 @@ public class ServiceSynchronize extends LifecycleService {
private static final int CONNECT_BACKOFF_START = 8; // seconds private static final int CONNECT_BACKOFF_START = 8; // seconds
private static final int CONNECT_BACKOFF_MAX = 1024; // seconds (1024 sec ~ 17 min) private static final int CONNECT_BACKOFF_MAX = 1024; // seconds (1024 sec ~ 17 min)
private static final long STORE_NOOP_INTERVAL = 9 * 60 * 1000L; // milliseconds
private static final int SYNC_BATCH_SIZE = 20; private static final int SYNC_BATCH_SIZE = 20;
private static final int DOWNLOAD_BATCH_SIZE = 20; private static final int DOWNLOAD_BATCH_SIZE = 20;
private static final int MESSAGE_AUTO_DOWNLOAD_SIZE = 32 * 1024; // bytes private static final int MESSAGE_AUTO_DOWNLOAD_SIZE = 32 * 1024; // bytes
@ -559,6 +556,7 @@ public class ServiceSynchronize extends LifecycleService {
// Debug // Debug
boolean debug = PreferenceManager.getDefaultSharedPreferences(this).getBoolean("debug", false); boolean debug = PreferenceManager.getDefaultSharedPreferences(this).getBoolean("debug", false);
debug = debug || BuildConfig.DEBUG;
System.setProperty("mail.socket.debug", Boolean.toString(debug)); System.setProperty("mail.socket.debug", Boolean.toString(debug));
// Create session // Create session
@ -569,7 +567,7 @@ public class ServiceSynchronize extends LifecycleService {
final IMAPStore istore = (IMAPStore) isession.getStore("imaps"); final IMAPStore istore = (IMAPStore) isession.getStore("imaps");
final Map<EntityFolder, IMAPFolder> folders = new HashMap<>(); final Map<EntityFolder, IMAPFolder> folders = new HashMap<>();
List<Thread> noops = new ArrayList<>(); List<Thread> pollers = new ArrayList<>();
List<Thread> idlers = new ArrayList<>(); List<Thread> idlers = new ArrayList<>();
try { try {
// Listen for store events // Listen for store events
@ -672,7 +670,7 @@ public class ServiceSynchronize extends LifecycleService {
db.folder().setFolderError(folder.id, null); db.folder().setFolderError(folder.id, null);
// Keep folder connection alive // Keep folder connection alive
Thread noop = new Thread(new Runnable() { Thread poller = new Thread(new Runnable() {
@Override @Override
public void run() { public void run() {
try { try {
@ -811,30 +809,15 @@ public class ServiceSynchronize extends LifecycleService {
} }
}); });
Log.i(Helper.TAG, folder.name + " start noop"); if (!capIdle) {
while (state.running && ifolder.isOpen()) { Log.i(Helper.TAG, folder.name + " start polling");
try { while (state.running) {
if (!EntityFolder.USER.equals(folder.type) && capIdle) { try {
Thread.sleep(account.poll_interval * 60 * 1000L); Thread.sleep((folder.poll_interval == null ? 9 : folder.poll_interval) * 60 * 1000L);
Log.i(Helper.TAG, folder.name + " request NOOP");
ifolder.doCommand(new IMAPFolder.ProtocolCommand() {
public Object doCommand(IMAPProtocol p) throws ProtocolException {
Log.i(Helper.TAG, ifolder.getName() + " start NOOP");
p.simpleCommand("NOOP", null);
Log.i(Helper.TAG, ifolder.getName() + " end NOOP");
return null;
}
});
} else {
if (folder.poll_interval == null)
Thread.sleep(account.poll_interval * 60 * 1000L);
else
Thread.sleep(folder.poll_interval * 60 * 1000L);
synchronizeMessages(account, folder, ifolder, state); synchronizeMessages(account, folder, ifolder, state);
} catch (InterruptedException ex) {
Log.w(Helper.TAG, folder.name + " poll " + ex.toString());
} }
} catch (InterruptedException ex) {
Log.w(Helper.TAG, folder.name + " noop " + ex.toString());
} }
} }
} catch (Throwable ex) { } catch (Throwable ex) {
@ -847,16 +830,17 @@ public class ServiceSynchronize extends LifecycleService {
state.notifyAll(); state.notifyAll();
} }
} finally { } finally {
Log.i(Helper.TAG, folder.name + " end noop"); if (!capIdle)
Log.i(Helper.TAG, folder.name + " end polling");
} }
} }
}, "sync.noop." + folder.id); }, "sync.poller." + folder.id);
noop.start(); poller.start();
noops.add(noop); pollers.add(poller);
// Receive folder events // Receive folder events
if (!EntityFolder.USER.equals(folder.type) && capIdle) { if (capIdle) {
Thread idle = new Thread(new Runnable() { Thread idler = new Thread(new Runnable() {
@Override @Override
public void run() { public void run() {
try { try {
@ -880,8 +864,8 @@ public class ServiceSynchronize extends LifecycleService {
} }
} }
}, "sync.idle." + folder.id); }, "sync.idle." + folder.id);
idle.start(); idler.start();
idlers.add(idle); idlers.add(idler);
} }
} }
@ -969,22 +953,18 @@ public class ServiceSynchronize extends LifecycleService {
try { try {
// Keep store alive // Keep store alive
while (state.running && istore.isConnected()) { while (state.running) {
Log.i(Helper.TAG, "Checking folders");
for (EntityFolder folder : folders.keySet())
if (!folders.get(folder).isOpen())
throw new FolderClosedException(folders.get(folder));
// Wait for stop or folder error
Log.i(Helper.TAG, account.name + " wait"); Log.i(Helper.TAG, account.name + " wait");
synchronized (state) { synchronized (state) {
try { try {
state.wait(STORE_NOOP_INTERVAL); state.wait(account.poll_interval * 60 * 1000L);
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
Log.w(Helper.TAG, account.name + " wait " + ex.toString()); Log.w(Helper.TAG, account.name + " wait " + ex.toString());
} }
} }
Log.i(Helper.TAG, account.name + " waited");
if (!istore.isConnected())
throw new StoreClosedException(istore);
} }
Log.i(Helper.TAG, account.name + " done running=" + state.running); Log.i(Helper.TAG, account.name + " done running=" + state.running);
} finally { } finally {
@ -996,11 +976,18 @@ public class ServiceSynchronize extends LifecycleService {
db.account().setAccountError(account.id, Helper.formatThrowable(ex)); db.account().setAccountError(account.id, Helper.formatThrowable(ex));
} finally { } finally {
// Close store
EntityLog.log(this, account.name + " closing"); EntityLog.log(this, account.name + " closing");
db.account().setAccountState(account.id, "closing"); db.account().setAccountState(account.id, "closing");
for (EntityFolder folder : folders.keySet()) for (EntityFolder folder : folders.keySet())
db.folder().setFolderState(folder.id, "closing"); db.folder().setFolderState(folder.id, "closing");
// Stop pollers
for (Thread poller : pollers) {
poller.interrupt();
join(poller);
}
// Close store
try { try {
Thread t = new Thread(new Runnable() { Thread t = new Thread(new Runnable() {
@Override @Override
@ -1030,16 +1017,10 @@ public class ServiceSynchronize extends LifecycleService {
db.folder().setFolderState(folder.id, null); db.folder().setFolderState(folder.id, null);
} }
// Stop noop // Stop idlers
for (Thread noop : noops) { for (Thread idler : idlers) {
noop.interrupt(); idler.interrupt();
join(noop); join(idler);
}
// Stop idle
for (Thread idle : idlers) {
idle.interrupt();
join(idle);
} }
} }
@ -1541,10 +1522,12 @@ public class ServiceSynchronize extends LifecycleService {
if (message == null) if (message == null)
full.add(imessage); full.add(imessage);
} }
long headers = SystemClock.elapsedRealtime(); if (full.size() > 0) {
ifolder.fetch(full.toArray(new Message[0]), fp); long headers = SystemClock.elapsedRealtime();
Log.i(Helper.TAG, folder.name + " fetched headers=" + full.size() + ifolder.fetch(full.toArray(new Message[0]), fp);
" " + (SystemClock.elapsedRealtime() - headers) + " ms"); Log.i(Helper.TAG, folder.name + " fetched headers=" + full.size() +
" " + (SystemClock.elapsedRealtime() - headers) + " ms");
}
for (int j = isub.length - 1; j >= 0; j--) for (int j = isub.length - 1; j >= 0; j--)
try { try {

Loading…
Cancel
Save