Skip to content

Commit

Permalink
optimize out busy wait writer, other minor fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
maxdeliso committed Jan 27, 2025
1 parent dd166e3 commit 4bd25c3
Show file tree
Hide file tree
Showing 21 changed files with 640 additions and 285 deletions.
31 changes: 11 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,13 @@ This project is being actively developed using various AI coding assistants to e
### Building

```bash
./mvnw clean package
mvn clean package
```

### Running

```bash
java -jar target/teflon-1.2.0-jar-with-dependencies.jar
mvn exec:java
```

### Available Commands
Expand All @@ -88,26 +88,10 @@ java -jar target/teflon-1.2.0-jar-with-dependencies.jar

### Testing

The project includes comprehensive test coverage:
The project includes some test coverage:

```bash
./mvnw test
```

### Code Style

Follows standard Java conventions, enforced by Checkstyle:

```bash
./mvnw checkstyle:check
```

### Code Coverage

JaCoCo is used for code coverage analysis:

```bash
./mvnw jacoco:report
mvn test
```

## References
Expand All @@ -124,6 +108,13 @@ JaCoCo is used for code coverage analysis:

## Version History

### 1.3.1

- Optimize out busy-wait in the net selector
- Add additional multicast delivery options
- Improve test strategy
- Fix some threading issues and reconnection

### 1.3.0

- Enhanced status command with HTML formatting
Expand Down
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

<groupId>name.maxdeliso</groupId>
<artifactId>teflon</artifactId>
<version>1.3.0</version>
<version>1.3.1</version>
<packaging>jar</packaging>
<name>teflon</name>
<url>https://github.com/maxdeliso/teflon</url>
Expand Down Expand Up @@ -175,7 +175,7 @@
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<argLine>@{argLine} -Dnet.bytebuddy.experimental=true -XX:+EnableDynamicAgentLoading --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED</argLine>
<argLine>@{argLine} -Xshare:off -Dnet.bytebuddy.experimental=true -XX:+EnableDynamicAgentLoading --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED</argLine>
<runOrder>random</runOrder>
<rerunFailingTestsCount>0</rerunFailingTestsCount>
<properties>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package name.maxdeliso.teflon.commands;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/**
* Processes chat commands.
* Maintains a registry of available commands and handles their execution.
Expand Down Expand Up @@ -88,8 +88,8 @@ public String getHelpText() {
StringBuilder helpText = new StringBuilder("Available commands:\n");
commands.forEach((name, command) -> {
String commandHelp = String.format("• /%s - %s\n",
org.apache.commons.text.StringEscapeUtils.escapeHtml4(name),
org.apache.commons.text.StringEscapeUtils.escapeHtml4(command.getDescription()));
org.apache.commons.text.StringEscapeUtils.escapeHtml4(name),
org.apache.commons.text.StringEscapeUtils.escapeHtml4(command.getDescription()));
helpText.append(commandHelp);
});
return helpText.toString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ public String getInstanceId() {
/**
* Cleans up messages that have timed out.
*/
void cleanupTimedOutMessages() {
public void cleanupTimedOutMessages() {
Instant cutoff = clock.now().minusSeconds(MESSAGE_TIMEOUT_SECONDS);

messageMap.entrySet().removeIf(entry -> {
Expand Down
31 changes: 28 additions & 3 deletions src/main/java/name/maxdeliso/teflon/net/ConnectionManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -84,14 +84,29 @@ private DatagramChannel openAndBindChannel(final InetAddress addr,
try {
var family = protocolFamilyForAddress(addr);
var dc = DatagramChannel.open(family);

// Common options for both IPv4 and IPv6
dc.setOption(StandardSocketOptions.SO_REUSEADDR, true);
dc.setOption(StandardSocketOptions.IP_MULTICAST_IF, netIf);
dc.setOption(StandardSocketOptions.IP_MULTICAST_TTL, 8);
dc.setOption(StandardSocketOptions.IP_MULTICAST_LOOP, true);

if (family == StandardProtocolFamily.INET6) {
LOG.debug("Configuring IPv6 channel for {}", addr);
// For IPv6, bind to any address (::) to receive multicast
dc.bind(new InetSocketAddress("::", port));
} else {
LOG.debug("Configuring IPv4 channel for {}", addr);
// For IPv4, bind to any address (0.0.0.0) to receive multicast
dc.bind(new InetSocketAddress(port));
}

dc.configureBlocking(false);
dc.bind(new InetSocketAddress(port));
LOG.debug("Channel configured and bound successfully");
return dc;
} catch (IOException e) {
String msg = String.format("Failed to open or bind channel for %s on interface %s",
addr, netIf);
String msg = String.format("Failed to open or bind channel for %s on interface %s: %s",
addr, netIf, e.getMessage());
LOG.error(msg, e);
throw new CompletionException(msg, e);
}
Expand All @@ -110,6 +125,16 @@ private MembershipKey joinGroup(final DatagramChannel channel,
final InetAddress groupAddr,
final NetworkInterface netIf) {
try {
// For IPv6, we need to ensure the scope ID is set for link-local addresses
if (groupAddr instanceof Inet6Address && groupAddr.isLinkLocalAddress()) {
// Create a new IPv6 address with the correct scope ID
var ipv6Addr = Inet6Address.getByAddress(
null,
groupAddr.getAddress(),
netIf
);
return channel.join(ipv6Addr, netIf);
}
return channel.join(groupAddr, netIf);
} catch (IOException e) {
String msg = String.format("Failed to join multicast group %s on interface %s",
Expand Down
25 changes: 25 additions & 0 deletions src/main/java/name/maxdeliso/teflon/net/MessageSource.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package name.maxdeliso.teflon.net;

import java.nio.ByteBuffer;

/**
* Interface for sourcing messages with peek and poll operations.
* This allows for checking message availability without consuming them,
* and consuming them only when they are successfully sent.
*/
public interface MessageSource {
/**
* Peeks at the next message without consuming it.
*
* @return The next message as a ByteBuffer, or null if no message is available
*/
ByteBuffer peek();

/**
* Consumes and returns the next message.
* This should be called only after a successful peek() and send.
*
* @return The next message as a ByteBuffer, or null if no message is available
*/
ByteBuffer poll();
}
Loading

0 comments on commit 4bd25c3

Please sign in to comment.