1
0
Fork 0

add ability to 3.3 to read compressed AqlItemBlocks (#6517)

but not the ability to produce them. This way we can support
running 3.3 as part of a mixed 3.3/3.4 cluster, and do not
break any clusters that run mixed versions of 3.3 current and
either 3.2 or 3.3 older versions
This commit is contained in:
Jan 2018-09-17 13:46:17 +02:00 committed by GitHub
parent 66ca6885e1
commit f549dbe8cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 122 additions and 54 deletions

View File

@ -100,77 +100,145 @@ AqlItemBlock::AqlItemBlock(ResourceMonitor* resourceMonitor, VPackSlice const sl
VPackArrayIterator dataIterator(data); VPackArrayIterator dataIterator(data);
VPackArrayIterator rawIterator(raw); VPackArrayIterator rawIterator(raw);
auto storeSingleValue = [this](size_t row, size_t column, VPackArrayIterator& it, std::vector<AqlValue>& madeHere) {
AqlValue a(it.value());
it.next();
try {
setValue(row, column, a); // if this throws, a is destroyed again
} catch (...) {
a.destroy();
throw;
}
madeHere.emplace_back(a);
};
enum RunType {
NoRun = 0,
EmptyRun,
NextRun,
PositionalRun
};
int64_t runLength = 0;
size_t tablePos = 0;
RunType runType = NoRun;
try { try {
// skip the first two records // skip the first two records
rawIterator.next(); rawIterator.next();
rawIterator.next(); rawIterator.next();
int64_t emptyRun = 0;
for (RegisterId column = 0; column < _nrRegs; column++) { for (RegisterId column = 0; column < _nrRegs; column++) {
for (size_t i = 0; i < _nrItems; i++) { for (size_t i = 0; i < _nrItems; i++) {
if (emptyRun > 0) { if (runLength > 0) {
emptyRun--; switch (runType) {
} else { case EmptyRun:
VPackSlice dataEntry = dataIterator.value(); // nothing to do
dataIterator.next(); break;
if (!dataEntry.isNumber()) {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, case NextRun:
"data must contain only numbers"); storeSingleValue(i, column, rawIterator, madeHere);
break;
case PositionalRun:
TRI_ASSERT(tablePos < madeHere.size());
setValue(i, column, madeHere[tablePos]);
break;
case NoRun: {
TRI_ASSERT(false);
}
} }
int64_t n = dataEntry.getNumericValue<int64_t>();
if (n == 0) { --runLength;
// empty, do nothing here if (runLength == 0) {
} else if (n == -1) { runType = NoRun;
// empty run: tablePos = 0;
VPackSlice runLength = dataIterator.value(); }
dataIterator.next();
TRI_ASSERT(runLength.isNumber()); continue;
emptyRun = runLength.getNumericValue<int64_t>(); }
emptyRun--;
} else if (n == -2) { VPackSlice dataEntry = dataIterator.value();
// a range dataIterator.next();
VPackSlice lowBound = dataIterator.value(); if (!dataEntry.isNumber()) {
dataIterator.next(); THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL,
VPackSlice highBound = dataIterator.value(); "data must contain only numbers");
dataIterator.next(); }
int64_t low = int64_t n = dataEntry.getNumericValue<int64_t>();
VelocyPackHelper::getNumericValue<int64_t>(lowBound, 0); if (n == 0) {
int64_t high = // empty, do nothing here
VelocyPackHelper::getNumericValue<int64_t>(highBound, 0); } else if (n == 1) {
AqlValue a(low, high); // a VelocyPack value
try { storeSingleValue(i, column, rawIterator, madeHere);
setValue(i, column, a); } else if (n == -1 || n == -3 || n == -4) {
} catch (...) { // -1: empty run, -3: run of "next" values, -4: run of positional values
a.destroy(); VPackSlice v = dataIterator.value();
throw; dataIterator.next();
TRI_ASSERT(v.isNumber());
runLength = v.getNumericValue<int64_t>();
runLength--;
switch (n) {
case -1:
runType = EmptyRun;
break;
case -3:
runType = NextRun;
storeSingleValue(i, column, rawIterator, madeHere);
break;
case -4: {
runType = PositionalRun;
VPackSlice v = dataIterator.value();
dataIterator.next();
TRI_ASSERT(v.isNumber());
tablePos = v.getNumericValue<size_t>();
if (tablePos >= madeHere.size()) {
// safeguard against out-of-bounds accesses
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL,
"found undefined data value");
}
setValue(i, column, madeHere[tablePos]);
} }
} else if (n == 1) { }
// a VelocyPack value } else if (n == -2) {
AqlValue a(rawIterator.value()); // a range
rawIterator.next(); VPackSlice lowBound = dataIterator.value();
try { dataIterator.next();
setValue(i, column, a); // if this throws, a is destroyed again VPackSlice highBound = dataIterator.value();
} catch (...) { dataIterator.next();
a.destroy();
throw; int64_t low =
} VelocyPackHelper::getNumericValue<int64_t>(lowBound, 0);
madeHere.emplace_back(a); int64_t high =
} else if (n >= 2) { VelocyPackHelper::getNumericValue<int64_t>(highBound, 0);
setValue(i, column, madeHere[static_cast<size_t>(n)]); emplaceValue(i, column, low, high);
// If this throws, all is OK, because it was already put into } else if (n >= 2) {
// the block elsewhere. if (static_cast<size_t>(n) >= madeHere.size()) {
} else { // safeguard against out-of-bounds accesses
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL,
"found undefined data value"); "found undefined data value");
} }
setValue(i, column, madeHere[static_cast<size_t>(n)]);
// If this throws, all is OK, because it was already put into
// the block elsewhere.
} else {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL,
"found invalid data encoding value");
} }
} }
} }
} catch (...) { } catch (...) {
destroy(); destroy();
// TODO: rethrow? throw;
} }
TRI_ASSERT(runLength == 0);
TRI_ASSERT(runType == NoRun);
} }
/// @brief destroy the block, used in the destructor and elsewhere /// @brief destroy the block, used in the destructor and elsewhere