Program: 55658
Project: 55658
Buggy source:
/** 
 * Creates a new sorter that reads the data from a given reader and provides an iterator returning that data in a sorted manner. The memory is divided among sort buffers, write buffers and read buffers automatically. <p> WARNING: The given comparator is used simultaneously in multiple threads (the sorting thread and the merging thread). Make sure that the given comparator is stateless and does not make use of member variables.
 * @param memoryManager The memory manager from which to allocate the memory.
 * @param ioManager The I/O manager, which is used to write temporary files to disk.
 * @param totalMemory The total amount of memory dedicated to sorting, merging and I/O.
 * @param maxWriteMem The maximal amount of memory to be dedicated to writing sorted runs. Will be subtracted from the totalamount of memory (<code>totalMemory</code>).
 * @param numSortBuffers The number of distinct buffers to use creation of the initial runs.
 * @param maxNumFileHandles The maximum number of files to be merged at once.
 * @param keyComparators The comparator used to define the order among the keys.
 * @param keyPositions The logical positions of the keys in the records.
 * @param keyClasses The types of the keys.
 * @param input The input that is sorted by this sorter.
 * @param parentTask The parent task, which owns all resources used by this sorter.
 * @param startSpillingFraction The faction of the buffers that have to be filled before the spilling threadactually begins spilling data to disk.
 * @throws IOException Thrown, if an error occurs initializing the resources for external sorting.
 * @throws MemoryAllocationException Thrown, if not enough memory can be obtained from the memory manager toperform the sort.
 */
public UnilateralSortMerger(MemoryManager memoryManager,IOManager ioManager,long totalMemory,long maxWriteMem,int numSortBuffers,int maxNumFileHandles,Comparator<Key>[] keyComparators,int[] keyPositions,Class<? extends Key>[] keyClasses,MutableObjectIterator<PactRecord> input,AbstractInvokable parentTask,float startSpillingFraction) throws IOException, MemoryAllocationException {
  if (memoryManager == null | ioManager == null | keyComparators == null | keyPositions == null | keyClasses == null) {
    throw new NullPointerException();
  }
  if (parentTask == null) {
    throw new NullPointerException("String_Node_Str");
  }
  if (maxNumFileHandles < 2) {
    throw new IllegalArgumentException("String_Node_Str");
  }
  if (keyComparators.length < 1) {
    throw new IllegalArgumentException("String_Node_Str");
  }
  if (keyComparators.length != keyPositions.length || keyPositions.length != keyClasses.length) {
    throw new IllegalArgumentException("String_Node_Str");
  }
  if (totalMemory < MIN_SORT_MEM + MIN_WRITE_MEM) {
    throw new IllegalArgumentException("String_Node_Str");
  }
  this.maxNumFileHandles=maxNumFileHandles;
  this.memoryManager=memoryManager;
  this.ioManager=ioManager;
  this.keyComparators=keyComparators;
  this.keyPositions=keyPositions;
  this.keyClasses=keyClasses;
  this.parent=parentTask;
  this.memoryToReleaseAtShutdown=new ArrayList<List<MemorySegment>>();
  this.channelsToDeleteAtShutdown=new ArrayList<Channel.ID>();
  this.openChannels=new ArrayList<BlockChannelAccess<?,?>>();
  if (maxWriteMem != 0) {
    if (maxWriteMem != -1 && maxWriteMem < MIN_WRITE_MEM) {
      throw new IllegalArgumentException("String_Node_Str" + "String_Node_Str" + MIN_WRITE_MEM + "String_Node_Str");
    }
    final int minBuffers=NUM_WRITE_BUFFERS + maxNumFileHandles;
    final int desiredBuffers=NUM_WRITE_BUFFERS + 2 * maxNumFileHandles;
    int bufferSize=(int)(totalMemory / desiredBuffers);
    if (bufferSize < MIN_IO_BUFFER_SIZE) {
      bufferSize=MIN_IO_BUFFER_SIZE;
      if (totalMemory / minBuffers < MIN_IO_BUFFER_SIZE) {
        maxNumFileHandles=(int)(totalMemory / MIN_IO_BUFFER_SIZE) - NUM_WRITE_BUFFERS;
        if (LOG.isWarnEnabled())         LOG.warn("String_Node_Str" + maxNumFileHandles + "String_Node_Str");
      }
    }
 else {
      bufferSize=Math.min(MAX_IO_BUFFER_SIZE,MathUtils.roundDownToPowerOf2(bufferSize));
    }
    if (maxWriteMem < 0) {
      maxWriteMem=Math.max(totalMemory / 64,MIN_WRITE_MEM);
    }
    this.ioBufferSize=Math.min(bufferSize,MathUtils.roundDownToPowerOf2((int)(maxWriteMem / NUM_WRITE_BUFFERS)));
    maxWriteMem=NUM_WRITE_BUFFERS * this.ioBufferSize;
  }
 else {
    this.ioBufferSize=-1;
  }
  final long sortMem=totalMemory - maxWriteMem;
  final long numSortMemSegments=sortMem / SORT_MEM_SEGMENT_SIZE;
  if (numSortBuffers < 1) {
    if (sortMem > 96 * 1024 * 1024) {
      numSortBuffers=3;
    }
 else     if (numSortMemSegments >= 2 * MIN_NUM_SORT_MEM_SEGMENTS) {
      numSortBuffers=2;
    }
 else {
      numSortBuffers=1;
    }
  }
  final int numSegmentsPerSortBuffer=numSortMemSegments / numSortBuffers > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)(numSortMemSegments / numSortBuffers);
  if (LOG.isDebugEnabled()) {
    LOG.debug("String_Node_Str" + maxWriteMem + "String_Node_Str"+ sortMem+ "String_Node_Str"+ numSortBuffers+ "String_Node_Str"+ numSegmentsPerSortBuffer+ "String_Node_Str"+ SORT_MEM_SEGMENT_SIZE+ "String_Node_Str"+ maxNumFileHandles+ "String_Node_Str");
  }
  final CircularQueues circularQueues=new CircularQueues();
  this.sortBuffers=new ArrayList<NormalizedKeySorter<?>>(numSortBuffers);
  final PactRecordAccessors accessors=new PactRecordAccessors(keyPositions,keyClasses);
  for (int i=0; i < numSortBuffers; i++) {
    final List<MemorySegment> sortSegments=memoryManager.allocateStrict(parentTask,numSegmentsPerSortBuffer,SORT_MEM_SEGMENT_SIZE);
    final NormalizedKeySorter<PactRecord> buffer=new NormalizedKeySorter<PactRecord>(accessors,sortSegments);
    this.sortBuffers.add(buffer);
    CircularElement element=new CircularElement(i,buffer);
    circularQueues.empty.add(element);
  }
  ExceptionHandler<IOException> exceptionHandler=new ExceptionHandler<IOException>(){
    public void handleException(    IOException exception){
      if (!closed) {
        setResultIteratorException(exception);
        close();
      }
    }
  }
