8303674: JFR: TypeLibrary class not thread safe

Reviewed-by: mgronlun
This commit is contained in:
Erik Gahlin 2023-03-10 17:09:56 +00:00
parent c26e1d0148
commit 9dd7b87997
2 changed files with 37 additions and 43 deletions

View File

@ -57,7 +57,6 @@ public final class MetadataRepository {
private final List<EventType> nativeEventTypes = new ArrayList<>(150);
private final List<EventControl> nativeControls = new ArrayList<EventControl>(nativeEventTypes.size());
private final TypeLibrary typeLibrary = TypeLibrary.getInstance();
private final SettingsManager settingsManager = new SettingsManager();
private final Map<String, Class<? extends Event>> mirrors = new HashMap<>();
private Constructor<EventConfiguration> cachedEventConfigurationConstructor;
@ -70,7 +69,8 @@ public final class MetadataRepository {
}
private void initializeJVMEventTypes() {
for (Type type : new ArrayList<>(typeLibrary.getTypes())) {
TypeLibrary.initialize();
for (Type type : TypeLibrary.getTypes()) {
if (type instanceof PlatformEventType pEventType) {
EventType eventType = PrivateAccess.getInstance().newEventType(pEventType);
pEventType.setHasDuration(eventType.getAnnotation(Threshold.class) != null);
@ -152,7 +152,7 @@ public final class MetadataRepository {
configuration = makeConfiguration(eventClass, pe, dynamicAnnotations, dynamicFields);
}
configuration.getPlatformEventType().setRegistered(true);
typeLibrary.addType(configuration.getPlatformEventType());
TypeLibrary.addType(configuration.getPlatformEventType());
if (jvm.isRecording()) {
settingsManager.setEventControl(configuration.getEventControl(), true, JVM.counterTime());
settingsManager.updateRetransform(Collections.singletonList((eventClass)));
@ -169,7 +169,7 @@ public final class MetadataRepository {
}
Utils.verifyMirror(mirrorClass, eventClass);
PlatformEventType et = (PlatformEventType) TypeLibrary.createType(mirrorClass);
typeLibrary.removeType(et.getId());
TypeLibrary.removeType(et.getId());
long id = Type.getTypeId(eventClass);
et.setId(id);
return et;
@ -260,7 +260,7 @@ public final class MetadataRepository {
ByteArrayOutputStream baos = new ByteArrayOutputStream(40000);
DataOutputStream daos = new DataOutputStream(baos);
try {
List<Type> types = typeLibrary.getVisibleTypes();
List<Type> types = TypeLibrary.getVisibleTypes();
if (Logger.shouldLog(LogTag.JFR_METADATA, LogLevel.DEBUG)) {
Collections.sort(types,Comparator.comparing(Type::getName));
for (Type t: types) {
@ -303,7 +303,7 @@ public final class MetadataRepository {
}
unregisterUnloaded();
if (unregistered) {
if (typeLibrary.clearUnregistered()) {
if (TypeLibrary.clearUnregistered()) {
storeDescriptorInJVM();
}
unregistered = false;
@ -320,7 +320,7 @@ public final class MetadataRepository {
for (Class<? extends jdk.internal.event.Event> ec: eventClasses) {
knownIds.add(Type.getTypeId(ec));
}
for (Type type : typeLibrary.getTypes()) {
for (Type type : TypeLibrary.getTypes()) {
if (type instanceof PlatformEventType pe) {
if (!knownIds.contains(pe.getId())) {
if (!pe.isJVM()) {
@ -354,7 +354,7 @@ public final class MetadataRepository {
}
static void unhideInternalTypes() {
for (Type t : TypeLibrary.getInstance().getTypes()) {
for (Type t : TypeLibrary.getTypes()) {
if (t.isInternal()) {
t.setVisible(true);
Logger.log(LogTag.JFR_METADATA, LogLevel.DEBUG, "Unhiding internal type " + t.getName());
@ -367,6 +367,6 @@ public final class MetadataRepository {
}
public synchronized List<Type> getVisibleTypes() {
return typeLibrary.getVisibleTypes();
return TypeLibrary.getVisibleTypes();
}
}

View File

@ -60,21 +60,16 @@ import jdk.jfr.Timestamp;
import jdk.jfr.ValueDescriptor;
public final class TypeLibrary {
private static TypeLibrary instance;
private static boolean implicitFieldTypes;
private static final Map<Long, Type> types = LinkedHashMap.newLinkedHashMap(350);
static final ValueDescriptor DURATION_FIELD = createDurationField();
static final ValueDescriptor THREAD_FIELD = createThreadField();
static final ValueDescriptor STACK_TRACE_FIELD = createStackTraceField();
static final ValueDescriptor START_TIME_FIELD = createStartTimeField();
private TypeLibrary(List<Type> jvmTypes) {
visitReachable(jvmTypes, t -> !types.containsKey(t.getId()), t -> types.put(t.getId(), t));
if (Logger.shouldLog(LogTag.JFR_SYSTEM_METADATA, LogLevel.INFO)) {
Stream<Type> s = types.values().stream().sorted((x, y) -> Long.compare(x.getId(), y.getId()));
s.forEach(t -> t.log("Added", LogTag.JFR_SYSTEM_METADATA, LogLevel.INFO));
}
private TypeLibrary() {
throw new InternalError("Don't instantiate");
}
private static ValueDescriptor createStartTimeField() {
@ -82,7 +77,6 @@ public final class TypeLibrary {
annos.add(new jdk.jfr.AnnotationElement(Timestamp.class, Timestamp.TICKS));
return PrivateAccess.getInstance().newValueDescriptor(EventInstrumentation.FIELD_START_TIME, Type.LONG, annos, 0, false,
EventInstrumentation.FIELD_START_TIME);
}
private static ValueDescriptor createStackTraceField() {
@ -103,28 +97,27 @@ public final class TypeLibrary {
return PrivateAccess.getInstance().newValueDescriptor(EventInstrumentation.FIELD_DURATION, Type.LONG, annos, 0, false, EventInstrumentation.FIELD_DURATION);
}
public static TypeLibrary getInstance() {
synchronized (TypeLibrary.class) {
if (instance == null) {
List<Type> jvmTypes;
try {
jvmTypes = MetadataLoader.createTypes();
jvmTypes.sort(Comparator.comparingLong(Type::getId));
} catch (IOException e) {
throw new Error("JFR: Could not read metadata");
}
instance = new TypeLibrary(jvmTypes);
}
return instance;
public static synchronized void initialize() {
List<Type> jvmTypes;
try {
jvmTypes = MetadataLoader.createTypes();
jvmTypes.sort(Comparator.comparingLong(Type::getId));
} catch (IOException e) {
throw new Error("JFR: Could not read metadata");
}
visitReachable(jvmTypes, t -> !types.containsKey(t.getId()), t -> types.put(t.getId(), t));
if (Logger.shouldLog(LogTag.JFR_SYSTEM_METADATA, LogLevel.INFO)) {
Stream<Type> s = types.values().stream().sorted((x, y) -> Long.compare(x.getId(), y.getId()));
s.forEach(t -> t.log("Added", LogTag.JFR_SYSTEM_METADATA, LogLevel.INFO));
}
}
public Collection<Type> getTypes() {
return types.values();
public static synchronized Collection<Type> getTypes() {
return new ArrayList<>(types.values());
}
// Returned list should be mutable (for in-place sorting)
public List<Type> getVisibleTypes() {
public static synchronized List<Type> getVisibleTypes() {
List<Type> visible = new ArrayList<>(types.size());
types.values().forEach(t -> {
if (t.isVisible()) {
@ -134,7 +127,7 @@ public final class TypeLibrary {
return visible;
}
public static Type createAnnotationType(Class<? extends Annotation> a) {
public static synchronized Type createAnnotationType(Class<? extends Annotation> a) {
if (shouldPersist(a)) {
Type type = defineType(a, Type.SUPER_TYPE_ANNOTATION, false);
if (type != null) {
@ -156,7 +149,7 @@ public final class TypeLibrary {
return null;
}
static AnnotationElement createAnnotation(Annotation annotation) {
public static synchronized AnnotationElement createAnnotation(Annotation annotation) {
Class<? extends Annotation> annotationType = annotation.annotationType();
Type type = createAnnotationType(annotationType);
if (type != null) {
@ -219,11 +212,12 @@ public final class TypeLibrary {
}
return null;
}
public static Type createType(Class<?> clazz) {
public static synchronized Type createType(Class<?> clazz) {
return createType(clazz, Collections.emptyList(), Collections.emptyList());
}
public static Type createType(Class<?> clazz, List<AnnotationElement> dynamicAnnotations, List<ValueDescriptor> dynamicFields) {
public static synchronized Type createType(Class<?> clazz, List<AnnotationElement> dynamicAnnotations, List<ValueDescriptor> dynamicFields) {
if (Thread.class == clazz) {
return Type.THREAD;
@ -327,7 +321,7 @@ public final class TypeLibrary {
}
// By convention all events have these fields.
static void addImplicitFields(Type type, boolean requestable, boolean hasDuration, boolean hasThread, boolean hasStackTrace, boolean hasCutoff) {
public synchronized static void addImplicitFields(Type type, boolean requestable, boolean hasDuration, boolean hasThread, boolean hasStackTrace, boolean hasCutoff) {
if (!implicitFieldTypes) {
createAnnotationType(Timespan.class);
createAnnotationType(Timestamp.class);
@ -423,7 +417,7 @@ public final class TypeLibrary {
// from registered event types. Those types that are not reachable can
// safely be removed
// Returns true if type was removed
public boolean clearUnregistered() {
public static synchronized boolean clearUnregistered() {
Logger.log(LogTag.JFR_METADATA, LogLevel.TRACE, "Cleaning out obsolete metadata");
List<Type> registered = new ArrayList<>();
for (Type type : types.values()) {
@ -452,11 +446,11 @@ public final class TypeLibrary {
return !removeIds.isEmpty();
}
public void addType(Type type) {
public static synchronized void addType(Type type) {
addTypes(Collections.singletonList(type));
}
public static void addTypes(List<Type> ts) {
public static synchronized void addTypes(List<Type> ts) {
if (!ts.isEmpty()) {
visitReachable(ts, t -> !types.containsKey(t.getId()), t -> types.put(t.getId(), t));
}
@ -504,7 +498,7 @@ public final class TypeLibrary {
}
}
public void removeType(long id) {
public static synchronized void removeType(long id) {
types.remove(id);
}
}