Browse Source

Make FlightRecorderApplicationStartup thread safe

Prior to this commit, in some cases application context startup steps
could be created concurrently, which could cause issues with the current
implementation tracking the parent/child relationship between steps.

This commit ensures that the flight recorder implementation is using
thread safe collection implementations for that.

Fixes gh-26941
pull/27012/head
Brian Clozel 5 years ago
parent
commit
7dbbf364f7
  1. 20
      spring-core/src/main/java/org/springframework/core/metrics/jfr/FlightRecorderApplicationStartup.java

20
spring-core/src/main/java/org/springframework/core/metrics/jfr/FlightRecorderApplicationStartup.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,8 +16,9 @@ @@ -16,8 +16,9 @@
package org.springframework.core.metrics.jfr;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.core.metrics.ApplicationStartup;
import org.springframework.core.metrics.StartupStep;
@ -37,24 +38,23 @@ import org.springframework.core.metrics.StartupStep; @@ -37,24 +38,23 @@ import org.springframework.core.metrics.StartupStep;
*/
public class FlightRecorderApplicationStartup implements ApplicationStartup {
private long currentSequenceId;
private final AtomicLong currentSequenceId = new AtomicLong(0);
private final Deque<Long> currentSteps;
public FlightRecorderApplicationStartup() {
this.currentSequenceId = 0;
this.currentSteps = new ArrayDeque<>();
this.currentSteps.offerFirst(0L);
this.currentSteps = new ConcurrentLinkedDeque<>();
this.currentSteps.offerFirst(this.currentSequenceId.get());
}
@Override
public StartupStep start(String name) {
FlightRecorderStartupStep step = new FlightRecorderStartupStep(++this.currentSequenceId, name,
this.currentSteps.getFirst(), committedStep -> this.currentSteps.removeFirst());
this.currentSteps.offerFirst(this.currentSequenceId);
return step;
long sequenceId = this.currentSequenceId.incrementAndGet();
this.currentSteps.offerFirst(sequenceId);
return new FlightRecorderStartupStep(sequenceId, name,
this.currentSteps.getFirst(), committedStep -> this.currentSteps.removeFirstOccurrence(sequenceId));
}
}

Loading…
Cancel
Save