diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 00000000..204c1c2a --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,100 @@ +# GitHub Copilot Instructions for GCToolKit + +## Project Overview +GCToolKit is a Java-based toolkit for analyzing Garbage Collection logs from various JVM implementations. The project uses Maven as its build system and is structured as a multi-module project. + +## Architecture & Design Patterns +- **Multi-module Maven project** with clear separation of concerns +- **Event-driven architecture** using Vert.x for message passing +- **Parser framework** for processing various GC log formats +- **Channel-based communication** between parsers and event consumers +- **Verticle pattern** for asynchronous processing with Vert.x + +## Module Structure +- `api/` - Core API definitions, interfaces, and base classes +- `parser/` - GC log parsing implementations for different JVM types +- `vertx/` - Vert.x-based messaging and event handling infrastructure +- `sample/` - Example usage and sample applications +- `IT/` - Integration tests +- `gclogs/` - Test data and sample GC logs + +## Key Technologies +- **Java 21+** with module system (module-info.java files) +- **Vert.x 5.0.2** for reactive programming and event bus +- **JUnit 5** for testing +- **Maven** for build management +- **Spotbugs, PMD, Checkstyle** for code quality + +## Code Style & Conventions +- Follow standard Java naming conventions +- Use proper JavaDoc for public APIs +- Implement equals/hashCode when appropriate +- Use logging with java.util.logging +- Handle exceptions appropriately with try-catch blocks +- Use Promise/Future patterns for asynchronous operations with Vert.x + +## Common Patterns in This Codebase + +### Event Processing +```java +public void start(Promise promise) { + vertx.eventBus().consumer(inbox, message -> { + processor.receive(message.body()); + }).completion() + .onComplete(ar -> promise.complete()); +} +``` + +### Channel Implementation +- Extend appropriate base channel classes +- Implement proper lifecycle management (open/close) +- Use Vert.x deployVerticle for async operations +- Handle deployment IDs for proper cleanup + +### Error Handling +- Use java.util.logging.Logger for logging +- Log warnings/errors with proper context +- Handle Future completion with onComplete callbacks + +## Vert.x Specific Guidelines +- Use Verticles for isolated processing units +- Deploy verticles asynchronously with completion handlers +- Use the event bus for inter-verticle communication +- Properly manage deployment IDs to avoid double-undeploy issues +- Handle Promise completion in start() methods + +## Testing Conventions +- Integration tests go in the `IT/` module +- Unit tests use JUnit 5 +- Test GC log files are stored in `gclogs/` with organized subdirectories +- Mock external dependencies appropriately + +## Build & Dependencies +- Maven 3.9.11+ required +- Use the Maven Wrapper (i.e., `mvnw`) +- Keep dependencies up to date, unless you see a comment saying why not to +- Use dependencyManagement in parent POM for version consistency +- Include proper test scopes for test dependencies + +## When Suggesting Code Changes +1. Consider the event-driven nature of the architecture +2. Ensure proper async handling with Vert.x patterns +3. Maintain compatibility with existing interfaces +4. Add appropriate logging and error handling +5. Follow the established module boundaries +6. Consider performance implications for GC log processing +7. Ensure proper resource cleanup (channels, verticles, etc.) + +## Common Issues to Avoid +- Double-undeployment of Vert.x verticles +- Blocking operations in Vert.x event loops +- Memory leaks from unclosed channels or resources +- Incorrect Promise/Future completion handling +- Missing error handling in async operations + +## File Naming Patterns +- Verticles: `*Verticle.java` +- Channels: `*Channel.java` +- Events: `*Event.java` +- Tests: `*Test.java` +- Integration tests: `*IT.java` or in IT module diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index d58ddb0c..efa17b70 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -14,5 +14,5 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.11/apache-maven-3.9.11-bin.zip wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar diff --git a/pom.xml b/pom.xml index 34d07c64..205e589d 100644 --- a/pom.xml +++ b/pom.xml @@ -45,27 +45,27 @@ 3.0.3-SNAPSHOT - 10.23.0 - 1.17.0 - 5.12.2 + 10.26.1 + 1.19.0 + 5.13.4 3.1.0 - 3.0.0-M2 + 3.0.0-M3 3.6.0 - 3.4.1 + 3.5.0 3.14.0 11 3.8.1 3.1.4 1.0 - 3.5.0 - 3.5.0 + 3.6.1 + 3.5.1 3.1.4 0.8.13 3.4.2 3.11.2 3.6.0 - 2.5.0 - + 2.6.0 + 3.21.2 3.9.0 0.16.1 @@ -73,12 +73,12 @@ 3.3.1 4.0.0-M16 3.3.1 - 4.9.3.0 + 4.9.3.2 3.5.3 - 3.9.9 + 3.9.11 2.18.0 0.9.1 - + 6.55.0 UTF-8 microsoft/gctoolkit @@ -385,10 +385,7 @@ org.apache.maven.plugins maven-changes-plugin - - https - 443 false false @@ -396,8 +393,6 @@ changes - - diff --git a/vertx/pom.xml b/vertx/pom.xml index e4603603..be7bb3ef 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -22,7 +22,7 @@ io.vertx vertx-core - 4.5.14 + 5.0.2 org.junit.jupiter diff --git a/vertx/src/main/java/com/microsoft/gctoolkit/vertx/DataSourceVerticle.java b/vertx/src/main/java/com/microsoft/gctoolkit/vertx/DataSourceVerticle.java index 59c6b323..354ea153 100644 --- a/vertx/src/main/java/com/microsoft/gctoolkit/vertx/DataSourceVerticle.java +++ b/vertx/src/main/java/com/microsoft/gctoolkit/vertx/DataSourceVerticle.java @@ -57,10 +57,9 @@ public void start(Promise promise) { try { vertx.eventBus().consumer(inbox, message -> { processor.receive(message.body()); - if (GCLogFile.END_OF_DATA_SENTINEL.equals(message.body())) { - vertx.undeploy(id); - } - }).completionHandler(result -> {promise.complete();}); + // Removed vertx.undeploy(id) to avoid double-undeploy + }).completion() + .onComplete(ar -> promise.complete()); } catch(Throwable t) { LOGGER.log(Level.WARNING,"Vertx: processing DataSource failed",t); } diff --git a/vertx/src/main/java/com/microsoft/gctoolkit/vertx/JVMEventVerticle.java b/vertx/src/main/java/com/microsoft/gctoolkit/vertx/JVMEventVerticle.java index 68cd585b..227eab51 100644 --- a/vertx/src/main/java/com/microsoft/gctoolkit/vertx/JVMEventVerticle.java +++ b/vertx/src/main/java/com/microsoft/gctoolkit/vertx/JVMEventVerticle.java @@ -59,13 +59,11 @@ public void start(Promise promise) { try { processor.receive(event); } catch (Throwable t) { - // Throwable is caught because we don't want the processor to blow up the message bus. LOGGER.log(Level.WARNING, "Vertx: processing JVMEvent failed", t); } - if (event instanceof JVMTermination) { - vertx.undeploy(id); - } - }).completionHandler(result -> {promise.complete();}); + // Removed vertx.undeploy(id) to avoid double-undeploy + }).completion() + .onComplete(ar -> promise.complete()); } @Override diff --git a/vertx/src/main/java/com/microsoft/gctoolkit/vertx/VertxChannel.java b/vertx/src/main/java/com/microsoft/gctoolkit/vertx/VertxChannel.java index 3de6b3fa..f91e821b 100644 --- a/vertx/src/main/java/com/microsoft/gctoolkit/vertx/VertxChannel.java +++ b/vertx/src/main/java/com/microsoft/gctoolkit/vertx/VertxChannel.java @@ -47,12 +47,13 @@ protected Vertx vertx() { * Closes the Vert.x instance. */ public void close() { - vertx().close(result -> { - if (result.succeeded()) { - LOGGER.log(Level.FINE, "Vertx: closed"); - } else { - LOGGER.log(Level.FINE, "Vertx: close failed", result.cause()); - } - }); + vertx().close() + .onComplete(ar -> { + if (ar.succeeded()) { + LOGGER.log(Level.FINE, "Vertx: closed"); + } else { + LOGGER.log(Level.WARNING, "Vertx: close failed", ar.cause()); + } + }); } } \ No newline at end of file diff --git a/vertx/src/main/java/com/microsoft/gctoolkit/vertx/VertxDataSourceChannel.java b/vertx/src/main/java/com/microsoft/gctoolkit/vertx/VertxDataSourceChannel.java index f873448f..47ccf54a 100644 --- a/vertx/src/main/java/com/microsoft/gctoolkit/vertx/VertxDataSourceChannel.java +++ b/vertx/src/main/java/com/microsoft/gctoolkit/vertx/VertxDataSourceChannel.java @@ -29,10 +29,11 @@ public VertxDataSourceChannel() { public void registerListener(DataSourceParser listener) { final DataSourceVerticle processor = new DataSourceVerticle(vertx(), listener.channel().getName(), listener); CountDownLatch latch = new CountDownLatch(1); - vertx().deployVerticle(processor, state -> { - processor.setID((state.succeeded()) ? state.result() : ""); - latch.countDown(); - }); + vertx().deployVerticle(processor) + .onComplete(ar -> { + processor.setID(ar.succeeded() ? ar.result() : ""); + latch.countDown(); + }); try { latch.await(); } catch (InterruptedException e) { diff --git a/vertx/src/main/java/com/microsoft/gctoolkit/vertx/VertxJVMEventChannel.java b/vertx/src/main/java/com/microsoft/gctoolkit/vertx/VertxJVMEventChannel.java index 6737ae9d..77eb0bdc 100644 --- a/vertx/src/main/java/com/microsoft/gctoolkit/vertx/VertxJVMEventChannel.java +++ b/vertx/src/main/java/com/microsoft/gctoolkit/vertx/VertxJVMEventChannel.java @@ -35,10 +35,11 @@ public VertxJVMEventChannel() {} public void registerListener(JVMEventChannelListener listener) { final JVMEventVerticle processor = new JVMEventVerticle(vertx(), listener.channel().getName(), listener); CountDownLatch latch = new CountDownLatch(1); - vertx().deployVerticle(processor, state -> { - processor.setID((state.succeeded()) ? state.result() : ""); - latch.countDown(); - }); + vertx().deployVerticle(processor) + .onComplete(ar -> { + processor.setID(ar.succeeded() ? ar.result() : ""); + latch.countDown(); + }); try { latch.await();