diff --git a/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests/src/org/eclipse/tracecompass/incubator/trace/server/jersey/rest/core/tests/stubs/TraceModelStub.java b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests/src/org/eclipse/tracecompass/incubator/trace/server/jersey/rest/core/tests/stubs/TraceModelStub.java index 90e757342..c772662af 100644 --- a/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests/src/org/eclipse/tracecompass/incubator/trace/server/jersey/rest/core/tests/stubs/TraceModelStub.java +++ b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests/src/org/eclipse/tracecompass/incubator/trace/server/jersey/rest/core/tests/stubs/TraceModelStub.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018, 2021 Ericsson + * Copyright (c) 2018, 2024 Ericsson * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License 2.0 which @@ -12,6 +12,7 @@ package org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests.stubs; import java.nio.charset.Charset; +import java.util.Map; import java.util.Objects; import java.util.UUID; @@ -37,6 +38,7 @@ public class TraceModelStub extends AbstractModelStub { private static final long serialVersionUID = -1030854786688167776L; private final String fPath; + private final Map fProperties; /** * {@link JsonCreator} Constructor for final fields @@ -53,6 +55,8 @@ public class TraceModelStub extends AbstractModelStub { * start time * @param end * end time + * @param properties + * the properties of the trace * @param indexingStatus * indexing status */ @@ -64,9 +68,11 @@ public TraceModelStub( @JsonProperty("nbEvents") long nbEvents, @JsonProperty("start") long start, @JsonProperty("end") long end, + @JsonProperty("properties") Map properties, @JsonProperty("indexingStatus") String indexingStatus) { super(name, uuid, nbEvents, start, end, indexingStatus); fPath = path; + fProperties = properties; } /** @@ -76,9 +82,11 @@ public TraceModelStub( * trace name * @param path * path to trace on server file system + * @param properties + * properties of the trace */ - public TraceModelStub(String name, String path) { - this(name, path, getUUID(path, name), 0, 0L, 0L, "RUNNING"); + public TraceModelStub(String name, String path, Map properties) { + this(name, path, getUUID(path, name), 0, 0L, 0L, properties, "RUNNING"); } private static UUID getUUID(String path, String name) { @@ -95,6 +103,14 @@ public String getPath() { return fPath; } + /** + * Returns the trace's properties + * @return the trace's properties + */ + public Map getProperties() { + return fProperties; + } + @Override public String toString() { return getName() + ": CONTEXT_SWITCHES_UST_PROPERTIES = new HashMap<>(Map.ofEntries( + Map.entry("hostname", "\"qemu1\""), + Map.entry("clock_offset", "1450192743562703624"), + Map.entry("domain", "\"ust\""), + Map.entry("host ID", "\"40b6dd3a-c130-431e-92ef-8c4dafe14627\""), + Map.entry("tracer_name", "\"lttng-ust\""), + Map.entry("tracer_major", "2"), + Map.entry("tracer_minor", "6") + )); + /** * {@link TraceModelStub} to represent the object returned by the server for * {@link CtfTestTrace#CONTEXT_SWITCHES_KERNEL}. @@ -173,6 +186,23 @@ public abstract class RestServerTest { */ protected static final String CONTEXT_SWITCHES_KERNEL_NAME = "kernel"; + /** + * The properties of the trace. + */ + public static final Map CONTEXT_SWITCHES_KERNEL_PROPERTIES = new HashMap<>(Map.ofEntries( + Map.entry("hostname", "\"qemu1\""), + Map.entry("kernel_version", "\"#1 SMP PREEMPT Sat Dec 12 14:52:43 CET 2015\""), + Map.entry("tracer_patchlevel", "3"), + Map.entry("clock_offset", "1450192747804379176"), + Map.entry("domain", "\"kernel\""), + Map.entry("sysname", "\"Linux\""), + Map.entry("host ID", "\"40b6dd3a-c130-431e-92ef-8c4dafe14627\""), + Map.entry("kernel_release", "\"4.1.13-WR8.0.0.0_standard\""), + Map.entry("tracer_name", "\"lttng-modules\""), + Map.entry("tracer_major", "2"), + Map.entry("tracer_minor", "6") + )); + /** * {@link TraceModelStub} to represent the object returned by the server for * {@link CtfTestTrace#ARM_64_BIT_HEADER}, with the same name as {@link #CONTEXT_SWITCHES_KERNEL_STUB} @@ -184,6 +214,23 @@ public abstract class RestServerTest { */ protected static final String ARM_64_KERNEL_NAME = "kernel"; + /** + * The properties of the trace. + */ + public static final Map ARM_64_KERNEL_PROPERTIES = new HashMap<>(Map.ofEntries( + Map.entry("hostname", "\"lager\""), + Map.entry("kernel_version", "\"#6 SMP PREEMPT Wed Oct 1 17:07:11 CEST 2014\""), + Map.entry("tracer_patchlevel", "0"), + Map.entry("clock_offset", "1412663327522716450"), + Map.entry("domain", "\"kernel\""), + Map.entry("sysname", "\"Linux\""), + Map.entry("host ID", "\"5a71a43c-1390-4365-9baf-111c565e78c3\""), + Map.entry("kernel_release", "\"3.10.31-ltsi\""), + Map.entry("tracer_name", "\"lttng-modules\""), + Map.entry("tracer_major", "2"), + Map.entry("tracer_minor", "5") + )); + /** * Expected toString() of all data providers for this experiment */ @@ -198,13 +245,13 @@ public abstract class RestServerTest { @BeforeClass public static void beforeTest() throws IOException { String contextSwitchesUstPath = FileLocator.toFileURL(CtfTestTrace.CONTEXT_SWITCHES_UST.getTraceURL()).getPath().replaceAll("/$", ""); - CONTEXT_SWITCHES_UST_STUB = new TraceModelStub(CONTEXT_SWITCHES_UST_NAME, contextSwitchesUstPath); + CONTEXT_SWITCHES_UST_STUB = new TraceModelStub(CONTEXT_SWITCHES_UST_NAME, contextSwitchesUstPath, CONTEXT_SWITCHES_UST_PROPERTIES); String contextSwitchesKernelPath = FileLocator.toFileURL(CtfTestTrace.CONTEXT_SWITCHES_KERNEL.getTraceURL()).getPath().replaceAll("/$", ""); - CONTEXT_SWITCHES_KERNEL_STUB = new TraceModelStub(CONTEXT_SWITCHES_KERNEL_NAME, contextSwitchesKernelPath); + CONTEXT_SWITCHES_KERNEL_STUB = new TraceModelStub(CONTEXT_SWITCHES_KERNEL_NAME, contextSwitchesKernelPath, CONTEXT_SWITCHES_KERNEL_PROPERTIES); String arm64Path = FileLocator.toFileURL(CtfTestTrace.ARM_64_BIT_HEADER.getTraceURL()).getPath().replaceAll("/$", ""); - ARM_64_KERNEL_STUB = new TraceModelStub(ARM_64_KERNEL_NAME, arm64Path); + ARM_64_KERNEL_STUB = new TraceModelStub(ARM_64_KERNEL_NAME, arm64Path, ARM_64_KERNEL_PROPERTIES); ImmutableList.Builder b = ImmutableList.builder(); b.add(new DataProviderDescriptorStub("org.eclipse.tracecompass.internal.analysis.timing.core.segmentstore.scatter.dataprovider:org.eclipse.linuxtools.lttng2.ust.analysis.callstack", diff --git a/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/model/Trace.java b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/model/Trace.java index 48ad40d30..7a75996cd 100644 --- a/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/model/Trace.java +++ b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/model/Trace.java @@ -1,5 +1,5 @@ /********************************************************************** - * Copyright (c) 2021 Ericsson + * Copyright (c) 2021, 2024 Ericsson * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License 2.0 which @@ -11,6 +11,7 @@ package org.eclipse.tracecompass.incubator.internal.trace.server.jersey.rest.core.model; +import java.util.Map; import java.util.UUID; import com.fasterxml.jackson.annotation.JsonProperty; @@ -59,6 +60,12 @@ public interface Trace { @Schema(description = "The trace's end time") long getEnd(); + /** + * @return The properties. + */ + @Schema(description = "The trace's properties") + Map getProperties(); + /** * @return The indexing status. */ diff --git a/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/Experiment.java b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/Experiment.java index 81f52fdd9..232bde236 100644 --- a/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/Experiment.java +++ b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/Experiment.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2020, 2021 Ericsson + * Copyright (c) 2020, 2024 Ericsson * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License 2.0 which @@ -83,7 +83,7 @@ public Experiment(@JsonProperty("name") String name, */ public static Experiment from(TmfExperiment experiment, UUID expUUID) { List traceUUIDs = ExperimentManagerService.getTraceUUIDs(expUUID); - Set traces = new LinkedHashSet<>(Lists.transform(traceUUIDs, uuid -> Trace.from(TraceManagerService.getTraceResource(uuid), uuid))); + Set traces = new LinkedHashSet<>(Lists.transform(traceUUIDs, uuid -> Trace.from(TraceManagerService.getOrCreateTraceInstance(uuid), uuid))); return new Experiment(experiment.getName(), expUUID, experiment.getNbEvents(), diff --git a/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/ExperimentManagerService.java b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/ExperimentManagerService.java index 6ef1570e0..26dffb2f2 100644 --- a/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/ExperimentManagerService.java +++ b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/ExperimentManagerService.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018, 2021 Ericsson + * Copyright (c) 2018, 2024 Ericsson * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License 2.0 which @@ -210,8 +210,8 @@ public Response deleteExperiment(@Parameter(description = EXP_UUID) @PathParam(" if (resource == null) { return Response.status(Status.NOT_FOUND).build(); } - Experiment experimentModel = Experiment.from(resource, expUUID); TmfExperiment experiment = EXPERIMENTS.remove(expUUID); + Experiment experimentModel = experiment != null ? Experiment.from(experiment, expUUID) : Experiment.from(resource, expUUID); if (experiment != null) { TmfSignalManager.dispatchSignal(new TmfTraceClosedSignal(this, experiment)); experiment.dispose(); diff --git a/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/Trace.java b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/Trace.java index fb59e2ba5..fa1cafc6f 100644 --- a/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/Trace.java +++ b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/Trace.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2020, 2021 Ericsson + * Copyright (c) 2020, 2024 Ericsson * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License 2.0 which @@ -12,11 +12,14 @@ package org.eclipse.tracecompass.incubator.internal.trace.server.jersey.rest.core.services; import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; import java.util.UUID; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.IPath; import org.eclipse.tracecompass.tmf.core.io.ResourceUtil; +import org.eclipse.tracecompass.tmf.core.project.model.ITmfPropertiesProvider; import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; import com.fasterxml.jackson.annotation.JsonCreator; @@ -33,6 +36,7 @@ public final class Trace implements Serializable { private final long fNbEvents; private final long fStart; private final long fEnd; + private final Map fProperties; private final String fIndexingStatus; /** @@ -50,6 +54,8 @@ public final class Trace implements Serializable { * start time * @param end * end time + * @param properties + * the properties of the trace * @param indexingStatus * indexing status */ @@ -60,6 +66,7 @@ public Trace(@JsonProperty("name") String name, @JsonProperty("nbEvents") long nbEvents, @JsonProperty("start") long start, @JsonProperty("end") long end, + @JsonProperty("properties") Map properties, @JsonProperty("indexingStatus") String indexingStatus) { fName = name; fUUID = uuid; @@ -67,6 +74,7 @@ public Trace(@JsonProperty("name") String name, fNbEvents = nbEvents; fStart = start; fEnd = end; + fProperties = properties; fIndexingStatus = indexingStatus; } @@ -86,6 +94,7 @@ public static Trace from(ITmfTrace trace, UUID uuid) { trace.getNbEvents(), trace.getStartTime().toNanos(), trace.getEndTime().toNanos(), + trace instanceof ITmfPropertiesProvider ? ((ITmfPropertiesProvider) trace).getProperties() : new HashMap<>(), trace.isIndexing() ? "RUNNING" : "COMPLETED"); //$NON-NLS-1$ //$NON-NLS-2$ } @@ -110,6 +119,7 @@ public static Trace from(IResource traceResource, UUID uuid) { 0L, 0L, 0L, + new HashMap<>(), "CLOSED"); //$NON-NLS-1$ } @@ -161,6 +171,14 @@ public long getEnd() { return fEnd; } + /** + * Returns the properties + * @return the properties + */ + public Map getProperties() { + return fProperties; + } + /** * Returns the indexing status * @return the indexing status @@ -171,6 +189,6 @@ public String getIndexingStatus() { @Override public String toString() { - return "Trace [fName=" + fName + ", fUUID=" + fUUID + ", fPath=" + fPath + ", fNbEvents=" + fNbEvents + ", fStart=" + fStart + ", fEnd=" + fEnd + ", fIndexingStatus=" + fIndexingStatus + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ + return "Trace [fName=" + fName + ", fUUID=" + fUUID + ", fPath=" + fPath + ", fNbEvents=" + fNbEvents + ", fStart=" + fStart + ", fEnd=" + fEnd + ", fIndexingStatus=" + fIndexingStatus + ", fProperties" + fProperties.toString() + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ } } \ No newline at end of file diff --git a/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/TraceManagerService.java b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/TraceManagerService.java index 875325a28..7c8d4e097 100644 --- a/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/TraceManagerService.java +++ b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/services/TraceManagerService.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2021 Ericsson + * Copyright (c) 2017, 2024 Ericsson * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License 2.0 which @@ -89,6 +89,11 @@ public class TraceManagerService { private static final Map TRACES = Collections.synchronizedMap(initTraces()); + /** + * The trace instance is created lazily, meaning it is only instantiated when its UUID is queried. + */ + private static final Map TRACE_INSTANCES = Collections.synchronizedMap(new HashMap<>()); + private static final String TRACES_FOLDER = "Traces"; //$NON-NLS-1$ /** @@ -214,7 +219,8 @@ private static Response put(String path, String name, String typeID) } UUID uuid = getTraceUUID(resource); TRACES.put(uuid, resource); - return Response.ok(createTraceModel(uuid)).build(); + Trace traceModel = createTraceModel(uuid); + return Response.ok(traceModel).build(); } /** @@ -241,6 +247,23 @@ public static UUID getTraceUUID(IResource resource) { return TRACES.get(uuid); } + /** + * Get or create an instance of a trace by its UUID. This trace instance lives + * as long as the trace is opened in the trace server. + * + * @param uuid + * the trace UUID + * @return the trace instance, or null if it could not be created + */ + public static @Nullable ITmfTrace getOrCreateTraceInstance(UUID uuid) { + if (TRACE_INSTANCES.containsKey(uuid)) { + return TRACE_INSTANCES.get(uuid); + } + ITmfTrace trace = createTraceInstance(uuid); + TRACE_INSTANCES.put(uuid, trace); + return trace; + } + /** * Create an instance of a trace by its UUID. The caller is responsible to * dispose the instance when it is no longer needed. @@ -278,11 +301,8 @@ public static UUID getTraceUUID(IResource resource) { } private static Trace createTraceModel(UUID uuid) { - IResource resource = TRACES.get(uuid); - if (resource == null) { - return null; - } - return Trace.from(resource, uuid); + ITmfTrace trace = getOrCreateTraceInstance(uuid); + return Trace.from(trace, uuid); } /** @@ -391,6 +411,10 @@ public Response deleteTrace(@Parameter(description = TRACE_UUID) @PathParam("uui if (ExperimentManagerService.isTraceInUse(uuid)) { return Response.status(Status.CONFLICT).entity(trace).build(); } + ITmfTrace traceInstance = TRACE_INSTANCES.remove(uuid); + if (traceInstance != null) { + traceInstance.dispose(); + } IResource resource = TRACES.remove(uuid); if (resource == null) { return Response.ok(trace).build(); diff --git a/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/webapp/TraceSerializer.java b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/webapp/TraceSerializer.java index 39b418b91..437472f9a 100644 --- a/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/webapp/TraceSerializer.java +++ b/trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/webapp/TraceSerializer.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018, 2020 Ericsson + * Copyright (c) 2018, 2024 Ericsson * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License 2.0 which @@ -12,6 +12,7 @@ package org.eclipse.tracecompass.incubator.internal.trace.server.jersey.rest.core.webapp; import java.io.IOException; +import java.util.Map.Entry; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.tracecompass.incubator.internal.trace.server.jersey.rest.core.services.Trace; @@ -48,6 +49,11 @@ public void serialize(Trace value, JsonGenerator gen, SerializerProvider provide gen.writeNumberField("nbEvents", value.getNbEvents()); //$NON-NLS-1$ gen.writeNumberField("start", value.getStart()); //$NON-NLS-1$ gen.writeNumberField("end", value.getEnd()); //$NON-NLS-1$ + gen.writeObjectFieldStart("properties"); //$NON-NLS-1$ + for (Entry entry : value.getProperties().entrySet()) { + gen.writeStringField(entry.getKey(), entry.getValue()); + } + gen.writeEndObject(); gen.writeStringField("indexingStatus", value.getIndexingStatus()); //$NON-NLS-1$ gen.writeEndObject(); }