Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Changelog

All notable changes to this project are documented in this file.

## 1.0.0 - 2026-08-23

Initial public release of the generic, thread-safe SFQ(D) scheduler.

### Included

- exact rational scheduling tags with bounded, fail-closed numeric handling;
- weighted and cost-aware dispatch with configurable issue depth;
- opaque flow and job handles, cancellation, completion, flow closure, and
atomic snapshots;
- Java 17 runtime compatibility and no third-party runtime dependencies;
- source and JavaDoc artifacts for Maven Central;
- unit, property, differential, concurrency, retention, static-analysis,
reproducibility, and publication-topology verification;
- compiled executor and bounded resource-pool integration examples;
- separate jcstress and JMH harnesses.

### Boundaries

- the library schedules work but does not execute it or own external resource
capacity;
- dispatch fairness begins after admission and does not provide admission
isolation;
- queued cancellation uses reserved-cost accounting as documented in the
README and formal specification;
- the repository contains a benchmark protocol, but no published production
throughput or latency result.
15 changes: 6 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,11 @@ Use it when several tenants, queues, users, or workloads share a bounded
number of execution slots and should receive service in proportion to their
weights.

Canonical repository: <https://github.com/pzhin/sfqd-java>

## Status

The implementation, tests, JavaDoc, concurrency harness, and benchmark
harness are complete. The source branch uses the pre-release coordinates
`io.github.pzhin:sfqd-core:0.1.0-SNAPSHOT` and Java package
`io.github.pzhin.sfqd`. No artifact has been published to a public Maven
repository yet.
Version 1.0.0 is the first stable release. The library is published to Maven
Central as `io.github.pzhin:sfqd-core:1.0.0` and uses the Java package
`io.github.pzhin.sfqd`.

