1313
1414import com .alibaba .ttl .TransmittableThreadLocal ;
1515import com .tencent .trpc .core .utils .StringUtils ;
16+ import org .slf4j .spi .MDCAdapter ;
17+
1618import java .util .Deque ;
17- import java .lang . reflect . Field ;
19+ import java .util . ArrayDeque ;
1820import java .util .HashMap ;
1921import java .util .Map ;
2022import java .util .Objects ;
2123import java .util .Optional ;
2224import java .util .concurrent .ConcurrentHashMap ;
23- import org .slf4j .spi .MDCAdapter ;
25+ import java .util .concurrent .ConcurrentLinkedDeque ;
26+ import java .util .concurrent .ConcurrentMap ;
2427
2528/**
2629 * TrpcMDCAdapter
@@ -42,22 +45,17 @@ public class TrpcMDCAdapter implements MDCAdapter {
4245
4346 private final ThreadLocal <Map <String , String >> copyOnInheritThreadLocal = new TransmittableThreadLocal <>();
4447
48+ private final ThreadLocal <ConcurrentMap <String , ConcurrentLinkedDeque <String >>> threadLocalDequeMap =
49+ ThreadLocal .withInitial (ConcurrentHashMap ::new );
50+
4551 /**
4652 * Keeps track of the last operation performed
4753 */
4854 private final ThreadLocal <Integer > lastOperation = new ThreadLocal <>();
4955
5056 static {
5157 mtcMDCAdapter = new TrpcMDCAdapter ();
52- try {
53- // In SLF4J 2.0, MDC.mdcAdapter is no longer directly accessible
54- // We need to use reflection to set it
55- Field field = MDC .class .getDeclaredField ("mdcAdapter" );
56- field .setAccessible (true );
57- field .set (null , mtcMDCAdapter );
58- } catch (Exception e ) {
59- throw new RuntimeException ("Failed to initialize TrpcMDCAdapter" , e );
60- }
58+ MDC .setMDCAdapter (mtcMDCAdapter );
6159 }
6260
6361 public static MDCAdapter init () {
@@ -188,77 +186,49 @@ private Map<String, String> duplicateAndInsertNewMap(Map<String, String> oldMap)
188186 return newMap ;
189187 }
190188
191- /**
192- * Push a context value as identified with the key parameter into the current thread's context map.
193- * This is a SLF4J 2.0 new method for supporting MDC stack operations.
194- *
195- * @param key the key
196- * @param value the value to push
197- * @throws NullPointerException in case the "key" parameter is null
198- */
199189 @ Override
200190 public void pushByKey (String key , String value ) {
201191 Objects .requireNonNull (key , "key cannot be null" );
202- Map <String , String > oldMap = copyOnInheritThreadLocal .get ();
203- Integer lastOp = getAndSetLastOperation ();
204- if (wasLastOpReadOrNull (lastOp ) || oldMap == null ) {
205- Map <String , String > newMap = duplicateAndInsertNewMap (oldMap );
206- newMap .put (key , value );
207- } else {
208- oldMap .put (key , value );
209- }
192+ ConcurrentMap <String , ConcurrentLinkedDeque <String >> dequeMap = threadLocalDequeMap .get ();
193+ ConcurrentLinkedDeque <String > deque = dequeMap .computeIfAbsent (key , k -> new ConcurrentLinkedDeque <>());
194+ deque .push (value );
210195 }
211196
212- /**
213- * Pop the context identified by key parameter from the current thread's context map.
214- * This is a SLF4J 2.0 new method for supporting MDC stack operations.
215- *
216- * @param key the key
217- * @return the value removed, or null if there was no value for the key
218- * @throws NullPointerException in case the "key" parameter is null
219- */
220197 @ Override
221198 public String popByKey (String key ) {
222199 Objects .requireNonNull (key , "key cannot be null" );
223- Map <String , String > oldMap = copyOnInheritThreadLocal .get ();
224- if (oldMap == null ) {
200+ ConcurrentMap <String , ConcurrentLinkedDeque <String >> dequeMap = threadLocalDequeMap .get ();
201+ ConcurrentLinkedDeque <String > deque = dequeMap .get (key );
202+ if (deque == null || deque .isEmpty ()) {
225203 return null ;
226204 }
227- Integer lastOp = getAndSetLastOperation ();
228- if (wasLastOpReadOrNull (lastOp )) {
229- Map <String , String > newMap = duplicateAndInsertNewMap (oldMap );
230- return newMap .remove (key );
231- } else {
232- return oldMap .remove (key );
205+ String value = deque .pollFirst ();
206+ if (deque .isEmpty ()) {
207+ dequeMap .remove (key );
233208 }
209+ return value ;
234210 }
235211
236- /**
237- * Clear all the entries in the deque identified by the key parameter.
238- * This is a SLF4J 2.0.7+ new method for clearing MDC stacks.
239- *
240- * @param key the key
241- * @throws NullPointerException in case the "key" parameter is null
242- */
243212 @ Override
244- public void clearDequeByKey (String key ) {
245- Objects .requireNonNull (key , "key cannot be null" );
246- remove (key );
213+ public Deque <String > getCopyOfDequeByKey (String key ) {
214+ if (key == null ) {
215+ return null ;
216+ }
217+ ConcurrentMap <String , ConcurrentLinkedDeque <String >> dequeMap = threadLocalDequeMap .get ();
218+ ConcurrentLinkedDeque <String > deque = dequeMap .get (key );
219+ if (deque == null ) {
220+ return null ;
221+ }
222+ return new ArrayDeque <>(deque );
247223 }
248224
249- /**
250- * Get a copy of the deque identified by the key parameter.
251- * This is a SLF4J 2.0 new method for supporting MDC stack operations.
252- * Since our implementation uses a simple Map, we return null to indicate no deque.
253- *
254- * @param key the key
255- * @return null (this implementation does not support deques)
256- */
257225 @ Override
258- public Deque <String > getCopyOfDequeByKey (String key ) {
259- // This implementation uses a simple Map structure, not Deque
260- // Return null to indicate no deque exists for the key
261- return null ;
226+ public void clearDequeByKey (String key ) {
227+ if (key == null ) {
228+ return ;
229+ }
230+ ConcurrentMap <String , ConcurrentLinkedDeque <String >> dequeMap = threadLocalDequeMap .get ();
231+ dequeMap .remove (key );
262232 }
263233
264234}
0 commit comments