@Override public boolean hasNext() { // fast succeed if (null != nextRecord) return true; // We would need to get another record, so check if we can either a record read from the input to the mark queue, or we have more that we should return. // There should be at no time records in the mark queue that are not tracked in the output buffer. return (backingIterator.hasNext() || !outputBuffer.isEmpty()); }
@Override public boolean hasNext() { // fast succeed if (null != nextRecord) return true; // We would need to get another record, so check if we can either a record read from the input to the mark queue, or we have more that we should return. // There should be at no time records in the mark queue that are not tracked in the output buffer. return (backingIterator.hasNext() || !outputBuffer.isEmpty()); }
/** * Add the given SAMRecordIndex to the buffer. The records must be added in order. * @param samRecordWithOrdinal The samRecordWithOrdinal to be added */ public void add(final SamRecordWithOrdinal samRecordWithOrdinal) { if (this.isEmpty()) { this.queueHeadRecordIndex = samRecordWithOrdinal.getRecordOrdinal(); this.queueTailRecordIndex = samRecordWithOrdinal.getRecordOrdinal() - 1; } this.queueTailRecordIndex++; if (samRecordWithOrdinal.getRecordOrdinal() != this.queueTailRecordIndex) { throw new SAMException("The records were added out of order"); } // If necessary, create a new block, using as much ram as available up to its total size if (this.blocks.isEmpty() || !this.blocks.getLast().canAdd()) { // once ram is given to a block, we can't give it to another block (until some is recovered from the head of the queue) final int blockRam = Math.min(this.blockSize, this.availableRecordsInMemory); this.availableRecordsInMemory = this.availableRecordsInMemory - blockRam; final BufferBlock block = new BufferBlock(this.blockSize, blockRam, this.tmpDirs, this.header, samRecordWithOrdinal.getRecordOrdinal()); this.blocks.addLast(block); } this.blocks.getLast().add(samRecordWithOrdinal); }
/** * Add the given SAMRecordIndex to the buffer. The records must be added in order. * @param samRecordWithOrdinal The samRecordWithOrdinal to be added */ public void add(final SamRecordWithOrdinal samRecordWithOrdinal) { if (this.isEmpty()) { this.queueHeadRecordIndex = samRecordWithOrdinal.getRecordOrdinal(); this.queueTailRecordIndex = samRecordWithOrdinal.getRecordOrdinal() - 1; } this.queueTailRecordIndex++; if (samRecordWithOrdinal.getRecordOrdinal() != this.queueTailRecordIndex) { throw new SAMException("The records were added out of order"); } // If necessary, create a new block, using as much ram as available up to its total size if (this.blocks.isEmpty() || !this.blocks.getLast().canAdd()) { // once ram is given to a block, we can't give it to another block (until some is recovered from the head of the queue) final int blockRam = Math.min(this.blockSize, this.availableRecordsInMemory); this.availableRecordsInMemory = this.availableRecordsInMemory - blockRam; final BufferBlock block = new BufferBlock(this.blockSize, blockRam, this.tmpDirs, this.header, samRecordWithOrdinal.getRecordOrdinal()); this.blocks.addLast(block); } this.blocks.getLast().add(samRecordWithOrdinal); }
/** * Returns the next element in the iteration. * * @return The next element in the iteration. * @throws java.util.NoSuchElementException if the buffer is empty. * @throws SAMException if the buffer is not competent to emit (canEmit returns false) */ public SamRecordWithOrdinal next() { if (this.isEmpty()) throw new NoSuchElementException("Attempting to remove an element from an empty SamRecordTrackingBuffer"); final BufferBlock headBlock = this.blocks.getFirst(); if (!headBlock.canEmit()) throw new SAMException("Attempting to get a samRecordWithOrdinal from the SamRecordTrackingBuffer that has not been through " + "marked as examined. canEmit() must return true in order to call next()"); // If the samRecordWithOrdinal was stored in memory, reclaim its ram for use in additional blocks at tail of queue // NB: this must be checked before calling next(), as that method updates the block-head if (!headBlock.headRecordIsFromDisk()) { this.availableRecordsInMemory++; } final SamRecordWithOrdinal samRecordWithOrdinal = headBlock.next(); if (headBlock.hasBeenDrained()) { blocks.poll(); // remove the block as it is now empty headBlock.clear(); // free any disk io resources associated with empty block } this.queueHeadRecordIndex++; return samRecordWithOrdinal; }
/** * Returns the next element in the iteration. * * @return The next element in the iteration. * @throws java.util.NoSuchElementException if the buffer is empty. * @throws SAMException if the buffer is not competent to emit (canEmit returns false) */ public SamRecordWithOrdinal next() { if (this.isEmpty()) throw new NoSuchElementException("Attempting to remove an element from an empty SamRecordTrackingBuffer"); final BufferBlock headBlock = this.blocks.getFirst(); if (!headBlock.canEmit()) throw new SAMException("Attempting to get a samRecordWithOrdinal from the SamRecordTrackingBuffer that has not been through " + "marked as examined. canEmit() must return true in order to call next()"); // If the samRecordWithOrdinal was stored in memory, reclaim its ram for use in additional blocks at tail of queue // NB: this must be checked before calling next(), as that method updates the block-head if (!headBlock.headRecordIsFromDisk()) { this.availableRecordsInMemory++; } final SamRecordWithOrdinal samRecordWithOrdinal = headBlock.next(); if (headBlock.hasBeenDrained()) { blocks.poll(); // remove the block as it is now empty headBlock.clear(); // free any disk io resources associated with empty block } this.queueHeadRecordIndex++; return samRecordWithOrdinal; }
/** * Gets a SAMRecord if one is available after marking. This enforces that we return records in the original * coordinate sort order in a stable fashion. * * @return record representing the head of the alignment-start sorted buffer, or null if the head record has not yet been duplicate marked */ private SAMRecord flush() { // Check that there is at least one record in the coordinate-sorted buffer, and that the head record has been through duplicate-marking while (!outputBuffer.isEmpty() && outputBuffer.canEmit()) { // the buffer contains wrapped SAMRecords, which we want to unwrap final SAMRecord record = outputBuffer.next().getRecord(); // If this read is a duplicate, do we want to remove it (continue the loop) or return it for emission? if (!removeDuplicates || !record.getDuplicateReadFlag()) { return record; } } return null; }
/** * Gets a SAMRecord if one is available after marking. This enforces that we return records in the original * coordinate sort order in a stable fashion. * * @return record representing the head of the alignment-start sorted buffer, or null if the head record has not yet been duplicate marked */ private SAMRecord flush() { // Check that there is at least one record in the coordinate-sorted buffer, and that the head record has been through duplicate-marking while (!outputBuffer.isEmpty() && outputBuffer.canEmit()) { // the buffer contains wrapped SAMRecords, which we want to unwrap final SAMRecord record = outputBuffer.next().getRecord(); // If this read is a duplicate, do we want to remove it (continue the loop) or return it for emission? if (!removeDuplicates || !record.getDuplicateReadFlag()) { return record; } } return null; }
/** * This handles unmapped records at the end of the file. If this is the first time we have found them, then we * can empty the toMarkQueue and call markDuplicatesAndGetTheNextAvailable, otherwise we can just emit them. The * duplication metrics will be updated. */ private SAMRecord nextIfRecordIsUnmappedAtEOF(final SAMRecord record) { // when we find unmapped reads with -1 as their reference index, there should be no mapped reads later in the file. if (foundUnmappedEOFReads) { // previously found unmapped reads at the end of the file final SAMRecord unmappedRecord = backingIterator.next(); // since we called backingIterator.peek() if (!record.isSecondaryOrSupplementary()) { // update metrics final DuplicationMetrics metrics = getMetrics(record); ++metrics.UNMAPPED_READS; } // We should have no more in the queue if (!outputBuffer.isEmpty()) { throw new PicardException("Encountered unmapped reads at the end of the file, but the alignment start buffer was not empty."); } return unmappedRecord; // unmapped end of file records can simply be emitted - no need to duplicate mark them } else { foundUnmappedEOFReads = true; // move past all mapped reads referenceIndex = header.getSequenceDictionary().getSequences().size(); // do the final round of duplicate marking tryPollingTheToMarkQueue(true, null); // NB: we do not call next here since we will recurse and perhaps hit the flush, or re-enter the if with unmapped EOF reads return markDuplicatesAndGetTheNextAvailable(); // this should flush the buffer } }
/** * This handles unmapped records at the end of the file. If this is the first time we have found them, then we * can empty the toMarkQueue and call markDuplicatesAndGetTheNextAvailable, otherwise we can just emit them. The * duplication metrics will be updated. */ private SAMRecord nextIfRecordIsUnmappedAtEOF(final SAMRecord record) { // when we find unmapped reads with -1 as their reference index, there should be no mapped reads later in the file. if (foundUnmappedEOFReads) { // previously found unmapped reads at the end of the file final SAMRecord unmappedRecord = backingIterator.next(); // since we called backingIterator.peek() if (!record.isSecondaryOrSupplementary()) { // update metrics final DuplicationMetrics metrics = getMetrics(record); ++metrics.UNMAPPED_READS; } // We should have no more in the queue if (!outputBuffer.isEmpty()) { throw new PicardException("Encountered unmapped reads at the end of the file, but the alignment start buffer was not empty."); } return unmappedRecord; // unmapped end of file records can simply be emitted - no need to duplicate mark them } else { foundUnmappedEOFReads = true; // move past all mapped reads referenceIndex = header.getSequenceDictionary().getSequences().size(); // do the final round of duplicate marking tryPollingTheToMarkQueue(true, null); // NB: we do not call next here since we will recurse and perhaps hit the flush, or re-enter the if with unmapped EOF reads return markDuplicatesAndGetTheNextAvailable(); // this should flush the buffer } }
if (!toMarkQueue.isEmpty() && outputBuffer.isEmpty()) { throw new PicardException("0 < toMarkQueue && outputBuffer.isEmpty()");
if (!toMarkQueue.isEmpty() && outputBuffer.isEmpty()) { throw new PicardException("0 < toMarkQueue && outputBuffer.isEmpty()");
if (outputBuffer.isEmpty()) { return null;
if (outputBuffer.isEmpty()) { return null;