The benchmark harness is an executable measurement protocol, not a benchmark
result. This repository intentionally contains no raw machine-specific runs,
Expand Down Expand Up @@ -47,7 +43,7 @@ On Windows Command Prompt or PowerShell:
.\mvnw.cmd --batch-mode --no-transfer-progress clean verify
```

Install the snapshot into your local Maven repository:
Install the release into your local Maven repository:

```shell
./mvnw --batch-mode --no-transfer-progress install
Expand All @@ -61,7 +57,7 @@ Then add it to a local consumer:
<dependency>
<groupId>io.github.pzhin</groupId>
<artifactId>sfqd-core</artifactId>
<version>0.1.0-SNAPSHOT</version>
<version>1.0.0</version>
</dependency>
```

Expand Down Expand Up @@ -434,4 +430,5 @@ measurement protocol.
- [Bounded resource-pool lifecycle example](sfqd-examples/README.md)
- [Theory in plain language and full papers](docs/THEORY.md)
- [Build, CI, artifact, and publication checks](docs/TOOLING.md)
- [Release history](CHANGELOG.md)
- [Benchmark workload guide](sfqd-benchmarks/README.md)
42 changes: 36 additions & 6 deletions docs/TOOLING.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,15 @@ The Java artifact verifier also inserts the project license into the source and
JavaDoc JARs without invoking platform-specific archive tools. Both the unit
gate and artifact verifier compare compiled output with
`sfqd-core/src/main/api/public-api.txt`; adding a documented public member to an
existing type therefore fails the build. Before the first release, regenerate
the candidate manifest after compilation with:
existing type therefore fails the build. Before an intentional public API
change, regenerate the candidate manifest after compilation with:

```shell
java -cp sfqd-core/target/test-classes:sfqd-core/target/classes \
io.github.pzhin.sfqd.build.PublicApiManifest sfqd-core/target/classes
```

Review and commit the output only for an intentional API change. After `0.1.0`,
Review and commit the output only for an intentional API change. After `1.0.0`,
artifact-to-artifact compatibility checking with Revapi or japicmp should use
the previous published release as its baseline; the manifest remains the
fail-closed exact-surface gate for the current release line.
Expand Down Expand Up @@ -133,9 +133,39 @@ deleted afterward.
There is no external `distributionManagement` target. An ordinary deploy
without an explicit alternate repository therefore fails instead of publishing
somewhere unexpected. The source branch records the Maven coordinates, Java
package, Apache-2.0 license, project URL, SCM, and developer metadata. A public
release still requires a non-snapshot release decision, destination
configuration, credentials, signing policy, tag, and release notes.
package, Apache-2.0 license, project URL, SCM, and developer metadata.

## Maven Central release

The `release` profile signs and publishes only `sfqd-java-parent` and
`sfqd-core`. Examples, coverage, jcstress, and benchmark artifacts retain
`maven.deploy.skip=true` and are not published. The profile uses Sonatype's
Central Publishing Maven Plugin, requests automatic publication after
validation, and waits for the deployment to reach `published`.

Before running the profile, the release engineer must have:

- publishing access to the verified `io.github.pzhin` namespace;
- a Maven Central user token in the `central` server entry of the user-level
Maven `settings.xml`;
- a primary PGP signing key available to GnuPG and distributed through a key
server supported by Maven Central;
- an unlocked GnuPG agent, or `MAVEN_GPG_PASSPHRASE` supplied through a secure
environment mechanism.

Publish the immutable 1.0.0 coordinates from the commit tagged `v1.0.0`:

```shell
./mvnw --batch-mode --no-transfer-progress -Prelease clean deploy
```

The release profile is opt-in. Normal `verify`, `install`, local publication
topology checks, and consumer builds do not need Maven Central credentials or a
PGP secret key.

Release wiring can be exercised without network publication by adding
`-Dcentral.publish.skip=true`. This switch does not skip compilation, tests,
artifact generation, or PGP signing.

## CI jobs

Expand Down
49 changes: 47 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>io.github.pzhin</groupId>
<artifactId>sfqd-java-parent</artifactId>
<version>0.1.0-SNAPSHOT</version>
<version>1.0.0</version>
<packaging>pom</packaging>
<name>SFQ(D) Java Parent</name>
<description>Build parent for the SFQ(D) Java library.</description>
Expand Down Expand Up @@ -35,7 +35,7 @@
<connection>scm:git:https://github.com/pzhin/sfqd-java.git</connection>
<developerConnection>scm:git:ssh://git@github.com/pzhin/sfqd-java.git</developerConnection>
<url>https://github.com/pzhin/sfqd-java</url>
<tag>HEAD</tag>
<tag>v1.0.0</tag>
</scm>

<modules>
Expand All @@ -52,6 +52,8 @@
<maven.deploy.skip>false</maven.deploy.skip>
<sfqd.harness.execution.skip>false</sfqd.harness.execution.skip>
<checkstyle.version>12.3.1</checkstyle.version>
<central.publishing.maven.plugin.version>0.11.0</central.publishing.maven.plugin.version>
<central.publish.skip>false</central.publish.skip>
<jacoco.version>0.8.15</jacoco.version>
<jcstress.version>0.16</jcstress.version>
<jmh.version>1.37</jmh.version>
Expand All @@ -66,6 +68,7 @@
<maven.enforcer.plugin.version>3.6.3</maven.enforcer.plugin.version>
<maven.help.plugin.version>3.5.2</maven.help.plugin.version>
<maven.install.plugin.version>3.1.4</maven.install.plugin.version>
<maven.gpg.plugin.version>3.2.8</maven.gpg.plugin.version>
<maven.jar.plugin.version>3.5.0</maven.jar.plugin.version>
<maven.javadoc.plugin.version>3.12.0</maven.javadoc.plugin.version>
<maven.resources.plugin.version>3.4.0</maven.resources.plugin.version>
Expand Down Expand Up @@ -250,6 +253,48 @@
</build>

<profiles>
<profile>
<id>release</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>${maven.gpg.plugin.version}</version>
<executions>
<execution>
<id>sign-release-artifacts</id>
<phase>verify</phase>
<goals><goal>sign</goal></goals>
<configuration>
<bestPractices>true</bestPractices>
<skip>${maven.deploy.skip}</skip>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.sonatype.central</groupId>
<artifactId>central-publishing-maven-plugin</artifactId>
<version>${central.publishing.maven.plugin.version}</version>
<extensions>true</extensions>
<configuration>
<publishingServerId>central</publishingServerId>
<skipPublishing>${central.publish.skip}</skipPublishing>
<excludeArtifacts>
<excludeArtifact>io.github.pzhin:sfqd-examples</excludeArtifact>
<excludeArtifact>io.github.pzhin:sfqd-coverage</excludeArtifact>
<excludeArtifact>io.github.pzhin:sfqd-jcstress</excludeArtifact>
<excludeArtifact>io.github.pzhin:sfqd-benchmarks</excludeArtifact>
</excludeArtifacts>
<autoPublish>true</autoPublish>
<waitUntil>published</waitUntil>
<deploymentName>sfqd-java 1.0.0</deploymentName>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>jcstress</id>
<modules><module>sfqd-jcstress</module></modules>
Expand Down
2 changes: 1 addition & 1 deletion sfqd-benchmarks/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>io.github.pzhin</groupId>
<artifactId>sfqd-java-parent</artifactId>
<version>0.1.0-SNAPSHOT</version>
<version>1.0.0</version>
</parent>
<artifactId>sfqd-benchmarks</artifactId>
<name>SFQ(D) JMH Harness</name>
Expand Down
2 changes: 1 addition & 1 deletion sfqd-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>io.github.pzhin</groupId>
<artifactId>sfqd-java-parent</artifactId>
<version>0.1.0-SNAPSHOT</version>
<version>1.0.0</version>
</parent>
<artifactId>sfqd-core</artifactId>
<name>SFQ(D) Core</name>
Expand Down
2 changes: 1 addition & 1 deletion sfqd-coverage/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>io.github.pzhin</groupId>
<artifactId>sfqd-java-parent</artifactId>
<version>0.1.0-SNAPSHOT</version>
<version>1.0.0</version>
</parent>
<artifactId>sfqd-coverage</artifactId>
<packaging>pom</packaging>
Expand Down
2 changes: 1 addition & 1 deletion sfqd-examples/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>io.github.pzhin</groupId>
<artifactId>sfqd-java-parent</artifactId>
<version>0.1.0-SNAPSHOT</version>
<version>1.0.0</version>
</parent>
<artifactId>sfqd-examples</artifactId>
<name>SFQ(D) Examples</name>
Expand Down
2 changes: 1 addition & 1 deletion sfqd-jcstress/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>io.github.pzhin</groupId>
<artifactId>sfqd-java-parent</artifactId>
<version>0.1.0-SNAPSHOT</version>
<version>1.0.0</version>
</parent>
<artifactId>sfqd-jcstress</artifactId>
<name>SFQ(D) jcstress Harness</name>
Expand Down
20 changes: 10 additions & 10 deletions tools/verify-publication-topology.sh
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ PY
)

readonly GROUP_DIRECTORY="${DEPLOY_REPOSITORY}/io/github/pzhin"
readonly PARENT_DIRECTORY="${GROUP_DIRECTORY}/sfqd-java-parent/0.1.0-SNAPSHOT"
readonly CORE_DIRECTORY="${GROUP_DIRECTORY}/sfqd-core/0.1.0-SNAPSHOT"
readonly PARENT_DIRECTORY="${GROUP_DIRECTORY}/sfqd-java-parent/1.0.0"
readonly CORE_DIRECTORY="${GROUP_DIRECTORY}/sfqd-core/1.0.0"

shopt -s nullglob
parent_poms=("${PARENT_DIRECTORY}"/*.pom)
Expand Down Expand Up @@ -143,7 +143,7 @@ import sys
import xml.etree.ElementTree as ET

namespace = {"m": "http://maven.apache.org/POM/4.0.0"}
expected_parent = ("io.github.pzhin", "sfqd-java-parent", "0.1.0-SNAPSHOT")
expected_parent = ("io.github.pzhin", "sfqd-java-parent", "1.0.0")

parent = ET.parse(sys.argv[1]).getroot()
parent_coordinates = tuple(
Expand Down Expand Up @@ -209,7 +209,7 @@ expected_scm = (
"scm:git:https://github.com/pzhin/sfqd-java.git",
"scm:git:ssh://git@github.com/pzhin/sfqd-java.git",
"https://github.com/pzhin/sfqd-java",
"HEAD",
"v1.0.0",
)
if scm_metadata != expected_scm:
raise SystemExit(
Expand All @@ -235,7 +235,7 @@ effective_core_coordinates = tuple(
effective_core.findtext(f"m:{name}", namespaces=namespace)
for name in ("groupId", "artifactId", "version")
)
expected_core = ("io.github.pzhin", "sfqd-core", "0.1.0-SNAPSHOT")
expected_core = ("io.github.pzhin", "sfqd-core", "1.0.0")
if effective_core_coordinates != expected_core:
raise SystemExit(
"ERROR: effective core coordinates are "
Expand Down Expand Up @@ -306,14 +306,14 @@ cat >"${CONSUMER_ROOT}/pom.xml" <<EOF
<id>publication-smoke</id>
<url>${DEPLOY_REPOSITORY_URI}</url>
<releases><enabled>true</enabled></releases>
<snapshots><enabled>true</enabled><updatePolicy>always</updatePolicy></snapshots>
<snapshots><enabled>false</enabled></snapshots>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>io.github.pzhin</groupId>
<artifactId>sfqd-core</artifactId>
<version>0.1.0-SNAPSHOT</version>
<version>1.0.0</version>
</dependency>
</dependencies>
<build>
Expand All @@ -339,12 +339,12 @@ final class Consumer {
EOF

LC_ALL=C LANG=C TZ=UTC "${REPOSITORY_ROOT}/mvnw" \
--batch-mode --no-transfer-progress --update-snapshots \
--batch-mode --no-transfer-progress \
-Dmaven.repo.local="${CONSUMER_LOCAL_REPOSITORY}" \
-f "${CONSUMER_ROOT}/pom.xml" clean compile

readonly RESOLVED_PARENT="${CONSUMER_LOCAL_REPOSITORY}/io/github/pzhin/sfqd-java-parent/0.1.0-SNAPSHOT"
readonly RESOLVED_CORE="${CONSUMER_LOCAL_REPOSITORY}/io/github/pzhin/sfqd-core/0.1.0-SNAPSHOT"
readonly RESOLVED_PARENT="${CONSUMER_LOCAL_REPOSITORY}/io/github/pzhin/sfqd-java-parent/1.0.0"
readonly RESOLVED_CORE="${CONSUMER_LOCAL_REPOSITORY}/io/github/pzhin/sfqd-core/1.0.0"
if [[ ! -f "${RESOLVED_PARENT}/_remote.repositories" ]]; then
fail "fresh consumer did not resolve the published parent"
fi
Expand Down