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