Program: 2120
Project: 2120
Buggy source:
/** 
 * The sequence of events is: <ul> <li>Build the aggregated TimelineChunk object, and save it, setting not_valid to true, and aggregation_level to 1.  This means that it won't be noticed by any of the dashboard queries.  The save operation returns the new timeline_times_id</li> <li>Then, in a single transaction, update the aggregated TimelineChunk object to have not_valid = 0, and also delete the TimelineChunk objects that were the basis of the aggregation, and flush any TimelineChunks that happen to be in the cache.</li> <p/>
 * @param timelineChunks the TimelineChunks to be aggregated
 */
private void aggregateHostSampleChunks(final List<TimelineChunk> timelineChunks,final int aggregationLevel,final boolean previouslyAggregated) throws IOException {
  final TimelineChunk firstTimesChunk=timelineChunks.get(0);
  final TimelineChunk lastTimesChunk=timelineChunks.get(timelineChunks.size() - 1);
  final int chunkCount=computeChunkCount(timelineChunks.size(),aggregationLevel,previouslyAggregated);
  final int hostId=firstTimesChunk.getHostId();
  final DateTime startTime=firstTimesChunk.getStartTime();
  final DateTime endTime=lastTimesChunk.getEndTime();
  final List<byte[]> timeParts=new ArrayList<byte[]>(chunkCount);
  final List<byte[]> sampleParts=new ArrayList<byte[]>(chunkCount);
  final List<Long> timelineChunkIds=new ArrayList<Long>(chunkCount);
  int sampleCount=0;
  for (  final TimelineChunk timelineChunk : timelineChunks) {
    timeParts.add(timelineChunk.getTimes());
    sampleParts.add(timelineChunk.getSamples());
    sampleCount+=timelineChunk.getSampleCount();
    timelineChunkIds.add(timelineChunk.getObjectId());
  }
  final byte[] combinedTimeBytes=TimelineCoder.combineTimelines(timeParts);
  final byte[] combinedSampleBytes=SampleCoder.combineSampleBytes(sampleParts);
  final int timeBytesLength=combinedTimeBytes.length;
  final int totalSize=4 + timeBytesLength + combinedSampleBytes.length;
  log.debug("String_Node_Str",new Object[]{firstTimesChunk.getHostId(),firstTimesChunk.getAggregationLevel(),timelineChunks.size(),totalSize,sampleCount});
  timelineChunksBytesCreated.addAndGet(totalSize);
  final int totalSampleCount=sampleCount;
  final TimelineChunk chunk=new TimelineChunk(0,hostId,firstTimesChunk.getSampleKindId(),startTime,endTime,combinedTimeBytes,combinedSampleBytes,totalSampleCount,aggregationLevel + 1,false,false);
  chunksToWrite.add(chunk);
  chunkIdsToInvalidateOrDelete.addAll(timelineChunkIds);
  timelineChunksQueuedForCreation.incrementAndGet();
  if (chunkIdsToInvalidateOrDelete.size() >= config.getMaxChunkIdsToInvalidateOrDelete()) {
    performWrites();
  }
}

Fixed version (ground truth):
/** 
 * The sequence of events is: <ul> <li>Build the aggregated TimelineChunk object, and save it, setting not_valid to true, and aggregation_level to 1.  This means that it won't be noticed by any of the dashboard queries.  The save operation returns the new timeline_times_id</li> <li>Then, in a single transaction, update the aggregated TimelineChunk object to have not_valid = 0, and also delete the TimelineChunk objects that were the basis of the aggregation, and flush any TimelineChunks that happen to be in the cache.</li> <p/>
 * @param timelineChunks the TimelineChunks to be aggregated
 */
private void aggregateHostSampleChunks(final List<TimelineChunk> timelineChunks,final int aggregationLevel,final boolean previouslyAggregated) throws IOException {
  final TimelineChunk firstTimesChunk=timelineChunks.get(0);
  final TimelineChunk lastTimesChunk=timelineChunks.get(timelineChunks.size() - 1);
  final int chunkCount=computeChunkCount(timelineChunks.size(),aggregationLevel,previouslyAggregated);
  final int hostId=firstTimesChunk.getHostId();
  final DateTime startTime=firstTimesChunk.getStartTime();
  final DateTime endTime=lastTimesChunk.getEndTime();
  final List<byte[]> timeParts=new ArrayList<byte[]>(chunkCount);
  final List<byte[]> sampleParts=new ArrayList<byte[]>(chunkCount);
  final List<Long> timelineChunkIds=new ArrayList<Long>(chunkCount);
  int sampleCount=0;
  for (  final TimelineChunk timelineChunk : timelineChunks) {
    timeParts.add(timelineChunk.getTimes());
    sampleParts.add(timelineChunk.getSamples());
    sampleCount+=timelineChunk.getSampleCount();
    timelineChunkIds.add(timelineChunk.getObjectId());
  }
  final byte[] combinedTimeBytes=TimelineCoder.combineTimelines(timeParts,sampleCount);
  final byte[] combinedSampleBytes=SampleCoder.combineSampleBytes(sampleParts);
  final int timeBytesLength=combinedTimeBytes.length;
  final int totalSize=4 + timeBytesLength + combinedSampleBytes.length;
  log.debug("String_Node_Str",new Object[]{firstTimesChunk.getHostId(),firstTimesChunk.getAggregationLevel(),timelineChunks.size(),totalSize,sampleCount});
  timelineChunksBytesCreated.addAndGet(totalSize);
  final int totalSampleCount=sampleCount;
  final TimelineChunk chunk=new TimelineChunk(0,hostId,firstTimesChunk.getSampleKindId(),startTime,endTime,combinedTimeBytes,combinedSampleBytes,totalSampleCount,aggregationLevel + 1,false,false);
  chunksToWrite.add(chunk);
  chunkIdsToInvalidateOrDelete.addAll(timelineChunkIds);
  timelineChunksQueuedForCreation.incrementAndGet();
  if (chunkIdsToInvalidateOrDelete.size() >= config.getMaxChunkIdsToInvalidateOrDelete()) {
    performWrites();
  }
}