You've already forked mariadb-columnstore-engine
							
							
				mirror of
				https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
				synced 2025-10-31 18:30:33 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			1004 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1004 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* Copyright (C) 2014 InfiniDB, Inc.
 | |
| 
 | |
|    This program 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; version 2 of
 | |
|    the License.
 | |
| 
 | |
|    This program 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 this program; if not, write to the Free Software
 | |
|    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 | |
|    MA 02110-1301, USA. */
 | |
| 
 | |
| /*****************************************************************************
 | |
|  * $Id: index.cpp 2035 2013-01-21 14:12:19Z rdempsey $
 | |
|  *
 | |
|  ****************************************************************************/
 | |
| 
 | |
| #include <iostream>
 | |
| using namespace std;
 | |
| 
 | |
| #include "primitiveprocessor.h"
 | |
| #include "we_index.h"
 | |
| #include "messagelog.h"
 | |
| #include "messageobj.h"
 | |
| 
 | |
| /** @file
 | |
|  * Brief description of the file contents
 | |
|  *
 | |
|  * More detailed description
 | |
|  */
 | |
| 
 | |
| using namespace logging;
 | |
| 
 | |
| #ifdef VERBOSE
 | |
| #define GET_BITTEST(test, string, x) \
 | |
| 	if (in->Shift + x >= in->SSlen) { \
 | |
| 		test = (string & masks[in->SSlen - in->Shift]); \
 | |
| 		lastStage = true; \
 | |
|  		cerr << "  bittest is 0x" << hex << (int) test << dec << " this is the last iteration" << endl; \
 | |
| 	} \
 | |
| 	else { \
 | |
| 		test = (string >> (in->SSlen - in->Shift - x)) & masks[x]; \
 | |
| 		lastStage = false; \
 | |
|  		cerr << "  bittest is 0x" << hex << (int) test << dec << endl; \
 | |
| 	}
 | |
| #else
 | |
| #define GET_BITTEST(test, string, x) \
 | |
| 	if (in->Shift + x >= in->SSlen) { \
 | |
| 		test = (string & masks[in->SSlen - in->Shift]); \
 | |
| 		lastStage = true; \
 | |
| 	} \
 | |
| 	else { \
 | |
| 		test = (string >> (in->SSlen - in->Shift - x)) & masks[x]; \
 | |
| 		lastStage = false; \
 | |
| 	}
 | |
| #endif
 | |
| 
 | |
| #define IDXWALK_INIT() \
 | |
| 	niceBlock = reinterpret_cast<uint8_t *>(block); \
 | |
| 	blockOffset = (in->SubBlock * WriteEngine::SUBBLOCK_TOTAL_BYTES) + \
 | |
| 		(in->SBEntry * 8); \
 | |
| 	treePtr = reinterpret_cast<WriteEngine::IdxBitTestEntry *>(&niceBlock[blockOffset]);
 | |
| 
 | |
| #define GET_GROUP_SIZE() \
 | |
| 		switch (treePtr->group) { \
 | |
| 			case 0: bitTestGroupSize = 1; break; \
 | |
| 			case 1: bitTestGroupSize = 2; break; \
 | |
| 			case 2: bitTestGroupSize = 4; break; \
 | |
| 			case 3: bitTestGroupSize = 8; break; \
 | |
| 			case 4: bitTestGroupSize = 16; break; \
 | |
| 			case 5: bitTestGroupSize = 32; break; \
 | |
| 			default: \
 | |
| 				cerr << "PrimitiveProcessor::IndexWalk*(): bad group field " << \
 | |
| 					treePtr->group << endl; \
 | |
| 				return; \
 | |
| 		}
 | |
| 
 | |
| #ifdef VERBOSE
 | |
| #define ADD_ELEMENT(index, shift, state) \
 | |
| 	element = new IndexWalkHeader(); \
 | |
| 	memcpy(element, in, sizeof(IndexWalkHeader)); \
 | |
| 	element->ism.Command = INDEX_WALK_RESULTS; \
 | |
| 	element->Shift += shift; \
 | |
| 	element->LBID = treePtr[index].fbo; \
 | |
| 	element->SubBlock = treePtr[index].sbid; \
 | |
| 	element->SBEntry = treePtr[index].entry; \
 | |
| 	element->State = state; \
 | |
| 	cerr << "  (no convert) creating a result from subblock entry " << (int) index << " with Shift=" << (int) element->Shift << \
 | |
| 		" LBID=" << element->LBID << " Subblock=" << (int) element->SubBlock << " Subblock entry=" << \
 | |
| 		(int) element->SBEntry << " State=" << (int) state; \
 | |
| 	if (element->LBID == in->LBID && element->Shift < element->SSlen) { \
 | |
| 		cerr << "  recursing..." << endl; \
 | |
| 		p_IdxWalk(element, out); \
 | |
| 		delete element; \
 | |
| 	} \
 | |
| 	else { \
 | |
| 		cerr << "  adding this to the result set" << endl; \
 | |
| 		out->push_back(element); \
 | |
| 	}
 | |
| #else
 | |
| #define ADD_ELEMENT(index, shift, state) \
 | |
| 	element = new IndexWalkHeader(); \
 | |
| 	memcpy(element, in, sizeof(IndexWalkHeader)); \
 | |
| 	element->ism.Command = INDEX_WALK_RESULTS; \
 | |
| 	element->Shift += shift; \
 | |
| 	element->LBID = treePtr[index].fbo; \
 | |
| 	element->SubBlock = treePtr[index].sbid; \
 | |
| 	element->SBEntry = treePtr[index].entry; \
 | |
| 	element->State = state; \
 | |
| 	if (element->LBID == in->LBID && element->Shift < element->SSlen) { \
 | |
| 		p_IdxWalk(element, out); \
 | |
| 		delete element; \
 | |
| 	} \
 | |
| 	else \
 | |
| 		out->push_back(element);
 | |
| #endif
 | |
| 
 | |
| #ifdef VERBOSE
 | |
| #define ADD_ELEMENT_WITH_CONVERT(index, shift, state) \
 | |
| 	element = new IndexWalkHeader(); \
 | |
| 	memcpy(element, in, sizeof(IndexWalkHeader)); \
 | |
| 	element->ism.Command = INDEX_WALK_RESULTS; \
 | |
| 	element->Shift += shift; \
 | |
| 	element->LBID = treePtr[index].fbo; \
 | |
