1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.work.impl.model; 18 19 import static android.arch.persistence.room.OnConflictStrategy.IGNORE; 20 21 import static androidx.work.impl.model.WorkTypeConverters.StateIds.COMPLETED_STATES; 22 23 import android.arch.lifecycle.LiveData; 24 import android.arch.persistence.room.Dao; 25 import android.arch.persistence.room.Insert; 26 import android.arch.persistence.room.Query; 27 import android.arch.persistence.room.Transaction; 28 import android.support.annotation.NonNull; 29 30 import androidx.work.Data; 31 import androidx.work.State; 32 33 import java.util.List; 34 35 /** 36 * The Data Access Object for {@link WorkSpec}s. 37 */ 38 @Dao 39 public interface WorkSpecDao { 40 41 /** 42 * Attempts to insert a {@link WorkSpec} into the database. 43 * 44 * @param workSpec The WorkSpec to insert. 45 */ 46 @Insert(onConflict = IGNORE) insertWorkSpec(WorkSpec workSpec)47 void insertWorkSpec(WorkSpec workSpec); 48 49 /** 50 * Deletes {@link WorkSpec}s from the database. 51 * 52 * @param id The WorkSpec id to delete. 53 */ 54 @Query("DELETE FROM workspec WHERE id=:id") delete(String id)55 void delete(String id); 56 57 /** 58 * @param id The identifier 59 * @return The WorkSpec associated with that id 60 */ 61 @Query("SELECT * FROM workspec WHERE id=:id") getWorkSpec(String id)62 WorkSpec getWorkSpec(String id); 63 64 /** 65 * Retrieves {@link WorkSpec}s with the identifiers. 66 * 67 * @param ids The identifiers of desired {@link WorkSpec}s 68 * @return The {@link WorkSpec}s with the requested IDs 69 */ 70 @Query("SELECT * FROM workspec WHERE id IN (:ids)") getWorkSpecs(List<String> ids)71 WorkSpec[] getWorkSpecs(List<String> ids); 72 73 /** 74 * Retrieves {@link WorkSpec}s labelled with a given name. 75 * 76 * @param name The work graph name 77 * @return The {@link WorkSpec}s labelled with the given name 78 */ 79 @Query("SELECT id, state FROM workspec WHERE id IN " 80 + "(SELECT work_spec_id FROM workname WHERE name=:name)") getWorkSpecIdAndStatesForName(String name)81 List<WorkSpec.IdAndState> getWorkSpecIdAndStatesForName(String name); 82 83 /** 84 * @return All WorkSpec ids in the database. 85 */ 86 @Query("SELECT id FROM workspec") getAllWorkSpecIds()87 List<String> getAllWorkSpecIds(); 88 89 /** 90 * Updates the state of at least one {@link WorkSpec} by ID. 91 * 92 * @param state The new state 93 * @param ids The IDs for the {@link WorkSpec}s to update 94 * @return The number of rows that were updated 95 */ 96 @Query("UPDATE workspec SET state=:state WHERE id IN (:ids)") setState(State state, String... ids)97 int setState(State state, String... ids); 98 99 /** 100 * Updates the output of a {@link WorkSpec}. 101 * 102 * @param id The {@link WorkSpec} identifier to update 103 * @param output The {@link Data} to set as the output 104 */ 105 @Query("UPDATE workspec SET output=:output WHERE id=:id") setOutput(String id, Data output)106 void setOutput(String id, Data output); 107 108 /** 109 * Updates the period start time of a {@link WorkSpec}. 110 * 111 * @param id The {@link WorkSpec} identifier to update 112 * @param periodStartTime The time when the period started. 113 */ 114 @Query("UPDATE workspec SET period_start_time=:periodStartTime WHERE id=:id") setPeriodStartTime(String id, long periodStartTime)115 void setPeriodStartTime(String id, long periodStartTime); 116 117 /** 118 * Increment run attempt count of a {@link WorkSpec}. 119 * 120 * @param id The identifier for the {@link WorkSpec} 121 * @return The number of rows that were updated (should be 0 or 1) 122 */ 123 @Query("UPDATE workspec SET run_attempt_count=run_attempt_count+1 WHERE id=:id") incrementWorkSpecRunAttemptCount(String id)124 int incrementWorkSpecRunAttemptCount(String id); 125 126 /** 127 * Reset run attempt count of a {@link WorkSpec}. 128 * 129 * @param id The identifier for the {@link WorkSpec} 130 * @return The number of rows that were updated (should be 0 or 1) 131 */ 132 @Query("UPDATE workspec SET run_attempt_count=0 WHERE id=:id") resetWorkSpecRunAttemptCount(String id)133 int resetWorkSpecRunAttemptCount(String id); 134 135 /** 136 * Retrieves the state of a {@link WorkSpec}. 137 * 138 * @param id The identifier for the {@link WorkSpec} 139 * @return The state of the {@link WorkSpec} 140 */ 141 @Query("SELECT state FROM workspec WHERE id=:id") getState(String id)142 State getState(String id); 143 144 /** 145 * For a {@link WorkSpec} identifier, retrieves its {@link WorkSpec.WorkStatusPojo}. 146 * 147 * @param id The identifier of the {@link WorkSpec} 148 * @return A list of {@link WorkSpec.WorkStatusPojo} 149 */ 150 @Transaction 151 @Query("SELECT id, state, output FROM workspec WHERE id=:id") getWorkStatusPojoForId(String id)152 WorkSpec.WorkStatusPojo getWorkStatusPojoForId(String id); 153 154 /** 155 * For a list of {@link WorkSpec} identifiers, retrieves a {@link List} of their 156 * {@link WorkSpec.WorkStatusPojo}. 157 * 158 * @param ids The identifier of the {@link WorkSpec}s 159 * @return A {@link List} of {@link WorkSpec.WorkStatusPojo} 160 */ 161 @Transaction 162 @Query("SELECT id, state, output FROM workspec WHERE id IN (:ids)") getWorkStatusPojoForIds(List<String> ids)163 List<WorkSpec.WorkStatusPojo> getWorkStatusPojoForIds(List<String> ids); 164 165 /** 166 * For a list of {@link WorkSpec} identifiers, retrieves a {@link LiveData} list of their 167 * {@link WorkSpec.WorkStatusPojo}. 168 * 169 * @param ids The identifier of the {@link WorkSpec}s 170 * @return A {@link LiveData} list of {@link WorkSpec.WorkStatusPojo} 171 */ 172 @Transaction 173 @Query("SELECT id, state, output FROM workspec WHERE id IN (:ids)") getWorkStatusPojoLiveDataForIds(List<String> ids)174 LiveData<List<WorkSpec.WorkStatusPojo>> getWorkStatusPojoLiveDataForIds(List<String> ids); 175 176 /** 177 * Retrieves a list of {@link WorkSpec.WorkStatusPojo} for all work with a given tag. 178 * 179 * @param tag The tag for the {@link WorkSpec}s 180 * @return A list of {@link WorkSpec.WorkStatusPojo} 181 */ 182 @Transaction 183 @Query("SELECT id, state, output FROM workspec WHERE id IN " 184 + "(SELECT work_spec_id FROM worktag WHERE tag=:tag)") getWorkStatusPojoForTag(String tag)185 List<WorkSpec.WorkStatusPojo> getWorkStatusPojoForTag(String tag); 186 187 /** 188 * Retrieves a {@link LiveData} list of {@link WorkSpec.WorkStatusPojo} for all work with a 189 * given tag. 190 * 191 * @param tag The tag for the {@link WorkSpec}s 192 * @return A {@link LiveData} list of {@link WorkSpec.WorkStatusPojo} 193 */ 194 @Transaction 195 @Query("SELECT id, state, output FROM workspec WHERE id IN " 196 + "(SELECT work_spec_id FROM worktag WHERE tag=:tag)") getWorkStatusPojoLiveDataForTag(String tag)197 LiveData<List<WorkSpec.WorkStatusPojo>> getWorkStatusPojoLiveDataForTag(String tag); 198 199 /** 200 * Retrieves a list of {@link WorkSpec.WorkStatusPojo} for all work with a given name. 201 * 202 * @param name The name of the {@link WorkSpec}s 203 * @return A list of {@link WorkSpec.WorkStatusPojo} 204 */ 205 @Transaction 206 @Query("SELECT id, state, output FROM workspec WHERE id IN " 207 + "(SELECT work_spec_id FROM workname WHERE name=:name)") getWorkStatusPojoForName(String name)208 List<WorkSpec.WorkStatusPojo> getWorkStatusPojoForName(String name); 209 210 /** 211 * Retrieves a {@link LiveData} list of {@link WorkSpec.WorkStatusPojo} for all work with a 212 * given name. 213 * 214 * @param name The name for the {@link WorkSpec}s 215 * @return A {@link LiveData} list of {@link WorkSpec.WorkStatusPojo} 216 */ 217 @Transaction 218 @Query("SELECT id, state, output FROM workspec WHERE id IN " 219 + "(SELECT work_spec_id FROM workname WHERE name=:name)") getWorkStatusPojoLiveDataForName(String name)220 LiveData<List<WorkSpec.WorkStatusPojo>> getWorkStatusPojoLiveDataForName(String name); 221 222 /** 223 * Gets all inputs coming from prerequisites for a particular {@link WorkSpec}. These are 224 * {@link Data} set via {@code Worker#setOutputData()}. 225 * 226 * @param id The {@link WorkSpec} identifier 227 * @return A list of all inputs coming from prerequisites for {@code id} 228 */ 229 @Query("SELECT output FROM workspec WHERE id IN " 230 + "(SELECT prerequisite_id FROM dependency WHERE work_spec_id=:id)") getInputsFromPrerequisites(String id)231 List<Data> getInputsFromPrerequisites(String id); 232 233 /** 234 * Retrieves work ids for unfinished work with a given tag. 235 * 236 * @param tag The tag used to identify the work 237 * @return A list of work ids 238 */ 239 @Query("SELECT id FROM workspec WHERE state NOT IN " + COMPLETED_STATES 240 + " AND id IN (SELECT work_spec_id FROM worktag WHERE tag=:tag)") getUnfinishedWorkWithTag(@onNull String tag)241 List<String> getUnfinishedWorkWithTag(@NonNull String tag); 242 243 /** 244 * Retrieves work ids for unfinished work with a given name. 245 * 246 * @param name THe tag used to identify the work 247 * @return A list of work ids 248 */ 249 @Query("SELECT id FROM workspec WHERE state NOT IN " + COMPLETED_STATES 250 + " AND id IN (SELECT work_spec_id FROM workname WHERE name=:name)") getUnfinishedWorkWithName(@onNull String name)251 List<String> getUnfinishedWorkWithName(@NonNull String name); 252 253 /** 254 * Retrieves work ids for all unfinished work. 255 * 256 * @return A list of work ids 257 */ 258 @Query("SELECT id FROM workspec WHERE state NOT IN " + COMPLETED_STATES) getAllUnfinishedWork()259 List<String> getAllUnfinishedWork(); 260 261 /** 262 * Marks a {@link WorkSpec} as scheduled. 263 * 264 * @param id The identifier for the {@link WorkSpec} 265 * @param startTime The time at which the {@link WorkSpec} was scheduled. 266 * @return The number of rows that were updated (should be 0 or 1) 267 */ 268 @Query("UPDATE workspec SET schedule_requested_at=:startTime WHERE id=:id") markWorkSpecScheduled(@onNull String id, long startTime)269 int markWorkSpecScheduled(@NonNull String id, long startTime); 270 271 /** 272 * Resets the scheduled state on the {@link WorkSpec}s that are not in a a completed state. 273 * @return The number of rows that were updated 274 */ 275 @Query("UPDATE workspec SET schedule_requested_at=" + WorkSpec.SCHEDULE_NOT_REQUESTED_YET 276 + " WHERE state NOT IN " + COMPLETED_STATES) resetScheduledState()277 int resetScheduledState(); 278 279 /** 280 * @return The List of {@link WorkSpec}s that are eligible to be scheduled. 281 */ 282 @Query("SELECT * from workspec WHERE " 283 + "state=" + WorkTypeConverters.StateIds.ENQUEUED 284 // We only want WorkSpecs which have not been previously scheduled. 285 + " AND schedule_requested_at=" + WorkSpec.SCHEDULE_NOT_REQUESTED_YET 286 + " LIMIT " 287 + "(SELECT :schedulerLimit" + "-COUNT(*) FROM workspec WHERE" 288 + " schedule_requested_at<>" + WorkSpec.SCHEDULE_NOT_REQUESTED_YET 289 + " AND state NOT IN " + COMPLETED_STATES 290 + ")" 291 ) getEligibleWorkForScheduling(int schedulerLimit)292 List<WorkSpec> getEligibleWorkForScheduling(int schedulerLimit); 293 294 /** 295 * Immediately prunes eligible work from the database meeting the following criteria: 296 * - Is finished (succeeded, failed, or cancelled) 297 * - Has zero unfinished dependents 298 */ 299 @Query("DELETE FROM workspec WHERE " 300 + "state IN " + COMPLETED_STATES 301 + " AND (SELECT COUNT(*)=0 FROM dependency WHERE " 302 + " prerequisite_id=id AND " 303 + " work_spec_id NOT IN " 304 + " (SELECT id FROM workspec WHERE state IN " + COMPLETED_STATES + "))") pruneFinishedWorkWithZeroDependentsIgnoringKeepForAtLeast()305 void pruneFinishedWorkWithZeroDependentsIgnoringKeepForAtLeast(); 306 } 307