Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
rdulmina committed Jan 21, 2025
2 parents 2558cd6 + daa0cb4 commit 7264bbb
Show file tree
Hide file tree
Showing 13 changed files with 203 additions and 107 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

Expand All @@ -45,10 +47,10 @@ public final class StrandDump {
private static final String WORKING_DIR = System.getProperty("user.dir") + "/";
private static final String FILENAME = "threadDump" + LocalDateTime.now();
private static final String VIRTUAL_THREAD_IDENTIFIER = "virtual";
private static final String ISOLATED_WORKER_IDENTIFIER = "io.ballerina.runtime.internal.scheduling." +
"Scheduler.lambda$startIsolatedWorker";
private static final String NON_ISOLATED_WORKER_IDENTIFIER = "io.ballerina.runtime.internal.scheduling." +
"Scheduler.lambda$startNonIsolatedWorker";
private static final String ISOLATED_IDENTIFIER = "io.ballerina.runtime.internal.scheduling." +
"Scheduler.lambda$startIsolated";
private static final String NON_ISOLATED_IDENTIFIER = "io.ballerina.runtime.internal.scheduling." +
"Scheduler.lambda$startNonIsolated";
private static final String JAVA_TRACE_PATTERN = "java\\.|\\.java(?::\\d+)?"; // .java, java., .java:(any number)
private static final String BAL_TRACE_PATTERN = "\\.bal:\\d+"; // .bal:(any number)
private static volatile HotSpotDiagnosticMXBean hotSpotDiagnosticMXBean;
Expand All @@ -69,16 +71,16 @@ public static String getStrandDump() {
private static String generateOutput(String dump) {
String[] dumpItems = dump.split("\\n\\n");
int id = 0;
Set<Integer> isolatedWorkerList = new HashSet<>();
Set<Integer> nonIsolatedWorkerList = new HashSet<>();
ArrayList<ArrayList<String>> balTraces = new ArrayList<>();
Set<Integer> isolatedStrandList = new HashSet<>();
Set<Integer> nonIsolatedStrandList = new HashSet<>();
Map<Integer, ArrayList<String>> balTraces = new HashMap<>();
Pattern javaPattern = Pattern.compile(JAVA_TRACE_PATTERN);
Pattern balPattern = Pattern.compile(BAL_TRACE_PATTERN);
for (String item : dumpItems) {
String[] lines = item.split("\\n");
String[] subitems = lines[0].split("\" ");
ArrayList<String> balTraceItems = new ArrayList<>();
boolean balStrand = false;
boolean isBalStrand = false;
if (subitems.length > 1 && subitems[1].equals(VIRTUAL_THREAD_IDENTIFIER)) {
balTraceItems.add("\tStrand " + lines[0].replace(VIRTUAL_THREAD_IDENTIFIER, ":") + "\n\t\tat");
String prefix = " ";
Expand All @@ -87,21 +89,21 @@ private static String generateOutput(String dump) {
balTraceItems.add(prefix + line + "\n");
prefix = "\t\t ";
if (balPattern.matcher(line).find()) {
balStrand = true;
isBalStrand = true;
}
} else {
if (line.contains(ISOLATED_WORKER_IDENTIFIER)) {
isolatedWorkerList.add(id);
} else if (line.contains(NON_ISOLATED_WORKER_IDENTIFIER)) {
nonIsolatedWorkerList.add(id);
if (line.contains(ISOLATED_IDENTIFIER)) {
isolatedStrandList.add(id);
} else if (line.contains(NON_ISOLATED_IDENTIFIER)) {
nonIsolatedStrandList.add(id);
}
}
}
if (balStrand) {
balTraces.add(balTraceItems);
if (isBalStrand) {
balTraces.put(id, balTraceItems);
} else {
isolatedWorkerList.remove(id);
nonIsolatedWorkerList.remove(id);
isolatedStrandList.remove(id);
nonIsolatedStrandList.remove(id);
}
id++;
}
Expand All @@ -112,19 +114,23 @@ private static String generateOutput(String dump) {
outputStr.append(dateTimeFormatter.format(localDateTime));
outputStr.append("]\n===============================================================\n\n");
outputStr.append("Total Strand count \t\t\t:\t").append(balTraces.size()).append("\n\n");
outputStr.append("Total Isolated Worker count \t\t:\t").append(isolatedWorkerList.size()).append("\n\n");
outputStr.append("Total Non Isolated Worker count \t\t:\t").append(nonIsolatedWorkerList.size()).
outputStr.append("Total Isolated Strand count \t\t:\t").append(isolatedStrandList.size()).append("\n\n");
outputStr.append("Total Non Isolated Strand count \t\t:\t").append(nonIsolatedStrandList.size()).
append("\n\n");
outputStr.append("================================================================\n");
outputStr.append("\nIsolated Workers:\n\n");
for (int strandId: isolatedWorkerList) {
balTraces.get(strandId).forEach(outputStr::append);
outputStr.append("\n");
outputStr.append("\nIsolated Strands:\n\n");
for (int strandId: isolatedStrandList) {
if (balTraces.containsKey(strandId)) {
balTraces.get(strandId).forEach(outputStr::append);
outputStr.append("\n");
}
}
outputStr.append("Non Isolated Workers:\n\n");
for (int strandId: nonIsolatedWorkerList) {
balTraces.get(strandId).forEach(outputStr::append);
outputStr.append("\n");
outputStr.append("Non Isolated Strands:\n\n");
for (int strandId: nonIsolatedStrandList) {
if (balTraces.containsKey(strandId)) {
balTraces.get(strandId).forEach(outputStr::append);
outputStr.append("\n");
}
}
return outputStr.toString();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2025, WSO2 LLC. (http://www.wso2.org).
*
* WSO2 LLC. licenses this file to you 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 org.ballerinalang.langserver.commons.workspace;

import io.ballerina.tools.diagnostics.Diagnostic;

import java.util.Collection;

/**
* Represents the result of {@link WorkspaceManager#run(RunContext)} operation.
*
* @param process {@link Process} instance representing the run operation
* @param diagnostics diagnostics generated during the compilation
* @since 2201.12.0
*/
public record RunResult(Process process, Collection<Diagnostic> diagnostics) {

}
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ public interface WorkspaceManager {
* @throws WorkspaceDocumentException when project or document not found
*/
void didChangeWatched(Path filePath, FileEvent fileEvent) throws WorkspaceDocumentException;

/**
* The file change notification is sent from the client to the server to signal changes to watched files.
*
Expand All @@ -245,7 +245,7 @@ public interface WorkspaceManager {
* @throws IOException If failed to start the process.
* @since 2201.6.0
*/
Optional<Process> run(RunContext runContext) throws IOException;
RunResult run(RunContext runContext) throws IOException;

/**
* Stop a running process started with {@link #run}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,17 @@
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import io.ballerina.tools.diagnostics.Diagnostic;
import io.ballerina.tools.diagnostics.DiagnosticSeverity;
import org.ballerinalang.annotation.JavaSPIService;
import org.ballerinalang.compiler.BLangCompilerException;
import org.ballerinalang.langserver.commons.ExecuteCommandContext;
import org.ballerinalang.langserver.commons.client.ExtendedLanguageClient;
import org.ballerinalang.langserver.commons.command.CommandArgument;
import org.ballerinalang.langserver.commons.command.LSCommandExecutorException;
import org.ballerinalang.langserver.commons.command.spi.LSCommandExecutor;
import org.ballerinalang.langserver.commons.workspace.RunContext;
import org.ballerinalang.langserver.commons.workspace.RunResult;
import org.eclipse.lsp4j.LogTraceParams;

import java.io.IOException;
Expand All @@ -34,10 +38,12 @@
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.StreamSupport;
Expand Down Expand Up @@ -67,25 +73,40 @@ public class RunExecutor implements LSCommandExecutor {
public Boolean execute(ExecuteCommandContext context) throws LSCommandExecutorException {
try {
RunContext workspaceRunContext = getWorkspaceRunContext(context);
Optional<Process> processOpt = context.workspace().run(workspaceRunContext);
if (processOpt.isEmpty()) {
RunResult runResult = context.workspace().run(workspaceRunContext);

Collection<Diagnostic> diagnostics = runResult.diagnostics();
for (Diagnostic diagnostic : diagnostics) {
LogTraceParams diagnosticMessage = new LogTraceParams(diagnostic.toString(), ERROR_CHANNEL);
context.getLanguageClient().logTrace(diagnosticMessage);
}
if (diagnostics.stream().anyMatch(d -> d.diagnosticInfo().severity() == DiagnosticSeverity.ERROR)) {
LogTraceParams error = new LogTraceParams("error: compilation contains errors", ERROR_CHANNEL);
context.getLanguageClient().logTrace(error);
return false;
}
Process process = processOpt.get();

Process process = runResult.process();
if (Objects.isNull(process)) {
return false;
}

listenOutputAsync(context.getLanguageClient(), process::getInputStream, OUT_CHANNEL);
listenOutputAsync(context.getLanguageClient(), process::getErrorStream, ERROR_CHANNEL);
return true;
} catch (BLangCompilerException e) {
LogTraceParams error = new LogTraceParams(e.getMessage(), ERROR_CHANNEL);
context.getLanguageClient().logTrace(error);
} catch (IOException e) {
LogTraceParams error = new LogTraceParams("Error while running the program in fast-run mode: " +
e.getMessage(), ERROR_CHANNEL);
context.getLanguageClient().logTrace(error);
throw new LSCommandExecutorException(e);
} catch (Exception e) {
LogTraceParams error = new LogTraceParams("Unexpected error while executing the fast-run: " +
e.getMessage(), ERROR_CHANNEL);
context.getLanguageClient().logTrace(error);
throw new LSCommandExecutorException(e);
}
return false;
}

private RunContext getWorkspaceRunContext(ExecuteCommandContext context) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
import org.ballerinalang.langserver.commons.eventsync.EventKind;
import org.ballerinalang.langserver.commons.eventsync.exceptions.EventSyncException;
import org.ballerinalang.langserver.commons.workspace.RunContext;
import org.ballerinalang.langserver.commons.workspace.RunResult;
import org.ballerinalang.langserver.commons.workspace.WorkspaceDocumentException;
import org.ballerinalang.langserver.commons.workspace.WorkspaceDocumentManager;
import org.ballerinalang.langserver.commons.workspace.WorkspaceManager;
Expand Down Expand Up @@ -92,6 +93,7 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
Expand Down Expand Up @@ -595,18 +597,39 @@ public String uriScheme() {
}

@Override
public Optional<Process> run(RunContext executionContext) throws IOException {
public RunResult run(RunContext executionContext) throws IOException {
Path projectRoot = projectRoot(executionContext.balSourcePath());
Optional<ProjectContext> projectContext = validateProjectContext(projectRoot);
if (projectContext.isEmpty()) {
return Optional.empty();
return new RunResult(null, Collections.emptyList());
}

if (!prepareProjectForExecution(projectContext.get())) {
return Optional.empty();
if (!stopProject(projectContext.get())) {
logError("Run command execution aborted because couldn't stop the previous run");
return new RunResult(null, Collections.emptyList());
}

Project project = projectContext.get().project();
Optional<PackageCompilation> packageCompilation = waitAndGetPackageCompilation(project.sourceRoot(), true);
if (packageCompilation.isEmpty()) {
logError("Run command execution aborted because package compilation failed");
return new RunResult(null, Collections.emptyList());
}

return executeProject(projectContext.get(), executionContext);
JBallerinaBackend jBallerinaBackend = execBackend(projectContext.get(), packageCompilation.get());
Collection<Diagnostic> diagnostics = new LinkedList<>();
// check for compilation errors
diagnostics.addAll(jBallerinaBackend.diagnosticResult().diagnostics(false));
// Add tool resolution diagnostics to diagnostics
diagnostics.addAll(project.currentPackage().getBuildToolResolution().getDiagnosticList());

if (diagnostics.stream().anyMatch(d -> d.diagnosticInfo().severity() == DiagnosticSeverity.ERROR)) {
return new RunResult(null, diagnostics);
}

Optional<Process> process = executeProject(projectContext.get(), executionContext);
return process.map(value -> new RunResult(value, diagnostics))
.orElseGet(() -> new RunResult(null, diagnostics));
}

private Optional<ProjectContext> validateProjectContext(Path projectRoot) {
Expand All @@ -619,31 +642,6 @@ private Optional<ProjectContext> validateProjectContext(Path projectRoot) {
return projectContextOpt;
}

private boolean prepareProjectForExecution(ProjectContext projectContext) {
// stop previous project run
if (!stopProject(projectContext)) {
logError("Run command execution aborted because couldn't stop the previous run");
return false;
}

Project project = projectContext.project();
Optional<PackageCompilation> packageCompilation = waitAndGetPackageCompilation(project.sourceRoot(), true);
if (packageCompilation.isEmpty()) {
logError("Run command execution aborted because package compilation failed");
return false;
}

// check for compilation errors
JBallerinaBackend jBallerinaBackend = execBackend(projectContext, packageCompilation.get());
Collection<Diagnostic> diagnostics = jBallerinaBackend.diagnosticResult().diagnostics(false);
if (diagnostics.stream().anyMatch(BallerinaWorkspaceManager::isError)) {
logError("Run command execution aborted due to compilation errors: " + diagnostics);
return false;
}

return true;
}

private Optional<Process> executeProject(ProjectContext projectContext, RunContext context) throws IOException {
Project project = projectContext.project();
Package pkg = project.currentPackage();
Expand Down Expand Up @@ -718,7 +716,7 @@ private void logError(String message) {

@Override
public boolean stop(Path filePath) {
Optional<ProjectContext> projectPairOpt = projectContext(projectRoot(filePath));
Optional<ProjectContext> projectPairOpt = projectContext(projectRoot(filePath).toAbsolutePath());
if (projectPairOpt.isEmpty()) {
clientLogger.logWarning("Failed to stop process: Project not found");
return false;
Expand Down
Loading

0 comments on commit 7264bbb

Please sign in to comment.