c5b3e0820b1c5ac74e8c3f3864f435598af2c82a angie Fri Jul 26 12:46:49 2013 -0700 Fixing bug reported by user in MLQ #11401. I missed a corner case:it's getFinestBin's job to set self->gotFinestBin, *but* nextRowFiltered calls nextRowRaw in a loop to skip past rows that precede minChrom,minEnd. nextRowRaw (nextRowFromBuffer) calls asdDoQueryChunking when it hits the end of the buffer, which it does when the entire buffer's contents precede the new minChrom,minEnd. In that case, getFinestBin is still waiting for a row so it has not yet set self->gotFinestBin. So before calling asdDoQueryChunking, nextRowFromBuffer needs to update self->gotFinestBin. While fixing that, I noticed that nextRowFromBuffer wasn't considering that rowBuf->size might be 0 if the query returns no rows. refs #11401 diff --git src/hg/lib/annoStreamDb.c src/hg/lib/annoStreamDb.c index cef93b4..f4e44f5 100644 --- src/hg/lib/annoStreamDb.c +++ src/hg/lib/annoStreamDb.c @@ -245,31 +245,32 @@ self->maxOutRows -= self->rowBuf.size; if (self->maxOutRows <= 0) self->eof = TRUE; } if (self->eof) return; int queryMaxItems = ASD_CHUNK_SIZE; if (self->useMaxOutRows && self->maxOutRows < queryMaxItems) queryMaxItems = self->maxOutRows; if (self->hasBin) { // Results will be in bin order, but we can restore chromStart order by // accumulating initial coarse-bin items and merge-sorting them with // subsequent finest-bin items which will be in chromStart order. if (self->doNextChunk && self->mergeBins && !self->gotFinestBin) - errAbort("annoStreamDb can't continue merge in chunking query; increase ASD_CHUNK_SIZE"); + errAbort("annoStreamDb %s: can't continue merge in chunking query; " + "increase ASD_CHUNK_SIZE", sSelf->name); self->mergeBins = TRUE; if (self->qLm == NULL) self->qLm = lmInit(0); } if (self->endFieldIndexName != NULL) // Don't let mysql use a (chrom, chromEnd) index because that messes up // sorting by chromStart. sqlDyStringPrintf(query, "IGNORE INDEX (%s) ", self->endFieldIndexName); if (sSelf->chrom != NULL) { uint start = sSelf->regionStart; if (minChrom) { if (differentString(minChrom, sSelf->chrom)) errAbort("annoStreamDb %s: nextRow minChrom='%s' but region chrom='%s'", @@ -350,32 +351,46 @@ asdDoQueryChunking(self, minChrom, minEnd); } } dyStringFree(&query); } static char **nextRowFromBuffer(struct annoStreamDb *self, char *minChrom, uint minEnd) /* Instead of streaming directly from self->sr, we have buffered up the results * of a chunked query; return the head of that queue. */ { struct rowBuf *rowBuf = &self->rowBuf; if (rowBuf->ix > rowBuf->size) errAbort("annoStreamDb %s: rowBuf overflow (%d > %d)", self->streamer.name, rowBuf->ix, rowBuf->size); if (rowBuf->ix == rowBuf->size) + { // Last row in buffer -- we'll need another query to get subsequent rows (if any). + // But first, see if we need to update gotFinestBin, since getFinestBin might be + // one of our callers. + if (rowBuf->size > 0) + { + char **lastRow = rowBuf->buf[rowBuf->size-1]; + int lastBin = atoi(lastRow[0]); + if (lastBin >= self->minFinestBin) + self->gotFinestBin = TRUE; + } asdDoQueryChunking(self, minChrom, minEnd); + } +if (rowBuf->size == 0) + return NULL; +else return rowBuf->buf[rowBuf->ix++]; } static char **nextRowFiltered(struct annoStreamDb *self, boolean *retRightFail, char *minChrom, uint minEnd) /* Skip past any left-join failures until we get a right-join failure, a passing row, * or end of data. Return row or NULL, and return right-join fail status via retRightFail. */ { int numCols = self->streamer.numCols; char **row = self->nextRowRaw(self, minChrom, minEnd); if (minChrom != NULL && row != NULL) { // Ignore rows that fall completely before (minChrom, minEnd) - save annoGrator's time int chromIx = self->omitBin+self->chromIx; int endIx = self->omitBin+self->endIx;