Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Add RestoringWeakReference #1357

Closed
wants to merge 2 commits into from

3 participants

@Shadowfiend
Owner

RestoringWeakReference contains a scala.ref.WeakReference that,
after it has been nulled out, uses a restorer function to restore
the value. This can be used for data that can afford to be evicted
by the garbage collector, but will be needed later. One good example
is Lift form callbacks, which may need the value of an object, but
where you don't necessarily want to be retaining the object
indefinitely while someone is on a page in the face of GC contention.

Examples are in the doc header.

@Shadowfiend Shadowfiend Add RestoringWeakReference to utils.
RestoringWeakReference contains a scala.ref.WeakReference that, after it
has been nulled out, uses a restorer function to restore the value.
This can be used for data that can afford to be evicted by the garbage
collector, but will be needed later. One good example is Lift form
callbacks, which may need the value of an object, but where you don't
necessarily want to be retaining the object indefinitely while someone
is on a page in the face of GC contention.
5833892
@Shadowfiend
Owner

We've used this class to great effect at OpenStudy to manage GC overhead from closure object retention.

@fmpwizard
Owner

Thanks for adding this, any chance to get a spec test with the pull req?

Looks nice.
It might be more in line with scala conventions to rename value to apply. Then you would write ref() instead of ref.value.

P.S. Would you you mind to fix the indentation?
Thanks.

Wow. No idea what happened to the indentation there. I'll definitely fix that.

As for apply vs value… Let me ponder that one for a bit.

Indeed, looks like WeakReference uses apply, no reason why we shouldn't do the same. Pushed that change to master.

@Shadowfiend Shadowfiend was assigned
@Shadowfiend
Owner

So, I'm not sure that's the greatest idea, as I don't know what effect it'll have on the test suite. The only real way to test something like this is to force a WeakReference's eviction. And the only semi-reliable way to do that (that I've found) is to basically create objects until you get an OutOfMemory exception, which you then catch, and allow those objects to go out of scope after the try/catch. It's a bit of a pain, definitely a hack, and may or may not hose the rest of the suite when it runs.

@fmpwizard
Owner

yes, I thought that adding a spec test for it would prove a challenge( well, this is more like, it will messed with all the other tests), so I guess it is ok not to have a test here, we do have plenty of scaladoc explaining it, so that's great, thanks!

@fmpwizard
Owner

rebased to master

@fmpwizard fmpwizard closed this
@Shadowfiend Shadowfiend deleted the asc_issue_1357 branch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Nov 9, 2012
  1. @Shadowfiend

    Add RestoringWeakReference to utils.

    Shadowfiend authored
    RestoringWeakReference contains a scala.ref.WeakReference that, after it
    has been nulled out, uses a restorer function to restore the value.
    This can be used for data that can afford to be evicted by the garbage
    collector, but will be needed later. One good example is Lift form
    callbacks, which may need the value of an object, but where you don't
    necessarily want to be retaining the object indefinitely while someone
    is on a page in the face of GC contention.
  2. @Shadowfiend
This page is out of date. Refresh to see the latest.
View
83 core/util/src/main/scala/net/liftweb/util/RestoringWeakReference.scala
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2006-2012 WorldWide Conferencing, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.liftweb
+package util
+
+import scala.ref.WeakReference
+
+/**
+ * `RestoringWeakReference` contains a `scala.ref.WeakReference` that,
+ * after it has been nulled out, uses a restorer function to restore the
+ * value. This can be used for data that can afford to be evicted by
+ * the garbage collector, but will be needed later. One good example is
+ * Lift form callbacks, which may need the value of an object, but where
+ * you don't necessarily want to be retaining the object indefinitely
+ * while someone is on a page in the face of GC contention.
+ *
+ * You can use `RestoringWeakReference` in a couple of basic ways:
+ *
+ * {{{
+ * val ref = RestoringWeakReference(() => User.find(id))
+ * }}}
+ * In this situation, the `RestoringWeakReference` will immediately call
+ * the passed function to provide the starting value for the reference,
+ * and then the same function will be used if the reference is evicted.
+ *
+ * {{{
+ * val ref = RestoringWeakReference(starter, () => User.find(id))
+ * }}}
+ * Here, starter is an `Option[User]` and `User.find` returns an
+ * `Option[User]`. The first parameter will be used to initialize the
+ * weak reference, while the function will be used to restore the value
+ * if the reference is evicted.
+ *
+ * {{{
+ * val baseRef = new WeakReference(starter)
+ * val ref = new RestoringWeakReference(baseRef, () => User.find(id))
+ * }}}
+ * If you already have a `WeakReference` instance, you can instantiate
+ * `RestoringWeakReference` directly and pass that reference as the
+ * starting value, as well.
+ *
+ * In all these cases, you use `ref.value` to get a hold of the value.
+ * That function will return the value if it is available, and, if not,
+ * it will restore the WeakReference and then return the value.
+ */
+class RestoringWeakReference[T <: AnyRef](private var reference:WeakReference[T], restorer:()=>T) {
+ def value : T = {
+ val existing = reference.get
+ if (! existing.isDefined) {
+ restoreReference
+ value
+ } else {
+ existing.get
+ }
+ }
+
+ private def restoreReference = {
+ reference = new WeakReference(restorer())
+ }
+}
+object RestoringWeakReference {
+ def apply[T <: AnyRef](restorer:()=>T) = {
+ new RestoringWeakReference(new WeakReference(restorer()), restorer)
+ }
+ def apply[T <: AnyRef](starter:T, restorer:()=>T) = {
+ new RestoringWeakReference(new WeakReference(starter), restorer)
+ }
+}
+
Something went wrong with that request. Please try again.