;
  this.readThread=getReadingThread(exceptionHandler,input,circularQueues,parentTask,((long)(startSpillingFraction * sortMem)));
  this.sortThread=getSortingThread(exceptionHandler,circularQueues,parentTask);
  this.spillThread=getSpillingThread(exceptionHandler,circularQueues,memoryManager,ioManager,sortMem,parentTask);
  startThreads();
}

Fixed version (ground truth):
/** 
 * Creates a new sorter that reads the data from a given reader and provides an iterator returning that data in a sorted manner. The memory is divided among sort buffers, write buffers and read buffers automatically. <p> WARNING: The given comparator is used simultaneously in multiple threads (the sorting thread and the merging thread). Make sure that the given comparator is stateless and does not make use of member variables.
 * @param memoryManager The memory manager from which to allocate the memory.
 * @param ioManager The I/O manager, which is used to write temporary files to disk.
 * @param totalMemory The total amount of memory dedicated to sorting, merging and I/O.
 * @param maxWriteMem The maximal amount of memory to be dedicated to writing sorted runs. Will be subtracted from the totalamount of memory (<code>totalMemory</code>).
 * @param numSortBuffers The number of distinct buffers to use creation of the initial runs.
 * @param maxNumFileHandles The maximum number of files to be merged at once.
 * @param keyComparators The comparator used to define the order among the keys.
 * @param keyPositions The logical positions of the keys in the records.
 * @param keyClasses The types of the keys.
 * @param input The input that is sorted by this sorter.
 * @param parentTask The parent task, which owns all resources used by this sorter.
 * @param startSpillingFraction The faction of the buffers that have to be filled before the spilling threadactually begins spilling data to disk.
 * @throws IOException Thrown, if an error occurs initializing the resources for external sorting.
 * @throws MemoryAllocationException Thrown, if not enough memory can be obtained from the memory manager toperform the sort.
 */