| 	element->SubBlock = treePtr[index].sbid; \
 | |
| 	element->SBEntry = treePtr[index].entry; \
 | |
| 	element->State = state; \
 | |
| 	cerr << "  (convert) creating a result from subblock entry " << (int) index << " with Shift=" << (int) element->Shift << \
 | |
| 		" LBID=" << element->LBID << " Subblock=" << (int) element->SubBlock << " Subblock entry=" << \
 | |
| 		(int) element->SBEntry << " State=" << (int) state << endl; \
 | |
| 	if (convertToSingleOp != -1) { \
 | |
| 		cerr << "  converting it to a single COP filter" << endl; \
 | |
| 		element->NVALS = 1; \
 | |
| 		if (convertToSingleOp == 1) { \
 | |
| 			element->COP1 = element->COP2; \
 | |
| 			element->SearchString[0] = element->SearchString[1]; \
 | |
| 		} \
 | |
| 	} \
 | |
| 	if (element->LBID == in->LBID && element->Shift < element->SSlen) { \
 | |
| 		cerr << "  recursing..." << endl; \
 | |
| 		p_IdxWalk(element, out); \
 | |
| 		delete element; \
 | |
| 	} \
 | |
| 	else { \
 | |
| 		cerr << "  adding it to the result set" << endl;\
 | |
| 		out->push_back(element); \
 | |
| 	}
 | |
| #else
 | |
| #define ADD_ELEMENT_WITH_CONVERT(index, shift, state) \
 | |
| 	element = new IndexWalkHeader(); \
 | |
| 	memcpy(element, in, sizeof(IndexWalkHeader)); \
 | |
| 	element->ism.Command = INDEX_WALK_RESULTS; \
 | |
| 	element->Shift += shift; \
 | |
| 	element->LBID = treePtr[index].fbo; \
 | |
| 	element->SubBlock = treePtr[index].sbid; \
 | |
| 	element->SBEntry = treePtr[index].entry; \
 | |
| 	element->State = state; \
 | |
| 	if (convertToSingleOp != -1) { \
 | |
| 		element->NVALS = 1; \
 | |
| 		if (convertToSingleOp == 1) { \
 | |
| 			element->COP1 = element->COP2; \
 | |
| 			element->SearchString[0] = element->SearchString[1]; \
 | |
| 		} \
 | |
| 	} \
 | |
| 	if (element->LBID == in->LBID && element->Shift < element->SSlen) { \
 | |
| 		p_IdxWalk(element, out); \
 | |
| 		delete element; \
 | |
| 	} \
 | |
| 	else \
 | |
| 		out->push_back(element);
 | |
| #endif
 | |
| 
 | |
| namespace primitives
 | |
