Custom Ref implementation

6 views
Skip to first unread message

Sciss

unread,
Aug 19, 2010, 6:07:22 PM8/19/10
to scala...@googlegroups.com
hi nathan,

i would like to add a custom Ref implementation that keeps a memory of its modification, that is, i want to roll my own Ref that replaces for instance private[ccstm] var data with some "def data" and "def data_=".

i am thus looking at impl.TAnyRef. could you tell me what exactly the purpose of the methods implemented there is:

- meta
- ref
- offset
- metaOffset

also i'm puzzled by metaCAS as an instance method reads the metaUpdater val from the companion object which in turn was created by instantiating a dummy TAnyRef in order to call newMetaUpdater. but the reference to that dummy object is immediately lost, and newMetaUpdater doesn't access anything inside the class, so wouldn't be sufficient to have

private object TAnyRef {
val metaUpdater = AtomicLongFieldUpdater.newUpdater(classOf[TAnyRef[_]], "meta")
}

and remove newMetaUpdater from TAnyRef?

best, -sciss-


Nathan Bronson

unread,
Aug 20, 2010, 8:10:17 PM8/20/10
to scala...@googlegroups.com
CCSTM has the option of separating the Ref[A] instance presented to the
user from the actual storage. This lets us store the values in a
TArray[Int] in an Array[Int], for example, rather than an
Array[Ref[Int]]. This provides a big reduction in overhead, because
primitive arrays are very efficient. If the user needs a Ref[Int] to
access an element of the TArray, then we can just create a short-lived
instance.

ref and offset are used to identify the _actual_ memory location managed
by a Ref. If the Ref holds the data itself (like a TAnyRef) then ref ==
this and offset == 0 (or any constant). For a Ref that accesses an
element of a TArray, however, ref == the_array and offset ==
element_index. This extra level of indirection provides the flexibility
to create Ref-s on demand and then discard them.

Another way in which this is used is for TxnFieldUpdater, which can
create Ref-s that access the fields of ordinary objects. In that case
ref == the_object and offset == some_index_different_for_each_field.

The meta field holds the extra information that CCSTM needs to track
transaction conflicts. This includes a counter that is increased by
every writing transaction, bits that record write permission, and a few
other bits, all packed into a single long. In the same way that a
<ref,offset> pair identifies a single memory location, <ref,metaOffset>
identifies a single metadata location. (This means its possible for a
single CCSTM lock to protect multiple fields or array elements.)

For any Ref implementation that holds the data and metadata directly
within itself, ref == this, offset == 0, and metaOffset == 0.

So in summary, ref and offset are used by CCSTM to determine whether two
Ref-s are referring to the same memory location, and ref and metaOffset
are used to determine whether they are protected by the same lock (or
rather lock-like thing). In TAnyRef, data and meta hold the actual data
and lock-like thing for that instance, but they could be stored
elsewhere in a different instance. Look at the getRef method in
TArray.scala (line 134) for an example.

The newUpdater function is required to comply with Java's security
model. When a public var is declared in Scala, it actually ends up as a
private field with public accessor functions. This means that only the
class itself can pass the security check performed by
AtomicLongFieldUpdater. The code that calls newUpdater directly from
the object will compile, but it will throw a security exception when you
try to run it.

Cheers,
Nathan

Reply all
Reply to author
Forward
0 new messages