public UnilateralSortMerger(MemoryManager memoryManager,IOManager ioManager,long totalMemory,long maxWriteMem,int numSortBuffers,int maxNumFileHandles,Comparator<Key>[] keyComparators,int[] keyPositions,Class<? extends Key>[] keyClasses,MutableObjectIterator<PactRecord> input,AbstractInvokable parentTask,float startSpillingFraction) throws IOException, MemoryAllocationException {
  if (memoryManager == null | ioManager == null | keyComparators == null | keyPositions == null | keyClasses == null) {
    throw new NullPointerException();
  }
  if (parentTask == null) {
    throw new NullPointerException("String_Node_Str");
  }
  if (maxNumFileHandles < 2) {
    throw new IllegalArgumentException("String_Node_Str");
  }
  if (keyComparators.length < 1) {
    throw new IllegalArgumentException("String_Node_Str");
  }
  if (keyComparators.length != keyPositions.length || keyPositions.length != keyClasses.length) {
    throw new IllegalArgumentException("String_Node_Str");
  }
  if (totalMemory < MIN_SORT_MEM + MIN_WRITE_MEM) {
    throw new IllegalArgumentException("String_Node_Str");
  }
  this.maxNumFileHandles=maxNumFileHandles;
  this.memoryManager=memoryManager;
  this.ioManager=ioManager;
  this.keyComparators=keyComparators;
  this.keyPositions=keyPositions;
  this.keyClasses=keyClasses;
  this.parent=parentTask;
  this.memoryToReleaseAtShutdown=new ArrayList<List<MemorySegment>>();
  this.channelsToDeleteAtShutdown=new ArrayList<Channel.ID>();
  this.openChannels=new ArrayList<BlockChannelAccess<?,?>>();
  if (maxWriteMem != 0) {
    if (maxWriteMem != -1 && maxWriteMem < MIN_WRITE_MEM) {
      throw new IllegalArgumentException("String_Node_Str" + "String_Node_Str" + MIN_WRITE_MEM + "String_Node_Str");
    }
    final int minBuffers=NUM_WRITE_BUFFERS + maxNumFileHandles;
    final int desiredBuffers=NUM_WRITE_BUFFERS + 2 * maxNumFileHandles;
    int bufferSize=(int)(totalMemory / desiredBuffers);
    if (bufferSize < MIN_IO_BUFFER_SIZE) {
      bufferSize=MIN_IO_BUFFER_SIZE;
      if (totalMemory / minBuffers < MIN_IO_BUFFER_SIZE) {
        maxNumFileHandles=(int)(totalMemory / MIN_IO_BUFFER_SIZE) - NUM_WRITE_BUFFERS;
        if (LOG.isWarnEnabled())         LOG.warn("String_Node_Str" + maxNumFileHandles + "String_Node_Str");
      }
    }
 else {
      bufferSize=Math.min(MAX_IO_BUFFER_SIZE,MathUtils.roundDownToPowerOf2(bufferSize));
    }
    if (maxWriteMem < 0) {
      maxWriteMem=Math.max(totalMemory / 64,MIN_WRITE_MEM);
    }
    this.ioBufferSize=Math.min(bufferSize,MathUtils.roundDownToPowerOf2((int)(maxWriteMem / NUM_WRITE_BUFFERS)));
    maxWriteMem=NUM_WRITE_BUFFERS * this.ioBufferSize;
  }
 else {
    this.ioBufferSize=-1;
  }
  final long sortMem=totalMemory - maxWriteMem;
  final long numSortMemSegments=sortMem / SORT_MEM_SEGMENT_SIZE;
  if (numSortBuffers < 1) {
    if (sortMem > 96 * 1024 * 1024) {
      numSortBuffers=3;
    }
 else     if (numSortMemSegments >= 2 * MIN_NUM_SORT_MEM_SEGMENTS) {
      numSortBuffers=2;
    }
 else {
      numSortBuffers=1;
    }
  }
  final int numSegmentsPerSortBuffer=numSortMemSegments / numSortBuffers > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)(numSortMemSegments / numSortBuffers);
  if (LOG.isDebugEnabled()) {
    LOG.debug("String_Node_Str" + maxWriteMem + "String_Node_Str"+ sortMem+ "String_Node_Str"+ numSortBuffers+ "String_Node_Str"+ numSegmentsPerSortBuffer+ "String_Node_Str"+ SORT_MEM_SEGMENT_SIZE+ "String_Node_Str"+ maxNumFileHandles+ "String_Node_Str");
  }
  final CircularQueues circularQueues=new CircularQueues();
  this.sortBuffers=new ArrayList<NormalizedKeySorter<?>>(numSortBuffers);
  for (int i=0; i < numSortBuffers; i++) {
    final List<MemorySegment> sortSegments=memoryManager.allocateStrict(parentTask,numSegmentsPerSortBuffer,SORT_MEM_SEGMENT_SIZE);
    final PactRecordAccessors accessors=new PactRecordAccessors(keyPositions,keyClasses);
    final NormalizedKeySorter<PactRecord> buffer=new NormalizedKeySorter<PactRecord>(accessors,sortSegments);
    this.sortBuffers.add(buffer);
    CircularElement element=new CircularElement(i,buffer);
    circularQueues.empty.add(element);
  }
  ExceptionHandler<IOException> exceptionHandler=new ExceptionHandler<IOException>(){
    public void handleException(    IOException exception){
      if (!closed) {
        setResultIteratorException(exception);
        close();
      }
    }
  }
;
  this.readThread=getReadingThread(exceptionHandler,input,circularQueues,parentTask,((long)(startSpillingFraction * sortMem)));
  this.sortThread=getSortingThread(exceptionHandler,circularQueues,parentTask);
  this.spillThread=getSpillingThread(exceptionHandler,circularQueues,memoryManager,ioManager,sortMem,parentTask);
  startThreads();
}