/* Read the posting list for [zTerm]; AND it with the doclist [in] to * produce the doclist [out], using the given offset [iOffset] for phrase * matching. * (*pSelect) is used to hold an SQLite statement used inside this function; * the caller should initialize *pSelect to NULL before the first call. */ static int query_merge(fulltext_vtab *v, sqlite3_stmt **pSelect, const char *zTerm, DocList *pIn, int iOffset, DocList *out){ int rc; DocListMerge merge; if( pIn!=NULL && !pIn->nData ){ /* If [pIn] is already empty, there's no point in reading the * posting list to AND it in; return immediately. */ return SQLITE_OK; } rc = term_select_doclist(v, zTerm, -1, pSelect); if( rc!=SQLITE_ROW && rc!=SQLITE_DONE ) return rc; mergeInit(&merge, pIn, iOffset, out); while( rc==SQLITE_ROW ){ DocList block; docListInit(&block, DL_POSITIONS_OFFSETS, sqlite3_column_blob(*pSelect, 0), sqlite3_column_bytes(*pSelect, 0)); mergeBlock(&merge, &block); docListDestroy(&block); rc = sqlite3_step(*pSelect); if( rc!=SQLITE_ROW && rc!=SQLITE_DONE ){ return rc; } } return SQLITE_OK; }
/* 7 Implementation of class ~SortAlgorithm~ */ SortAlgorithm::SortAlgorithm( Word stream, const SortOrderSpecification& spec, SortProgressLocalInfo* p, Supplier s, size_t maxFanIn, size_t maxMemSize, size_t ioBufferSize) : F0(0) , W(0) , nextRunNumber(1) , checkProgressAfter(10) , stream(stream) , attributes(-1) , spec(spec) //, cmpObj(cmpObj) , usedMemory(0) , traceMode(RTFlag::isActive("ERA:TraceSort")) , traceModeExtended(RTFlag::isActive("ERA:TraceSortExtended")) , progress(p) { SortedRun *curRun = 0, *nextRun = 0; Word wTuple(Address(0)); // Check specified fan-in for a merge phase setMaxFanIn(maxFanIn); // Check specified main memory for this operation setMemory(maxMemSize, s); // Check I/O buffer size for this operation setIoBuffer(ioBufferSize); if ( traceMode ) { info = new SortInfo(MAX_MEMORY, IO_BUFFER_SIZE); info->RunBuildPhase(); info->MaxMergeFanIn = FMAX; TupleQueueCompare::ResetComparisonCounter(); } // Request first tuple and consume the stream completely qp->Request(stream.addr, wTuple); while( qp->Received(stream.addr) ) { Tuple *t = static_cast<Tuple*>( wTuple.addr ); progress->read++; size_t memSize = t->GetMemSize(); // Save number of attributes if ( attributes == -1 ) { attributes = t->GetNoAttributes(); curRun = new SortedRun(nextRunNumber++, attributes, spec, IO_BUFFER_SIZE); runs.push_back(curRun); } if ( traceMode ) { info->UpdateStatistics(t->GetSize()); } if( usedMemory <= MAX_MEMORY ) { curRun->AppendToMemory(t); usedMemory += memSize; } else { if ( curRun->IsFirstTupleOnDisk() ) { // memory is completely used, append to disk progress->state = 1; curRun->AppendToDisk(t); } else { if ( curRun->IsInSortOrder(t) ) { // tuple is on sort order, append to disk curRun->AppendToDisk(t); } else { if ( traceMode ) { curRun->Info()->TuplesPassedToNextRun++; } // create next run if necessary if ( nextRun == 0 ) { nextRun = new SortedRun( nextRunNumber++, attributes, spec, IO_BUFFER_SIZE ); runs.push_back(nextRun); updateIntermediateMergeCost(); } // next tuple is smaller, save it for the next relation if ( !curRun->IsAtDisk() ) { // push minimum tuple of current run to disk curRun->AppendToDisk(); // append tuple to memory nextRun->AppendToMemory(t); } else { // finish current run curRun->RunFinished(); // switch runs curRun = nextRun; nextRun = 0; curRun->AppendToDisk(t); } } } } qp->Request(stream.addr, wTuple); } if ( traceMode ) { for (size_t i = 0; i < runs.size(); i++) { info->InitialRunInfo.push_back(runs[i]->InfoCopy()); info->InitialRunsCount = runs.size(); } } mergeInit(); }