Skip to content

Commit e942a75

Browse files
authored
Merge pull request #601 from scireum/feature/ymo/SIRI-915-iterate
Use streamBlockwise for cascadeDelete
2 parents 4786811 + 67cb68a commit e942a75

File tree

8 files changed

+27
-60
lines changed

8 files changed

+27
-60
lines changed

src/main/java/sirius/db/es/ElasticQuery.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1424,7 +1424,7 @@ private void close() {
14241424

14251425
@Override
14261426
public void delete(@Nullable Consumer<E> entityCallback) {
1427-
iterateAll(entity -> {
1427+
streamBlockwise().forEach(entity -> {
14281428
if (entityCallback != null) {
14291429
entityCallback.accept(entity);
14301430
}

src/main/java/sirius/db/jdbc/SmartQuery.java

Lines changed: 8 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,9 @@
2424
import sirius.kernel.commons.Monoflop;
2525
import sirius.kernel.commons.PullBasedSpliterator;
2626
import sirius.kernel.commons.Strings;
27-
import sirius.kernel.commons.Timeout;
2827
import sirius.kernel.commons.Tuple;
2928
import sirius.kernel.commons.Value;
3029
import sirius.kernel.commons.Watch;
31-
import sirius.kernel.di.std.ConfigValue;
3230
import sirius.kernel.di.std.Part;
3331
import sirius.kernel.health.Exceptions;
3432
import sirius.kernel.health.HandledException;
@@ -39,7 +37,6 @@
3937
import java.sql.PreparedStatement;
4038
import java.sql.ResultSet;
4139
import java.sql.SQLException;
42-
import java.time.Duration;
4340
import java.util.ArrayList;
4441
import java.util.Arrays;
4542
import java.util.Collections;
@@ -50,7 +47,6 @@
5047
import java.util.Map;
5148
import java.util.Set;
5249
import java.util.TreeMap;
53-
import java.util.concurrent.atomic.AtomicBoolean;
5450
import java.util.concurrent.atomic.AtomicInteger;
5551
import java.util.function.Consumer;
5652
import java.util.function.Predicate;
@@ -64,9 +60,6 @@
6460
*/
6561
public class SmartQuery<E extends SQLEntity> extends Query<SmartQuery<E>, E, SQLConstraint> {
6662

67-
@ConfigValue("jdbc.queryIterateTimeout")
68-
private static Duration queryIterateTimeout;
69-
7063
@Part
7164
private static OMA oma;
7265

@@ -254,41 +247,15 @@ public boolean exists() {
254247
return copy().fields(SQLEntity.ID).first().isPresent();
255248
}
256249

257-
/**
258-
* Deletes all matches using the {@link OMA#delete(BaseEntity)}.
259-
* <p>
260-
* Note that for very large result sets, we perform a blockwise strategy. We therefore iterate over
261-
* the results until the timeout ({@link #queryIterateTimeout} is reached). In this case, we abort the
262-
* iteration, execute the query again and continue deleting until all entities are gone.
263-
*
264-
* @param entityCallback a callback to be invoked for each entity to be deleted
265-
*/
266250
@Override
267251
public void delete(@Nullable Consumer<E> entityCallback) {
268-
if (forceFail) {
269-
return;
270-
}
271-
AtomicBoolean continueDeleting = new AtomicBoolean(true);
272-
TaskContext taskContext = TaskContext.get();
273-
while (continueDeleting.get() && taskContext.isActive()) {
274-
continueDeleting.set(false);
275-
Timeout timeout = new Timeout(queryIterateTimeout);
276-
iterate(entity -> {
277-
if (entityCallback != null) {
278-
entityCallback.accept(entity);
279-
}
280-
oma.delete(entity);
281-
if (timeout.isReached()) {
282-
// Timeout has been reached, set the flag so that another delete query is attempted....
283-
continueDeleting.set(true);
284-
// and abort processing the results of this query...
285-
return false;
286-
} else {
287-
// Timeout not yet reached, continue deleting...
288-
return true;
289-
}
290-
});
291-
}
252+
streamBlockwise().forEach(entity -> {
253+
if (entityCallback != null) {
254+
entityCallback.accept(entity);
255+
}
256+
257+
oma.delete(entity);
258+
});
292259
}
293260

294261
@Override
@@ -427,7 +394,7 @@ private BaseEntity<?> findParent(Mapping mapping, BaseEntity<?> entity) {
427394
/**
428395
* Creates a sql constraint for sorting purposes.
429396
* </p>
430-
* In MySQL/MariaDB, NULL is considered as a 'missing, unkonwn value'. Any arithmetic comparison with NULL
397+
* In MySQL/MariaDB, NULL is considered as a 'missing, unknown value'. Any arithmetic comparison with NULL
431398
* returns false e.g. NULL != 'any' returns false.
432399
* Therefore, comparisons with NULL values must be treated specially.
433400
*

src/main/java/sirius/db/mixing/properties/BaseEntityRefListProperty.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ public void parseValues(Object e, Values values) {
180180
/**
181181
* Returns the {@link EntityDescriptor} of the referenced entity.
182182
*
183-
* @return the referenced entity drescriptor
183+
* @return the referenced entity descriptor
184184
*/
185185
public EntityDescriptor getReferencedDescriptor() {
186186
if (referencedDescriptor == null) {
@@ -241,7 +241,8 @@ protected void onDeleteSetNull(Object e) {
241241
referenceInstance.getMapper()
242242
.select(referenceInstance.getClass())
243243
.eq(nameAsMapping, idBeingDeleted)
244-
.iterateAll(other -> cascadeSetNull(taskContext, idBeingDeleted, other));
244+
.streamBlockwise()
245+
.forEach(other -> cascadeSetNull(taskContext, idBeingDeleted, other));
245246
}
246247
}
247248

@@ -264,7 +265,8 @@ protected void onDeleteCascade(Object e) {
264265
referenceInstance.getMapper()
265266
.select(referenceInstance.getClass())
266267
.eq(nameAsMapping, ((BaseEntity<?>) e).getId())
267-
.iterateAll(other -> cascadeDelete(taskContext, other));
268+
.streamBlockwise()
269+
.forEach(other -> cascadeDelete(taskContext, other));
268270
}
269271

270272
private void cascadeDelete(TaskContext taskContext, BaseEntity<?> other) {

src/main/java/sirius/db/mixing/properties/BaseEntityRefProperty.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ public Class<? extends BaseEntity<?>> getReferencedType() {
7474
/**
7575
* Returns the {@link EntityDescriptor} of the referenced entity.
7676
*
77-
* @return the referenced entity drescriptor
77+
* @return the referenced entity descriptor
7878
*/
7979
public EntityDescriptor getReferencedDescriptor() {
8080
if (referencedDescriptor == null) {
@@ -253,7 +253,7 @@ protected static void ensureLabelsArePresent(Property property,
253253
EntityDescriptor referencedDescriptor,
254254
BaseEntityRef.OnDelete deleteHandler) {
255255
// If a cascade delete handler is present and the referenced entity is not explicitly marked as
256-
// "non complex" and we're within the IDE or running as a test, we force the system to compute / lookup
256+
// "non-complex" and we're within the IDE or running as a test, we force the system to compute / lookup
257257
// the associated NLS keys which might be required to generated appropriate deletion logs or rejection
258258
// errors (otherwise this might be missed while developing or testing the system).
259259
if ((referencedDescriptor.getAnnotation(ComplexDelete.class).map(ComplexDelete::value).orElse(true)
@@ -286,7 +286,8 @@ protected void onDeleteSetNull(Object e) {
286286
referenceInstance.getMapper()
287287
.select(referenceInstance.getClass())
288288
.eq(nameAsMapping, ((BaseEntity<?>) e).getId())
289-
.iterateAll(other -> cascadeSetNull(taskContext, other));
289+
.streamBlockwise()
290+
.forEach(other -> cascadeSetNull(taskContext, other));
290291
}
291292

292293
private void cascadeSetNull(TaskContext taskContext, BaseEntity<?> other) {
@@ -309,7 +310,8 @@ protected void onDeleteCascade(Object e) {
309310
referenceInstance.getMapper()
310311
.select(referenceInstance.getClass())
311312
.eq(nameAsMapping, ((BaseEntity<?>) e).getId())
312-
.iterateAll(other -> cascadeDelete(taskContext, other));
313+
.streamBlockwise()
314+
.forEach(other -> cascadeDelete(taskContext, other));
313315
}
314316

315317
private void cascadeDelete(TaskContext taskContext, BaseEntity<?> other) {

src/main/java/sirius/db/mixing/query/Query.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ protected Query(EntityDescriptor descriptor) {
3232
}
3333

3434
/**
35-
* Applies the given contraints to the query.
35+
* Applies the given constraints to the query.
3636
*
37-
* @param constraint the constraint which has to be fullfilled
37+
* @param constraint the constraint which has to be fulfilled
3838
* @return the query itself for fluent method calls
3939
*/
4040
public abstract Q where(C constraint);
@@ -131,6 +131,7 @@ public Q queryString(String query, QueryField... fields) {
131131
* Deletes all matches using the {@link BaseMapper#delete(BaseEntity)} of the appropriate mapper.
132132
* <p>
133133
* Be aware that this might be slow for very large result sets.
134+
* Attention: Some implementations (especially mongo) does not support deleting via streamBlockwise with a sort order.
134135
*
135136
* @param entityCallback a callback to be invoked for each entity to be deleted
136137
*/

src/main/java/sirius/db/mongo/MongoQuery.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ public MongoQuery<E> orderDesc(Mapping field) {
114114
* Adds a limit to the query.
115115
*
116116
* @param skip the number of items to skip (used for pagination).
117-
* @param limit the max. number of items to return (exluding those who have been skipped).
117+
* @param limit the max. number of items to return (excluding those who have been skipped).
118118
* @return the builder itself for fluent method calls
119119
*/
120120
public MongoQuery<E> limit(int skip, int limit) {
@@ -282,7 +282,7 @@ public List<E> randomList() {
282282
}
283283

284284
/**
285-
* Aggregates the documents in the result of the given query with an sum operator.
285+
* Aggregates the documents in the result of the given query with a sum operator.
286286
* <p>
287287
* Note that limits are ignored for this query.
288288
*
@@ -294,7 +294,7 @@ public Value aggregateSum(@Nonnull Mapping field) {
294294
}
295295

296296
/**
297-
* Aggregates the documents in the result of the given query with an an average operator.
297+
* Aggregates the documents in the result of the given query with an average operator.
298298
* <p>
299299
* Note that limits are ignored for this query.
300300
*
@@ -331,7 +331,7 @@ public Value aggregateMin(@Nonnull Mapping field) {
331331

332332
@Override
333333
public void delete(@Nullable Consumer<E> entityCallback) {
334-
iterateAll(entity -> {
334+
streamBlockwise().forEach(entity -> {
335335
if (entityCallback != null) {
336336
entityCallback.accept(entity);
337337
}

src/main/resources/component-060-db.conf

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,6 @@ jdbc {
148148
# Every connection which lasts longer will be logged to "db-slow" on level INFO
149149
logConnectionThreshold = 30 seconds
150150

151-
# The default timeout at which a running query will get interrupted and restarted at the current position
152-
queryIterateTimeout = 15 minutes
153-
154151
# A profile provides a template for database connections.
155152
# Each value of the profile serves as backup or default value for the one in the database secion.
156153
# Also a profile value can reference properties defined in one of both sections like this: ${name}.

src/test/resources/test.conf

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
docker.file = ["src/test/resources/docker-db.yml"]
22

33
jdbc {
4-
# a very aggressive timeout finds more potential problems
5-
queryIterateTimeout = 1s
64

75
database {
86
test {

0 commit comments

Comments
 (0)