mirror of https://github.com/hyperledger/besu
[PAN-2786] Stop Transaction Pool Queue from Growing Unbounded (#1586)
* [PAN-2786] Stop Transaction Pool Queue from Growing Unbounded - use a `ArrayBlockingQueue` with a fixed size to limit the transaction task queue - expose a method in `MonitoredExecutors` to create a working queue with a maximum capacity - update `EthScheduler` to use a limited working queue for the `txWorkerExecutor` * [PAN-2786] Implement a bounded timed queue - implement a custom bounded queue - use a time based policy with keep alive configuration - implement eviction process based on the policy - add metrics * use field instead of parameter * fix PR pass 1 - use concrete class instead of interface - change metric name to comply with global policy - update unit test - wrap `Runnable` into `scheduleTxWorkerTask` * fix PR - remove time based policy - use raw `Runnable` - make a room for a new element at full capacity * Update BoundedQueueTest.java invert condition * fix PR comments - remove Mock class - make logic more thread safe, avoid race condition - remove element until the new one is accepted * Update ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/manager/EthScheduler.java Co-Authored-By: Adrian Sutton <adrian@symphonious.net> * spotless apply * fix nit comments - use assertj assertions for better readability - improve unit test * spotless apply Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>pull/2/head
parent
04069f20c2
commit
395ccae15e
@ -0,0 +1,44 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2019 ConsenSys AG. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||||
|
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||||
|
* specific language governing permissions and limitations under the License. |
||||||
|
*/ |
||||||
|
package tech.pegasys.pantheon.ethereum.eth.manager.bounded; |
||||||
|
|
||||||
|
import tech.pegasys.pantheon.metrics.Counter; |
||||||
|
import tech.pegasys.pantheon.metrics.MetricsSystem; |
||||||
|
import tech.pegasys.pantheon.metrics.PantheonMetricCategory; |
||||||
|
|
||||||
|
import java.util.concurrent.LinkedBlockingDeque; |
||||||
|
|
||||||
|
public class BoundedQueue extends LinkedBlockingDeque<Runnable> { |
||||||
|
private final MetricsSystem metricsSystem; |
||||||
|
private final Counter totalEvictedTaskCounter; |
||||||
|
|
||||||
|
public BoundedQueue( |
||||||
|
final int capacity, final String metricName, final MetricsSystem metricsSystem) { |
||||||
|
super(capacity); |
||||||
|
this.metricsSystem = metricsSystem; |
||||||
|
this.totalEvictedTaskCounter = |
||||||
|
this.metricsSystem.createCounter( |
||||||
|
PantheonMetricCategory.EXECUTORS, |
||||||
|
metricName + "_dropped_tasks_total", |
||||||
|
"Total number of tasks rejected by this working queue."); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean offer(final Runnable task) { |
||||||
|
while (!super.offer(task)) { |
||||||
|
remove(); |
||||||
|
totalEvictedTaskCounter.inc(); |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,53 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2019 ConsenSys AG. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||||
|
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||||
|
* specific language governing permissions and limitations under the License. |
||||||
|
*/ |
||||||
|
package tech.pegasys.pantheon.ethereum.eth.manager.bounded; |
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||||
|
|
||||||
|
import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; |
||||||
|
|
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
public class BoundedQueueTest { |
||||||
|
|
||||||
|
@Test |
||||||
|
public void offerShouldAcceptNewElements() { |
||||||
|
int size = 10; |
||||||
|
final BoundedQueue queue = new BoundedQueue(size, "test", new NoOpMetricsSystem()); |
||||||
|
for (int i = 0; i < size; i++) { |
||||||
|
final Runnable task = () -> {}; |
||||||
|
assertThat(queue.offer(task)).isTrue(); |
||||||
|
assertThat(queue).contains(task); |
||||||
|
assertThat(queue.size()).isEqualTo(i + 1); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void offerShouldMakeARoomAndAcceptNewElementAtFullCapacity() { |
||||||
|
final BoundedQueue queue = new BoundedQueue(2, "test", new NoOpMetricsSystem()); |
||||||
|
final Runnable task1 = () -> {}; |
||||||
|
final Runnable task2 = () -> {}; |
||||||
|
final Runnable task3 = () -> {}; |
||||||
|
assertThat(queue.offer(task1)).isTrue(); |
||||||
|
assertThat(queue.size()).isEqualTo(1); |
||||||
|
assertThat(queue).contains(task1); |
||||||
|
assertThat(queue.offer(task2)).isTrue(); |
||||||
|
assertThat(queue.size()).isEqualTo(2); |
||||||
|
assertThat(queue).contains(task2); |
||||||
|
assertThat(queue.offer(task3)).isTrue(); |
||||||
|
assertThat(queue).doesNotContain(task1); |
||||||
|
assertThat(queue).contains(task2); |
||||||
|
assertThat(queue).contains(task3); |
||||||
|
assertThat(queue.size()).isEqualTo(2); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue