Experiment: auto tune keep alive interval

This commit is contained in:
M66B 2019-12-28 20:35:41 +01:00
parent 32583890f6
commit d5ea82631e
7 changed files with 2128 additions and 18 deletions

File diff suppressed because it is too large Load Diff

View File

@ -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);

View File

@ -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) + "]";
}
}
}

View File

@ -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();
}

View File

@ -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);

View File

@ -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

View File

@ -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);