Advertisement
Guest User

Untitled

a guest
Jan 28th, 2020
167
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Kotlin 3.27 KB | None | 0 0
  1. import kotlinx.atomicfu.*
  2.  
  3. /**
  4.  * Atomic block.
  5.  */
  6. fun <T> atomic(block: TxScope.() -> T): T {
  7.     while (true) {
  8.         val transaction = Transaction()
  9.         try {
  10.             val result = block(transaction)
  11.             if (transaction.commit()) return result
  12.             transaction.abort()
  13.         } catch (e: AbortException) {
  14.             transaction.abort()
  15.         }
  16.     }
  17. }
  18.  
  19. /**
  20.  * Transactional operations are performed in this scope.
  21.  */
  22. abstract class TxScope {
  23.     abstract fun <T> TxVar<T>.read(): T
  24.     abstract fun <T> TxVar<T>.write(x: T): T
  25. }
  26.  
  27. fun contention(tx: Transaction, owner: Transaction) {
  28.     owner.abort()
  29. }
  30. /**
  31.  * Transactional variable.
  32.  */
  33. class TxVar<T>(initial: T)  {
  34.     private val loc = atomic(Loc(initial, initial, rootTx))
  35.  
  36.     /**
  37.      * Opens this transactional variable in the specified transaction [tx] and applies
  38.      * updating function [update] to it. Returns the updated value.
  39.      */
  40.     fun openIn(tx: Transaction, update: (T) -> T): T {
  41.         // todo: FIXME: this implementation does not actually implement transactional update
  42. //        while (true) {
  43. //            val curLoc = loc.value
  44. //            val curValue = curLoc.oldValue
  45. //            val updValue = update(curValue)
  46. //            if (loc.compareAndSet(curLoc, Loc(updValue, updValue, tx))) return updValue
  47. //        }
  48.         while (true) {
  49.             val curLoc = loc.value;
  50.             val curValue = curLoc.valueIn(tx) { owner ->
  51.                 contention(tx, owner)
  52.             }
  53.             if (curValue === TxStatus.ACTIVE) continue
  54.             val updValue = update(curValue as T)
  55.             val updLoc = Loc(curValue, updValue, tx)
  56.             if (loc.compareAndSet(curLoc, updLoc)) {
  57.                 if (tx.status == TxStatus.ABORTED)
  58.                     throw AbortException
  59.                 return updValue
  60.             }
  61.         }
  62.     }
  63. }
  64.  
  65. /**
  66.  * State of transactional value
  67.  */
  68. private class Loc<T>(
  69.     val oldValue: T,
  70.     val newValue: T,
  71.     val owner: Transaction) {
  72.  
  73.     fun valueIn(
  74.         tx: Transaction,
  75.         onActive: (Transaction) -> Unit
  76.     ): Any? =
  77.         if (owner === tx) newValue else
  78.             when (owner.status) {
  79.                 TxStatus.ABORTED -> oldValue
  80.                 TxStatus.COMMITTED -> newValue
  81.                 TxStatus.ACTIVE -> {
  82.                     onActive(owner)
  83.                     TxStatus.ACTIVE
  84.                 }
  85.             }
  86.  
  87. }
  88.  
  89. private val rootTx = Transaction().apply { commit() }
  90.  
  91. /**
  92.  * Transaction status.
  93.  */
  94. enum class TxStatus { ACTIVE, COMMITTED, ABORTED }
  95.  
  96. /**
  97.  * Transaction implementation.
  98.  */
  99. class Transaction : TxScope() {
  100.     private val _status = atomic(TxStatus.ACTIVE)
  101.     val status: TxStatus get() = _status.value
  102.  
  103.     fun commit(): Boolean =
  104.         _status.compareAndSet(TxStatus.ACTIVE, TxStatus.COMMITTED)
  105.  
  106.     fun abort() {
  107.         _status.compareAndSet(TxStatus.ACTIVE, TxStatus.ABORTED)
  108.     }
  109.  
  110.     override fun <T> TxVar<T>.read(): T = openIn(this@Transaction) { it }
  111.     override fun <T> TxVar<T>.write(x: T) = openIn(this@Transaction) { x }
  112. }
  113.  
  114. /**
  115.  * This exception is thrown when transaction is aborted.
  116.  */
  117. private object AbortException : Exception() {
  118.     override fun fillInStackTrace(): Throwable = this
  119. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement