WritableComparator subclasses that rely on deserialization for each compare are already not threadsafe, but if you don't use the static define, you'll get a new instance for each call to get, but *only for the ordering defined by the WritableComparable type.* This is the intent, I think: that the comparators registered with the cache in WritableComparator are low-level comparators matching the semantics of the WritableComparable type.

Other comparators with state are odd beasts; if it is required, then a ThreadLocal instance of whatever you need is probably easier to reason about. If you just want to change the ordering for the sort, the registry doesn't enter into it. As a side-node (I think you're clear on this), JobConf will return the same instance if it comes from the registry. It only creates new instances for user-defined comparators.

For the (vast, vast) majority of RawComparators, there shouldn't be any state, so sharing an instance is a modest, but clear win. Is there something special about your use case that makes a new instance necessary? Is there a particular reason why a ThreadLocal instance of its members wouldn't be more appropriate? Can you define your serialized format in a way that would make defining the raw compare() simpler? -C

On Sep 3, 2008, at 6:53 AM, Igor Maximchuk wrote:

Hello,

We have experienced thread safety issues when subclassing WritableComparator and subsequently calling WritableComparator.define. It seems that same comparator instance has its methods called from different threads. This makes the following code failing from time to time due to race condition

public class PComparator extends WritableComparator {

 ....

 private DataInputBuffer buf = new  DataInputBuffer();
public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) {

       ... [do something that modifies buf]
  }
}
...
static {
      WritableComparator.define(PKey.class, new PComparator());
}

So, no member variables can be modified in compare without the explicit synchronization.

On the other hand, when comparator class is specified in JobConf, each thread recieives it's own instance and no race condition occurs.

I think this case should be mentioned in documentation

I can also suggest to implement another version WritableComparator.define(Class c, Class comparatorClass) which registers the comparaator class, not comparator class instance and make WritableComparator.get to instantiate comparators registered in such a way and declare old defile method deprecated

Reply via email to