code: Futures lockAndInvalidate( H2ONode sender, Futures fs ) {
      assert _key.home(); // Only the HOME node for a key tracks replicas
      // Write-Lock against further GETs
      while( true ) {      // Repeat, in case racing GETs are bumping the counter
        int old = _rwlock.get();
        assert old >= 0 : _key+", rwlock="+old;  // Count does not go negative
        assert old != -1; // Only the thread doing a PUT ever locks
        if( old !=0 ) { // has readers?
          // Active readers: need to block until the GETs (of this very Value!)
          // all complete, before we can invalidate this Value - lest a racing
          // Invalidate bypass a GET.
          try { ForkJoinPool.managedBlock(this); } catch( InterruptedException e ) { }
        } else if( RW_CAS(0,-1,"wlock") )
          break;                  // Got the write-lock!
      }
      // We have the set of Nodes with replicas now.  Ship out invalidates.
      int max = _replicas.length();
      for( int i=0; i<max; i++ )
        if( _replicas.contains(i) && H2ONode.IDX[i] != sender )
          TaskInvalidateKey.invalidate(H2ONode.IDX[i],_key,fs);
      return fs;
    }
docs: This value was atomically extracted from the local STORE by a successful
  TaskPutKey attempt (only 1 thread can ever extract and thus call here).
  No future lookups will find this Value, but there may be existing uses.
  Atomically set the rwlock count to -1 locking it from further GETs and
  ship out invalidates to caching replicas.  May need to block on active
  GETs.  Updates a set of Future invalidates that can be blocked against.