From 3ca5064a72179290521d72d695a67b32e9bf3439 Mon Sep 17 00:00:00 2001 From: Diego Date: Tue, 11 Sep 2018 21:22:42 -0300 Subject: Improvements in ThreadLocalStorage --- .../src/main/scala/kamon/context/Storage.scala | 33 +++++++++++++++++----- 1 file changed, 26 insertions(+), 7 deletions(-) (limited to 'kamon-core/src/main') diff --git a/kamon-core/src/main/scala/kamon/context/Storage.scala b/kamon-core/src/main/scala/kamon/context/Storage.scala index 4f4e6cbb..f116142d 100644 --- a/kamon-core/src/main/scala/kamon/context/Storage.scala +++ b/kamon-core/src/main/scala/kamon/context/Storage.scala @@ -15,6 +15,8 @@ package kamon.context +import kamon.context.Storage.ThreadLocal.ContextHolder + trait Storage { def current(): Context def store(context: Context): Storage.Scope @@ -27,28 +29,45 @@ object Storage { def close(): Unit } - + /** + * Wrapper that implements optimized {@link ThreadLocal} access pattern ideal for heavily used + * ThreadLocals. + * + * It is faster to use a mutable holder object and always perform ThreadLocal.get() and never use + * ThreadLocal.set(), because the value is more likely to be found in the ThreadLocalMap direct hash + * slot and avoid the slow path ThreadLocalMap.getEntryAfterMiss(). + * + * Important: this thread local will live in ThreadLocalMap forever, so use with care. + */ class ThreadLocal extends Storage { - private val tls = new java.lang.ThreadLocal[Context]() { - override def initialValue(): Context = Context.Empty + private val tls = new java.lang.ThreadLocal[ContextHolder]() { + override def initialValue() = new ContextHolder(Context.Empty) } override def current(): Context = - tls.get() + get() override def store(context: Context): Scope = { val newContext = context - val previousContext = tls.get() - tls.set(newContext) + val previousContext = get() + set(newContext) new Scope { override def context: Context = newContext - override def close(): Unit = tls.set(previousContext) + override def close(): Unit = set(previousContext) } } + + private def get():Context = + tls.get().value + + private def set(value:Context) : Unit = + tls.get().value = value } object ThreadLocal { def apply(): ThreadLocal = new ThreadLocal() + + final class ContextHolder(var value:Context) } } \ No newline at end of file -- cgit v1.2.3 From bcc0780ddc022e2bf43b07be5f59cec081b5c89a Mon Sep 17 00:00:00 2001 From: Diego Date: Thu, 27 Sep 2018 09:26:38 -0300 Subject: avoid use an Kamon-defined holder object as that would prevent class unloading. --- .../src/main/scala/kamon/context/Storage.scala | 40 +++++++++------------- 1 file changed, 17 insertions(+), 23 deletions(-) (limited to 'kamon-core/src/main') diff --git a/kamon-core/src/main/scala/kamon/context/Storage.scala b/kamon-core/src/main/scala/kamon/context/Storage.scala index f116142d..2b409592 100644 --- a/kamon-core/src/main/scala/kamon/context/Storage.scala +++ b/kamon-core/src/main/scala/kamon/context/Storage.scala @@ -1,5 +1,5 @@ /* ========================================================================================= - * Copyright © 2013-2017 the kamon project + * Copyright © 2013-2018 the kamon project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at @@ -15,8 +15,6 @@ package kamon.context -import kamon.context.Storage.ThreadLocal.ContextHolder - trait Storage { def current(): Context def store(context: Context): Storage.Scope @@ -33,41 +31,37 @@ object Storage { * Wrapper that implements optimized {@link ThreadLocal} access pattern ideal for heavily used * ThreadLocals. * - * It is faster to use a mutable holder object and always perform ThreadLocal.get() and never use + *

It is faster to use a mutable holder object and always perform ThreadLocal.get() and never use * ThreadLocal.set(), because the value is more likely to be found in the ThreadLocalMap direct hash * slot and avoid the slow path ThreadLocalMap.getEntryAfterMiss(). * - * Important: this thread local will live in ThreadLocalMap forever, so use with care. - */ + *

Credit to @trask from the FastThreadLocal in glowroot. + * + *

One small change is that we don't use an kamon-defined holder object as that would prevent class unloading. + * + * */ class ThreadLocal extends Storage { - private val tls = new java.lang.ThreadLocal[ContextHolder]() { - override def initialValue() = new ContextHolder(Context.Empty) + private val tls = new java.lang.ThreadLocal[Array[AnyRef]]() { + override def initialValue(): Array[AnyRef] = + Array(Context.Empty) } override def current(): Context = - get() + tls.get()(0).asInstanceOf[Context] - override def store(context: Context): Scope = { - val newContext = context - val previousContext = get() - set(newContext) + override def store(newContext: Context): Scope = { + val ref = tls.get() + val previousContext = ref(0) + ref(0) = newContext new Scope { override def context: Context = newContext - override def close(): Unit = set(previousContext) + override def close(): Unit = ref(0) = previousContext } } - - private def get():Context = - tls.get().value - - private def set(value:Context) : Unit = - tls.get().value = value } object ThreadLocal { def apply(): ThreadLocal = new ThreadLocal() - - final class ContextHolder(var value:Context) } -} \ No newline at end of file +} -- cgit v1.2.3