1
0
mirror of https://github.com/mariadb-corporation/mariadb-columnstore-engine.git synced 2025-04-26 11:48:52 +03:00
2017-10-26 17:18:17 +01:00

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: