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 
			
		
		
		
	
		
			
				
	
	
		
			1155 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1155 lines
		
	
	
		
			39 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:
 | |
| 
 |