Project

Profile

Help

Maintenance. Planio will be undergoing a scheduled maintenance this weekend. Between Saturday, July 24 at 9:00 UTC and Sunday, July 25, 22:00 UTC your account might observe occasional downtimes which may last up to several minutes in some cases.

weak references

Added by Vladimir Nesterovsky over 2 years ago

While inspecting key manager code I've seen that you often use weak references. In some cases you even try to model weak reference for two objects at once.

I've tried to model a simple thread safe class to keep objects alive when all its keys alive:

import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

public class WeakStore<T>
{
  public T get(Object ...keys)
  {
    poll();
    
    return store.get(new Key(queue, keys));
  }
  
  public T set(T value, Object ...keys)
  {
    poll();
    
    Key key = new Key(queue, keys);
    
    return value == null ? store.remove(key) : store.put(key, value);
  }
  
  public void poll()
  {
    while(true)
    {
      Ref ref = (Ref)queue.poll();
      
      if (ref == null)
      {
        break;
      }
      
      store.remove(ref.key);
    }
  }
  
  private static class Key
  {
    public Key(ReferenceQueue<Object> queue, Object ...keys)
    {
      int hashCode = 0;
      
      refs = new Ref[keys.length];
      
      for(int i = 0; i < keys.length; ++i)
      {
        Object key = Objects.requireNonNull(keys[i]);

        hashCode ^= key.hashCode();
        refs[i] = new Ref(key, queue, this);
      }
      
      this.hashCode = hashCode;
    }
    
    @Override
    public int hashCode()
    {
      return hashCode;
    }
    
    @Override
    public boolean equals(Object obj)
    {
      if (this == obj)
      {
        return true;
      }

      if (!(obj instanceof Key))
      {
        return false;
      }
      
      Key that = (Key)obj;
      
      if (hashCode != that.hashCode)
      {
        return false;
      }
      
      if (refs.length != that.refs.length)
      {
        return false;
      }
      
      for(int i = 0; i < refs.length; ++i)
      {
        Object key = refs[i].get();
        Object thatKey = that.refs[i].get();
        
        if ((key != thatKey) || (key == null))
        {
          return false;
        }
      }
      
      return false;
    }
    
    private final int hashCode;
    private final Ref[] refs;
  }
  
  private static class Ref extends WeakReference<Object>
  {
    public Ref(Object value, ReferenceQueue<Object> queue, Key key)
    {
      super(value, queue);
      this.key = key;
    }
    
    private final Key key;
  }
  
  private final ReferenceQueue<Object> queue = new ReferenceQueue<>();
  private final ConcurrentHashMap<Key, T> store = new ConcurrentHashMap<>();
}

I think you can even create a singleton to keep different associated objects by keys, e.g. index by document and key definition.


Replies (3)

Please register to reply

RE: weak references - Added by Michael Kay over 2 years ago

Thanks, but I think we do now have a solution to the thread-safety issues in the KeyManager which is going into the maintenance releases we are currently preparing for release.

RE: weak references - Added by Vladimir Nesterovsky over 2 years ago

I was thinking about why do you have two code pathes for local vs shared indices, and cam to conclusion it is due to way you're trying to store them. This way weak storage by two (or even three) keys would make code much simpler, as there is no need to differentiate.

RE: weak references - Added by Michael Kay over 2 years ago

The reason that we distinguish local vs shared keys is that most indexes are reusable across multiple transformations using the same stylesheet, but some are not: specifically, if the xsl:key definition contains references to global variables or parameters, then each transformation needs to build its own local indexes, whereas in the "normal" case, when a stylesheet is used very many times and accesses the same fixed lookup document each time it is run, the indexes for the lookup document can be reused and shared. So the local indexes are owned (in effect) by the Controller, while the shared indexes are jointly owned by the KeyManager and the document itself (using WeakReferences), such that the index disappears if either the KeyManager or the Document disappears.

    (1-3/3)

    Please register to reply