Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Overload Protection #112

Merged
merged 8 commits into from
Jul 31, 2016
44 changes: 41 additions & 3 deletions src/main/java/erlyberly/DbgController.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,44 @@

public class DbgController implements Initializable {

public final ObservableList<TraceLog> traceLogs = FXCollections.observableArrayList();
/**
* The maximum trace logs that erlyberly can show in the table before it must
* load shed them e.g. start throwing them away so that the UI does not attempt
* to take an unlimited amount of memory, and fail!
*
* This is only checked at start up, so if it is changed it requires a restart.
*/
private static final int MAX_TRACE_LOGS;

static {
Number maxTraceLogs = (Number) PrefBind.getOrDefault("maxTraceLogs", 1000);
MAX_TRACE_LOGS = maxTraceLogs.intValue();
}

private final ObservableList<TraceLog> traceLogs = FXCollections.observableArrayList();

private final ObservableList<ModFunc> traces = FXCollections.observableArrayList();

private final ObservableList<SeqTraceLog> seqTraces = FXCollections.observableArrayList();

private volatile boolean collectingSeqTraces;

private TraceLog loadSheddingLog;

@Override
public void initialize(URL url, ResourceBundle r) {
ErlyBerly.nodeAPI().setTraceLogCallback((traceLog) -> {
if(traceLogs.size() > MAX_TRACE_LOGS) {
if(loadSheddingLog == null) {
loadSheddingLog = TraceLog.newLoadShedding();
traceLogs.add(loadSheddingLog);
}
return;
}
if(loadSheddingLog != null) {
traceLogs.remove(loadSheddingLog);
loadSheddingLog = null;
}
traceLogs.add(traceLog);
});
ErlyBerly.nodeAPI().suspendedProperty().addListener((o, oldv, suspended) -> {
Expand All @@ -58,6 +85,12 @@ public void initialize(URL url, ResourceBundle r) {
reapplyTraces();
}
});
ErlyBerly.nodeAPI().connectedProperty().addListener(
(o, oldV, newV) -> {
if(oldV && !newV) {
traceLogs.add(TraceLog.newNodeDown());
}
});
new SeqTraceCollectorThread((seqs) -> { seqTraces.addAll(seqs); }).start();
}

Expand All @@ -82,7 +115,7 @@ public void toggleTraceModFunc(ModFunc function) {

private void traceModFunc(ModFunc function) {
try {
ErlyBerly.nodeAPI().startTrace(function);
ErlyBerly.nodeAPI().startTrace(function, getMaxTraceQueueLengthConfig());

traces.add(function);
}
Expand All @@ -91,6 +124,11 @@ private void traceModFunc(ModFunc function) {
}
}

private int getMaxTraceQueueLengthConfig() {
Number maxTraceQueueLength = (Number) PrefBind.getOrDefault("maxTraceQueueLength", 1000);
return maxTraceQueueLength.intValue();
}

private void onRemoveTracer(ActionEvent e, ModFunc function) {
try {
ErlyBerly.nodeAPI().stopTrace(function);
Expand All @@ -107,7 +145,7 @@ public void reapplyTraces() {

for (ModFunc function : tracesCopy) {
try {
ErlyBerly.nodeAPI().startTrace(function);
ErlyBerly.nodeAPI().startTrace(function, getMaxTraceQueueLengthConfig());
} catch (Exception e) {
e.printStackTrace();

Expand Down
43 changes: 8 additions & 35 deletions src/main/java/erlyberly/DbgTraceView.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.WeakChangeListener;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.collections.transformation.SortedList;
import javafx.css.PseudoClass;
Expand All @@ -53,27 +50,23 @@

public class DbgTraceView extends VBox {

private final ObservableList<TraceLog> traceLogs = FXCollections.observableArrayList();
private final DbgController dbgController;

private final SortedList<TraceLog> sortedTtraces = new SortedList<TraceLog>(traceLogs);
private final SortedList<TraceLog> sortedTtraces;

private final FilteredList<TraceLog> filteredTraces = new FilteredList<TraceLog>(sortedTtraces);
private final FilteredList<TraceLog> filteredTraces;

private final TableView<TraceLog> tracesBox;

/**
* Set insertTracesAtTop=true in the .erlyberly file in your home directory to
* make traces be inserted at the top of the list.
*/
private boolean insertTracesAtTop;
public DbgTraceView(DbgController aDbgController) {
dbgController = aDbgController;
sortedTtraces = new SortedList<TraceLog>(dbgController.getTraceLogs());
filteredTraces = new FilteredList<TraceLog>(sortedTtraces);

public DbgTraceView(DbgController dbgController) {
setSpacing(5d);
setStyle("-fx-background-insets: 5;");
setMaxHeight(Double.MAX_VALUE);

insertTracesAtTop = PrefBind.getOrDefaultBoolean("insertTracesAtTop", false);

tracesBox = new TableView<TraceLog>();
tracesBox.getStyleClass().add("trace-log-table");
tracesBox.setOnMouseClicked(this::onTraceClicked);
Expand All @@ -95,15 +88,6 @@ public DbgTraceView(DbgController dbgController) {
Parent p = traceLogFloatySearchControl();

getChildren().addAll(p, tracesBox);

dbgController.getTraceLogs().addListener(this::traceLogsChanged);

ErlyBerly.nodeAPI().connectedProperty().addListener(
(o, oldV, newV) -> {
if(oldV && !newV) {
traceLogs.add(TraceLog.newNodeDown());
}
});
}

@SuppressWarnings({ "unchecked", "rawtypes" })
Expand Down Expand Up @@ -195,7 +179,7 @@ private void configureColumnWidth(String widthProperty, TableColumn<TraceLog, ?>

private void putTraceContextMenu() {
TraceContextMenu traceContextMenu = new TraceContextMenu();
traceContextMenu.setItems(traceLogs);
traceContextMenu.setItems(dbgController.getTraceLogs());
traceContextMenu
.setSelectedItems(tracesBox.getSelectionModel().getSelectedItems());

Expand Down Expand Up @@ -307,15 +291,4 @@ private Region traceLogFloatySearchControl() {

return fxmlNode;
}

public void traceLogsChanged(ListChangeListener.Change<? extends TraceLog> e) {
while(e.next()) {
for (TraceLog trace : e.getAddedSubList()) {
if(insertTracesAtTop)
traceLogs.add(0, trace);
else
traceLogs.add(trace);
}
}
}
}
4 changes: 3 additions & 1 deletion src/main/java/erlyberly/TopBarView.java
Original file line number Diff line number Diff line change
Expand Up @@ -258,11 +258,13 @@ public void initialize(URL url, ResourceBundle r) {
private void onSuspendedStateChanged(Boolean suspended) {
if(suspended) {
suspendButton.setText("Unsuspend");
suspendButton.setGraphic(FAIcon.create().icon(AwesomeIcon.PLAY));
suspendButton.setGraphic(FAIcon.create().style("-fx-text-fill: white;").icon(AwesomeIcon.PLAY));
suspendButton.getStyleClass().add("button-suspended");
}
else {
suspendButton.setText("Suspend");
suspendButton.setGraphic(FAIcon.create().icon(AwesomeIcon.PAUSE));
suspendButton.getStyleClass().remove("button-suspended");
}
}

Expand Down
5 changes: 1 addition & 4 deletions src/main/java/erlyberly/TraceContextMenu.java
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,7 @@ private void copyToClipboard(StringBuilder sbuilder) {

private void onDelete(ActionEvent e) {
ArrayList<TraceLog> arrayList = new ArrayList<TraceLog>(selectedItems);

for (TraceLog traceLog : arrayList) {
items.remove(traceLog);
}
items.removeAll(arrayList);
}

private void onDeleteAll(ActionEvent e) {
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/erlyberly/TraceLog.java
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,10 @@ public static TraceLog newNodeDown() {
return new TraceLog("breaker-row", "NODE DOWN");
}

public static TraceLog newLoadShedding() {
return new TraceLog("breaker-row", "LOAD SHEDDING");
}

public OtpErlangList getStackTrace() {
OtpErlangList stacktrace = (OtpErlangList) map.get(OtpUtil.atom("stack_trace"));
if(stacktrace == null)
Expand Down
22 changes: 14 additions & 8 deletions src/main/java/erlyberly/node/NodeAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@
import javafx.collections.ObservableList;

public class NodeAPI {

private static final OtpErlangAtom ERLYBERLY_TRACE_OVERLOAD_ATOM = atom("erlyberly_trace_overload");

private static final String ERLYBERLY = "erlyberly";

private static final String CANNOT_RUN_THIS_METHOD_FROM_THE_FX_THREAD = "cannot run this method from the FX thread";
Expand All @@ -85,6 +88,8 @@ public class NodeAPI {

private static final OtpErlangAtom BET_SERVICES_MSG_ATOM = new OtpErlangAtom("add_locator");

private static final OtpErlangAtom REX_ATOM = atom("rex");

public interface RpcCallback<T> {
void callback(T result);
}
Expand Down Expand Up @@ -408,7 +413,10 @@ else if(isTupleTagged(ERLYBERLY_MODULE_RELOADED_ATOM, receive)) {
});
return receiveRPC(timeout);
}
else if(!isTupleTagged(atom("rex"), receive)) {
else if(isTupleTagged(ERLYBERLY_TRACE_OVERLOAD_ATOM, receive)) {
Platform.runLater(() -> { suspendedProperty.set(true); });
}
else if(!isTupleTagged(REX_ATOM, receive)) {
throw new RuntimeException("Expected tuple tagged with atom rex but got " + receive);
}
OtpErlangObject result = receive.elementAt(1);
Expand Down Expand Up @@ -498,20 +506,18 @@ public synchronized OtpErlangList requestFunctions() throws Exception {
return (OtpErlangList) receiveRPC();
}

public synchronized void startTrace(ModFunc mf) throws Exception {
public synchronized void startTrace(ModFunc mf, int maxQueueLen) throws Exception {
assert mf.getFuncName() != null : "function name cannot be null";
// if tracing is suspended, we can't apply a new trace because that will
// leave us in a state where some traces are active and others are not
if(isSuspended())
return;
sendRPC(ERLYBERLY, "start_trace", toTraceTuple(mf));
sendRPC(ERLYBERLY, "start_trace", toStartTraceFnArgs(mf, maxQueueLen));

OtpErlangObject result = receiveRPC();

if(isTupleTagged(atom("error"), result)) {
if(!isTupleTagged(OK_ATOM, result)) {
System.out.println(result);


// TODO notify caller of failure!
return;
}
Expand All @@ -538,15 +544,15 @@ public synchronized void stopAllTraces() throws IOException, OtpErlangException
receiveRPC();
}

private OtpErlangList toTraceTuple(ModFunc mf) {
private OtpErlangList toStartTraceFnArgs(ModFunc mf, int maxQueueLen) {
String node = self.node();
OtpErlangPid self2 = mbox.self();
return list(
tuple(OtpUtil.atom(node), self2),
atom(mf.getModuleName()),
atom(mf.getFuncName()),
mf.getArity(),
mf.isExported()
maxQueueLen
);
}

Expand Down
7 changes: 5 additions & 2 deletions src/main/java/erlyberly/node/OtpUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,14 @@ private static OtpErlangObject[] toOtpElementArray(Object... elements) {
if(e instanceof Integer) {
tuple[i] = new OtpErlangLong((Integer)e);
}
else if(e instanceof Long) {
tuple[i] = new OtpErlangLong((Long)e);
}
else if(e instanceof OtpErlangObject) {
tuple[i] = (OtpErlangObject) elements[i];
tuple[i] = (OtpErlangObject) e;
}
else if(e instanceof String) {
tuple[i] = new OtpErlangString((String)elements[i]);
tuple[i] = new OtpErlangString((String)e);
}
else if(e instanceof Boolean) {
if(Boolean.TRUE.equals(e))
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/ui/FAIcon.java
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public FAIcon size(String iconSize) {
}

public FAIcon style(String style) {
setStyle(style);
setStyle(getStyle() + style);
return this;
}

Expand Down
Loading