/* * Copyright 2011, Ben Langmead * * This file is part of Bowtie 2. * * Bowtie 2 is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Bowtie 2 is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Bowtie 2. If not, see . */ #include "outq.h" /** * Caller is telling us that they're about to write output record(s) for * the read with the given id. */ void OutputQueue::beginRead(TReadId rdid, size_t threadId) { ThreadSafe t(&mutex_m, threadSafe_); nstarted_++; if(reorder_) { assert_geq(rdid, cur_); assert_eq(lines_.size(), finished_.size()); assert_eq(lines_.size(), started_.size()); if(rdid - cur_ >= lines_.size()) { // Make sure there's enough room in lines_, started_ and finished_ size_t oldsz = lines_.size(); lines_.resize(rdid - cur_ + 1); started_.resize(rdid - cur_ + 1); finished_.resize(rdid - cur_ + 1); for(size_t i = oldsz; i < lines_.size(); i++) { started_[i] = finished_[i] = false; } } started_[rdid - cur_] = true; finished_[rdid - cur_] = false; } } /** * Writer is finished writing to */ void OutputQueue::finishRead(const BTString& rec, TReadId rdid, size_t threadId) { ThreadSafe t(&mutex_m, threadSafe_); if(reorder_) { assert_geq(rdid, cur_); assert_eq(lines_.size(), finished_.size()); assert_eq(lines_.size(), started_.size()); assert_lt(rdid - cur_, lines_.size()); assert(started_[rdid - cur_]); assert(!finished_[rdid - cur_]); lines_[rdid - cur_] = rec; nfinished_++; finished_[rdid - cur_] = true; flush(false, false); // don't force; already have lock } else { // obuf_ is the OutFileBuf for the output file obuf_.writeString(rec); nfinished_++; nflushed_++; } } /** * Write already-finished lines starting from cur_. */ void OutputQueue::flush(bool force, bool getLock) { if(!reorder_) { return; } ThreadSafe t(&mutex_m, getLock && threadSafe_); size_t nflush = 0; while(nflush < finished_.size() && finished_[nflush]) { assert(started_[nflush]); nflush++; } // Waiting until we have several in a row to flush cuts down on copies // (but requires more buffering) if(force || nflush >= NFLUSH_THRESH) { for(size_t i = 0; i < nflush; i++) { assert(started_[i]); assert(finished_[i]); obuf_.writeString(lines_[i]); } lines_.erase(0, nflush); started_.erase(0, nflush); finished_.erase(0, nflush); cur_ += nflush; nflushed_ += nflush; } } #ifdef OUTQ_MAIN #include using namespace std; int main(void) { cerr << "Case 1 (one thread) ... "; { OutFileBuf ofb; OutputQueue oq(ofb, false); assert_eq(0, oq.numFlushed()); assert_eq(0, oq.numStarted()); assert_eq(0, oq.numFinished()); oq.beginRead(1); assert_eq(0, oq.numFlushed()); assert_eq(1, oq.numStarted()); assert_eq(0, oq.numFinished()); oq.beginRead(3); assert_eq(0, oq.numFlushed()); assert_eq(2, oq.numStarted()); assert_eq(0, oq.numFinished()); oq.beginRead(2); assert_eq(0, oq.numFlushed()); assert_eq(3, oq.numStarted()); assert_eq(0, oq.numFinished()); oq.flush(); assert_eq(0, oq.numFlushed()); assert_eq(3, oq.numStarted()); assert_eq(0, oq.numFinished()); oq.beginRead(0); assert_eq(0, oq.numFlushed()); assert_eq(4, oq.numStarted()); assert_eq(0, oq.numFinished()); oq.flush(); assert_eq(0, oq.numFlushed()); assert_eq(4, oq.numStarted()); assert_eq(0, oq.numFinished()); oq.finishRead(0); assert_eq(0, oq.numFlushed()); assert_eq(4, oq.numStarted()); assert_eq(1, oq.numFinished()); oq.flush(); assert_eq(0, oq.numFlushed()); assert_eq(4, oq.numStarted()); assert_eq(1, oq.numFinished()); oq.flush(true); assert_eq(1, oq.numFlushed()); assert_eq(4, oq.numStarted()); assert_eq(1, oq.numFinished()); oq.finishRead(2); assert_eq(1, oq.numFlushed()); assert_eq(4, oq.numStarted()); assert_eq(2, oq.numFinished()); oq.flush(true); assert_eq(1, oq.numFlushed()); assert_eq(4, oq.numStarted()); assert_eq(2, oq.numFinished()); oq.finishRead(1); assert_eq(1, oq.numFlushed()); assert_eq(4, oq.numStarted()); assert_eq(3, oq.numFinished()); oq.flush(true); assert_eq(3, oq.numFlushed()); assert_eq(4, oq.numStarted()); assert_eq(3, oq.numFinished()); } cerr << "PASSED" << endl; cerr << "Case 2 (one thread) ... "; { OutFileBuf ofb; OutputQueue oq(ofb, false); BTString& buf1 = oq.beginRead(0); BTString& buf2 = oq.beginRead(1); BTString& buf3 = oq.beginRead(2); BTString& buf4 = oq.beginRead(3); BTString& buf5 = oq.beginRead(4); assert_eq(5, oq.numStarted()); assert_eq(0, oq.numFinished()); buf1.install("A\n"); buf2.install("B\n"); buf3.install("C\n"); buf4.install("D\n"); buf5.install("E\n"); oq.finishRead(4); oq.finishRead(1); oq.finishRead(0); oq.finishRead(2); oq.finishRead(3); oq.flush(true); assert_eq(5, oq.numFlushed()); assert_eq(5, oq.numStarted()); assert_eq(5, oq.numFinished()); ofb.flush(); } cerr << "PASSED" << endl; return 0; } #endif /*def ALN_SINK_MAIN*/