timwspence / cats-stm Goto Github PK
View Code? Open in Web Editor NEWA STM implementation for Cats Effect
Home Page: https://timwspence.github.io/cats-stm/
License: Apache License 2.0
A STM implementation for Cats Effect
Home Page: https://timwspence.github.io/cats-stm/
License: Apache License 2.0
We should publish artifacts for ScalaJS as well
Currently we eval
stm actions as a criticalSection
(under a global lock basically). This shouldn't be necessary and I've never produced a test that fails but if we don't do this then the Santa Claus example stops producing output after a few seconds. My best guess is that we don't update fibers to be retried correctly (either we forget about them or we fail to register them for retry in time). The alternative is that it is deadlock simply because we have too many threads contenting for a lock on STM
. So it would be nice to fix #168 first to see if this issue magically goes away.
Hi, thanks for the library !
I was going through the tutorial, but the code published on github.io
does not compile.
If you copy the code directly from https://github.com/TimWSpence/cats-stm/blob/master/docs/docs/tutorial/tutorial.md it works just fine, but it seems the publish process to github.io
gets confused by the ;
instances in the code.
This :
}; object Gate{
somehow gets translated to
}; object Gate{; object Gate{
on github.io
I'm guessing getting rid of the ;
and putting the companion object on a separate line will fix the issue.
Let me know if you'd like me to submit a PR, I'm happy to do so.
We should cross-build the laws (and maybe docs?) for ScalaJS
We should start cross-building against Dotty as well
We should have one!
Currently out critical sections are implemented using blocker.blockOn(F.delay(STM.synchronized{...}))
which sucks. It also means we have to statically allocate a Blocker
backed by a daemon threadpool. Which sucks. It might well also be to blame for #164. Which sucks.
It would be nice to move to cats effect non-thread-blocking concurrency primitives. However, we can't statically allocate these as we don't know what the concrete monad will be. The only solution I can think of right now is to add an implicit runtime: STMRuntime
to atomically
. This might look something like:
trait STMRuntime[F[_]] {
val globalLock: Semaphore[F]
}
but I'd love to hear other suggestions!
I've been building and publishing with Java 11. It turns out this is a bad idea.
Possibly a case of adding
.jvmSettings(
javacOptions ++= Seq("-source", "1.8", "-target", "1.8")
)
to build.sbt
I'm looking for a ready made purely functional caching solution, and wonder if something based on cats-stm exist out there ?
Currently blocked on sbt/sbt-unidoc#83 as publishing the docs requires unidoc, which fails because DottyDoc
was deprecated
We currently store a List[Deferred[F, Unit]]
in every TVar
to signal transactions that are blocked on that TVar
. Is it possible to just store a single Deferred[F, Unit]
instead and have all txns block on that Deferred
being completed?
Hi,
I can't find a lot of documentation or post online about this module of cats which i find amazing. Where can i find good material to learn from it.
I have a use case where i am relying on a very old Java api, which is all about mutation. I want to isolate it and get back a sense of referential transparency. The all api, is all about mutating value. It is an api to mange RDF model.
Hence I was thinking about finding an abstraction other than just IO, which would help me write some good referentially transparent code and track the mutation
any advise ?
STM[F]
should define mapK
Opacity is a correctness property for STM algorithms. Here is a short description and pointers to more reading: https://nbronson.github.io/scala-stm/semantics.html#opacity. The really short version is that opacity guarantees that a running transaction will never read inconsistent values from transactional varables, even if that transaction will never commit or fail.
It seems that currently cats-stm
does not provide opacity. We can see this with the following example: let's have two TVar[Int]
s, r1
and r2
, with the invariant that r1 < r2
. One transaction increments the values (transactionally), upholding this invariant:
def txn1(r1: TVar[Int], r2: TVar[Int]): Txn[Unit] = {
r1.modify(_ + 1) *> r2.modify(_ + 1)
}
Another transaction reads from both TVar
s, and compares the values; if it reads impossible (inconsistent) values, it prints ERROR: ...
:
def txn2(r1: TVar[Int], r2: TVar[Int]): Txn[Int] = {
r1.get.flatMap { v1 =>
r2.get.map { v2 =>
if (v2 <= v1) {
println(s"ERROR: (${v1}, ${v2})")
}
v2 - v1
}
}
}
Sometimes when txn1
and txn2
run concurrently, txn2
can observe the impossible (inconsistent) values (see below for a full reproduction). Such running instances of txn2
seem to not commit/fail (they seem to be retried). However, observing such inconsistency in a running transaction can still be problematic; for example, we could have while (true) {}
instead of println(...)
, which would cause the transaction to never commit or fail.
Full code example:
package com.example
import cats.effect.kernel.Concurrent
import cats.effect.IO
import cats.syntax.all._
import io.github.timwspence.cats.stm.STM
import munit.CatsEffectSuite
class StmExample[F[_]](stm: STM[F])(implicit F: Concurrent[F]) {
import stm._
private[this] def txn1(r1: TVar[Int], r2: TVar[Int]): Txn[Unit] = {
r1.modify(_ + 1) *> r2.modify(_ + 1)
}
private[this] def txn2(r1: TVar[Int], r2: TVar[Int]): Txn[Int] = {
r1.get.flatMap { v1 =>
r2.get.map { v2 =>
if (v2 <= v1) {
println(s"ERROR: (${v1}, ${v2})")
}
v2 - v1
}
}
}
def example: F[Int] = for {
r1 <- stm.commit(TVar.of(0))
r2 <- stm.commit(TVar.of(1))
t1 = stm.commit(txn1(r1, r2))
t2 = F.parReplicateAN(32)(
replicas = 64,
ma = stm.commit(txn2(r1, r2)).flatTap {
case 1 => F.unit
case x => F.raiseError[Unit](new Exception(s"result was $x"))
}
)
b = F.both(F.cede *> t1, F.cede *> t2)
r <- b.replicateA(8192).map(_.last._2)
} yield r.last
}
final class CatsStmTest extends CatsEffectSuite {
test("Test STM") {
STM.Make[IO].runtime(Long.MaxValue).flatMap { stm =>
assertIO(new StmExample[IO](stm).example, 1)
}
}
}
Running this test results in output like this:
ERROR: (1388, 1388)
ERROR: (1388, 1388)
ERROR: (1388, 1388)
ERROR: (2205, 2205)
ERROR: (2205, 2205)
(The number of ERROR
lines is non-deterministic, sometimes even zero.)
It would be great to use cachix to cache our shell derivation for building the microsite
The current behaviour (which is expected but not desired) is that retry is biased in favour of newer transactions, leading to the risk of starvation for older transactions. You can see this in action with the santa claus problem, where the behaviour stabilises on only running the reindeer transactions.
This is because every time a transaction T succeeds, it picks up any transactions which are new candidates for retry and clears the pending state. If any of these retried transactions T1 succeed, they will do the same thing and hence the other transactions being retried by T will effectively go to the "back of the line", behind those being retried by T1 and so on.
I'm documenting this behaviour here both as a reminder to myself and in case anyone else sees this first and feels like fixing it before I get round to it!
Hello
Having upgraded from 0.8.0 to 0.11.0 I have what is either a question or an issue (I am unsure but raising it as an issue to hopefully at least get an answer).
I have a class that requires a TVar to be passed in at instantiation which is posing an import based issue.
class MyClass(val stuff: TVar[String]) { ... }
Previously (0.8.0) I could have an "import io.github.timwspence.cats.stm.TVar" at the top of my class, this no longer works and from the examples the approach is something akin to
val stm = STM.runtime[IO].unsafeRunSync()
import stm._
but this does not work outside of a class or object?
Is there a way to reference the TVar class without having to instatiate the Stm Runtime?
Please advise if this is a legitimate issue, a misuse issue or just a misunderstanding?
Karl
Would be nice to have a TDeferred
Now that we have a Make
typeclass, we should fix this as well
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.