Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fallback IOLocal#unsafeThreadLocal by a true ThreadLocal #4200

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 8 additions & 14 deletions core/jvm/src/main/scala/cats/effect/IOLocalPlatform.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,31 +21,25 @@ import IOFiberConstants.ioLocalPropagation
private[effect] trait IOLocalPlatform[A] { self: IOLocal[A] =>

/**
* Returns a [[java.lang.ThreadLocal]] view of this [[IOLocal]] that allows to unsafely get,
* set, and remove (aka reset) the value in the currently running fiber. The system property
* `cats.effect.ioLocalPropagation` must be `true`, otherwise throws an
* Creates a [[java.lang.ThreadLocal]] based on this [[IOLocal]]. This allows to unsafely get,
* set, and remove (aka reset) the [[IOLocal]]'s value in the currently running fiber. When
* used outside of a fiber, behaves like an ordinary `ThreadLocal`.
*
* The system property `cats.effect.ioLocalPropagation` must be `true`, otherwise throws an
* [[java.lang.UnsupportedOperationException]].
*/
def unsafeThreadLocal(): ThreadLocal[A] = if (ioLocalPropagation)
new ThreadLocal[A] {
override def get(): A = {
val fiber = IOFiber.currentIOFiber()
val state = if (fiber ne null) fiber.getLocalState() else IOLocalState.empty
self.getOrDefault(state)
self.getOrDefault(IOLocal.getThreadLocalState())
}

override def set(value: A): Unit = {
val fiber = IOFiber.currentIOFiber()
if (fiber ne null) {
fiber.setLocalState(self.set(fiber.getLocalState(), value))
}
IOLocal.setThreadLocalState(self.set(IOLocal.getThreadLocalState(), value))
}

override def remove(): Unit = {
val fiber = IOFiber.currentIOFiber()
if (fiber ne null) {
fiber.setLocalState(self.reset(fiber.getLocalState()))
}
IOLocal.setThreadLocalState(self.reset(IOLocal.getThreadLocalState()))
}
}
else
Expand Down
15 changes: 11 additions & 4 deletions core/shared/src/main/scala/cats/effect/IOLocal.scala
Original file line number Diff line number Diff line change
Expand Up @@ -273,14 +273,21 @@ object IOLocal {
*/
def isPropagating: Boolean = IOFiberConstants.ioLocalPropagation

private[effect] def getThreadLocalState() = {
private[effect] val threadLocal = new ThreadLocal[IOLocalState] {
override def initialValue() = IOLocalState.empty
}

private[effect] def getThreadLocalState(): IOLocalState = {
val fiber = IOFiber.currentIOFiber()
if (fiber ne null) fiber.getLocalState() else IOLocalState.empty
if (fiber ne null) fiber.getLocalState() else threadLocal.get()
}

private[effect] def setThreadLocalState(state: IOLocalState) = {
private[effect] def setThreadLocalState(state: IOLocalState): Unit = {
val fiber = IOFiber.currentIOFiber()
if (fiber ne null) fiber.setLocalState(state)
if (fiber ne null)
fiber.setLocalState(state)
else
threadLocal.set(state)
}

private final class IOLocalImpl[A](default: A) extends IOLocal[A] {
Expand Down
Loading