Program: 15884
Project: 15884
Buggy source:
/** 
 * Compact the store by moving all chunks next to each other, if there is free space between chunks. This might temporarily double the file size. Chunks are overwritten irrespective of the current retention time. Before overwriting chunks and before resizing the file, syncFile() is called.
 * @return if anything was written
 */
public synchronized boolean compactMoveChunks(){
  checkOpen();
  if (chunks.size() == 0) {
    return false;
  }
  int oldRetentionTime=retentionTime;
  retentionTime=0;
  long time=getTime();
  ArrayList<Chunk> free=New.arrayList();
  for (  Chunk c : chunks.values()) {
    if (c.maxLengthLive == 0) {
      if (canOverwriteChunk(c,time)) {
        free.add(c);
      }
    }
  }
  for (  Chunk c : free) {
    chunks.remove(c.id);
    meta.remove("String_Node_Str" + c.id);
    int length=MathUtils.roundUpInt(c.length,BLOCK_SIZE) + BLOCK_SIZE;
    fileStore.free(c.start,length);
  }
  if (fileStore.getFillRate() == 100) {
    return false;
  }
  long firstFree=fileStore.getFirstFree();
  ArrayList<Chunk> move=New.arrayList();
  for (  Chunk c : chunks.values()) {
    if (c.start > firstFree) {
      move.add(c);
    }
  }
  for (  Chunk c : move) {
    ByteBuffer buff=getWriteBuffer();
    int length=MathUtils.roundUpInt(c.length,BLOCK_SIZE) + BLOCK_SIZE;
    buff=DataUtils.ensureCapacity(buff,length);
    buff.limit(length);
    ByteBuffer buff2=fileStore.readFully(c.start,length);
    buff.put(buff2);
    long end=getEndPosition();
    fileStore.markUsed(end,length);
    fileStore.free(c.start,length);
    c.start=end;
    buff.position(0);
    c.writeHeader(buff);
    buff.position(buff.limit() - BLOCK_SIZE);
    byte[] header=getStoreHeaderBytes();
    buff.put(header);
    buff.put(new byte[BLOCK_SIZE - header.length]);
    buff.position(0);
    fileStore.writeFully(end,buff);
    releaseWriteBuffer(buff);
    meta.put("String_Node_Str" + c.id,c.asString());
  }
  boolean oldReuse=reuseSpace;
  reuseSpace=false;
  store();
  sync();
  reuseSpace=true;
  for (  Chunk c : move) {
    ByteBuffer buff=getWriteBuffer();
    int length=MathUtils.roundUpInt(c.length,BLOCK_SIZE) + BLOCK_SIZE;
    buff=DataUtils.ensureCapacity(buff,length);
    buff.limit(length);
    ByteBuffer buff2=fileStore.readFully(c.start,length);
    buff.put(buff2);
    long pos=fileStore.allocate(length);
    fileStore.free(c.start,length);
    buff.position(0);
    c.start=pos;
    c.writeHeader(buff);
    buff.position(buff.limit() - BLOCK_SIZE);
    byte[] header=getStoreHeaderBytes();
    buff.put(header);
    buff.put(new byte[BLOCK_SIZE - header.length]);
    buff.position(0);
    fileStore.writeFully(pos,buff);
    releaseWriteBuffer(buff);
    meta.put("String_Node_Str" + c.id,c.asString());
  }
  store();
  sync();
  shrinkFileIfPossible(0);
  reuseSpace=oldReuse;
  retentionTime=oldRetentionTime;
  return true;
}

Fixed version (ground truth):
/** 
 * Compact the store by moving all chunks next to each other, if there is free space between chunks. This might temporarily double the file size. Chunks are overwritten irrespective of the current retention time. Before overwriting chunks and before resizing the file, syncFile() is called.
 * @return if anything was written
 */
public synchronized boolean compactMoveChunks(){
  checkOpen();
  if (chunks.size() == 0) {
    return false;
  }
  int oldRetentionTime=retentionTime;
  retentionTime=0;
  long time=getTime();
  ArrayList<Chunk> free=New.arrayList();
  for (  Chunk c : chunks.values()) {
    if (c.maxLengthLive == 0) {
      if (canOverwriteChunk(c,time)) {
        free.add(c);
      }
    }
  }
  for (  Chunk c : free) {
    chunks.remove(c.id);
    meta.remove("String_Node_Str" + c.id);
    int length=MathUtils.roundUpInt(c.length,BLOCK_SIZE) + BLOCK_SIZE;
    fileStore.free(c.start,length);
  }
  if (fileStore.getFillRate() == 100) {
    return false;
  }
  long firstFree=fileStore.getFirstFree();
  ArrayList<Chunk> move=New.arrayList();
  for (  Chunk c : chunks.values()) {
    if (c.start > firstFree) {
      move.add(c);
    }
  }
  for (  Chunk c : move) {
    ByteBuffer buff=getWriteBuffer();
    int length=MathUtils.roundUpInt(c.length,BLOCK_SIZE) + BLOCK_SIZE;
    buff=DataUtils.ensureCapacity(buff,length);
    buff.limit(length);
    ByteBuffer buff2=fileStore.readFully(c.start,length);
    buff.put(buff2);
    long end=getEndPosition();
    fileStore.markUsed(end,length);
    fileStore.free(c.start,length);
    c.start=end;
    buff.position(0);
    c.writeHeader(buff);
    buff.position(buff.limit() - BLOCK_SIZE);
    byte[] header=getStoreHeaderBytes();
    buff.put(header);
    buff.put(new byte[BLOCK_SIZE - header.length]);
    buff.position(0);
    fileStore.writeFully(end,buff);
    releaseWriteBuffer(buff);
    meta.put("String_Node_Str" + c.id,c.asString());
  }
  boolean oldReuse=reuseSpace;
  reuseSpace=false;
  store();
  sync();
  reuseSpace=true;
  for (  Chunk c : move) {
    if (!chunks.containsKey(c.id)) {
      continue;
    }
    ByteBuffer buff=getWriteBuffer();
    int length=MathUtils.roundUpInt(c.length,BLOCK_SIZE) + BLOCK_SIZE;
    buff=DataUtils.ensureCapacity(buff,length);
    buff.limit(length);
    ByteBuffer buff2=fileStore.readFully(c.start,length);
    buff.put(buff2);
    long pos=fileStore.allocate(length);
    fileStore.free(c.start,length);
    buff.position(0);
    c.start=pos;
    c.writeHeader(buff);
    buff.position(buff.limit() - BLOCK_SIZE);
    byte[] header=getStoreHeaderBytes();
    buff.put(header);
    buff.put(new byte[BLOCK_SIZE - header.length]);
    buff.position(0);
    fileStore.writeFully(pos,buff);
    releaseWriteBuffer(buff);
    meta.put("String_Node_Str" + c.id,c.asString());
  }
  store();
  sync();
  shrinkFileIfPossible(0);
  reuseSpace=oldReuse;
  retentionTime=oldRetentionTime;
  return true;
}