[concurrency-interest] Scalable object cache

Peter Firmstone peter.firmstone at zeus.net.au
Wed Feb 29 15:40:45 EST 2012


Thanks Nathan,

That's the sort of info I'm after, I don't have access to the hardware
I'm targeting unfortunately.

Cheers,

Peter.

On Thu, 2012-03-01 at 02:18, Nathan Reynolds wrote:
> While clock is constant, get() will scale very well.  So, the only
> concern is an occasional scalability issue when clock is updated.  The
> problem will show up as high CPU usage.
> 
> Every time clock is updated in the worst case, each thread will detect
> that "read" is behind and write to "read".  The fence after the write
> won't be a scalability issue.  The act of invalidating and updating
> the cache line holding "read" will be a bottleneck.  Unless the
> optimizer moves instructions in between, the window of vulnerability
> is very small (i.e. 1-2 instructions). Most likely only 1 thread is
> going to do the update.  Rarely 2 threads will.  So, I highly doubt
> you will have any trouble from get().
> 
> Nathan Reynolds | Consulting Member of Technical Staff | 602.333.9091
> Oracle PSR Engineering | Server Technology
> 
> On 2/29/2012 6:37 AM, Peter Firmstone wrote: 
> > I don't have the hardware to test this so I'm hoping someone on the list
> > will know.
> > 
> > In the class below, the get() method returns the referent, provided it
> > hasn't been enqueued.
> > 
> > Both read and clock are volatile, clock is written to, once every 10
> > seconds (or an interval the developer sets) by a single thread.
> > 
> > if (read < clock) read = clock; //Avoid unnecessary volatile write.
> > 
> > If many threads are retrieving the referent, the volatile read variable
> > is written at least once in between clock updates, but any further
> > retrievals will only be reads.
> > 
> > So in this case the volatile long values are multi read, with occasional
> > writes, does get() look scalable to you?
> > 
> > Regards,
> > 
> > Peter.
> > 
> > /*
> >  * Copyright 2012 Zeus Project Services Pty Ltd.
> >  *
> >  * 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 au.net.zeus.collection;
> > 
> > /**
> >  * 
> >  * @author Peter Firmstone.
> >  */
> > class TimedReferrer<T> implements Referrer<T>, TimeBomb {
> >     
> >     private volatile long clock;
> >     private volatile long read;
> >     private final TimedRefQueue queue;
> >     private volatile T referent;
> >     private volatile boolean enqued;
> >     private final Object lock;
> >     private final int hash;
> >     
> >     TimedReferrer(T k, TimedRefQueue q){
> >         long time = System.nanoTime();
> >         clock = time;
> >         read = time;
> >         referent = k;
> >         queue = q;
> >         enqued = false;
> >         lock = new Object();
> >         int hash = 7;
> >         hash = 29 * hash + k.hashCode();
> >         hash = 29 * hash + k.getClass().hashCode();
> >         this.hash = hash;
> >     }
> > 
> >     public T get() {
> >         // Doesn't need to be atomic.
> >         if (read < clock) read = clock; //Avoid unnecessary volatile
> > write.
> >         return referent;
> >     }
> > 
> >     public void clear() {
> >         referent = null;
> >     }
> > 
> >     public boolean isEnqueued() {
> >         return enqued;
> >     }
> > 
> >     public boolean enqueue() {
> >         if (enqued) return false;
> >         if (referent == null) return false;
> >         if (queue == null) return false;
> >         synchronized (lock){ // Sync for atomic write of enqued.
> >             if (enqued) return false;
> >             enqued = queue.offer(this);
> >         }
> >         return enqued;
> >     }
> >     
> >     @Override
> >     public void updateClock(long time){
> >         if (read < clock) { // only write volatile if necessary.
> >             enqueue();
> >             clear();
> >         } else {
> >             clock = time;
> >         }
> >     }
> >     
> >     @Override
> >     public boolean equals(Object o) {
> >         if (this == o)  return true; // Same reference.
> >         if (!(o instanceof Referrer))  return false;
> >         Object k1 = get();
> >         Object k2 = ((Referrer) o).get();
> >         if ( k1 != null && k1.equals(k2)) return true;
> >         return ( k1 == null && k2 == null && hashCode() ==
> > o.hashCode()); // Both objects were collected.
> >     }
> > 
> >     @Override
> >     public int hashCode() {
> >         Object k = get();
> >         int hash = 7;
> >         if (k != null) {
> >             hash = 29 * hash + k.hashCode();
> >             hash = 29 * hash + k.getClass().hashCode();
> >         } else {
> >             hash = this.hash;
> >         }
> >         return hash;
> >     }
> >     
> >     @Override
> >     public String toString(){
> >         Object s = get();
> >         if (s != null) return s.toString();
> >         return super.toString();
> >     }
> >     
> > }
> > 
> > _______________________________________________
> > Concurrency-interest mailing list
> > Concurrency-interest at cs.oswego.edu
> > http://cs.oswego.edu/mailman/listinfo/concurrency-interest



More information about the Concurrency-interest mailing list