Skip to content

Commit

Permalink
Pinned executors (#12)
Browse files Browse the repository at this point in the history
* Added Pinned.current() utility method

* Fixed checkstyle formatting
Upgraded detekt version

* Simplified executors interface

* Added snyk badge

* Test fixes

* Needle formatting fixes

* Fixed detekt errors

* Detekt fixes

* Detekt fixes

* Codecov reduction threshold addition

* codecov.yml fixes

* codecov.yml fixes

* codecov.yml fixes
  • Loading branch information
sheinbergon authored Oct 17, 2020
1 parent 2d8d53c commit 5081f48
Show file tree
Hide file tree
Showing 24 changed files with 409 additions and 570 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/sheinbergon/needle/multi-platform-ci?logo=github&style=for-the-badge)](https://github.com/sheinbergon/needle/actions?query=workflow%3Amulti-platform-ci)
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/sheinbergon/needle?color=%2340E0D0&logo=github&style=for-the-badge)](https://github.com/sheinbergon/needle/releases/latest)
[![Maven Central](https://img.shields.io/maven-central/v/org.sheinbergon/needle-core?color=Crimson&logo=Apache%20Maven&style=for-the-badge)](https://search.maven.org/search?q=g:org.sheinbergon%20a:needle*)
[![Snyk](https://img.shields.io/snyk/vulnerabilities/github/sheinbergon/needle?color=%2340E0D0&label=Snyk&logo=snyk&logoColor=silver&style=for-the-badge)](https://snyk.io/test/github/sheinbergon/needle?targetFile=build.gradle)


**Needle** provides feature rich core affinity support for the JVM,
focusing on ease of integration and extensibility
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,53 @@ public class NeedleAgentConfiguration {
*/
public static final NeedleAgentConfiguration DEFAULT = new NeedleAgentConfiguration()
.defaultAffinity(AffinityDescriptor.from(NumberUtils.LONG_ZERO));
/**
* A collection of affinity group descriptors used to match different affinity descriptors to threads upon
* instantiation.
*/
@Nullable
private List<AffinityGroup> affinityGroups;
/**
* The default affinity to use for all threads without a precise {@link AffinityGroup} match.
*/
@Nonnull
private AffinityDescriptor defaultAffinity;

@Data
@NoArgsConstructor
@Accessors(fluent = true, chain = true)
public static final class AffinityGroup {

/**
* This group inflated {@link AffinityDescriptor}, to be used to apply affinity settings via {@code Needle}.
*
* @see org.sheinbergon.needle.Needle
*/
@Nonnull
private AffinityDescriptor affinity;
/**
* The match target qualifier, used to extract the match target string from a given {@code Thread}.
*/
@Nullable
private Qualifier qualifier;
/**
* The matching logic encapsulation (determined upon deserialization).
*/
@Nullable
private Matcher matcher;
/**
* The affinity group's identifier, meant to be used for descriptive purposes only.
*/
@Nonnull
private String identifier;

/**
* @param target the match target to be matched using this affinity group's {@link AffinityGroup#matcher}.
* @return A boolean value indicating whether or not this group matches the given target or not.
*/
public boolean matches(final @Nonnull String target) {
return matcher.matches(target);
}
public enum Qualifier {

/**
Expand All @@ -53,6 +94,13 @@ public enum Qualifier {
})
public interface Matcher {

/**
* @param target the match target to be matched
* @return Boolean value indicating whether or not this {@code Matcher} implementation matches the given
* match target.
*/
boolean matches(@Nonnull String target);

@Data
@NoArgsConstructor
@Accessors(fluent = true, chain = true)
Expand Down Expand Up @@ -88,57 +136,6 @@ public boolean matches(final @Nonnull String target) {
return pattern.matcher(target).matches();
}
}

/**
* @param target the match target to be matched
* @return Boolean value indicating whether or not this {@code Matcher} implementation matches the given
* match target.
*/
boolean matches(@Nonnull String target);
}

/**
* This group inflated {@link AffinityDescriptor}, to be used to apply affinity settings via {@code Needle}.
*
* @see org.sheinbergon.needle.Needle
*/
@Nonnull
private AffinityDescriptor affinity;
/**
* The match target qualifier, used to extract the match target string from a given {@code Thread}.
*/
@Nullable
private Qualifier qualifier;
/**
* The matching logic encapsulation (determined upon deserialization).
*/
@Nullable
private Matcher matcher;
/**
* The affinity group's identifier, meant to be used for descriptive purposes only.
*/
@Nonnull
private String identifier;

/**
* @param target the match target to be matched using this affinity group's {@link AffinityGroup#matcher}.
* @return A boolean value indicating whether or not this group matches the given target or not.
*/
public boolean matches(final @Nonnull String target) {
return matcher.matches(target);
}
}

/**
* A collection of affinity group descriptors used to match different affinity descriptors to threads upon
* instantiation.
*/
@Nullable
private List<AffinityGroup> affinityGroups;

/**
* The default affinity to use for all threads without a precise {@link AffinityGroup} match.
*/
@Nonnull
private AffinityDescriptor defaultAffinity;
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ public final class AffinityGroupMatcher {
*/
private static NeedleAgentConfiguration.AffinityGroup defaultAffinityGroup = null;

private AffinityGroupMatcher() {
}

/**
* Match an affintiy group for a given {@code Thread} according to the following logic
* <p>
Expand Down Expand Up @@ -141,7 +144,4 @@ private static List<NeedleAgentConfiguration.AffinityGroup> affinityGroups(
final @Nonnull NeedleAgentConfiguration configuration) {
return ObjectUtils.defaultIfNull(configuration.affinityGroups(), List.of());
}

private AffinityGroupMatcher() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ public final class YamlCodec {
.addMixIn(Pattern.class, RegexPatternMixIn.class)
.readerFor(NeedleAgentConfiguration.class);

private YamlCodec() {
}

/**
* @param url Agent configuration file URL.
* @return Deserialized {@link NeedleAgentConfiguration} instance.
Expand Down Expand Up @@ -89,7 +92,4 @@ public Pattern deserialize(
return Pattern.compile(node.asText());
}
}

private YamlCodec() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ import com.sun.tools.attach.VirtualMachine
import org.amshove.kluent.shouldBeEqualTo
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.sheinbergon.needle.*
import org.sheinbergon.needle.AffinityDescriptor
import org.sheinbergon.needle.Needle
import org.sheinbergon.needle.PinnedThread
import org.sheinbergon.needle.default
import org.sheinbergon.needle.`1L`
import org.sheinbergon.needle.`2L`
import org.sheinbergon.needle.util.NeedleAffinity
import java.nio.file.Paths

Expand All @@ -14,8 +19,8 @@ class AffinityAgentTest {
private val AGENT_PATH = System.getProperty("test.agent.jar.path")!!

private val CONFIGURATION_PATH = AffinityAgentTest::class.java
.getResource("/test-configuration.yml")
.toString()
.getResource("/test-configuration.yml")
.toString()

private const val THREAD_NAME_PREFIX = "needle-agent-thread"

Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ allprojects {
ext.nexus.url = nexus.target.equals('SNAPSHOT') ? ossSnapshotsRepositoryUrl : ossReleasesRepositoryUrl

group "org.sheinbergon"
version "0.2.1"
version "0.3.0"

sourceCompatibility = 11

Expand Down
11 changes: 10 additions & 1 deletion codecov.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
coverage:
precision: 2
round: up
range: "75..95"
range: 75..95
status:
patch:
default:
target: auto
threshold: 2%
project:
default:
target: auto
threshold: 2%
ignore:
- "agent/**/*"
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package org.sheinbergon.needle.concurrent;

import javax.annotation.Nonnull;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ScheduledExecutorService;

public final class PinnedExecutors {

/**
* Static factory methods for affinity aware single-thread {@code ExecutorService} inception.
*
* @param factory the {@code PinnedThreadFactory} used to create affinity aware {@code PinnedThread} instances
* @return the affinity aware {@code ExecutorService}
*/
public static ExecutorService newSinglePinnedThreadExecutor(final @Nonnull PinnedThreadFactory factory) {
return Executors.newSingleThreadExecutor(factory);
}

/**
* Static factory methods for affinity aware fixed-size {@code ExecutorService} inception.
*
* @param size number of {@code PinnedThread} instances to maintain in the pool
* @param factory the {@code PinnedThreadFactory} used create affinity aware {@code PinnedThread} instances
* @return the affinity aware {@code ExecutorService}
*/
public static ExecutorService newFixedPinnedThreadPool(final int size, final @Nonnull PinnedThreadFactory factory) {
return Executors.newFixedThreadPool(size, factory);
}

/**
* Static factory methods for affinity aware single-thread {@code ScheduledExecutorService} inception.
*
* @param factory the {@code PinnedThreadFactory} used create affinity aware {@code PinnedThread} instances
* @return the affinity aware {@code ScheduledExecutorService}
*/
public static ScheduledExecutorService newSinglePinnedThreadScheduledExecutor(
final @Nonnull PinnedThreadFactory factory) {
return Executors.newSingleThreadScheduledExecutor(factory);
}

/**
* Static factory methods for affinity aware fixed-size {@code ScheduledExecutorService} inception.
*
* @param size number of {@code PinnedThread} instances to maintain in the pool
* @param factory the {@code PinnedThreadFactory} used create affinity aware {@code PinnedThread} instances
* @return the affinity aware {@code ScheduledExecutorService}
*/
public static ScheduledExecutorService newScheduledPinnedThreadPool(
final int size,
final @Nonnull PinnedThreadFactory factory) {
return Executors.newScheduledThreadPool(size, factory);
}

/**
* Creates a new affinity aware {@code ForkJoinPool} with the given parameters.
*
* @param parallelism the parallelism level (amount of worker threads to be spawned)
* @param factory the {@code PinnedThread} factory to use when the executor
* creates new fork-join worker threads
* @return an affinity aware {@code ForkJoinPool}
*/
public static ForkJoinPool newPinnedWorkStealingPool(
final int parallelism,
final @Nonnull PinnedThreadFactory factory) {
return new ForkJoinPool(parallelism, factory, null, true);
}

private PinnedExecutors() {
}
}

This file was deleted.

Loading

0 comments on commit 5081f48

Please sign in to comment.