Skip to content

Commit b6625e9

Browse files
authored
Add scheduled executor to enforce deadlines, make packager closable (#907)
* Add scheduled executor to enforce deadlines, make packager closable * Add fool-proofed duration check
1 parent 8d6ad0d commit b6625e9

File tree

38 files changed

+1278
-1151
lines changed

38 files changed

+1278
-1151
lines changed

api/src/main/java/com/github/skjolber/packing/api/Packager.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package com.github.skjolber.packing.api;
22

3+
import java.io.Closeable;
4+
35
/**
46
* Fit boxes into container, i.e. perform bin packing to a single container.
57
*
68
* Thread-safe implementation.
79
*/
810

9-
public interface Packager<B extends PackagerResultBuilder<B>> {
11+
public interface Packager<B extends PackagerResultBuilder<B>> extends Closeable {
1012

1113
B newResultBuilder();
1214

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,34 @@
11
package com.github.skjolber.packing.deadline;
22

3-
public class DeadlineCheckPackagerInterruptSupplier implements PackagerInterruptSupplier {
3+
import java.io.Closeable;
4+
import java.util.concurrent.ScheduledFuture;
45

5-
protected final long deadline;
6+
public class DeadlineCheckPackagerInterruptSupplier implements PackagerInterruptSupplier, Runnable, Closeable {
67

7-
public DeadlineCheckPackagerInterruptSupplier(long deadline) {
8-
super();
9-
this.deadline = deadline;
8+
// this is not entirely accurate for multi-threading, but close enough
9+
// (should have been volatile)
10+
protected boolean expired = false;
11+
protected ScheduledFuture<?> future;
12+
13+
public DeadlineCheckPackagerInterruptSupplier() {
1014
}
1115

1216
@Override
1317
public boolean getAsBoolean() {
14-
return System.currentTimeMillis() > deadline;
18+
return expired;
19+
}
20+
21+
@Override
22+
public void run() {
23+
this.expired = true;
24+
}
25+
26+
public void close() {
27+
future.cancel(true);
28+
}
29+
30+
public void setFuture(ScheduledFuture<?> future) {
31+
this.future = future;
1532
}
1633

1734
}
Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,38 @@
11
package com.github.skjolber.packing.deadline;
22

3+
import java.io.Closeable;
4+
import java.util.concurrent.ScheduledFuture;
35
import java.util.function.BooleanSupplier;
46

5-
public class DelegateDeadlineCheckPackagerInterruptSupplier implements PackagerInterruptSupplier {
7+
public class DelegateDeadlineCheckPackagerInterruptSupplier implements PackagerInterruptSupplier, Runnable, Closeable {
68

9+
// this is not entirely accurate for multi-threading, but close enough
10+
// (should have been volatile)
11+
protected boolean expired = false;
12+
protected ScheduledFuture<?> future;
713
protected final BooleanSupplier delegate;
8-
protected final long deadline;
9-
10-
public DelegateDeadlineCheckPackagerInterruptSupplier(long deadline, BooleanSupplier delegate) {
14+
15+
public DelegateDeadlineCheckPackagerInterruptSupplier(BooleanSupplier delegate) {
1116
super();
12-
this.deadline = deadline;
1317
this.delegate = delegate;
1418
}
1519

1620
@Override
1721
public boolean getAsBoolean() {
18-
return delegate.getAsBoolean() || System.currentTimeMillis() > deadline;
22+
return expired || delegate.getAsBoolean();
23+
}
24+
25+
@Override
26+
public void run() {
27+
this.expired = true;
28+
}
29+
30+
public void close() {
31+
future.cancel(true);
32+
}
33+
34+
public void setFuture(ScheduledFuture<?> future) {
35+
this.future = future;
1936
}
2037

2138
}

core/src/main/java/com/github/skjolber/packing/deadline/DelegateNthDeadlineCheckPackagerInterruptSupplier.java

Lines changed: 0 additions & 34 deletions
This file was deleted.

core/src/main/java/com/github/skjolber/packing/deadline/NthDeadlineCheckPackagerInterruptSupplier.java

Lines changed: 0 additions & 29 deletions
This file was deleted.

core/src/main/java/com/github/skjolber/packing/deadline/NthPackagerInterruptSupplier.java

Lines changed: 0 additions & 31 deletions
This file was deleted.
Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
package com.github.skjolber.packing.deadline;
22

3+
import java.io.Closeable;
4+
35
@FunctionalInterface
4-
public interface PackagerInterruptSupplier {
6+
public interface PackagerInterruptSupplier extends Closeable {
57

68
/**
79
* Gets a result.
810
*
911
* @return a result
1012
*/
1113
boolean getAsBoolean();
14+
15+
default void close() {
16+
}
1217
}
Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,68 @@
11
package com.github.skjolber.packing.deadline;
22

3+
import java.util.concurrent.ScheduledFuture;
4+
import java.util.concurrent.ScheduledThreadPoolExecutor;
5+
import java.util.concurrent.TimeUnit;
36
import java.util.function.BooleanSupplier;
47

58
public class PackagerInterruptSupplierBuilder {
69

7-
public static final NegativePackagerInterruptSupplier NOOP = new NegativePackagerInterruptSupplier();
10+
public static final NegativePackagerInterruptSupplier NEGATIVE = new NegativePackagerInterruptSupplier();
11+
public static final PositivePackagerInterruptSupplier POSITIVE = new PositivePackagerInterruptSupplier();
812

913
private long deadline = Long.MAX_VALUE;
10-
private int checkpointsPerDeadlineCheck = 1;
1114
private BooleanSupplier interrupt = null;
15+
private ScheduledThreadPoolExecutor scheduledThreadPoolExecutor;
1216

1317
public static PackagerInterruptSupplierBuilder builder() {
1418
return new PackagerInterruptSupplierBuilder();
1519
}
1620

17-
public PackagerInterruptSupplierBuilder withDeadline(long deadline, int checkpointsPerDeadlineCheck) {
21+
public PackagerInterruptSupplierBuilder withDeadline(long deadline) {
1822
this.deadline = deadline;
19-
this.checkpointsPerDeadlineCheck = checkpointsPerDeadlineCheck;
2023
return this;
2124
}
2225

2326
public PackagerInterruptSupplierBuilder withInterrupt(BooleanSupplier interrupt) {
2427
this.interrupt = interrupt;
2528
return this;
2629
}
30+
31+
public PackagerInterruptSupplierBuilder withScheduledThreadPoolExecutor(ScheduledThreadPoolExecutor executor) {
32+
this.scheduledThreadPoolExecutor = executor;
33+
return this;
34+
}
2735

2836
public PackagerInterruptSupplier build() {
29-
if(checkpointsPerDeadlineCheck == Integer.MAX_VALUE || checkpointsPerDeadlineCheck == -1 || deadline == Long.MAX_VALUE || deadline == -1L) {
37+
38+
if(deadline == Long.MAX_VALUE || deadline == -1L) {
3039
// no deadline
3140
if(interrupt != null) {
3241
return new DefaultPackagerInterrupt(interrupt);
3342
}
34-
return NOOP;
43+
return NEGATIVE;
3544
}
3645

37-
if(checkpointsPerDeadlineCheck == 1) {
38-
if(interrupt == null) {
39-
return new DeadlineCheckPackagerInterruptSupplier(deadline);
40-
}
41-
return new DelegateDeadlineCheckPackagerInterruptSupplier(deadline, interrupt);
46+
long delay = deadline - System.currentTimeMillis();
47+
if(delay <= 0) {
48+
return POSITIVE; // i.e. time is already up
49+
}
50+
51+
if(scheduledThreadPoolExecutor == null) {
52+
throw new IllegalStateException("Expected scheduler");
4253
}
54+
4355
if(interrupt == null) {
44-
return new NthDeadlineCheckPackagerInterruptSupplier(deadline, checkpointsPerDeadlineCheck);
56+
DeadlineCheckPackagerInterruptSupplier supplier = new DeadlineCheckPackagerInterruptSupplier();
57+
ScheduledFuture<?> schedule = scheduledThreadPoolExecutor.schedule(supplier, delay, TimeUnit.MILLISECONDS);
58+
supplier.setFuture(schedule);
59+
return supplier;
4560
}
46-
return new DelegateNthDeadlineCheckPackagerInterruptSupplier(deadline, checkpointsPerDeadlineCheck, interrupt);
61+
62+
DelegateDeadlineCheckPackagerInterruptSupplier supplier = new DelegateDeadlineCheckPackagerInterruptSupplier(interrupt);
63+
ScheduledFuture<?> schedule = scheduledThreadPoolExecutor.schedule(supplier, delay, TimeUnit.MILLISECONDS);
64+
supplier.setFuture(schedule);
65+
return supplier;
4766
}
4867

4968
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.github.skjolber.packing.deadline;
2+
3+
public class PositivePackagerInterruptSupplier implements PackagerInterruptSupplier {
4+
5+
@Override
6+
public boolean getAsBoolean() {
7+
return true;
8+
}
9+
10+
}

core/src/main/java/com/github/skjolber/packing/iterator/PermutationRotationIterator.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public interface PermutationRotationIterator {
4040
/**
4141
* Get current permutations
4242
*
43-
* @return
43+
* @return current permutations array
4444
*/
4545

4646
int[] getPermutations();
@@ -49,7 +49,7 @@ public interface PermutationRotationIterator {
4949
*
5050
* Get current length
5151
*
52-
* @return
52+
* @return current length of permutations array
5353
*/
5454

5555
int length();
@@ -112,7 +112,7 @@ public interface PermutationRotationIterator {
112112
*
113113
* @param state previously saved state
114114
* @param length number of items
115-
* @return
115+
* @return current permutations + rotations
116116
*/
117117

118118
List<PermutationRotation> get(PermutationRotationState state, int length);

0 commit comments

Comments
 (0)