mirror of
https://github.com/oxen-io/session-android.git
synced 2025-12-30 23:36:32 +00:00
Add support for memory-only jobs.
This commit is contained in:
@@ -5,6 +5,8 @@ import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.annimon.stream.Stream;
|
||||
|
||||
import net.sqlcipher.database.SQLiteDatabase;
|
||||
|
||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
|
||||
@@ -89,6 +91,10 @@ public class JobDatabase extends Database {
|
||||
}
|
||||
|
||||
public synchronized void insertJobs(@NonNull List<FullSpec> fullSpecs) {
|
||||
if (Stream.of(fullSpecs).map(FullSpec::getJobSpec).allMatch(JobSpec::isMemoryOnly)) {
|
||||
return;
|
||||
}
|
||||
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
|
||||
db.beginTransaction();
|
||||
@@ -149,32 +155,38 @@ public class JobDatabase extends Database {
|
||||
}
|
||||
|
||||
public synchronized void updateJobs(@NonNull List<JobSpec> jobs) {
|
||||
if (Stream.of(jobs).allMatch(JobSpec::isMemoryOnly)) {
|
||||
return;
|
||||
}
|
||||
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
|
||||
db.beginTransaction();
|
||||
|
||||
try {
|
||||
for (JobSpec job : jobs) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(Jobs.JOB_SPEC_ID, job.getId());
|
||||
values.put(Jobs.FACTORY_KEY, job.getFactoryKey());
|
||||
values.put(Jobs.QUEUE_KEY, job.getQueueKey());
|
||||
values.put(Jobs.CREATE_TIME, job.getCreateTime());
|
||||
values.put(Jobs.NEXT_RUN_ATTEMPT_TIME, job.getNextRunAttemptTime());
|
||||
values.put(Jobs.RUN_ATTEMPT, job.getRunAttempt());
|
||||
values.put(Jobs.MAX_ATTEMPTS, job.getMaxAttempts());
|
||||
values.put(Jobs.MAX_BACKOFF, job.getMaxBackoff());
|
||||
values.put(Jobs.MAX_INSTANCES, job.getMaxInstances());
|
||||
values.put(Jobs.LIFESPAN, job.getLifespan());
|
||||
values.put(Jobs.SERIALIZED_DATA, job.getSerializedData());
|
||||
values.put(Jobs.SERIALIZED_INPUT_DATA, job.getSerializedInputData());
|
||||
values.put(Jobs.IS_RUNNING, job.isRunning() ? 1 : 0);
|
||||
Stream.of(jobs)
|
||||
.filterNot(JobSpec::isMemoryOnly)
|
||||
.forEach(job -> {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(Jobs.JOB_SPEC_ID, job.getId());
|
||||
values.put(Jobs.FACTORY_KEY, job.getFactoryKey());
|
||||
values.put(Jobs.QUEUE_KEY, job.getQueueKey());
|
||||
values.put(Jobs.CREATE_TIME, job.getCreateTime());
|
||||
values.put(Jobs.NEXT_RUN_ATTEMPT_TIME, job.getNextRunAttemptTime());
|
||||
values.put(Jobs.RUN_ATTEMPT, job.getRunAttempt());
|
||||
values.put(Jobs.MAX_ATTEMPTS, job.getMaxAttempts());
|
||||
values.put(Jobs.MAX_BACKOFF, job.getMaxBackoff());
|
||||
values.put(Jobs.MAX_INSTANCES, job.getMaxInstances());
|
||||
values.put(Jobs.LIFESPAN, job.getLifespan());
|
||||
values.put(Jobs.SERIALIZED_DATA, job.getSerializedData());
|
||||
values.put(Jobs.SERIALIZED_INPUT_DATA, job.getSerializedInputData());
|
||||
values.put(Jobs.IS_RUNNING, job.isRunning() ? 1 : 0);
|
||||
|
||||
String query = Jobs.JOB_SPEC_ID + " = ?";
|
||||
String[] args = new String[]{ job.getId() };
|
||||
String query = Jobs.JOB_SPEC_ID + " = ?";
|
||||
String[] args = new String[]{ job.getId() };
|
||||
|
||||
db.update(Jobs.TABLE_NAME, values, query, args);
|
||||
}
|
||||
db.update(Jobs.TABLE_NAME, values, query, args);
|
||||
});
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
@@ -228,6 +240,10 @@ public class JobDatabase extends Database {
|
||||
}
|
||||
|
||||
private void insertJobSpec(@NonNull SQLiteDatabase db, @NonNull JobSpec job) {
|
||||
if (job.isMemoryOnly()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(Jobs.JOB_SPEC_ID, job.getId());
|
||||
contentValues.put(Jobs.FACTORY_KEY, job.getFactoryKey());
|
||||
@@ -247,21 +263,25 @@ public class JobDatabase extends Database {
|
||||
}
|
||||
|
||||
private void insertConstraintSpecs(@NonNull SQLiteDatabase db, @NonNull List<ConstraintSpec> constraints) {
|
||||
for (ConstraintSpec constraintSpec : constraints) {
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(Constraints.JOB_SPEC_ID, constraintSpec.getJobSpecId());
|
||||
contentValues.put(Constraints.FACTORY_KEY, constraintSpec.getFactoryKey());
|
||||
db.insertWithOnConflict(Constraints.TABLE_NAME, null ,contentValues, SQLiteDatabase.CONFLICT_IGNORE);
|
||||
}
|
||||
Stream.of(constraints)
|
||||
.filterNot(ConstraintSpec::isMemoryOnly)
|
||||
.forEach(constraintSpec -> {
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(Constraints.JOB_SPEC_ID, constraintSpec.getJobSpecId());
|
||||
contentValues.put(Constraints.FACTORY_KEY, constraintSpec.getFactoryKey());
|
||||
db.insertWithOnConflict(Constraints.TABLE_NAME, null ,contentValues, SQLiteDatabase.CONFLICT_IGNORE);
|
||||
});
|
||||
}
|
||||
|
||||
private void insertDependencySpecs(@NonNull SQLiteDatabase db, @NonNull List<DependencySpec> dependencies) {
|
||||
for (DependencySpec dependencySpec : dependencies) {
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(Dependencies.JOB_SPEC_ID, dependencySpec.getJobId());
|
||||
contentValues.put(Dependencies.DEPENDS_ON_JOB_SPEC_ID, dependencySpec.getDependsOnJobId());
|
||||
db.insertWithOnConflict(Dependencies.TABLE_NAME, null, contentValues, SQLiteDatabase.CONFLICT_IGNORE);
|
||||
}
|
||||
Stream.of(dependencies)
|
||||
.filterNot(DependencySpec::isMemoryOnly)
|
||||
.forEach(dependencySpec -> {
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(Dependencies.JOB_SPEC_ID, dependencySpec.getJobId());
|
||||
contentValues.put(Dependencies.DEPENDS_ON_JOB_SPEC_ID, dependencySpec.getDependsOnJobId());
|
||||
db.insertWithOnConflict(Dependencies.TABLE_NAME, null, contentValues, SQLiteDatabase.CONFLICT_IGNORE);
|
||||
});
|
||||
}
|
||||
|
||||
private @NonNull JobSpec jobSpecFromCursor(@NonNull Cursor cursor) {
|
||||
@@ -277,16 +297,19 @@ public class JobDatabase extends Database {
|
||||
cursor.getInt(cursor.getColumnIndexOrThrow(Jobs.MAX_INSTANCES)),
|
||||
cursor.getString(cursor.getColumnIndexOrThrow(Jobs.SERIALIZED_DATA)),
|
||||
cursor.getString(cursor.getColumnIndexOrThrow(Jobs.SERIALIZED_INPUT_DATA)),
|
||||
cursor.getInt(cursor.getColumnIndexOrThrow(Jobs.IS_RUNNING)) == 1);
|
||||
cursor.getInt(cursor.getColumnIndexOrThrow(Jobs.IS_RUNNING)) == 1,
|
||||
false);
|
||||
}
|
||||
|
||||
private @NonNull ConstraintSpec constraintSpecFromCursor(@NonNull Cursor cursor) {
|
||||
return new ConstraintSpec(cursor.getString(cursor.getColumnIndexOrThrow(Constraints.JOB_SPEC_ID)),
|
||||
cursor.getString(cursor.getColumnIndexOrThrow(Constraints.FACTORY_KEY)));
|
||||
cursor.getString(cursor.getColumnIndexOrThrow(Constraints.FACTORY_KEY)),
|
||||
false);
|
||||
}
|
||||
|
||||
private @NonNull DependencySpec dependencySpecFromCursor(@NonNull Cursor cursor) {
|
||||
return new DependencySpec(cursor.getString(cursor.getColumnIndexOrThrow(Dependencies.JOB_SPEC_ID)),
|
||||
cursor.getString(cursor.getColumnIndexOrThrow(Dependencies.DEPENDS_ON_JOB_SPEC_ID)));
|
||||
cursor.getString(cursor.getColumnIndexOrThrow(Dependencies.DEPENDS_ON_JOB_SPEC_ID)),
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,6 +245,7 @@ public abstract class Job {
|
||||
private final String queue;
|
||||
private final List<String> constraintKeys;
|
||||
private final Data inputData;
|
||||
private final boolean memoryOnly;
|
||||
|
||||
private Parameters(@NonNull String id,
|
||||
long createTime,
|
||||
@@ -254,7 +255,8 @@ public abstract class Job {
|
||||
int maxInstances,
|
||||
@Nullable String queue,
|
||||
@NonNull List<String> constraintKeys,
|
||||
@Nullable Data inputData)
|
||||
@Nullable Data inputData,
|
||||
boolean memoryOnly)
|
||||
{
|
||||
this.id = id;
|
||||
this.createTime = createTime;
|
||||
@@ -265,6 +267,7 @@ public abstract class Job {
|
||||
this.queue = queue;
|
||||
this.constraintKeys = constraintKeys;
|
||||
this.inputData = inputData;
|
||||
this.memoryOnly = memoryOnly;
|
||||
}
|
||||
|
||||
@NonNull String getId() {
|
||||
@@ -303,8 +306,12 @@ public abstract class Job {
|
||||
return inputData;
|
||||
}
|
||||
|
||||
boolean isMemoryOnly() {
|
||||
return memoryOnly;
|
||||
}
|
||||
|
||||
public Builder toBuilder() {
|
||||
return new Builder(id, createTime, maxBackoff, lifespan, maxAttempts, maxInstances, queue, constraintKeys, inputData);
|
||||
return new Builder(id, createTime, maxBackoff, lifespan, maxAttempts, maxInstances, queue, constraintKeys, inputData, memoryOnly);
|
||||
}
|
||||
|
||||
|
||||
@@ -319,13 +326,14 @@ public abstract class Job {
|
||||
private String queue;
|
||||
private List<String> constraintKeys;
|
||||
private Data inputData;
|
||||
private boolean memoryOnly;
|
||||
|
||||
public Builder() {
|
||||
this(UUID.randomUUID().toString());
|
||||
}
|
||||
|
||||
Builder(@NonNull String id) {
|
||||
this(id, System.currentTimeMillis(), TimeUnit.SECONDS.toMillis(30), IMMORTAL, 1, UNLIMITED, null, new LinkedList<>(), null);
|
||||
this(id, System.currentTimeMillis(), TimeUnit.SECONDS.toMillis(30), IMMORTAL, 1, UNLIMITED, null, new LinkedList<>(), null, false);
|
||||
}
|
||||
|
||||
private Builder(@NonNull String id,
|
||||
@@ -336,7 +344,8 @@ public abstract class Job {
|
||||
int maxInstances,
|
||||
@Nullable String queue,
|
||||
@NonNull List<String> constraintKeys,
|
||||
@Nullable Data inputData)
|
||||
@Nullable Data inputData,
|
||||
boolean memoryOnly)
|
||||
{
|
||||
this.id = id;
|
||||
this.createTime = createTime;
|
||||
@@ -347,6 +356,7 @@ public abstract class Job {
|
||||
this.queue = queue;
|
||||
this.constraintKeys = constraintKeys;
|
||||
this.inputData = inputData;
|
||||
this.memoryOnly = memoryOnly;
|
||||
}
|
||||
|
||||
/** Should only be invoked by {@link JobController} */
|
||||
@@ -424,6 +434,17 @@ public abstract class Job {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether or not you want this job to only live in memory. If true, this job will
|
||||
* *not* survive application death. This defaults to false, and should be used with care.
|
||||
*
|
||||
* Defaults to false.
|
||||
*/
|
||||
public @NonNull Builder setMemoryOnly(boolean memoryOnly) {
|
||||
this.memoryOnly = memoryOnly;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the input data that will be made availabe to the job when it is run.
|
||||
* Should only be set by {@link JobController}.
|
||||
@@ -434,7 +455,7 @@ public abstract class Job {
|
||||
}
|
||||
|
||||
public @NonNull Parameters build() {
|
||||
return new Parameters(id, createTime, lifespan, maxAttempts, maxBackoff, maxInstances, queue, constraintKeys, inputData);
|
||||
return new Parameters(id, createTime, lifespan, maxAttempts, maxBackoff, maxInstances, queue, constraintKeys, inputData, memoryOnly);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -354,14 +354,20 @@ class JobController {
|
||||
job.getParameters().getMaxInstances(),
|
||||
dataSerializer.serialize(job.serialize()),
|
||||
null,
|
||||
false);
|
||||
false,
|
||||
job.getParameters().isMemoryOnly());
|
||||
|
||||
List<ConstraintSpec> constraintSpecs = Stream.of(job.getParameters().getConstraintKeys())
|
||||
.map(key -> new ConstraintSpec(jobSpec.getId(), key))
|
||||
.map(key -> new ConstraintSpec(jobSpec.getId(), key, jobSpec.isMemoryOnly()))
|
||||
.toList();
|
||||
|
||||
List<DependencySpec> dependencySpecs = Stream.of(dependsOn)
|
||||
.map(depends -> new DependencySpec(job.getId(), depends))
|
||||
.map(depends -> {
|
||||
JobSpec dependsOnJobSpec = jobStorage.getJobSpec(depends);
|
||||
boolean memoryOnly = job.getParameters().isMemoryOnly() || (dependsOnJobSpec != null && dependsOnJobSpec.isMemoryOnly());
|
||||
|
||||
return new DependencySpec(job.getId(), depends, memoryOnly);
|
||||
})
|
||||
.toList();
|
||||
|
||||
return new FullSpec(jobSpec, constraintSpecs, dependencySpecs);
|
||||
@@ -371,7 +377,7 @@ class JobController {
|
||||
private void scheduleJobs(@NonNull List<Job> jobs) {
|
||||
for (Job job : jobs) {
|
||||
List<Constraint> constraints = Stream.of(job.getParameters().getConstraintKeys())
|
||||
.map(key -> new ConstraintSpec(job.getId(), key))
|
||||
.map(key -> new ConstraintSpec(job.getId(), key, job.getParameters().isMemoryOnly()))
|
||||
.map(ConstraintSpec::getFactoryKey)
|
||||
.map(constraintInstantiator::instantiate)
|
||||
.toList();
|
||||
@@ -460,7 +466,8 @@ class JobController {
|
||||
jobSpec.getMaxInstances(),
|
||||
jobSpec.getSerializedData(),
|
||||
dataSerializer.serialize(inputData),
|
||||
jobSpec.isRunning());
|
||||
jobSpec.isRunning(),
|
||||
jobSpec.isMemoryOnly());
|
||||
}
|
||||
|
||||
interface Callback {
|
||||
|
||||
@@ -76,7 +76,8 @@ public class JobMigrator {
|
||||
jobSpec.getMaxInstances(),
|
||||
dataSerializer.serialize(updatedJobData.getData()),
|
||||
jobSpec.getSerializedInputData(),
|
||||
jobSpec.isRunning());
|
||||
jobSpec.isRunning(),
|
||||
jobSpec.isMemoryOnly());
|
||||
|
||||
iter.set(updatedJobSpec);
|
||||
}
|
||||
|
||||
@@ -6,12 +6,14 @@ import java.util.Objects;
|
||||
|
||||
public final class ConstraintSpec {
|
||||
|
||||
private final String jobSpecId;
|
||||
private final String factoryKey;
|
||||
private final String jobSpecId;
|
||||
private final String factoryKey;
|
||||
private final boolean memoryOnly;
|
||||
|
||||
public ConstraintSpec(@NonNull String jobSpecId, @NonNull String factoryKey) {
|
||||
public ConstraintSpec(@NonNull String jobSpecId, @NonNull String factoryKey, boolean memoryOnly) {
|
||||
this.jobSpecId = jobSpecId;
|
||||
this.factoryKey = factoryKey;
|
||||
this.memoryOnly = memoryOnly;
|
||||
}
|
||||
|
||||
public String getJobSpecId() {
|
||||
@@ -22,22 +24,27 @@ public final class ConstraintSpec {
|
||||
return factoryKey;
|
||||
}
|
||||
|
||||
public boolean isMemoryOnly() {
|
||||
return memoryOnly;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
ConstraintSpec that = (ConstraintSpec) o;
|
||||
return Objects.equals(jobSpecId, that.jobSpecId) &&
|
||||
Objects.equals(factoryKey, that.factoryKey);
|
||||
return Objects.equals(jobSpecId, that.jobSpecId) &&
|
||||
Objects.equals(factoryKey, that.factoryKey) &&
|
||||
memoryOnly == that.memoryOnly;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(jobSpecId, factoryKey);
|
||||
return Objects.hash(jobSpecId, factoryKey, memoryOnly);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull String toString() {
|
||||
return String.format("jobSpecId: JOB::%s | factoryKey: %s", jobSpecId, factoryKey);
|
||||
return String.format("jobSpecId: JOB::%s | factoryKey: %s | memoryOnly: %b", jobSpecId, factoryKey, memoryOnly);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,12 +6,14 @@ import java.util.Objects;
|
||||
|
||||
public final class DependencySpec {
|
||||
|
||||
private final String jobId;
|
||||
private final String dependsOnJobId;
|
||||
private final String jobId;
|
||||
private final String dependsOnJobId;
|
||||
private final boolean memoryOnly;
|
||||
|
||||
public DependencySpec(@NonNull String jobId, @NonNull String dependsOnJobId) {
|
||||
public DependencySpec(@NonNull String jobId, @NonNull String dependsOnJobId, boolean memoryOnly) {
|
||||
this.jobId = jobId;
|
||||
this.dependsOnJobId = dependsOnJobId;
|
||||
this.memoryOnly = memoryOnly;
|
||||
}
|
||||
|
||||
public @NonNull String getJobId() {
|
||||
@@ -22,22 +24,27 @@ public final class DependencySpec {
|
||||
return dependsOnJobId;
|
||||
}
|
||||
|
||||
public boolean isMemoryOnly() {
|
||||
return memoryOnly;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
DependencySpec that = (DependencySpec) o;
|
||||
return Objects.equals(jobId, that.jobId) &&
|
||||
Objects.equals(dependsOnJobId, that.dependsOnJobId);
|
||||
return Objects.equals(jobId, that.jobId) &&
|
||||
Objects.equals(dependsOnJobId, that.dependsOnJobId) &&
|
||||
memoryOnly == that.memoryOnly;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(jobId, dependsOnJobId);
|
||||
return Objects.hash(jobId, dependsOnJobId, memoryOnly);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull String toString() {
|
||||
return String.format("jobSpecId: JOB::%s | dependsOnJobSpecId: JOB::%s", jobId, dependsOnJobId);
|
||||
return String.format("jobSpecId: JOB::%s | dependsOnJobSpecId: JOB::%s | memoryOnly: %b", jobId, dependsOnJobId, memoryOnly);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,9 @@ public final class FullSpec {
|
||||
return dependencySpecs;
|
||||
}
|
||||
|
||||
public boolean isMemoryOnly() {
|
||||
return jobSpec.isMemoryOnly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
|
||||
@@ -21,6 +21,7 @@ public final class JobSpec {
|
||||
private final String serializedData;
|
||||
private final String serializedInputData;
|
||||
private final boolean isRunning;
|
||||
private final boolean memoryOnly;
|
||||
|
||||
public JobSpec(@NonNull String id,
|
||||
@NonNull String factoryKey,
|
||||
@@ -34,7 +35,8 @@ public final class JobSpec {
|
||||
int maxInstances,
|
||||
@NonNull String serializedData,
|
||||
@Nullable String serializedInputData,
|
||||
boolean isRunning)
|
||||
boolean isRunning,
|
||||
boolean memoryOnly)
|
||||
{
|
||||
this.id = id;
|
||||
this.factoryKey = factoryKey;
|
||||
@@ -49,6 +51,7 @@ public final class JobSpec {
|
||||
this.serializedData = serializedData;
|
||||
this.serializedInputData = serializedInputData;
|
||||
this.isRunning = isRunning;
|
||||
this.memoryOnly = memoryOnly;
|
||||
}
|
||||
|
||||
public @NonNull String getId() {
|
||||
@@ -103,6 +106,10 @@ public final class JobSpec {
|
||||
return isRunning;
|
||||
}
|
||||
|
||||
public boolean isMemoryOnly() {
|
||||
return memoryOnly;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
@@ -116,6 +123,7 @@ public final class JobSpec {
|
||||
lifespan == jobSpec.lifespan &&
|
||||
maxInstances == jobSpec.maxInstances &&
|
||||
isRunning == jobSpec.isRunning &&
|
||||
memoryOnly == jobSpec.memoryOnly &&
|
||||
Objects.equals(id, jobSpec.id) &&
|
||||
Objects.equals(factoryKey, jobSpec.factoryKey) &&
|
||||
Objects.equals(queueKey, jobSpec.queueKey) &&
|
||||
@@ -125,13 +133,13 @@ public final class JobSpec {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, factoryKey, queueKey, createTime, nextRunAttemptTime, runAttempt, maxAttempts, maxBackoff, lifespan, maxInstances, serializedData, serializedInputData, isRunning);
|
||||
return Objects.hash(id, factoryKey, queueKey, createTime, nextRunAttemptTime, runAttempt, maxAttempts, maxBackoff, lifespan, maxInstances, serializedData, serializedInputData, isRunning, memoryOnly);
|
||||
}
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
@Override
|
||||
public @NonNull String toString() {
|
||||
return String.format("id: JOB::%s | factoryKey: %s | queueKey: %s | createTime: %d | nextRunAttemptTime: %d | runAttempt: %d | maxAttempts: %d | maxBackoff: %d | maxInstances: %d | lifespan: %d | isRunning: %b",
|
||||
id, factoryKey, queueKey, createTime, nextRunAttemptTime, runAttempt, maxAttempts, maxBackoff, maxInstances, lifespan, isRunning);
|
||||
return String.format("id: JOB::%s | factoryKey: %s | queueKey: %s | createTime: %d | nextRunAttemptTime: %d | runAttempt: %d | maxAttempts: %d | maxBackoff: %d | maxInstances: %d | lifespan: %d | isRunning: %b | memoryOnly: %b",
|
||||
id, factoryKey, queueKey, createTime, nextRunAttemptTime, runAttempt, maxAttempts, maxBackoff, maxInstances, lifespan, isRunning, memoryOnly);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,12 +69,13 @@ final class WorkManagerDatabase extends SQLiteOpenHelper {
|
||||
Job.Parameters.UNLIMITED,
|
||||
dataSerializer.serialize(DataMigrator.convert(data)),
|
||||
null,
|
||||
false,
|
||||
false);
|
||||
|
||||
|
||||
|
||||
if (cursor.getInt(cursor.getColumnIndexOrThrow("required_network_type")) != 0) {
|
||||
constraints.add(new ConstraintSpec(id, NetworkConstraint.KEY));
|
||||
constraints.add(new ConstraintSpec(id, NetworkConstraint.KEY, false));
|
||||
}
|
||||
|
||||
fullSpecs.add(new FullSpec(jobSpec, constraints, Collections.emptyList()));
|
||||
|
||||
@@ -85,9 +85,12 @@ public class FastJobStorage implements JobStorage {
|
||||
|
||||
@Override
|
||||
public synchronized void insertJobs(@NonNull List<FullSpec> fullSpecs) {
|
||||
serialExecutor.execute(() -> {
|
||||
jobDatabase.insertJobs(fullSpecs);
|
||||
});
|
||||
List<FullSpec> durable = Stream.of(fullSpecs).filterNot(FullSpec::isMemoryOnly).toList();
|
||||
if (durable.size() > 0) {
|
||||
serialExecutor.execute(() -> {
|
||||
jobDatabase.insertJobs(durable);
|
||||
});
|
||||
}
|
||||
|
||||
for (FullSpec fullSpec : fullSpecs) {
|
||||
jobs.add(fullSpec.getJobSpec());
|
||||
@@ -168,9 +171,12 @@ public class FastJobStorage implements JobStorage {
|
||||
|
||||
@Override
|
||||
public synchronized void updateJobRunningState(@NonNull String id, boolean isRunning) {
|
||||
serialExecutor.execute(() -> {
|
||||
jobDatabase.updateJobRunningState(id, isRunning);
|
||||
});
|
||||
JobSpec job = getJobById(id);
|
||||
if (job == null || !job.isMemoryOnly()) {
|
||||
serialExecutor.execute(() -> {
|
||||
jobDatabase.updateJobRunningState(id, isRunning);
|
||||
});
|
||||
}
|
||||
|
||||
ListIterator<JobSpec> iter = jobs.listIterator();
|
||||
|
||||
@@ -189,7 +195,8 @@ public class FastJobStorage implements JobStorage {
|
||||
existing.getMaxInstances(),
|
||||
existing.getSerializedData(),
|
||||
existing.getSerializedInputData(),
|
||||
isRunning);
|
||||
isRunning,
|
||||
existing.isMemoryOnly());
|
||||
iter.set(updated);
|
||||
}
|
||||
}
|
||||
@@ -197,9 +204,12 @@ public class FastJobStorage implements JobStorage {
|
||||
|
||||
@Override
|
||||
public synchronized void updateJobAfterRetry(@NonNull String id, boolean isRunning, int runAttempt, long nextRunAttemptTime, @NonNull String serializedData) {
|
||||
serialExecutor.execute(() -> {
|
||||
jobDatabase.updateJobAfterRetry(id, isRunning, runAttempt, nextRunAttemptTime, serializedData);
|
||||
});
|
||||
JobSpec job = getJobById(id);
|
||||
if (job == null || !job.isMemoryOnly()) {
|
||||
serialExecutor.execute(() -> {
|
||||
jobDatabase.updateJobAfterRetry(id, isRunning, runAttempt, nextRunAttemptTime, serializedData);
|
||||
});
|
||||
}
|
||||
|
||||
ListIterator<JobSpec> iter = jobs.listIterator();
|
||||
|
||||
@@ -218,7 +228,8 @@ public class FastJobStorage implements JobStorage {
|
||||
existing.getMaxInstances(),
|
||||
serializedData,
|
||||
existing.getSerializedInputData(),
|
||||
isRunning);
|
||||
isRunning,
|
||||
existing.isMemoryOnly());
|
||||
iter.set(updated);
|
||||
}
|
||||
}
|
||||
@@ -245,16 +256,27 @@ public class FastJobStorage implements JobStorage {
|
||||
existing.getMaxInstances(),
|
||||
existing.getSerializedData(),
|
||||
existing.getSerializedInputData(),
|
||||
false);
|
||||
false,
|
||||
existing.isMemoryOnly());
|
||||
iter.set(updated);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateJobs(@NonNull List<JobSpec> jobSpecs) {
|
||||
serialExecutor.execute(() -> {
|
||||
jobDatabase.updateJobs(jobSpecs);
|
||||
});
|
||||
List<JobSpec> durable = new ArrayList<>(jobSpecs.size());
|
||||
for (JobSpec update : jobSpecs) {
|
||||
JobSpec found = getJobById(update.getId());
|
||||
if (found == null || !found.isMemoryOnly()) {
|
||||
durable.add(update);
|
||||
}
|
||||
}
|
||||
|
||||
if (durable.size() > 0) {
|
||||
serialExecutor.execute(() -> {
|
||||
jobDatabase.updateJobs(durable);
|
||||
});
|
||||
}
|
||||
|
||||
Map<String, JobSpec> updates = Stream.of(jobSpecs).collect(Collectors.toMap(JobSpec::getId));
|
||||
ListIterator<JobSpec> iter = jobs.listIterator();
|
||||
@@ -276,10 +298,19 @@ public class FastJobStorage implements JobStorage {
|
||||
|
||||
@Override
|
||||
public synchronized void deleteJobs(@NonNull List<String> jobIds) {
|
||||
serialExecutor.execute(() -> {
|
||||
jobDatabase.deleteJobs(jobIds);
|
||||
});
|
||||
List<String> durableIds = new ArrayList<>(jobIds.size());
|
||||
for (String id : jobIds) {
|
||||
JobSpec job = getJobById(id);
|
||||
if (job == null || !job.isMemoryOnly()) {
|
||||
durableIds.add(id);
|
||||
}
|
||||
}
|
||||
|
||||
if (durableIds.size() > 0) {
|
||||
serialExecutor.execute(() -> {
|
||||
jobDatabase.deleteJobs(durableIds);
|
||||
});
|
||||
}
|
||||
|
||||
Set<String> deleteIds = new HashSet<>(jobIds);
|
||||
|
||||
@@ -355,4 +386,14 @@ public class FastJobStorage implements JobStorage {
|
||||
.flatMap(Stream::of)
|
||||
.toList();
|
||||
}
|
||||
|
||||
private JobSpec getJobById(@NonNull String id) {
|
||||
for (JobSpec job : jobs) {
|
||||
if (job.getId().equals(id)) {
|
||||
return job;
|
||||
}
|
||||
}
|
||||
Log.w(TAG, "Was looking for job with ID JOB::" + id + ", but it doesn't exist in memory!");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package org.thoughtcrime.securesms.jobs;
|
||||
|
||||
import android.net.Network;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.annimon.stream.Stream;
|
||||
@@ -10,6 +12,7 @@ import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
||||
@@ -43,6 +46,8 @@ public class TypingSendJob extends BaseJob {
|
||||
.setQueue(getQueue(threadId))
|
||||
.setMaxAttempts(1)
|
||||
.setLifespan(TimeUnit.SECONDS.toMillis(5))
|
||||
.addConstraint(NetworkConstraint.KEY)
|
||||
.setMemoryOnly(true)
|
||||
.build(),
|
||||
threadId,
|
||||
typing);
|
||||
|
||||
Reference in New Issue
Block a user