net.sf.eBus.config.ENetConfigure Maven / Gradle / Ivy
//
// Copyright 2015, 2016 Charles W. Rapp
//
// 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 net.sf.eBus.config;
import com.google.common.base.Strings;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigException;
import com.typesafe.config.ConfigFactory;
import com.typesafe.config.ConfigObject;
import java.io.File;
import java.time.Duration;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* This immutable class contains selector thread configuration
* extracted from properties. Selector threads configuration is
* taken from the typesafe JSON file specified by the command
* line parameter
* {@code -Dnet.sf.eBus.config.jsonFile=}<conf file path>.
* Selector threads may not be created at runtime but
* only on JVM start up. That said, selector threads are not
* started on JVM start time but only when its name referenced by
* an {@code AsyncChannel}. So if no channels use the selector
* during an application run, then the thread is never started.
*
* Selector thread configuration uses the following property
* keys:
*
*
* -
* {@code eBus.net.selectors}: a comma-separated list of
* selector thread names. The names should be unique (no
* duplicates). All duplicates are logged and ignored. The
* selector thread name is used to retrieve the remaining
* keys.
*
* -
* {@code eBus.net.selector}.name.{@code type}:
* The selector thread type must be one of {@link ThreadType}.
*
* This property is required.
*
*
* -
* {@code eBus.net.selector}.name.{@code isDefault}:
* Set to "true" if this is the default selector. The default
* selector is used by all {@code AsyncChannels} not
* explicitly assigned to a selector. If multiple selectors
* are designated as the default, then it cannot be determined
* which selector will be used as the default.
*
* The default value for this setting is {@code false}.
*
*
* -
* {@code eBus.net.selector}.name.{@code priority}:
* The selector thread runs at this thread priority. The
* specified value must be ≥ {@link Thread#MIN_PRIORITY}
* and ≤ {@link Thread#MAX_PRIORITY}.
*
* The default value for this setting is
* {@link Thread#NORM_PRIORITY}.
*
*
* -
* {@code eBus.net.selector}.name.{@code spinLimit}:
* If {@code type} is {@link ThreadType#SPINPARK}, then this
* property specifies the number of times the thread will spin
* on {@link java.nio.channels.Selector#selectNow()} before
* parking.
*
* The default value is {@link #DEFAULT_SPIN_LIMIT}.
*
*
* -
* {@code eBus.net.selector}.name.{@code parkTime}:
* If {@code type} is {@link ThreadType#SPINPARK}, then this
* property specifies the number of nanoseconds the thread
* will park before returning to spinning.
*
* The default value is {@link #DEFAULT_PARK_TIME}.
*
*
*
*
*
*
* Example select thread configuration:
*
* selectors : [
{
name : faster // required, must be unique.
type : spinning // required.
isDefault : false // optional, defaults to false.
priority : 10 // optional, defaults to Thread.NORM_PRIORITY
},
{
name : slower
type" : "spin+park"
isDefault : true
priority : 7
spinLimit : 1000000
parkTime : 500ns
}
]
*
* @see SelectorInfo
* @see SelectorInfoBuilder
*
* @author Charles W. Rapp
*/
public final class ENetConfigure
{
//---------------------------------------------------------------
// Member data.
//
//-----------------------------------------------------------
// Constants.
//
/**
* The minimum allowed port number is zero.
*/
public static final int MIN_PORT = 0;
/**
* The maximum allowed port number is 65,535.
*/
public static final int MAX_PORT = 65535;
/**
* Use the value {@value} to specify socket is opened and
* bound to any port.
*/
public static final int ANY_PORT = 0;
//
// System property keys.
//
// Property keys.
/**
* The key {@code eBus.net.selectors} contains a
* comma-separated list of selector thread names.
*/
public static final String SELECTORS_KEY = "selectors";
/**
* Selector keys are prefixed by {@code eBus.net.selector.}
* and followed by a selector thread, which must appear in
* the {@link #SELECTORS_KEY} property.
*/
public static final String SELECTOR_PREFIX =
"eBus.net.selector";
/**
* The {@value} property is used to specify the unique
* selector name. Uniqueness is within the JVM.
*
* This property is required.
*
*/
public static final String NAME_KEY = "name";
/**
* The {@link ThreadType type} property is used to specify
* the {@code ESelector} used with the selector thread.
*
* This property is required.
*
*/
public static final String TYPE_KEY = "type";
/**
* The boolean {@value} property is used to
* specify when this selector thread should be used as the
* default selector thread. At most one selector should be
* designated as the default selector. If more than one is
* so designated, the subsequent {@code .isDefault} keys are
* ignored.
*
* If no user-defined selector is marked as default, then
* a {@link ThreadType#BLOCKING blocking},
* {@link Thread#NORM_PRIORITY normal priority} selector
* named {@code AsyncChannel.sDefaultSelector} is used as the
* default selector.
*
*
* The default value is {@code false}
* (not the default selector).
*
*/
public static final String DEFAULT_KEY = "isDefault";
/**
* The integer {@value} property is used to
* set the select thread priority.
*
* The default value is {@link Thread#NORM_PRIORITY}.
*
*/
public static final String PRIORITY_KEY = "priority";
/**
* If the selector type is
* {@link ThreadType#SPINPARK spin+park}, then the
* integer {@value} property may be specified. This
* setting defines the number of times the selector thread
* may call
* {@link java.nio.channels.Selector#selectNow()} before
* parking.
*
* This value must be > zero.
*
*
* Default values is {@link #DEFAULT_SPIN_LIMIT}.
*
*
* This property is ignored is the selector type is not
* spin+park.
*
*/
public static final String SPIN_LIMIT_KEY = "spinLimit";
/**
* If the selector type is
* {@link ThreadType#SPINPARK spin+park}, then the
* integer {@value} property may be specified. This
* setting specifies the nanosecond park time taken
* between
* {@link java.nio.channels.Selector#selectNow()} spin
* cycles.
*
* This value must be > zero.
*
*
* Default values is {@link #DEFAULT_PARK_TIME}.
*
*
* This property is ignored is the selector type is not
* spin+park.
*
*/
public static final String PARK_TIME_KEY = "parkTime";
/**
* Optional thread affinity configuration. May be
* {@code null}. Thread affinity is best used when thread
* type is {@link ThreadType#SPINNING}.
*/
public static final String AFFINITY_KEY = "threadAffinity";
//
// Default values.
//
/**
* The default selector thread priority is
* {@link Thread#NORM_PRIORITY normal}.
*/
public static final int DEFAULT_PRIORITY =
Thread.NORM_PRIORITY;
/**
* The default select spin limit is {@value} calls to
* {@link java.nio.channels.Selector#selectNow()} before
* parking the thread.
*/
public static final int DEFAULT_SPIN_LIMIT = 2_500_000;
/**
* The default thread park time is 1 microsecond.
*/
public static final Duration DEFAULT_PARK_TIME =
Duration.ofNanos(1_000L);
/**
* The default input and output socket buffer size is
* {@value} bytes.
*/
public static final int DEFAULT_BUFFER_SIZE = 2_048;
/**
* The default selector type is
* {@link ThreadType#BLOCKING}.
*/
public static final ThreadType DEFAULT_SELECTOR_TYPE =
ThreadType.BLOCKING;
/**
* The default selector thread name is "__DEFAULT__".
* The default selector type is
* {@link ThreadType#BLOCKING blocking}.
*/
private static final String DEFAULT_SELECTOR =
"eBus:selectorThread:__DEFAULT__";
//-----------------------------------------------------------
// Statics.
//
/**
* The default selector name as defined in the eBus
* configuration file.
*/
private static SelectorInfo sDefaultSelector;
/**
* The user-defined selectors mapped by selector name.
* May be empty.
*/
private static Map sSelectors;
// Class static initialization
static
{
final String jsonFile =
System.getProperty(EConfigure.JSON_FILE_ENV);
sDefaultSelector = null;
// Load the eBus configuration if specified on the
// command line and fill in the selectors.
if (!Strings.isNullOrEmpty(jsonFile))
{
loadJsonFile(jsonFile);
}
// Was a default selector specified?
if (sDefaultSelector == null)
{
// No. Then set the default selector information to
// a blocking selector with normal priority.
final SelectorInfoBuilder builder =
new SelectorInfoBuilder();
sDefaultSelector = builder.name(DEFAULT_SELECTOR)
.type(DEFAULT_SELECTOR_TYPE)
.isDefault(true)
.priority(Thread.NORM_PRIORITY)
.build();
}
if (sSelectors == null)
{
final Map selectors =
new HashMap<>(1);
selectors.put(
sDefaultSelector.name(), sDefaultSelector);
sSelectors = Collections.unmodifiableMap(selectors);
}
} // end of class static initialization.
//---------------------------------------------------------------
// Member methods.
//
//-----------------------------------------------------------
// Constructors.
//
/**
* Private constructor to prevent instantiation.
*/
private ENetConfigure()
{}
//
// end of Constructors.
//-----------------------------------------------------------
//-----------------------------------------------------------
// Get Methods.
//
public static SelectorInfo defaultSelector()
{
return (sDefaultSelector);
} // end of defaultSelector()
/**
* Returns {@code true} if {@code name} is a known selector
* and {@code false} if not known.
* @param name the name to be checked.
* @return {@code true} if {@code name} is a known selector.
*/
public static boolean isKnownSelector(final String name)
{
return (sSelectors.containsKey(name));
} // end of isKnownSelector(String)
/**
* Returns the selector for the given name;
* returns {@code null} if {@code name} does not reference
* a known selector.
* @param name selector name.
* @return configured selector information.
*/
public static SelectorInfo selector(final String name)
{
return (sSelectors.get(name));
} // end of selector(String)
/**
* Returns the selector thread configurations. The returned
* list is unmodifiable.
* @return selector thread configurations.
*/
public static Map selectors()
{
return (sSelectors);
} // end of selectors()
/**
* Returns the loaded network configuration as text.
* @return textual representation of network configuration.
*/
public static String asText()
{
String sep = "";
final StringBuilder retval = new StringBuilder();
for (SelectorInfo info : sSelectors.values())
{
retval.append(sep).append(info);
sep = "\n";
}
return (retval.toString());
} // end of asText()
//
// end of Get Methods.
//-----------------------------------------------------------
/**
* Returns a selector thread configuration extracted from the
* given JSON properties.
* @param config JSON configuration.
*/
public static void load(final Config config)
{
SelectorInfo selector;
final Map selectors =
new HashMap<>();
// Are any selectors defined?
if (config.hasPath(SELECTORS_KEY))
{
// Yes. Load each selector in turn.
for (ConfigObject co :
config.getObjectList(SELECTORS_KEY))
{
selector = loadInfo(co.toConfig());
selectors.put(selector.name(), selector);
}
}
sSelectors = Collections.unmodifiableMap(selectors);
} // end of load(Config)
/**
* Returns a builder used to create a {@link SelectorInfo}
* instance.
* @return {@link SelectorInfo} builder.
*/
public static SelectorInfoBuilder selectorBuilder()
{
return (new SelectorInfoBuilder());
} // end of selectorBuilder()
/**
* Sets the eBus network selectors to the given map. Used for
* testing purposes only.
* @param selectors network selectors map.
* @throws IllegalArgumentException
* if {@code selectors} is either {@code null} or empty.
*/
/* package */ static void load(final Map selectors)
{
if (selectors == null || selectors.isEmpty())
{
throw (
new IllegalArgumentException(
"selectors is null or empty"));
}
sSelectors = Collections.unmodifiableMap(selectors);
selectors.values()
.stream()
.filter(selector -> (selector.isDefault()))
.forEachOrdered(
selector -> sDefaultSelector = selector);
} // end of load(Map)
/**
* Initializes the eBus network configuration from the
* typesafe JSON configuration file.
* @param jsonFileName JSON configuration file.
*/
private static void loadJsonFile(final String jsonFileName)
{
final File jsonFile = new File(jsonFileName);
final Config netConfig =
ConfigFactory.parseFile(jsonFile);
ENetConfigure.load(netConfig);
} // end of loadJsonFile(String)
/**
* Returns a single {@link SelectorInfo} instance loaded
* from the given JSON configuration.
* @param config JSON configuration for a single selector.
* @return selector information.
* @throws ConfigException
* if {@code config} contains an invalid selector
* configuration.
*/
private static SelectorInfo loadInfo(final Config config)
{
final String value = config.getString(TYPE_KEY);
final ThreadType type = ThreadType.find(value);
final SelectorInfoBuilder builder =
new SelectorInfoBuilder();
if (type == null)
{
throw (
new ConfigException.BadValue(
TYPE_KEY,
"\"" + value + "\" is not a valid selector type"));
}
builder.name(config.getString(NAME_KEY))
.type(type)
.isDefault(config.getBoolean(DEFAULT_KEY))
.priority(config.hasPath(PRIORITY_KEY) ?
config.getInt(PRIORITY_KEY) :
DEFAULT_PRIORITY)
.threadAffinity(
ThreadAffinityConfigure.loadAffinity(
AFFINITY_KEY, config));
if (builder.mType == ThreadType.SPINPARK ||
builder.mType == ThreadType.SPINYIELD)
{
builder.spinLimit(config.hasPath(SPIN_LIMIT_KEY) ?
config.getLong(SPIN_LIMIT_KEY) :
DEFAULT_SPIN_LIMIT);
}
if (builder.mType == ThreadType.SPINPARK)
{
builder.parkTime(config.hasPath(PARK_TIME_KEY) ?
config.getDuration(PARK_TIME_KEY) :
DEFAULT_PARK_TIME);
}
return (builder.build());
} // end of loadInfo(Config)
//---------------------------------------------------------------
// Inner classes.
//
/**
* Constructs an {@link SelectorInfo} instance based on the
* parameters set via the builder's API. The minimally
* allowed configuration is based on the selector's thread
* type. In all cases a unique selector name and type must be
* provided. The selector parameters are:
*
* -
* name: unique selector name.
* Uniqueness is within the JVM.
*
* Required: Yes.
*
*
* -
* type: selector
* {@link ThreadType thread type}.
*
* Required: Yes.
*
*
* -
* isDefault: if set to {@code true},
* then this is the default selector for all channels
* which do not specify a selector.
*
* Required: No.
*
*
* Default Setting: {@code false}.
*
*
* -
* priority: the selector thread's
* priority. Should be one of {@link Thread#MIN_PRIORITY},
* {@link Thread#NORM_PRIORITY}, or
* {@link Thread#MAX_PRIORITY}.
*
* Required: No.
*
*
* Default Setting:
* {@link #DEFAULT_PRIORITY}.
*
*
* -
* spinLimit: number of times a selector
* thread may spin before parking.
*
* Required: No.
*
*
* Default Setting:
* {@link #DEFAULT_SPIN_LIMIT}.
*
*
* -
* parkTime: nanosecond duration for a
* selector park.
*
* Required: No.
*
*
* Default Setting:
* {@link #DEFAULT_PARK_TIME}.
*
*
* -
* threadAffinity:
* {@link ThreadAffinityConfigure} used to associate
* selector thread with a core. Thread affinity should be
* considered when using a spinning thread type.
*
* Required: No.
*
*
* Default Setting: {@code null}.
*
*
*
* Example building a {@code SelectorInfo}
* final ENetConfigure.SelectorInfoBuilder builder = ENetConfigure.selectorBuilder();
* final ENetConfigure.SelectorInfo selectorInfo = builder.name("app_selector")
* .type(ThreadType.SPINPARK)
* .isDefault(true)
* .spinLimit(2_000_000L)
* .parkTime(500L)
* .build();
*/
public static final class SelectorInfoBuilder
{
//-----------------------------------------------------------
// Member data.
//
//-------------------------------------------------------
// Locals.
//
/**
* The selector thread's unique name.
*/
private String mName;
/**
* The select thread's encapsulated {@link ESelector}
* type.
*/
private ThreadType mType;
/**
* {@code true} if this selector thread is used as the
* default.
*/
private boolean mIsDefault;
/**
* The selector thread priority.
*/
private int mPriority;
/**
* The spin limit for a
* {@link ThreadType#SPINPARK spin+park} selector
* type.
*/
private long mSpinLimit;
/**
* The park time for a
* {@link ThreadType#SPINPARK spin+park} selector
* type.
*/
private Duration mParkTime;
/**
* Optional thread affinity configuration. Defaults to
* {@code null}. Thread affinity should be considered
* when using {@link ThreadType#SPINNING} thread type.
*/
private ThreadAffinityConfigure mAffinity;
//-----------------------------------------------------------
// Member methods.
//
//-------------------------------------------------------
// Constructors.
//
/**
* Creates a {@link SelectorInfo} builder setting fields
* to default values.
*/
private SelectorInfoBuilder()
{
mName = null;
mType = null;
mPriority = DEFAULT_PRIORITY;
mIsDefault = false;
mSpinLimit = 0L;
mParkTime = Duration.ZERO;
} // end of SelectorInfoBuilder()
//
// end of Constructors.
//-------------------------------------------------------
//-------------------------------------------------------
// Set Methods.
//
/**
* Sets the selector name to the given value.
* @param name selector name.
* @return {@code this SelectorInfoBuilder}.
* @throws ConfigException
* if {@code name} is either {@code null} or an empty
* string.
*/
public SelectorInfoBuilder name(final String name)
{
if (Strings.isNullOrEmpty(name))
{
throw (
new ConfigException.BadValue(
NAME_KEY,
"\"" + name + "\" is null or empty"));
}
mName = name;
return (this);
} // end of name(String)
/**
* Sets the selector thread type to the given value.
* @param type selector thread type.
* @return {@code this SelectorInfoBuilder}.
* @throws ConfigException
* if {@code type} is {@code null}.
*/
public SelectorInfoBuilder type(final ThreadType type)
{
if (type == null)
{
throw (
new ConfigException.BadValue(
EConfigure.THREAD_TYPE_KEY,
"type is null"));
}
mType = type;
return (this);
} // end of type(ThreadType)
/**
* Sets the selector flag marking whether this is the
* default selector or not.
* @param flag {@code true} if this is the default
* selector thread.
* @return {@code this SelectorInfoBuilder}.
*/
public SelectorInfoBuilder isDefault(final boolean flag)
{
mIsDefault = flag;
return (this);
} // end of isDefault(boolean)
/**
* Sets the selector thread priority to the given value.
* @param priority thread priority.
* @return {@code this SelectorInfoBuilder}.
* @throws ConfigException
* if {@code priority} is < {@link Thread#MIN_PRIORITY}
* or > {@link Thread#MAX_PRIORITY}.
*/
public SelectorInfoBuilder priority(final int priority)
{
if (priority < Thread.MIN_PRIORITY ||
priority > Thread.MAX_PRIORITY)
{
throw (
new ConfigException.BadValue(
PRIORITY_KEY,
String.format(
"%d is not valid; must be >= %d and <= %d",
priority,
Thread.MIN_PRIORITY,
Thread.MAX_PRIORITY)));
}
mPriority = priority;
return (this);
} // end of priority(int)
/**
* Sets a spinning selector thread's spin limit.
* @param limit number of time the thread may spin on
* select before parking.
* @return {@code this SelectorInfoBuilder}.
* @throws ConfigException
* if {@code limit} is ≤ zero.
*/
public SelectorInfoBuilder spinLimit(final long limit)
{
if (limit < 0L)
{
throw (
new ConfigException.BadValue(
SPIN_LIMIT_KEY, limit + " < zero"));
}
// If the spin limit is zero, then use the default
// setting.
mSpinLimit =
(limit == 0L ? DEFAULT_SPIN_LIMIT : limit);
return (this);
} // end of spinLimit(long)
/**
* Sets a spin+park selector thread's park time.
* @param time nanosecond thread park time.
* @return {@code this SelectorInfoBuilder}.
* @throws ConfigException
* if {@code time} is {@code null} or ≤ zero.
*/
public SelectorInfoBuilder parkTime(final Duration time)
{
if (time == null)
{
throw (
new ConfigException.BadValue(
PARK_TIME_KEY, time + " is null"));
}
if (time.isNegative())
{
throw (
new ConfigException.BadValue(
PARK_TIME_KEY, time + " < zero"));
}
// If the park time is zero, then use the default
// setting.
mParkTime =
(time.isZero() ? DEFAULT_PARK_TIME : time);
return (this);
} // end of parkTime(Duration)
/**
* Sets thread affinity configuration.
* @param affinity thread affinity configuration. May be
* {@code null}.
* @return {@code this SelectorInfoBuilder}.
*/
public SelectorInfoBuilder threadAffinity(final ThreadAffinityConfigure affinity)
{
mAffinity = affinity;
return (this);
} // end of threadAffinity(ThreadAffinityConfigure)
//
// end of Set Methods.
//-------------------------------------------------------
/**
* Returns the {@link SelectorInfo} instance created from
* the configuration settings. Sets spin limit for
* spin/park and spin/yield thread types to
* {@link #DEFAULT_SPIN_LIMIT} if spin limit is not set.
* Sets park time to {@link #DEFAULT_PARK_TIME} if not
* configured for spin/park thread type.
* @return {@code SelectorInfo} instance.
* @throws ConfigException
* if {@code SelectorInfo} configuration is invalid.
*/
public SelectorInfo build()
{
validate();
// If spin limit and park time are not set, then
// use the default settings.
if ((mType == ThreadType.SPINPARK ||
mType == ThreadType.SPINYIELD) &&
mSpinLimit == 0L)
{
mSpinLimit = DEFAULT_SPIN_LIMIT;
}
if (mType == ThreadType.SPINPARK &&
mParkTime.isZero())
{
mParkTime = DEFAULT_PARK_TIME;
}
return (new SelectorInfo(this));
} // end of build()
/**
* This method validates the selector configuration and
* returns if the configuration passes. Otherwise throws
* an {@code ConfigException}. This method is called for
* effect only.
* @throws ConfigException
* if {@code SelectorInfo} configuration is invalid.
*/
private void validate()
{
if (mName == null)
{
throw (
new ConfigException.BadValue(
NAME_KEY,
"selector name not configured"));
}
if (mType == null)
{
throw (
new ConfigException.BadValue(
TYPE_KEY,
"selector type not configured"));
}
} // end of validate()
} // end of class SelectorInfoBuilder
/**
* This immutable class contains the selector thread
* configuration for the named selector. This includes:
*
* -
* a unique selector name,
*
* -
* the selector {@link ThreadType thread type},
*
* -
* a flag specifying whether this is the default selector
* or not,
*
* -
* the spin limit used for {@link ThreadType#SPINPARK}
* and {@link ThreadType#SPINYIELD} selectors, and
*
* -
* the nanosecond park time limit used for
* {@link ThreadType#SPINPARK} selectors.
*
*
*
* An example {@code SelectorInfo} configuration follows:
*
* name : s1
type : "spin+park"
isDefault : true
priority : 7
spinLimit : 1000000
parkTime : 500ns
*/
public static final class SelectorInfo
implements Comparable
{
//-----------------------------------------------------------
// Member data.
//
//-------------------------------------------------------
// Locals.
//
/**
* The selector thread's unique name.
*/
private final String mName;
/**
* The select thread's encapsulated {@link ESelector}
* type.
*/
private final ThreadType mType;
/**
* {@code true} if this selector thread is used as the
* default.
*/
private final boolean mIsDefault;
/**
* The selector thread priority.
*/
private final int mPriority;
/**
* The spin limit for a
* {@link ThreadType#SPINPARK spin+park} selector
* type.
*/
private final long mSpinLimit;
/**
* The park time for a
* {@link ThreadType#SPINPARK spin+park} selector
* type.
*/
private final Duration mParkTime;
/**
* Optional thread affinity configuration. Defaults to
* {@code null}. Thread affinity should be considered
* when using {@link ThreadType#SPINNING} thread type.
*/
private final ThreadAffinityConfigure mAffinity;
//-----------------------------------------------------------
// Member methods.
//
//-------------------------------------------------------
// Constructors.
//
/**
* Creates a new selector thread configuration from the
* given builder settings.
* @param builder contains selector thread settings.
*/
private SelectorInfo(final SelectorInfoBuilder builder)
{
mName = builder.mName;
mType = builder.mType;
mIsDefault = builder.mIsDefault;
mPriority = builder.mPriority;
mSpinLimit = builder.mSpinLimit;
mParkTime = builder.mParkTime;
mAffinity = builder.mAffinity;
} // end of SelectorInfo(...)
//
// end of Constructors.
//-------------------------------------------------------
//-------------------------------------------------------
// Comparable Interface Implementation.
//
/**
* Compares {@code this} object with the specified
* selector. Returns negative, zero, or positive integer
* value based on whether {@code this} object is <,
* equal to, or > {@code selector}. Comparison is
* based on on the selector name.
* @param selector object used in the comparison.
* @return a negative, zero, or positive integer value.
*/
@Override
public int compareTo(final SelectorInfo selector)
{
return (mName.compareTo(selector.mName));
} // end of compareTo(SelectorInfo)
//
// end of Comparable Interface Implementation.
//-------------------------------------------------------
//-------------------------------------------------------
// Object Method Overrides.
//
/**
* Returns {@code true} if {@code this} object equals
* {@code o} and {@code false} otherwise. Comparison is
* based on the name, thread type, "is default" flag,
* thread priority, spin limit and park time.
* @param o comparison object.
* @return {@code true} if {@code o} is a
* {@code SelectorInfo} instance with the same settings
* as {@code this SelectorInfo} instance.
*/
@Override
public boolean equals(final Object o)
{
boolean retcode = (this == o);
if (!retcode && o instanceof SelectorInfo)
{
final SelectorInfo si = (SelectorInfo) o;
retcode = (mName.equals(si.name()) &&
mType == si.type() &&
mIsDefault == si.isDefault() &&
mPriority == si.priority() &&
mSpinLimit == si.spinLimit() &&
Objects.equals(
mParkTime, si.mParkTime) &&
Objects.equals(mAffinity, si.mAffinity));
}
return (retcode);
} // end of equals(Object)
/**
* Returns a hash code for this object. The hash is based
* on the selector name, thread type, "is default" flag,
* thread priority, spin limit, and park time.
* @return object hash code.
*/
@Override
public int hashCode()
{
return (Objects.hash(mName,
mType,
mIsDefault,
mPriority,
mSpinLimit,
mParkTime,
mAffinity));
} // end of hashCode()
/**
* Returns a string representation of this selector
* info.
* @return object string representation.
*/
@Override
public String toString()
{
final StringBuilder retval = new StringBuilder();
retval.append('[')
.append(mName)
.append("]\nselector type: ")
.append(mType)
.append("\n priority: ")
.append(mPriority)
.append("\n is default: ")
.append(mIsDefault);
if (mType == ThreadType.SPINPARK)
{
retval.append("\n spin limit: ")
.append(String.format("%,d", mSpinLimit))
.append("\n park time: ")
.append(mParkTime);
}
if (mAffinity != null)
{
retval.append("\n affinity: ")
.append(mAffinity);
}
return (retval.toString());
} // end of toString()
//
// end of Object Method Overrides.
//-------------------------------------------------------
//-------------------------------------------------------
// Get Methods.
//
/**
* Returns the unique selector thread name.
* @return selector thread name.
*/
public String name()
{
return (mName);
} // end of name()
/**
* Returns the {@code ESelector} type.
* @return selector type.
*/
public ThreadType type()
{
return (mType);
} // end of type()
/**
* Returns {@code true} if this user-defined selector
* thread is the default selector.
* @return {@code true} if the default selector thread.
*/
public boolean isDefault()
{
return (mIsDefault);
} // end of isDefault()
/**
* Returns the selector thread priority.
* @return thread priority.
*/
public int priority()
{
return (mPriority);
} // end of priority()
/**
* Returns a spin+park {@code ESelector} spin limit.
* @return spin limit.
*/
public long spinLimit()
{
return (mSpinLimit);
} // end of spinLimit()
/**
* Returns the spin+park park time limit.
* @return park time limit.
*/
public Duration parkTime()
{
return (mParkTime);
} // end of parkTime()
/**
* Returns thread affinity and {@code null} if no
* affinity is set. This affinity is used to associate a
* thread with a particular CPU.
* @return thread affinity.
*/
public ThreadAffinityConfigure affinity()
{
return (mAffinity);
} // end of affinity()
//
// end of Get Methods.
//-------------------------------------------------------
} // end of class SelectorInfo
} // end of class ENetConfigure