isovector / take2

the real accio analytics platform
7 stars 2 forks source link

Possible race condition in Flyweight.preload() #68

Closed edmundnoble closed 9 years ago

edmundnoble commented 9 years ago

It's possible that after we check the cache to determine which objects to add and which to update, some of the objects are reclaimed before the synchronization block begins. Then, we'll have an NPE when we try to find the object to update in the map and update its last-touched time.

To fix this, I suggest starting the synchronization block just before we partition the cache.

  def preload(objs: Seq[T]) = {
    val now = DateTime.now
    // Move cached.synchronized here?
    val (toUpdate, toAdd) = objs.partition { obj =>
      cached.contains(obj.id)
    }
    // Some objects in toUpdate possibly reclaimed here
    cached.synchronized {
      cached ++= toAdd.map { obj =>
        obj.id -> new Access(obj, now)
      }

      toUpdate.map { obj =>
        cached(obj.id).lastTouched = now
        // NullPointerException ^
      }
    }
  }