/* 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; }
static void mergeBlock(int mergeIdx, metadata_t *currBlock) { // base case if (mergeIdx == 7) { return; } // add the current block to the freelist if (freelist[mergeIdx] != NULL) { // if there is any other blocks in the freelist[mergeIdx] freelist[mergeIdx]->prev = currBlock; currBlock->next = freelist[mergeIdx]; } freelist[mergeIdx] = currBlock; // calculate the potential address (metadata address) of the buddy block metadata_t *buddyBlock = (metadata_t*) ((char*)currBlock + currBlock->size); if (buddyBlock == NULL) { return; } // see if the buddy is free if (buddyBlock->in_use) { return; } // see if two blocks are of the same size if (currBlock->size != buddyBlock->size) { return; } // see if two blocks are paired correctly int shift = (int)log2(currBlock->size) + 1; int currBit = ((int)((char*)currBlock-(char*)heap)) >> shift & 1; int buddyBit = ((int)((char*)buddyBlock-(char*)heap)) >> shift & 1; if (currBit != buddyBit) { return; } /*~~~~~~~if all criteira are met, merge the two blocks~~~~~~~*/ currBlock->size *= 2; currBlock->in_use = 0; currBlock->next = NULL; currBlock->prev = NULL; // remove the two blocks from the free list if (buddyBlock->prev != NULL) { buddyBlock->prev->next = buddyBlock->next; if (buddyBlock->next != NULL) { buddyBlock->next->prev = buddyBlock->prev; } buddyBlock->prev = NULL; buddyBlock->next = NULL; buddyBlock = NULL; } if (currBlock->next != NULL) { freelist[mergeIdx] = currBlock->next; } else { freelist[mergeIdx] = NULL; } // recursion occurs here! mergeBlock(mergeIdx++, currBlock); }
void my_free(void* ptr) { // get the address of the metadata char *p = (char*) ptr; // get the address of the current metadata_t *currBlock = (metadata_t*)(p - sizeof(metadata_t)); // detect double free if (!currBlock->in_use) { ERRNO = DOUBLE_FREE_DETECTED; return; } else { currBlock->in_use = 0; } // recursively merge blocks if possible int idx = getIdx(currBlock->size); mergeBlock(idx, currBlock); // set the error code ERRNO = NO_ERROR; }