| {
 | |
| 
 | |
| void PrimitiveProcessor::indexWalk_1(const IndexWalkHeader *in, 
 | |
| 	vector<IndexWalkHeader *> *out) throw()
 | |
| {
 | |
| 	uint16_t bitTest;
 | |
| 	uint8_t *niceBlock;
 | |
| 	int blockOffset, bitTestGroupSize, i;
 | |
| 	WriteEngine::IdxBitTestEntry *treePtr;
 | |
| 	IndexWalkHeader *element;
 | |
| 	int cmp;
 | |
| 
 | |
| 	IDXWALK_INIT();
 | |
| 
 | |
| 	if (in->SubBlock == 1 && in->Shift == 0) {		//assume this is the first lookup step 
 | |
| 													//which happens in the direct pointer block
 | |
| 		bitTest = in->SearchString[0] >> (in->SSlen - 5);
 | |
| #ifdef VERBOSE
 | |
|  		cerr << "  first iteration of search for 0x" << hex << in->SearchString[0] << dec << endl;
 | |
|  		cerr << "  bitTest is 0x" << hex << bitTest << dec << endl;
 | |
| #endif
 | |
| 		switch (in->COP1) {
 | |
| 			case COMPARE_LT:
 | |
| 			case COMPARE_LE:
 | |
| 				for (i = 0; i <= bitTest; i++) {
 | |
| 					if (treePtr[i].fbo == 0 && treePtr[i].sbid == 0 && treePtr[i].entry == 0)
 | |
| 						continue;
 | |
| 					ADD_ELEMENT(i, 5, (i < bitTest ? 1 : 0));
 | |
| 				}
 | |
| 				break;
 | |
| 			case COMPARE_GT:
 | |
| 			case COMPARE_GE:
 | |
| 				for (i = bitTest; i < 32; i++) {
 | |
| 					if (treePtr[i].fbo == 0 && treePtr[i].sbid == 0 && treePtr[i].entry == 0)
 | |
| 						continue;
 | |
| 					ADD_ELEMENT(i, 5, (i > bitTest ? 1 : 0));
 | |
| 				}
 | |
| 				break;
 | |
| 			case COMPARE_EQ:
 | |
| 				if (treePtr[bitTest].fbo == 0 && treePtr[bitTest].sbid == 0 && treePtr[bitTest].entry == 0)
 | |
| 						break;
 | |
| 				ADD_ELEMENT(bitTest, 5, 0);
 | |
| 				break;
 | |
| 			case COMPARE_NE:
 | |
| 				for (i = 0; i < 32; i++) {
 | |
| 					if (treePtr[i].fbo == 0 && treePtr[i].sbid == 0 && treePtr[i].entry == 0)
 | |
| 						continue;
 | |
| 					ADD_ELEMENT(i, 5, (i != bitTest ? 1 : 0));
 | |
| 				}
 | |
| 				break;
 | |
| 			default:
 | |
| 				MessageLog logger(LoggingID(28));
 | |
| 				logging::Message::Args colWidth;
 | |
| 				Message msg(34);
 | |
| 
 | |
| 				colWidth.add(in->COP1);
 | |
| 				colWidth.add("indexWalk_1");
 | |
| 				msg.format(colWidth);
 | |
| 				logger.logDebugMessage(msg);
 | |
| 				return;
 | |
| 		}
 | |
| 	}
 | |
| 	// This is the general case where we're working within a bit test group
 | |
| 	else {
 | |
| 		GET_GROUP_SIZE();
 | |
| #ifdef VERBOSE
 | |
|  		cerr << "  search string is 0x" << hex << in->SearchString[0] << dec << endl;
 | |
| #endif 
 | |
| 		
 | |
| 
 | |
| 		for (i = 0; i < bitTestGroupSize; i++) {
 | |
| 			bool lastStage;
 | |
| 
 | |
| 			// skip holes
 | |
| 			if (treePtr[i].fbo == 0 && treePtr[i].sbid == 0 && treePtr[i].entry == 0)
 | |
| 				continue;
 | |
| 
 | |
| 			if (treePtr[i].bitCompare == 0) {
 | |
| 				GET_BITTEST(bitTest, in->SearchString[0], 5);
 | |
| 			}
 | |
| 			else {
 | |
| 				GET_BITTEST(bitTest, in->SearchString[0], 10);
 | |
| 			}
 | |
| 			
 | |
| 			cmp = compare(treePtr[i].bitTest, bitTest, in->COP1, lastStage);
 | |
| 			if (cmp > 0) {
 | |
| 				ADD_ELEMENT(i, (treePtr[i].bitCompare == 0 ? 5 : 10), (cmp == 2 ? 1 : 0));
 | |
| 			}
 | |
| 		}
 | |
| 	} 
 | |
| }
 | |
| 
 | |
| inline int PrimitiveProcessor::compare(int val1, int val2, uint8_t COP, 
 | |
| 	bool lastStage) throw()
 | |
| {
 | |
| 	switch (COP) {
 | |
| 		case COMPARE_LT:
 | |
| 			if (val1 < val2)
 | |
| 				return 2;
 | |
| 			if (val1 == val2 && !lastStage)
 | |
| 				return 1;
 | |
| 			return 0;
 | |
| 		case COMPARE_LE:
 | |
| 			if (val1 < val2)
 | |
| 				return 2;
 | |
| 			if (val1 == val2)
 | |
| 				return 1;
 | |
| 			return 0;
 | |
| 		case COMPARE_GT:
 | |
| 			if (val1 > val2)
 | |
| 				return 2;
 | |
| 			if (val1 == val2 && !lastStage)
 | |
| 				return 1;
 | |
| 			return 0;
 | |
| 		case COMPARE_GE:
 | |
| 			if (val1 > val2)
 | |
| 				return 2;
 | |
| 			if (val1 == val2)
 | |
| 				return 1;
 | |
| 			return 0;
 | |
| 		case COMPARE_EQ:
 | |
| 			if (val1 == val2)
 | |
| 				return 1;
 | |
| 			return 0;
 | |
| 		case COMPARE_NE:
 | |
| 			if (val1 != val2)
 | |
| 				return 2;
 | |
| 			if (!lastStage)
 | |
| 				return 1;
 | |
| 			return 0;
 | |
| 		default:
 | |
| 			MessageLog logger(LoggingID(28));
 | |
| 			logging::Message::Args colWidth;
 | |
| 			Message msg(34);
 | |
| 
 | |
| 			colWidth.add(COP);
 | |
| 			colWidth.add("compare");
 | |
| 			msg.format(colWidth);
 | |
| 			logger.logDebugMessage(msg);
 | |
| 			return false;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void PrimitiveProcessor::indexWalk_2(const IndexWalkHeader *in, 
 | |
| 	vector<IndexWalkHeader *> *out) throw()
 | |
| {
 | |
| 	uint16_t bitTest1, bitTest2;
 | |
| 	uint8_t *niceBlock;
 | |
| 	int blockOffset, bitTestGroupSize, cmp[2], i;
 | |
| 	WriteEngine::IdxBitTestEntry *treePtr;
 | |
| 	IndexWalkHeader *element;
 | |
| 	int convertToSingleOp;
 | |
| 	bool lastStage, setState;
 | |
| 
 | |
| 	IDXWALK_INIT();
 | |
| 
 | |
| 	if (in->SubBlock == 1 && in->Shift == 0) {		//assume this is the first lookup step 
 | |
| 													//which happens in the direct pointer block
 | |
| 		bitTest1 = in->SearchString[0] >> (in->SSlen - 5);
 | |
| 		bitTest2 = in->SearchString[1] >> (in->SSlen - 5);
 | |
| #ifdef VERBOSE
 | |
|  		cerr << "  first iteration.  SearchString[0]=0x" << hex << in->SearchString[0] << 
 | |
|  			" bittest=0x" << bitTest1 << " SearchString[1]=0x" << in->SearchString[1] <<
 | |
|  			" bittest=0x" << bitTest2 << dec << endl;
 | |
| #endif
 | |
| 		for (i = 0; i < 32; i++) {
 | |
| 			if (treePtr[i].fbo == 0 && treePtr[i].sbid == 0 && treePtr[i].entry == 0)
 | |
| 				continue;
 | |
| 			setState = false;
 | |
| 			convertToSingleOp = -1;
 | |
| 			cmp[0] = compare(i, bitTest1, in->COP1, false);
 | |
| 			cmp[1] = compare(i, bitTest2, in->COP2, false);
 | |
| 	
 | |
| 			switch (in->BOP) {
 | |
| 				case BOP_OR:
 | |
| 					if (cmp[0] == 2 || cmp[1] == 2) {
 | |
| 						setState = true;
 | |
| 						goto add2;
 | |
| 					}
 | |
| // 					if (cmp[0] == 1 || cmp[1] == 1)
 | |
| // 						goto add2;
 | |
| 
 | |
| 					/* XXXPAT: clean up this logic */
 | |
| 
 | |
|  					if (cmp[0] == 1 && cmp[1] == 1) 
 | |
|  						goto add2;
 | |
| 					if (cmp[0] == 1) {
 | |
| 						convertToSingleOp = 0;
 | |
| 						ADD_ELEMENT_WITH_CONVERT(i, 5, 0);
 | |
| 						goto skip2;
 | |
| 					}
 | |
| 					else if (cmp[1] == 1) {
 | |
| 						convertToSingleOp = 1;
 | |
| 						ADD_ELEMENT_WITH_CONVERT(i, 5, 0);
 | |
| 						goto skip2;
 | |
| 					}
 | |
| 					break;
 | |
| 
 | |
| 				/* XXXPAT:  Need to verify the logic for AND.
 | |
| 					observations: if control reaches this point, then in the previous iteration the
 | |
| 					decision must have been 1, which implies equality for every previous comparison.
 | |
| 
 | |
| 					If one of the comparisons returns 0, then there are no entries in this subtree
 | |
| 						in the result set and it can stop here.
 | |
| 					else, if both of the comparisons return 2, then the whole subtree is in the result set.
 | |
| 					else, if only one of the comparisons returns 2, then that comparison will be 2 for 
 | |
| 						every comparison made down this subtree, and it is equivalent to being
 | |
| 						(cmp1 && true).  In this case, we repackage the query as a single argument version
 | |
| 						(using the comparison operator that was 1) to be processed by indexwalk_1().
 | |
| 					else, the comparisons are both 1, meaning we have equality so far and can't decide on
 | |
| 						this subtree yet.
 | |
| 				*/
 | |
| 				case BOP_AND:
 | |
| 					if (cmp[0] == 0 || cmp[1] == 0)
 | |
| 						break;
 | |
| 					else if (cmp[0] == 2 && cmp[1] == 2)
 | |
| 						setState = true;
 | |
| 					else if (cmp[0] == 2) 
 | |
| 						convertToSingleOp = 1;
 | |
| 					else if (cmp[1] == 2)
 | |
| 						convertToSingleOp = 0;
 | |
| 					goto add2;
 | |
| 
 | |
| 				default:
 | |
| 					MessageLog logger(LoggingID(28));
 | |
| 					logging::Message::Args colWidth;
 | |
| 					Message msg(39);
 | |
| 
 | |
| 					colWidth.add(in->BOP);
 | |
| 					colWidth.add("indexwalk_2");
 | |
| 					msg.format(colWidth);
 | |
| 					logger.logDebugMessage(msg);
 | |
| 					return;
 | |
| 			}
 | |
| 			continue;
 | |
| add2:
 | |
| 			ADD_ELEMENT_WITH_CONVERT(i, 5, (setState ? 1 : 0));
 | |
| skip2:		;
 | |
| 		}
 | |
| 	}
 | |
| 	else {			// the general case
 | |
| 		GET_GROUP_SIZE();
 | |
| 
 | |
| #ifdef VERBOSE
 | |
|  		cerr << "  SearchString[0]=0x" << hex << in->SearchString[0] << 
 | |
|  			" SearchString[1]=0x" << in->SearchString[1] << dec << endl;
 | |
| #endif
 | |
| 		
 | |
| 		for (i = 0; i < bitTestGroupSize; i++) {
 | |
| 			
 | |
| 			if (treePtr[i].fbo == 0 && treePtr[i].sbid == 0 && treePtr[i].entry == 0)
 | |
| 				continue;
 | |
| 		
 | |
| 			setState = false;
 | |
| 			lastStage = false;
 | |
| 			convertToSingleOp = -1;
 | |
| 
 | |
| 			if (treePtr[i].bitCompare == 0) {
 | |
| 				GET_BITTEST(bitTest1, in->SearchString[0], 5);
 | |
| 				GET_BITTEST(bitTest2, in->SearchString[1], 5);
 | |
| 			}
 | |
| 			else {
 | |
| 				GET_BITTEST(bitTest1, in->SearchString[0], 10);
 | |
| 				GET_BITTEST(bitTest2, in->SearchString[1], 10);
 | |
| 			}
 | |
| 
 | |
| 			cmp[0] = compare(treePtr[i].bitTest, bitTest1, in->COP1, lastStage);
 | |
| 			cmp[1] = compare(treePtr[i].bitTest, bitTest2, in->COP2, lastStage);
 | |
| 			
 | |
| 			switch (in->BOP) {
 | |
| 				case BOP_OR:
 | |
| 					if (cmp[0] == 2 || cmp[1] == 2) {
 | |
| 						setState = true;
 | |
| 						goto add3;
 | |
| 					}
 | |
| // 					if (cmp[0] == 1 || cmp[1] == 1) 
 | |
| // 						goto add3;
 | |
| 
 | |
| 					/* XXXPAT: clean up this logic */
 | |
| 
 | |
|  					if (cmp[0] == 1 && cmp[1] == 1) 
 | |
|  						goto add3;
 | |
| 					if (cmp[0] == 1) {
 | |
| 						convertToSingleOp = 0;
 | |
| 						ADD_ELEMENT_WITH_CONVERT(i, (treePtr[i].bitCompare == 0 ? 5 : 10), 0);
 | |
| 						goto skip3;
 | |
| 					}
 | |
| 					else if (cmp[1] == 1) {
 | |
| 						convertToSingleOp = 1;
 | |
| 						ADD_ELEMENT_WITH_CONVERT(i, (treePtr[i].bitCompare == 0 ? 5 : 10), 0);
 | |
| 						goto skip3;
 | |
| 					}
 | |
| 
 | |
| 					break;			
 | |
| 
 | |
| 			/* XXXPAT:  Need to verify the logic for AND.
 | |
| 					observations: if control reaches this point, then in the previous iteration the
 | |
| 					decision must have been 1, which implies equality for every previous comparison.
 | |
| 
 | |
| 					If one of the comparisons returns 0, then there are no entries in this subtree
 | |
| 						in the result set and it can stop here.
 | |
| 					else, if both of the comparisons return 2, then the whole subtree is in the result set.
 | |
| 					else, if only one of the comparisons returns 2, then that comparison will be 2 for 
 | |
| 						every comparison made down this subtree, and it is equivalent to being
 | |
| 						(cmp1 && true).  In this case, we repackage the query as a single argument version
 | |
| 						(using the comparison operator that was 1) to be processed by indexwalk_1().
 | |
| 					else, the comparisons are both 1, meaning we have equality so far and can't decide on
 | |
| 						this subtree yet.
 | |
| 				*/
 | |
| 				case BOP_AND:
 | |
| 					if (cmp[0] == 0 || cmp[1] == 0)
 | |
| 						break;
 | |
| 					else if (cmp[0] == 2 && cmp[1] == 2)
 | |
| 						setState = true;
 | |
| 					else if (cmp[0] == 2) 
 | |
| 						convertToSingleOp = 1;
 | |
| 					else if (cmp[1] == 2)
 | |
| 						convertToSingleOp = 0;
 | |
| 					goto add3;
 | |
| 											
 | |
| 				default:
 | |
| 					MessageLog logger(LoggingID(28));
 | |
| 					logging::Message::Args colWidth;
 | |
| 					Message msg(39);
 | |
| 
 | |
| 					colWidth.add(in->BOP);
 | |
| 					colWidth.add("indexWalk_2");
 | |
| 					msg.format(colWidth);
 | |
| 					logger.logDebugMessage(msg);
 | |
| 					return;
 | |
| 			}
 | |
| 			continue;
 | |
| add3:
 | |
| 			ADD_ELEMENT_WITH_CONVERT(i, (treePtr[i].bitCompare == 0 ? 5 : 10), 
 | |
| 				(setState ? 1 : 0));
 | |
| skip3: 		;
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void PrimitiveProcessor::indexWalk_many(const IndexWalkHeader *in, 
 | |
| 	vector<IndexWalkHeader *> *out) throw()
 | |
| {
 | |
| 	uint16_t bitTest;
 | |
| 	uint8_t *niceBlock;
 | |
| 	int blockOffset, bitTestGroupSize, i;
 | |
| 	WriteEngine::IdxBitTestEntry *treePtr;
 | |
| 	IndexWalkHeader *element;
 | |
| 	bool lastStage;
 | |
| 	vector<uint64_t>::const_iterator it;
 | |
| 	struct {
 | |
| 		int action;
 | |
| 		vector<uint64_t> *searchStrings;
 | |
| 	} nextIteration[32];
 | |
| 
 | |
| 	IDXWALK_INIT();
 | |
| 
 | |
| 	/* 
 | |
| 		Here's the high-level algorithm for this function:
 | |
| 		1) Iterate over the bit test tree entries (index is i)
 | |
| 			1a) if it is not a match, set nextIteration[i].action = 0 (searchStrings = NULL)
 | |
| 			1b) if it is a match which determines the whole subtree goes in the result set action = 2 (searchStrings = NULL)
 | |
| 			1c) if it's a match that determines the result is somewhere further down the tree, set action = 1,
 | |
| 					stuff the matching search string into nextIteration[i].searchStrings.
 | |
| 		2) Iterate over the nextIteration structures
 | |
| 			2a) if action == 0 do nothing
 | |
| 			2b) if action == 1,
 | |
| 					make an intermediate IndexWalkHeader configured s.t. it makes sense given the # of search strings
 | |
| 					that match on that subtree
 | |
| 			2c) if action == 2,
 | |
| 					make an intermediate IndexWalkHeader with state = 1 so the whole subtree will be included.
 | |
| 			2d) if the current LBID is also the next LBID, recurse at p_IdxWalk()
 | |
| 				otherwise, add it to the result set to return.
 | |
| 
 | |
| 		An implementation that is definitely simpler and which may be faster
 | |
| 		in some circumstances:
 | |
| 		1) if BOP is OR, COP is =, so split the query into one single-op
 | |
| 			query for each search string.
 | |
| 		2) if BOP is AND, COP is !=, so grab every indexed value and eliminate
 | |
| 			the entries in the argument list.  (Need to store the index values somewhere).
 | |
| 		*** 3) Generalize the index_many case; get rid of the NVALS=[1,2] cases.
 | |
| 				- need to find a way to avoid dynamic mem allocation.
 | |
| 	*/
 | |
| 
 | |
| 
 | |
| 	if (in->SubBlock == 1 && in->Shift == 0) {			// direct pointer block
 | |
| 		bitTestGroupSize = 32;
 | |
| #ifdef VERBOSE
 | |
|  		cerr << "  first iteration using many search strings" << endl;
 | |
| #endif
 | |
| 		switch (in->BOP) {
 | |
| 			case BOP_OR:
 | |
| 				// according to the design doc, it's safe to assume COP1 is '='
 | |
| 				for (i = 0; i < bitTestGroupSize; i++) {
 | |
| 					nextIteration[i].action = 0;
 | |
| 					nextIteration[i].searchStrings = NULL;
 | |
| 				}
 | |
| 				for (it = in->SearchStrings->begin(); it != in->SearchStrings->end(); it++) {
 | |
| 					bitTest = *it >> (in->SSlen - 5);
 | |
| #ifdef VERBOSE
 | |
|  					cerr << "  search string=0x" << hex << *it << " bittest=0x" << bitTest << dec << endl;
 | |
| #endif
 | |
| 					if (treePtr[bitTest].fbo == 0 && treePtr[bitTest].sbid == 0 && treePtr[bitTest].entry == 0)
 | |
| 						continue;
 | |
| 					
 | |
| 					if (nextIteration[bitTest].action == 0) {
 | |
| 						nextIteration[bitTest].searchStrings = new vector<uint64_t>();
 | |
| 						nextIteration[bitTest].action = 1;
 | |
| 					}
 | |
| 					nextIteration[bitTest].searchStrings->push_back(*it);
 | |
| 				}
 | |
| 				break;
 | |
| 			case BOP_AND:
 | |
| 				// safe to assume COP1 is '!='
 | |
| 				/*  Here's the logic here....
 | |
| 					With a set of 0 search strings, the result set is the entire index.
 | |
| 					With a set of 1 search strings, recurse the subtree containing that string, return every other subtree.
 | |
| 					So, for every search string, we flag the respective subtree as one that has to be recursed.
 | |
| 				*/
 | |
| 
 | |
| 				for (i = 0; i < bitTestGroupSize; i++) {
 | |
| 					if (treePtr[i].fbo == 0 && treePtr[i].sbid == 0 && treePtr[i].entry == 0)
 | |
| 						nextIteration[i].action = 0;
 | |
| 					else
 | |
| 						nextIteration[i].action = 2;
 | |
| 					nextIteration[i].searchStrings = NULL;
 | |
| 				}
 | |
| 			
 | |
| 				for (it = in->SearchStrings->begin();
 | |
| 					it != in->SearchStrings->end();
 | |
| 					it++) {
 | |
| 					
 | |
| 					bitTest = *it >> (in->SSlen - 5);
 | |
| #ifdef VERBOSE
 | |
|  					cerr << "  search string=0x" << hex << *it << " bittest=0x" << bitTest << dec << endl;
 | |
| #endif
 | |
| 					if (nextIteration[bitTest].action == 2) {
 | |
| 						nextIteration[bitTest].searchStrings = new vector<uint64_t>();
 | |
| 						nextIteration[bitTest].action = 1;
 | |
| 					}
 | |
| 					nextIteration[bitTest].searchStrings->push_back(*it);
 | |
| 				}
 | |
| 				break;
 | |
| 			default:
 | |
| 					MessageLog logger(LoggingID(28));
 | |
| 					logging::Message::Args colWidth;
 | |
| 					Message msg(39);
 | |
| 
 | |
| 					colWidth.add(in->BOP);
 | |
| 					msg.format(colWidth);
 | |
| 					logger.logDebugMessage(msg);
 | |
| 					return;
 | |
| 		}
 | |
| 	}
 | |
| 	else {		// The general case of being at a node in the middle of the tree
 | |
| 		GET_GROUP_SIZE();
 | |
| 
 | |
| 		switch (in->BOP) {
 | |
| 			case BOP_OR:
 | |
| 				// COP1 == '='
 | |
| 				for (i = 0; i < bitTestGroupSize; i++) {
 | |
| 					nextIteration[i].action = 0;
 | |
| 					nextIteration[i].searchStrings = NULL;
 | |
| 				}
 | |
| 				for (i = 0; i < bitTestGroupSize; i++) {
 | |
| 		
 | |
| 					if (treePtr[i].fbo == 0 && treePtr[i].sbid == 0 && treePtr[i].entry == 0)
 | |
| 						continue;
 | |
| 
 | |
| 					for (it = in->SearchStrings->begin(); it != in->SearchStrings->end(); it++) {
 | |
| #ifdef VERBOSE
 | |
|  					cerr << "  search string=0x" << hex << *it << dec << endl;
 | |
| #endif
 | |
| 						if (treePtr[i].bitCompare == 0) {
 | |
| 							GET_BITTEST(bitTest, *it, 5);
 | |
| 						}
 | |
| 						else {
 | |
| 							GET_BITTEST(bitTest, *it, 10);
 | |
| 						}
 | |
| 
 | |
| 						if (bitTest == treePtr[i].bitTest) {
 | |
| 							if (nextIteration[i].action == 0) {
 | |
| 								nextIteration[i].searchStrings = new vector<uint64_t>();
 | |
| 								nextIteration[i].action = 1;
 | |
| 							}
 | |
| 							nextIteration[i].searchStrings->push_back(*it);
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 				break;
 | |
| 			case BOP_AND:
 | |
| 				// COP1 == '!='
 | |
| 				for (i = 0; i < bitTestGroupSize; i++) {
 | |
| 					nextIteration[i].action = 2;
 | |
| 					nextIteration[i].searchStrings = NULL;
 | |
| 				}
 | |
| 
 | |
| 				for (i = 0; i < bitTestGroupSize; i++) {
 | |
| 
 | |
| 					if (treePtr[i].fbo == 0 && treePtr[i].sbid == 0 && treePtr[i].entry == 0) {
 | |
| 						nextIteration[i].action = 0;
 | |
| 						continue;
 | |
| 					}
 | |
| 
 | |
| 					for (it = in->SearchStrings->begin(); it != in->SearchStrings->end(); it++) {
 | |
| #ifdef VERBOSE
 | |
|  						cerr << "  search string=0x" << hex << *it << dec << endl;
 | |
| #endif
 | |
| 						if (treePtr[i].bitCompare == 0) {
 | |
| 							GET_BITTEST(bitTest, *it, 5);
 | |
| 						}
 | |
| 						else {
 | |
| 							GET_BITTEST(bitTest, *it, 10);
 | |
| 						}
 | |
| 
 | |
| 						// note: at the last stage, matches are left with action = 2 and NULL searchStrings
 | |
| 						if (!lastStage && bitTest == treePtr[i].bitTest) {
 | |
| 							if (nextIteration[i].action == 2) {
 | |
| 								nextIteration[i].searchStrings = new vector<uint64_t>();
 | |
| 								nextIteration[i].action = 1;
 | |
| 							}
 | |
| 							nextIteration[i].searchStrings->push_back(*it);
 | |
| 						}
 | |
| 						else if (lastStage && bitTest == treePtr[i].bitTest)
 | |
| 							nextIteration[i].action = 0;
 | |
| 					}
 | |
| 				}
 | |
| 				break;
 | |
| 			default:
 | |
| 				MessageLog logger(LoggingID(28));
 | |
| 				logging::Message::Args colWidth;
 | |
| 				Message msg(39);
 | |
| 
 | |
| 				colWidth.add(in->BOP);
 | |
| 				colWidth.add("indexWalk_many");
 | |
| 				msg.format(colWidth);
 | |
| 				logger.logDebugMessage(msg);
 | |
| 				return;	
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	for (i = 0; i < bitTestGroupSize; i++) {
 | |
| 		if (nextIteration[i].action > 0) {
 | |
| 			element = new IndexWalkHeader();
 | |
| 			memcpy(element, in, sizeof(IndexWalkHeader));
 | |
| 			element->ism.Command = INDEX_WALK_RESULTS;
 | |
| 			element->Shift += (treePtr[i].bitCompare ? 10 : 5);
 | |
| 			element->LBID = treePtr[i].fbo;
 | |
| 			element->SubBlock = treePtr[i].sbid;
 | |
| 			element->SBEntry = treePtr[i].entry;
 | |
| #ifdef VERBOSE
 | |
| 			cerr << "  (inline _many) creating a result from subblock entry " << i << " with Shift=" << (int) element->Shift << 
 | |
| 				" LBID=" << element->LBID << " Subblock=" << (int)element->SubBlock << " Subblock entry=" << 
 | |
| 				(int) element->SBEntry << " State=0" << endl;
 | |
| #endif
 | |
| 			if (nextIteration[i].action == 1) {
 | |
| 				element->NVALS = nextIteration[i].searchStrings->size();
 | |
| 				if (nextIteration[i].searchStrings->size() > 2) 
 | |
| 					element->SearchStrings = nextIteration[i].searchStrings;
 | |
| 				else if (nextIteration[i].searchStrings->size() == 2) {
 | |
| 					element->SearchString[0] = nextIteration[i].searchStrings->at(0);
 | |
| 					element->SearchString[1] = nextIteration[i].searchStrings->at(1);
 | |
| 					element->COP2 = element->COP1;
 | |
| 					delete nextIteration[i].searchStrings;
 | |
| 				}
 | |
| 				else { // size == 1
 | |
| 					element->SearchString[0] = nextIteration[i].searchStrings->at(0);
 | |
| 					delete nextIteration[i].searchStrings;
 | |
| 				}
 | |
| 			}
 | |
| 			else		// action == 2
 | |
| 				element->State = 1;
 | |
| 			if (element->LBID == in->LBID && element->Shift < element->SSlen) {
 | |
| #ifdef VERBOSE	
 | |
| 				cerr << "  recursing..." << endl;
 | |
| #endif
 | |
| 				p_IdxWalk(element, out);
 | |
| 				if (element->State == 0 && element->NVALS > 2)
 | |
| 					delete element->SearchStrings;
 | |
| 				delete element;
 | |
| 			}
 | |
| 			else 
 | |
| 				out->push_back(element);
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void PrimitiveProcessor::grabSubTree(const IndexWalkHeader *in, 
 | |
| 	vector<IndexWalkHeader *> *out) throw()
 | |
| {
 | |
| 	uint8_t *niceBlock;
 | |
| 	int blockOffset, bitTestGroupSize, i;
 | |
| 	WriteEngine::IdxBitTestEntry *treePtr;
 | |
| 	IndexWalkHeader *element;
 | |
| 
 | |
| 	IDXWALK_INIT();
 | |
| 	GET_GROUP_SIZE();
 | |
| 
 | |
| 	for (i = 0; i < bitTestGroupSize; i++) {
 | |
| 
 | |
| 		if (treePtr[i].fbo == 0 && treePtr[i].sbid == 0 && treePtr[i].entry == 0)
 | |
| 			continue;
 | |
| 
 | |
| 		ADD_ELEMENT(i, (treePtr[i].bitCompare ? 10 : 5), 1);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void PrimitiveProcessor::p_IdxWalk(const IndexWalkHeader *in, 
 | |
| 	vector<IndexWalkHeader *> *out) throw()
 | |
| {
 | |
| 	
 | |
| #ifdef VERBOSE
 | |
| 	cerr << "p_IdxWalk()" << endl;
 | |
| 	cerr << "  COP1=" << (int) in->COP1 << endl;
 | |
| 	cerr << "  COP2=" << (int) in->COP2 << endl;
 | |
| 	cerr << "  BOP=" << (int) in->BOP << endl;
 | |
| 	cerr << "  Shift=" << (int) in->Shift << endl;
 | |
| 	cerr << "  SSlen=" << (int) in->SSlen << endl;
 | |
| 	cerr << "  LBID=" << (int) in->LBID << endl;
 | |
| 	cerr << "  Subblock=" << (int) in->SubBlock << endl;
 | |
| 	cerr << "  SBEntry=" << (int) in->SBEntry << endl;
 | |
| 	cerr << "  NVALS=" << (int) in->NVALS << endl;
 | |
| #endif
 | |
| 
 | |
| #ifdef PRIM_DEBUG
 | |
| 	if (in->Shift >= in->SSlen)
 | |
| 		throw logic_error("p_IdxWalk: called on a completed search");
 | |
| #endif
 | |
| 
 | |
| 	if (in->State == 1)
 | |
| 		grabSubTree(in, out);
 | |
| 	else 
 | |
| 		switch(in->NVALS) {
 | |
| 			case 1:
 | |
| 				indexWalk_1(in, out);
 | |
| 				break;
 | |
| 			case 2:
 | |
| 				indexWalk_2(in, out);
 | |
| 				break;
 | |
| 			default:
 | |
| 				indexWalk_many(in, out);
 | |
| 				break;
 | |
| 		}
 | |
| #ifdef VERBOSE
 | |
| 	cerr << "/p_IdxWalk()" << endl;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Following the headers for both the request and result will be at variable
 | |
|  * length list of the IndexListParam structure, where the type field is used to
 | |
|  * indicate whether the Index List section is a header (0), sub-block (4), or 
 | |
|  * a block (5).
 | |
|  */
 | |
| void PrimitiveProcessor::p_IdxList(const IndexListHeader *rqst,
 | |
| 				   IndexListHeader *rslt, int mode)
 | |
| {
 | |
|     uint8_t *listPtr;
 | |
|     IndexListParam *linkList;
 | |
|     IndexListEntry *listEntry, *rsltList, *sizeEntry=0;
 | |
|     int listOfst, listType, ridCt, i, j, originalRidCt;
 | |
| 	unsigned entryNumber, lastEntry=0;
 | |
|     int subblk_sz  = WriteEngine::SUBBLOCK_TOTAL_BYTES;
 | |
|     int entry_sz   = WriteEngine::NEXT_PTR_BYTES;
 | |
| 
 | |
| #ifdef VERBOSE
 | |
| 	cerr << "p_IdxList()" << endl;
 | |
| #endif
 | |
| 
 | |
| 	memcpy(rslt, rqst, sizeof(IndexListHeader));
 | |
| 	rslt->ism.Command = INDEX_LIST_RESULTS;
 | |
| 	rslt->NVALS = 0;
 | |
| 
 | |
|     listPtr  = (uint8_t *)block;
 | |
|     linkList = (IndexListParam *)(rqst + 1);
 | |
|     rsltList = (IndexListEntry *)(rslt + 1);
 | |
| 
 | |
|     for (i = 0; i < rqst->NVALS; i++) {
 | |
| 		j = 0;
 | |
| 		listOfst  = (linkList->sbid * subblk_sz) + (linkList->entry * entry_sz);
 | |
| 		entryNumber = linkList->entry;
 | |
| 		listEntry = (IndexListEntry *)(listPtr + listOfst);
 | |
| 
 | |
| #ifdef VERBOSE
 | |
| 		cerr << "  processing argument number " << i + 1 << endl;
 | |
| 		cerr << "    type=" << linkList->type << " LBID=" << linkList->fbo << " subblock=" <<
 | |
| 			linkList->sbid << " entry=" << linkList->entry << endl;
 | |
| #endif
 | |
| 
 | |
| 		listType = linkList->type;
 | |
| 		if (listType == LIST_SIZE) {
 | |
| 			if (listEntry->type != LIST_SIZE) {
 | |
| 				MessageLog logger(LoggingID(28));
 | |
| 				Message msg(40);
 | |
| 				logger.logDebugMessage(msg);
 | |
| #ifdef VERBOSE
 | |
| 				cerr << "PrimitiveProcessor::p_IdxList: was told to parse a header, but the given pointer does not point to one.  sbid=" << linkList->sbid << " entry=" << linkList->entry << endl;
 | |
| #endif
 | |
| 				throw runtime_error("p_IdxList: not a header");
 | |
| 			}
 | |
| 		    ridCt      = listEntry->value;
 | |
| 			originalRidCt = ridCt;
 | |
| #ifdef VERBOSE
 | |
| 			uint64_t *tmp = (uint64_t *) &listEntry[1];
 | |
| 			cerr << "    ridCount=" << ridCt << " key value=0x" << hex << *tmp << 
 | |
| 				dec << endl;
 | |
| #endif
 | |
| 		    listEntry += 2;	// Skip size and key values
 | |
| 			entryNumber += 2;
 | |
| 			lastEntry = linkList->entry + 4;
 | |
| 		}
 | |
| 
 | |
| 		else {
 | |
| 		    if (listType == LLP_SUBBLK) {
 | |
| 				sizeEntry = listEntry + WriteEngine::LIST_SUB_LLP_POS; 
 | |
| 				lastEntry = linkList->entry + 32;
 | |
| 			}
 | |
| 			else if (listType == LLP_BLK) {
 | |
| 				sizeEntry = listEntry + WriteEngine::LIST_BLOCK_LLP_POS;
 | |
| 				lastEntry = linkList->entry + (mode == 0 ? 1024 : 1023);  
 | |
| 					// ignore the size entry for blocks if mode == 1
 | |
| 			}
 | |
| 			else
 | |
| 				cerr << "p_IdxList: bad pointer type " << listType << endl;
 | |
| 		    ridCt = sizeEntry->ridCt;		//XXXPAT: make sure these are the right bits
 | |
| 			originalRidCt = ridCt;
 | |
| #ifdef VERBOSE
 | |
| 			cerr << "    ridCount for this " << (listType == LLP_SUBBLK ? "subblock: " : "block: ") << 
 | |
| 				ridCt << endl;
 | |
| #endif
 | |
| 		}
 | |
| 
 | |
| // 		while (ridCt > 0 && entryNumber < lastEntry) {
 | |
| 		while (entryNumber < lastEntry) {
 | |
| 		    switch (listEntry->type) {
 | |
| 			    case LLP_SUBBLK:
 | |
| 		    	case LLP_BLK:
 | |
| 
 | |
| 					/* the second to last entry of a subblock 
 | |
| 					can now be a HWM disguised as a continuation ptr. */
 | |
| 					if (mode &&
 | |
| 						entryNumber == static_cast<unsigned>(linkList->entry + 30) &&
 | |
| 						listType == LLP_SUBBLK)
 | |
| 						break; 
 | |
| #ifdef VERBOSE
 | |
| 					ilptmp = reinterpret_cast<IndexListParam *>(listEntry);
 | |
| 
 | |
| 					cerr << "   found a continuation pointer: LBID=" << ilptmp->fbo <<
 | |
| 						" subblock=" << ilptmp->sbid << " subblock entry=" <<
 | |
|  						 ilptmp->entry << endl;
 | |
| #endif
 | |
| 					*rsltList = *listEntry;
 | |
| 					rslt->NVALS++;
 | |
| 					rsltList++;
 | |
| 					break;
 | |
| /*
 | |
| #ifdef VERBOSE
 | |
| 					cerr << "   reached the end of the list" << endl;
 | |
| 					if (listEntry != sizeEntry && listType != LIST_SIZE) 
 | |
| 						cerr << "   ERROR: there's a list pointer in the middle of the list" << endl;
 | |
| 					else if (listType != LIST_SIZE)
 | |
| 						cerr << "   Possible error: the pointer clause executed for a subblock or block" << endl;
 | |
| #endif
 | |
| 					endOfList = true;
 | |
| 					break;
 | |
| */
 | |
| 			    case RID:
 | |
| #ifdef VERBOSE
 | |
| // 					cerr << "    returning rid " << listEntry->value << endl;
 | |
| #endif
 | |
| 					*rsltList = *listEntry;
 | |
| 					rslt->NVALS++;
 | |
| 					rsltList++;
 | |
| 					ridCt--;
 | |
| 					j++;
 | |
| 					break;
 | |
| 			    case LIST_SIZE:
 | |
| 	    		case NOT_IN_USE:
 | |
| 	    		case EMPTY_LIST_PTR:
 | |
| 	    		case EMPTY_PTR:
 | |
| 				case PARENT:
 | |
| 					break;
 | |
| 		
 | |
| 				default:
 | |
| #ifdef VERBOSE
 | |
| 					IndexListParam *tmp = reinterpret_cast<IndexListParam *>(listEntry);
 | |
| 					cerr << "PrimitiveProcessor::p_IdxList: invalid list entry type" << endl;
 | |
| 					cerr << "   Entry contents: type=" << listEntry->type << " value/RID=" << listEntry->value << endl;
 | |
| 					cerr << "   (if a pointer, fbo=" << tmp->fbo << " subblock=" << tmp->sbid << 
 | |
| 						" entry=" << tmp->entry << ")" << endl;
 | |
| 					cerr << "   Location of the entry: lbid=" << linkList->fbo << " subblock=" << 
 | |
| 						linkList->sbid + entryNumber/32 << " entry=" << entryNumber % 32 << endl;
 | |
| 					cerr << "   Input parameter indicates the start of the list is sbid=" <<
 | |
| 						linkList->sbid << " entry=" << linkList->entry << endl;
 | |
| 					cerr << "   Type of search: " << 
 | |
| 						(linkList->type == LIST_SIZE ? "header" : 
 | |
| 						(linkList->type == LLP_SUBBLK ? "subblock" : 
 | |
| 						(linkList->type == LLP_BLK ? "block" : "unknown..?"))) << endl;
 | |
| 					cerr << "   Processed " << entryNumber - linkList->entry << 
 | |
| 						" entries for this request so far." << endl;
 | |
| 					cerr << "   Rid count read from the list is " << originalRidCt << endl;
 | |
| #endif
 | |
| 					MessageLog logger(LoggingID(28));
 | |
| 					Message msg(40);
 | |
| 					logger.logDebugMessage(msg);
 | |
| 					throw runtime_error("Bad index list entry, see stderr");
 | |
| 				return;
 | |
| 			}
 | |
| 
 | |
| 			listEntry++;
 | |
| 			entryNumber++;
 | |
| 		}
 | |
| #ifdef VERBOSE
 | |
| 	cerr << "  RIDs in result generated from input arg #" << i + 1 << ": " << j << endl;
 | |
| #endif
 | |
| 
 | |
| 	linkList++;
 | |
|     }
 | |
| 
 | |
|     return;
 | |
| }
 | |
| 
 | |
| }
 | |
| // vim:ts=4 sw=4:
 | |
| 
 |