mirror of https://github.com/M66B/FairEmail.git
Experiment: auto tune keep alive interval
This commit is contained in:
parent
32583890f6
commit
d5ea82631e
File diff suppressed because it is too large
Load Diff
|
@ -167,7 +167,11 @@ public class AdapterAccount extends RecyclerView.Adapter<AdapterAccount.ViewHold
|
|||
|
||||
tvHost.setText(String.format("%s:%d", account.host, account.port));
|
||||
tvLast.setText(context.getString(R.string.title_last_connected,
|
||||
account.last_connected == null ? "-" : DTF.format(account.last_connected)));
|
||||
(account.last_connected == null ? "-" : DTF.format(account.last_connected)) +
|
||||
(BuildConfig.DEBUG ?
|
||||
" " + account.poll_interval +
|
||||
"/" + account.keep_alive_ok +
|
||||
"/" + account.keep_alive_failed : "")));
|
||||
|
||||
tvIdentity.setVisibility(account.identities > 0 || !settings ? View.GONE : View.VISIBLE);
|
||||
tvDrafts.setVisibility(account.drafts || !settings ? View.GONE : View.VISIBLE);
|
||||
|
|
|
@ -3201,6 +3201,7 @@ class Core {
|
|||
private Semaphore semaphore = new Semaphore(0);
|
||||
private boolean running = true;
|
||||
private boolean recoverable = true;
|
||||
private Long lastActivity = null;
|
||||
|
||||
State(ConnectionHelper.NetworkState networkState) {
|
||||
this.networkState = networkState;
|
||||
|
@ -3264,6 +3265,7 @@ class Core {
|
|||
|
||||
void reset() {
|
||||
recoverable = true;
|
||||
lastActivity = null;
|
||||
}
|
||||
|
||||
private void yield() {
|
||||
|
@ -3308,10 +3310,20 @@ class Core {
|
|||
}
|
||||
}
|
||||
|
||||
synchronized void activity() {
|
||||
lastActivity = SystemClock.elapsedRealtime();
|
||||
}
|
||||
|
||||
long getIdleTime() {
|
||||
return (lastActivity == null ? 0 : SystemClock.elapsedRealtime() - lastActivity);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[running=" + running + ",recoverable=" + recoverable + "]";
|
||||
return "[running=" + running +
|
||||
",recoverable=" + recoverable +
|
||||
",activity=" + new Date(lastActivity == null ? 0 : lastActivity) + "]";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ import io.requery.android.database.sqlite.RequerySQLiteOpenHelperFactory;
|
|||
// https://developer.android.com/topic/libraries/architecture/room.html
|
||||
|
||||
@Database(
|
||||
version = 126,
|
||||
version = 127,
|
||||
entities = {
|
||||
EntityIdentity.class,
|
||||
EntityAccount.class,
|
||||
|
@ -1224,6 +1224,14 @@ public abstract class DB extends RoomDatabase {
|
|||
db.execSQL("ALTER TABLE `message` ADD COLUMN `autocrypt` TEXT");
|
||||
}
|
||||
})
|
||||
.addMigrations(new Migration(126, 127) {
|
||||
@Override
|
||||
public void migrate(@NonNull SupportSQLiteDatabase db) {
|
||||
Log.i("DB migration from version " + startVersion + " to " + endVersion);
|
||||
db.execSQL("ALTER TABLE `account` ADD COLUMN `keep_alive_ok` INTEGER NOT NULL DEFAULT 0");
|
||||
db.execSQL("ALTER TABLE `account` ADD COLUMN `keep_alive_failed` INTEGER NOT NULL DEFAULT 0");
|
||||
}
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
|
|
|
@ -121,6 +121,15 @@ public interface DaoAccount {
|
|||
@Query("UPDATE account SET last_connected = :last_connected WHERE id = :id")
|
||||
int setAccountConnected(long id, long last_connected);
|
||||
|
||||
@Query("UPDATE account SET poll_interval = :value WHERE id = :id")
|
||||
int setAccountKeepAliveInterval(long id, int value);
|
||||
|
||||
@Query("UPDATE account SET keep_alive_ok = :ok WHERE id = :id")
|
||||
int setAccountKeepAliveOk(long id, boolean ok);
|
||||
|
||||
@Query("UPDATE account SET keep_alive_failed = :value WHERE id = :id")
|
||||
int setAccountKeepAliveFailed(long id, int value);
|
||||
|
||||
@Query("UPDATE account SET `order` = :order WHERE id = :id")
|
||||
int setAccountOrder(long id, Integer order);
|
||||
|
||||
|
|
|
@ -101,7 +101,11 @@ public class EntityAccount extends EntityOrder implements Serializable {
|
|||
public Long swipe_right;
|
||||
public Long move_to;
|
||||
@NonNull
|
||||
public Integer poll_interval = DEFAULT_KEEP_ALIVE_INTERVAL; // keep-alive interval
|
||||
public Integer poll_interval = DEFAULT_KEEP_ALIVE_INTERVAL;
|
||||
@NonNull
|
||||
public Boolean keep_alive_ok = false;
|
||||
@NonNull
|
||||
public Integer keep_alive_failed = 0;
|
||||
@NonNull
|
||||
public Boolean partial_fetch = true;
|
||||
@NonNull
|
||||
|
|
|
@ -1020,6 +1020,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
|
|||
while (ifolder.isOpen() && state.isRunning() && state.isRecoverable()) {
|
||||
Log.i(folder.name + " do idle");
|
||||
ifolder.idle(false);
|
||||
state.activity();
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
Log.e(folder.name, ex);
|
||||
|
@ -1144,23 +1145,51 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
|
|||
|
||||
|
||||
// Keep alive
|
||||
boolean first = true;
|
||||
while (state.isRunning()) {
|
||||
if (!state.isRecoverable())
|
||||
throw new StoreClosedException(iservice.getStore(), "Unrecoverable");
|
||||
try {
|
||||
if (!state.isRecoverable())
|
||||
throw new StoreClosedException(iservice.getStore(), "Unrecoverable");
|
||||
|
||||
// Sends store NOOP
|
||||
if (!iservice.getStore().isConnected())
|
||||
throw new StoreClosedException(iservice.getStore(), "NOOP");
|
||||
// Sends store NOOP
|
||||
if (!iservice.getStore().isConnected())
|
||||
throw new StoreClosedException(iservice.getStore(), "NOOP");
|
||||
|
||||
if (sync)
|
||||
for (EntityFolder folder : mapFolders.keySet())
|
||||
if (folder.synchronize)
|
||||
if (!folder.poll && capIdle) {
|
||||
// Sends folder NOOP
|
||||
if (!mapFolders.get(folder).isOpen())
|
||||
throw new StoreClosedException(iservice.getStore(), folder.name);
|
||||
} else
|
||||
EntityOperation.sync(this, folder.id, false);
|
||||
if (sync)
|
||||
for (EntityFolder folder : mapFolders.keySet())
|
||||
if (folder.synchronize)
|
||||
if (!folder.poll && capIdle) {
|
||||
// Sends folder NOOP
|
||||
if (!mapFolders.get(folder).isOpen())
|
||||
throw new StoreClosedException(iservice.getStore(), folder.name);
|
||||
} else
|
||||
EntityOperation.sync(this, folder.id, false);
|
||||
} catch (Throwable ex) {
|
||||
if (!first && !account.keep_alive_ok &&
|
||||
account.poll_interval > 9 &&
|
||||
state.getIdleTime() > (account.poll_interval - 1) * 60 * 1000L) {
|
||||
account.keep_alive_failed++;
|
||||
if (account.keep_alive_failed > 10) {
|
||||
account.keep_alive_failed = 0;
|
||||
account.poll_interval--;
|
||||
db.account().setAccountKeepAliveInterval(account.id, account.poll_interval);
|
||||
}
|
||||
db.account().setAccountKeepAliveFailed(account.id, account.keep_alive_failed);
|
||||
EntityLog.log(ServiceSynchronize.this, account.name +
|
||||
" keep alive failed=" + account.keep_alive_failed +
|
||||
" keep alive interval=" + account.poll_interval +
|
||||
" max idle=" + state.getIdleTime());
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
|
||||
if (!first && !account.keep_alive_ok &&
|
||||
account.poll_interval > 9 &&
|
||||
state.getIdleTime() > (account.poll_interval - 1) * 60 * 1000L) {
|
||||
account.keep_alive_ok = true;
|
||||
db.account().setAccountKeepAliveOk(account.id, true);
|
||||
EntityLog.log(ServiceSynchronize.this, account.name + " keep alive ok");
|
||||
}
|
||||
|
||||
// Successfully connected: reset back off time
|
||||
state.setBackoff(CONNECT_BACKOFF_START);
|
||||
|
@ -1201,6 +1230,8 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
|
|||
} finally {
|
||||
am.cancel(pi);
|
||||
}
|
||||
|
||||
first = false;
|
||||
}
|
||||
|
||||
Log.i(account.name + " done state=" + state);
|
||||
|
|
Loading…
Reference in New Issue