summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2006-04-05 16:36:56 +0000
committerMartin Odersky <odersky@gmail.com>2006-04-05 16:36:56 +0000
commit512b362d7361684cad87d9e899f234328ea0bb6e (patch)
treefca5076d8783da2d0e8f0dab4b14949dc6c36e8c /test
parent13aeb49173bf851ee65cf49d314b80cb981b2a74 (diff)
downloadscala-512b362d7361684cad87d9e899f234328ea0bb6e.tar.gz
scala-512b362d7361684cad87d9e899f234328ea0bb6e.tar.bz2
scala-512b362d7361684cad87d9e899f234328ea0bb6e.zip
added new pending test case
Diffstat (limited to 'test')
-rw-r--r--test/pending/pos/Transactions.scala114
1 files changed, 114 insertions, 0 deletions
diff --git a/test/pending/pos/Transactions.scala b/test/pending/pos/Transactions.scala
new file mode 100644
index 0000000000..8fb23268dc
--- /dev/null
+++ b/test/pending/pos/Transactions.scala
@@ -0,0 +1,114 @@
+package scala.concurrent;
+
+class AbortException extends RuntimeException;
+
+object Transaction {
+ private var cnt = 0L
+ def nextId: long = synchronized {
+ cnt = cnt + 1; cnt
+ }
+
+ // Transaction status constants
+ val Running = 0
+ val Committed = 1
+ val Abortable = 2
+ val Aborted = 3
+ val Compound = 4
+
+ def atomic[T](b: Transaction => T): Option[T] =
+ (new Transaction).run(b)
+}
+
+class Transaction {
+ var status: int = _
+
+ var id: long = _ // only for real transactions
+
+ var head: Transaction = this
+ var next: Transaction = null
+
+ def this(hd: Transaction, tl: Transaction) = { this(); this.head = head; this.next = next }
+
+ def makeAbort() = synchronized {
+ while (status != Transaction.Aborted && status != Transaction.Committed) {
+ status = Transaction.Abortable
+ wait()
+ }
+ }
+ private def abort() = synchronized { status = Transaction.Aborted; notifyAll() }
+ private def commit() = synchronized { status = Transaction.Committed; notifyAll() }
+ def run[T](b: Transaction => T): Option[T] =
+ try {
+ status = Transaction.Running
+ id = Transaction.nextId
+ val result = Some(b(this))
+ commit()
+ result
+ } catch {
+ case ex: AbortException => abort(); None
+ case ex: Throwable => abort(); throw ex
+ }
+
+}
+
+trait Transactional {
+
+ /** create a new snapshot */
+ def checkPoint(): unit
+
+ /** copy back snapshot */
+ def rollBack(): unit
+
+ var readers: Transaction
+ var writer: Transaction
+
+ def currentWriter(): Transaction = null
+ if (writer == null) null
+ else if (writer.status == Transaction.Running) writer
+ else {
+ if (writer.status != Transaction.Committed) rollBack();
+ writer = null;
+ null
+ }
+
+ def getter(thisTrans: Transaction): unit = {
+ if (writer == thisTrans) return
+ var r = readers
+ while (r != null && r.head.status != Transaction.Running) { r = r.next; readers = r }
+ while (r != null) {
+ if (r.head == thisTrans) return
+ val last = r
+ r = r.next
+ while (r != null && r.head.status != Transaction.Running) { r = r.next; last.next = r }
+ }
+ synchronized {
+ if (thisTrans.status == Transaction.Abortable) throw new AbortException
+ val w = currentWriter()
+ if (w != null)
+ if (thisTrans.id < w.id) { w.makeAbort(); rollBack(); writer = null }
+ else throw new AbortException
+ readers = if (readers == null) thisTrans else new Transaction(thisTrans, readers)
+ }
+ }
+
+ def setter(thisTrans: Transaction): unit = {
+ if (writer == thisTrans) return
+ synchronized {
+ val w = currentWriter()
+ if (w != null)
+ if (thisTrans.id < w.id) { w.makeAbort(); rollBack() }
+ else throw new AbortException
+ var r = readers
+ while (r != null && r.head.status != Transaction.Running) { r = r.next; readers = r }
+ while (r != null) {
+ if (r.id < thisTrans.id) throw new AbortException
+ else w.makeAbort()
+ val last = r
+ r = r.next
+ while (r != null && r.head.status != Transaction.Running) { r = r.next; last.next = r }
+ }
+ checkPoint()
+ }
+ }
+}
+