All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.swirlds.common.wiring.schedulers.TaskScheduler Maven / Gradle / Ivy

Go to download

Swirlds is a software platform designed to build fully-distributed applications that harness the power of the cloud without servers. Now you can develop applications with fairness in decision making, speed, trust and reliability, at a fraction of the cost of traditional server-based platforms.

There is a newer version: 0.56.6
Show newest version
/*
 * Copyright (C) 2023-2024 Hedera Hashgraph, LLC
 *
 * 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 com.swirlds.common.wiring.schedulers;

import com.swirlds.common.wiring.counters.ObjectCounter;
import com.swirlds.common.wiring.model.TraceableWiringModel;
import com.swirlds.common.wiring.schedulers.builders.TaskSchedulerBuilder;
import com.swirlds.common.wiring.schedulers.builders.TaskSchedulerType;
import com.swirlds.common.wiring.schedulers.internal.DefaultSquelcher;
import com.swirlds.common.wiring.schedulers.internal.Squelcher;
import com.swirlds.common.wiring.schedulers.internal.ThrowingSquelcher;
import com.swirlds.common.wiring.wires.input.BindableInputWire;
import com.swirlds.common.wiring.wires.input.InputWire;
import com.swirlds.common.wiring.wires.input.TaskSchedulerInput;
import com.swirlds.common.wiring.wires.output.OutputWire;
import com.swirlds.common.wiring.wires.output.StandardOutputWire;
import edu.umd.cs.findbugs.annotations.NonNull;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;

/**
 * Schedules tasks for a component.
 * 

* The lifecycle of a task is as follows: *

    *
  1. Unscheduled: the task has not been passed to the scheduler yet (e.g. via {@link InputWire#put(Object)})
  2. *
  3. Scheduled but not processed: the task has been passed to the scheduler but the corresponding handler has not * yet returned (either because the handler has not yet been called or because the handler has been called but hasn't * finished yet)
  4. *
  5. Processed: the corresponding handle method for the task has been called and has returned.
  6. *
* * @param the output type of the primary output wire (use {@link Void} if no output is needed) */ public abstract class TaskScheduler extends TaskSchedulerInput { private final boolean flushEnabled; private final TraceableWiringModel model; private final String name; private final TaskSchedulerType type; private final StandardOutputWire primaryOutputWire; private final boolean insertionIsBlocking; /** * Handles squelching for this task scheduler. Will be a valid object whether or not squelching is enabled for this * task scheduler. */ private final Squelcher squelcher; /** * Constructor. * * @param model the wiring model containing this task scheduler * @param name the name of the task scheduler * @param type the type of task scheduler * @param flushEnabled if true, then {@link #flush()} will be enabled, otherwise it will throw. * @param squelchingEnabled if true, then squelching will be enabled, otherwise trying to squelch will throw. * @param insertionIsBlocking when data is inserted into this task scheduler, will it block until capacity is * available? */ protected TaskScheduler( @NonNull final TraceableWiringModel model, @NonNull final String name, @NonNull final TaskSchedulerType type, final boolean flushEnabled, final boolean squelchingEnabled, final boolean insertionIsBlocking) { this.model = Objects.requireNonNull(model); this.name = Objects.requireNonNull(name); this.type = Objects.requireNonNull(type); this.flushEnabled = flushEnabled; if (squelchingEnabled) { this.squelcher = new DefaultSquelcher(); } else { this.squelcher = new ThrowingSquelcher(); } primaryOutputWire = buildPrimaryOutputWire(model, name); this.insertionIsBlocking = insertionIsBlocking; } /** * Build an input wire for passing data to this task scheduler. In order to use this wire, a handler must be bound * via {@link BindableInputWire#bind(Function)} {@link BindableInputWire#bindConsumer(Consumer)}. * * @param name the name of the input wire * @param the type of data that is inserted via this input wire * @return the input wire */ @NonNull public BindableInputWire buildInputWire(@NonNull final String name) { return new BindableInputWire<>(model, this, name); } /** * Build the primary output wire for this scheduler. * * @param model the wiring model that contains this scheduler * @param name the name of this scheduler * @return the primary output wire */ @NonNull protected StandardOutputWire buildPrimaryOutputWire( @NonNull final TraceableWiringModel model, @NonNull final String name) { return new StandardOutputWire<>(model, name); } /** * Get the default output wire for this task scheduler. Sometimes referred to as the "primary" output wire. All data * returned by handlers is passed ot this output wire. Calling this method more than once will always return the * same object. * * @return the primary output wire */ @NonNull public OutputWire getOutputWire() { return primaryOutputWire; } /** * By default a component has a single output wire (i.e. the primary output wire). This method allows additional * output wires to be created. * *

* Unlike primary wires, secondary output wires need to be passed to a component's constructor. It is considered a * violation of convention to push data into a secondary output wire from any code that is not executing within this * task scheduler. * * @param the type of data that is transmitted over this output wire * @return the secondary output wire */ @NonNull public StandardOutputWire buildSecondaryOutputWire() { // Intentionally do not register this with the model. Connections using this output wire will be represented // in the model in the same way as connections to the primary output wire. return new StandardOutputWire<>(model, name); } /** * Get the name of this task scheduler. * * @return the name of this task scheduler */ @NonNull public String getName() { return name; } /** * Get the type of this task scheduler. * * @return the type of this task scheduler */ @NonNull public TaskSchedulerType getType() { return type; } /** * Get whether or not this task scheduler can block when data is inserted into it. * * @return true if this task scheduler can block when data is inserted into it, false otherwise */ public boolean isInsertionBlocking() { return insertionIsBlocking; } /** * Cast this scheduler into whatever a variable is expecting. Sometimes the compiler gets confused with generics, * and path of least resistance is to just cast to the proper data type. * *

* Warning: this will appease the compiler, but it is possible to cast a scheduler into a data type that will cause * runtime exceptions. Use with appropriate caution. * * @param the type to cast to * @return this, cast into whatever type is requested */ @NonNull @SuppressWarnings("unchecked") public final TaskScheduler cast() { return (TaskScheduler) this; } /** * Get the number of unprocessed tasks. A task is considered to be unprocessed until the data has been passed to the * handler method (i.e. the one given to {@link BindableInputWire#bind(Function)} or * {@link BindableInputWire#bindConsumer(Consumer)}) and that handler method has returned. *

* Returns {@link ObjectCounter#COUNT_UNDEFINED} if this task scheduler is not monitoring the number of unprocessed * tasks. Schedulers do not track the number of unprocessed tasks by default. This method will always return * {@link ObjectCounter#COUNT_UNDEFINED} unless one of the following is true: *

    *
  • {@link TaskSchedulerBuilder#withUnhandledTaskMetricEnabled(boolean)} is called with the value * true
  • *
  • {@link TaskSchedulerBuilder#withUnhandledTaskCapacity(long)} is passed a positive value
  • *
  • {@link TaskSchedulerBuilder#withOnRamp(ObjectCounter)} is passed a counter that is not a no op counter
  • *
*/ public abstract long getUnprocessedTaskCount(); /** * Get this task scheduler's desired maximum desired capacity. If {@link TaskSchedulerBuilder#UNLIMITED_CAPACITY} is * returned, then this task scheduler does not have a maximum capacity. * * @return the maximum desired capacity of this task scheduler */ public abstract long getCapacity(); /** * Flush all data in the task scheduler. Blocks until all data currently in flight has been processed. * *

* Note: must be enabled by passing true to {@link TaskSchedulerBuilder#withFlushingEnabled(boolean)}. * *

* Warning: some implementations of flush may block indefinitely if new work is continuously added to the scheduler * while flushing. Such implementations are guaranteed to finish flushing once new work is no longer being added. * Some implementations do not have this restriction, and will return as soon as all of the in flight work has been * processed, regardless of whether or not new work is being added. * * @throws UnsupportedOperationException if {@link TaskSchedulerBuilder#withFlushingEnabled(boolean)} was set to * false (or was unset, default is false) */ public abstract void flush(); /** * Throw an {@link UnsupportedOperationException} if flushing is not enabled. */ protected final void throwIfFlushDisabled() { if (!flushEnabled) { throw new UnsupportedOperationException("Flushing is not enabled for the task scheduler " + name); } } /** * Start squelching, and continue doing so until {@link #stopSquelching()} is called. * * @throws UnsupportedOperationException if squelching is not supported by this scheduler * @throws IllegalStateException if scheduler is already squelching */ public void startSquelching() { squelcher.startSquelching(); } /** * Stop squelching. * * @throws UnsupportedOperationException if squelching is not supported by this scheduler * @throws IllegalStateException if scheduler is not currently squelching */ public void stopSquelching() { squelcher.stopSquelching(); } /** * Get whether or not this task scheduler is currently squelching. * * @return true if this task scheduler is currently squelching, false otherwise */ public final boolean currentlySquelching() { return squelcher.shouldSquelch(); } /** * {@inheritDoc} */ @Override protected void forward(@NonNull final OUT data) { primaryOutputWire.forward(data); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy