mirror of https://gitee.com/bigwinds/arangodb
529 lines
15 KiB
C
529 lines
15 KiB
C
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief shape accessor
|
|
///
|
|
/// @file
|
|
///
|
|
/// DISCLAIMER
|
|
///
|
|
/// Copyright 2004-2013 triAGENS GmbH, Cologne, Germany
|
|
///
|
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|
/// you may not use this file except in compliance with the License.
|
|
/// You may obtain a copy of the License at
|
|
///
|
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
|
///
|
|
/// Unless required by applicable law or agreed to in writing, software
|
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
/// See the License for the specific language governing permissions and
|
|
/// limitations under the License.
|
|
///
|
|
/// Copyright holder is triAGENS GmbH, Cologne, Germany
|
|
///
|
|
/// @author Dr. Frank Celler
|
|
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "shape-accessor.h"
|
|
|
|
#include "BasicsC/logging.h"
|
|
#include "BasicsC/vector.h"
|
|
#include "ShapedJson/json-shaper.h"
|
|
#include "ShapedJson/shaped-json.h"
|
|
|
|
// #define DEBUG_SHAPE_ACCESSOR 1
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- private functions
|
|
// -----------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @addtogroup Json
|
|
/// @{
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief computes a byte-code sequence
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static bool BytecodeShapeAccessor (TRI_shaper_t* shaper, TRI_shape_access_t* accessor) {
|
|
TRI_shape_aid_t const* paids;
|
|
TRI_shape_path_t const* path;
|
|
TRI_shape_t const* shape;
|
|
TRI_vector_pointer_t ops;
|
|
size_t i;
|
|
size_t j;
|
|
int res;
|
|
|
|
// find the shape
|
|
shape = shaper->lookupShapeId(shaper, accessor->_sid);
|
|
|
|
if (shape == NULL) {
|
|
LOG_ERROR("unknown shape id %llu", (unsigned long long) accessor->_sid);
|
|
return false;
|
|
}
|
|
|
|
// find the attribute path
|
|
path = shaper->lookupAttributePathByPid(shaper, accessor->_pid);
|
|
|
|
if (path == NULL) {
|
|
LOG_ERROR("unknown attribute path %llu", (unsigned long long) accessor->_pid);
|
|
return false;
|
|
}
|
|
|
|
paids = (TRI_shape_aid_t*) (((char const*) path) + sizeof(TRI_shape_path_t));
|
|
|
|
// collect the bytecode
|
|
// we need at least 4 entries in the vector to store an accessor
|
|
TRI_InitVectorPointer2(&ops, shaper->_memoryZone, 4);
|
|
|
|
// start with the shape
|
|
res = TRI_PushBackVectorPointer(&ops, (void*) TRI_SHAPE_AC_SHAPE_PTR);
|
|
|
|
if (res != TRI_ERROR_NO_ERROR) {
|
|
LOG_ERROR("out of memory");
|
|
TRI_DestroyVectorPointer(&ops);
|
|
return false;
|
|
}
|
|
|
|
res = TRI_PushBackVectorPointer(&ops, CONST_CAST(shape));
|
|
|
|
if (res != TRI_ERROR_NO_ERROR) {
|
|
LOG_ERROR("out of memory");
|
|
TRI_DestroyVectorPointer(&ops);
|
|
return false;
|
|
}
|
|
|
|
// and follow it
|
|
for (i = 0; i < path->_aidLength; ++i, ++paids) {
|
|
#ifdef DEBUG_SHAPE_ACCESSOR
|
|
printf("%lu: aid: %lu, sid: %lu, type %lu\n",
|
|
(unsigned long) i,
|
|
(unsigned long) *paids,
|
|
(unsigned long) shape->_sid,
|
|
(unsigned long) shape->_type);
|
|
#endif
|
|
|
|
if (shape->_type == TRI_SHAPE_ARRAY) {
|
|
TRI_array_shape_t* s;
|
|
TRI_shape_aid_t const* aids;
|
|
TRI_shape_sid_t const* sids;
|
|
TRI_shape_sid_t sid;
|
|
TRI_shape_size_t const* offsetsF;
|
|
TRI_shape_size_t f;
|
|
TRI_shape_size_t n;
|
|
TRI_shape_size_t v;
|
|
char const* qtr;
|
|
|
|
s = (TRI_array_shape_t*) shape;
|
|
f = s->_fixedEntries;
|
|
v = s->_variableEntries;
|
|
n = f + v;
|
|
|
|
// find the aid within the shape
|
|
qtr = (char const*) shape;
|
|
qtr += sizeof(TRI_array_shape_t);
|
|
|
|
sids = (TRI_shape_sid_t const*) qtr;
|
|
qtr += n * sizeof(TRI_shape_sid_t);
|
|
|
|
aids = (TRI_shape_aid_t const*) qtr;
|
|
qtr += n * sizeof(TRI_shape_aid_t);
|
|
|
|
offsetsF = (TRI_shape_size_t const*) qtr;
|
|
|
|
// check for fixed size aid
|
|
for (j = 0; j < f; ++j, ++sids, ++aids, ++offsetsF) {
|
|
if (*paids == *aids) {
|
|
sid = *sids;
|
|
|
|
LOG_TRACE("found aid '%ld' as fixed entry with sid '%ld' and offset '%ld' - '%ld'",
|
|
(unsigned long) *paids,
|
|
(unsigned long) sid,
|
|
(unsigned long) offsetsF[0],
|
|
(unsigned long) offsetsF[1]);
|
|
|
|
shape = shaper->lookupShapeId(shaper, sid);
|
|
|
|
if (shape == NULL) {
|
|
LOG_ERROR("unknown shape id '%ld' for attribute id '%ld'",
|
|
(unsigned long) accessor->_sid,
|
|
(unsigned long) *paids);
|
|
|
|
TRI_DestroyVectorPointer(&ops);
|
|
return false;
|
|
}
|
|
|
|
res = TRI_PushBackVectorPointer(&ops, (void*) TRI_SHAPE_AC_OFFSET_FIX);
|
|
|
|
if (res != TRI_ERROR_NO_ERROR) {
|
|
LOG_ERROR("out of memory");
|
|
TRI_DestroyVectorPointer(&ops);
|
|
return false;
|
|
}
|
|
|
|
res = TRI_PushBackVectorPointer(&ops, (void*) (uintptr_t) (offsetsF[0])); // offset is always smaller than 4 GByte
|
|
|
|
if (res != TRI_ERROR_NO_ERROR) {
|
|
LOG_ERROR("out of memory");
|
|
TRI_DestroyVectorPointer(&ops);
|
|
return false;
|
|
}
|
|
|
|
res = TRI_PushBackVectorPointer(&ops, (void*) (uintptr_t) (offsetsF[1])); // offset is always smaller than 4 GByte
|
|
|
|
if (res != TRI_ERROR_NO_ERROR) {
|
|
LOG_ERROR("out of memory");
|
|
TRI_DestroyVectorPointer(&ops);
|
|
return false;
|
|
}
|
|
|
|
res = TRI_PushBackVectorPointer(&ops, (void*) TRI_SHAPE_AC_SHAPE_PTR);
|
|
|
|
if (res != TRI_ERROR_NO_ERROR) {
|
|
LOG_ERROR("out of memory");
|
|
TRI_DestroyVectorPointer(&ops);
|
|
return false;
|
|
}
|
|
|
|
res = TRI_PushBackVectorPointer(&ops, CONST_CAST(shape));
|
|
|
|
if (res != TRI_ERROR_NO_ERROR) {
|
|
LOG_ERROR("out of memory");
|
|
TRI_DestroyVectorPointer(&ops);
|
|
return false;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (j < f) {
|
|
continue;
|
|
}
|
|
|
|
// check for variable size aid
|
|
for (j = 0; j < v; ++j, ++sids, ++aids) {
|
|
if (*paids == *aids) {
|
|
sid = *sids;
|
|
|
|
LOG_TRACE("found aid '%ld' as variable entry with sid '%ld'",
|
|
(unsigned long) *paids,
|
|
(unsigned long) sid);
|
|
|
|
shape = shaper->lookupShapeId(shaper, sid);
|
|
|
|
if (shape == NULL) {
|
|
LOG_ERROR("unknown shape id '%ld' for attribute id '%ld'",
|
|
(unsigned long) accessor->_sid,
|
|
(unsigned long) *paids);
|
|
|
|
LOG_ERROR("out of memory");
|
|
TRI_DestroyVectorPointer(&ops);
|
|
return false;
|
|
}
|
|
|
|
res = TRI_PushBackVectorPointer(&ops, (void*) TRI_SHAPE_AC_OFFSET_VAR);
|
|
|
|
if (res != TRI_ERROR_NO_ERROR) {
|
|
LOG_ERROR("out of memory");
|
|
TRI_DestroyVectorPointer(&ops);
|
|
return false;
|
|
}
|
|
|
|
res = TRI_PushBackVectorPointer(&ops, (void*) j);
|
|
|
|
if (res != TRI_ERROR_NO_ERROR) {
|
|
LOG_ERROR("out of memory");
|
|
TRI_DestroyVectorPointer(&ops);
|
|
return false;
|
|
}
|
|
|
|
res = TRI_PushBackVectorPointer(&ops, (void*) TRI_SHAPE_AC_SHAPE_PTR);
|
|
|
|
if (res != TRI_ERROR_NO_ERROR) {
|
|
LOG_ERROR("out of memory");
|
|
TRI_DestroyVectorPointer(&ops);
|
|
return false;
|
|
}
|
|
|
|
res = TRI_PushBackVectorPointer(&ops, CONST_CAST(shape));
|
|
|
|
if (res != TRI_ERROR_NO_ERROR) {
|
|
LOG_ERROR("out of memory");
|
|
TRI_DestroyVectorPointer(&ops);
|
|
return false;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (j < v) {
|
|
continue;
|
|
}
|
|
|
|
LOG_TRACE("unknown attribute id '%ld'", (unsigned long) *paids);
|
|
|
|
TRI_DestroyVectorPointer(&ops);
|
|
|
|
accessor->_shape = NULL;
|
|
accessor->_code = NULL;
|
|
|
|
return true;
|
|
}
|
|
else {
|
|
TRI_DestroyVectorPointer(&ops);
|
|
|
|
accessor->_shape = NULL;
|
|
accessor->_code = NULL;
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// travel attribute path to the end
|
|
res = TRI_PushBackVectorPointer(&ops, (void*) TRI_SHAPE_AC_DONE);
|
|
|
|
if (res != TRI_ERROR_NO_ERROR) {
|
|
LOG_ERROR("out of memory");
|
|
TRI_DestroyVectorPointer(&ops);
|
|
return false;
|
|
}
|
|
|
|
accessor->_shape = shape;
|
|
accessor->_code = TRI_Allocate(shaper->_memoryZone, ops._length * sizeof(void*), false);
|
|
|
|
if (accessor->_code == NULL) {
|
|
LOG_ERROR("out of memory");
|
|
TRI_DestroyVectorPointer(&ops);
|
|
return false;
|
|
}
|
|
|
|
memcpy(CONST_CAST(accessor->_code), ops._buffer, ops._length * sizeof(void*));
|
|
|
|
TRI_DestroyVectorPointer(&ops);
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief executes a byte-code sequence
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static bool ExecuteBytecodeShapeAccessor (TRI_shape_access_t const* accessor,
|
|
void** begin,
|
|
void** end) {
|
|
TRI_shape_size_t b;
|
|
TRI_shape_size_t e;
|
|
TRI_shape_size_t pos;
|
|
TRI_shape_size_t* offsetsV;
|
|
void* const* ops;
|
|
|
|
if (accessor->_shape == NULL) {
|
|
return false;
|
|
}
|
|
|
|
ops = accessor->_code;
|
|
|
|
while (true) {
|
|
TRI_shape_ac_bc_e op;
|
|
|
|
op = * (TRI_shape_ac_bc_e*) ops;
|
|
ops++;
|
|
|
|
switch (op) {
|
|
case TRI_SHAPE_AC_DONE:
|
|
return true;
|
|
|
|
case TRI_SHAPE_AC_SHAPE_PTR:
|
|
ops++;
|
|
break;
|
|
|
|
case TRI_SHAPE_AC_OFFSET_FIX:
|
|
b = (TRI_shape_size_t) (uintptr_t) *ops++; // offset is always smaller than 4 GByte
|
|
e = (TRI_shape_size_t) (uintptr_t) *ops++; // offset is always smaller than 4 GByte
|
|
|
|
*end = ((char*) *begin) + e;
|
|
*begin = ((char*) *begin) + b;
|
|
|
|
break;
|
|
|
|
case TRI_SHAPE_AC_OFFSET_VAR:
|
|
pos = (TRI_shape_size_t) (uintptr_t) *ops++; // offset is always smaller than 4 GByte
|
|
|
|
offsetsV = (TRI_shape_size_t*) *begin;
|
|
|
|
*end = ((char*) *begin) + offsetsV[pos + 1];
|
|
*begin = ((char*) *begin) + offsetsV[pos];
|
|
|
|
break;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @}
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- public functions
|
|
// -----------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @addtogroup Json
|
|
/// @{
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief free a shape accessor
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void TRI_FreeShapeAccessor (TRI_shape_access_t* accessor) {
|
|
assert(accessor != NULL);
|
|
|
|
if (accessor->_code != NULL) {
|
|
TRI_Free(accessor->_memoryZone, (void*) accessor->_code);
|
|
}
|
|
|
|
TRI_Free(accessor->_memoryZone, accessor);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief creates a shape accessor
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_shape_access_t* TRI_ShapeAccessor (TRI_shaper_t* shaper,
|
|
TRI_shape_sid_t sid,
|
|
TRI_shape_pid_t pid) {
|
|
TRI_shape_access_t* accessor;
|
|
bool ok;
|
|
|
|
accessor = TRI_Allocate(shaper->_memoryZone, sizeof(TRI_shape_access_t), false);
|
|
|
|
if (accessor == NULL) {
|
|
TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY);
|
|
return NULL;
|
|
}
|
|
|
|
accessor->_sid = sid;
|
|
accessor->_pid = pid;
|
|
accessor->_code = NULL;
|
|
accessor->_memoryZone = shaper->_memoryZone;
|
|
|
|
ok = BytecodeShapeAccessor(shaper, accessor);
|
|
|
|
if (ok) {
|
|
return accessor;
|
|
}
|
|
|
|
TRI_FreeShapeAccessor(accessor);
|
|
return NULL;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief executes a shape accessor
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool TRI_ExecuteShapeAccessor (TRI_shape_access_t const* accessor,
|
|
TRI_shaped_json_t const* shaped,
|
|
TRI_shaped_json_t* result) {
|
|
void* begin;
|
|
void* end;
|
|
bool ok;
|
|
|
|
begin = shaped->_data.data;
|
|
end = ((char*) begin) + shaped->_data.length;
|
|
|
|
ok = ExecuteBytecodeShapeAccessor(accessor, &begin, &end);
|
|
|
|
if (! ok) {
|
|
return false;
|
|
}
|
|
|
|
result->_sid = accessor->_shape->_sid;
|
|
result->_data.data = (char*) begin;
|
|
result->_data.length = (uint32_t) (((char const*) end) - ((char const*) begin));
|
|
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief prints a TRI_shape_t for debugging
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void TRI_PrintShapeAccessor (TRI_shape_access_t* accessor) {
|
|
TRI_shape_size_t b;
|
|
TRI_shape_size_t e;
|
|
TRI_shape_size_t pos;
|
|
TRI_shape_t const* shape;
|
|
void* const* ops;
|
|
|
|
printf("shape accessor for sid: %lu, pid: %lu\n",
|
|
(unsigned long) accessor->_sid,
|
|
(unsigned long) accessor->_pid);
|
|
|
|
if (accessor->_shape == NULL) {
|
|
printf(" result shape: -\n");
|
|
return;
|
|
}
|
|
|
|
printf(" result shape: %lu\n", (unsigned long) accessor->_shape->_sid);
|
|
|
|
ops = accessor->_code;
|
|
shape = accessor->_shape;
|
|
|
|
while (true) {
|
|
TRI_shape_ac_bc_e op;
|
|
|
|
op = * (TRI_shape_ac_bc_e*) ops;
|
|
ops++;
|
|
|
|
switch (op) {
|
|
case TRI_SHAPE_AC_DONE:
|
|
return;
|
|
|
|
case TRI_SHAPE_AC_SHAPE_PTR:
|
|
shape = *ops++;
|
|
|
|
printf(" OP: shape %lu\n",
|
|
(unsigned long) shape->_sid);
|
|
break;
|
|
|
|
case TRI_SHAPE_AC_OFFSET_FIX:
|
|
b = (TRI_shape_size_t) (uintptr_t) *ops++; // offset is always smaller than 4 GByte
|
|
e = (TRI_shape_size_t) (uintptr_t) *ops++; // offset is always smaller than 4 GByte
|
|
|
|
printf(" OP: fixed offset %lu - %lu\n",
|
|
(unsigned long) b,
|
|
(unsigned long) e);
|
|
break;
|
|
|
|
case TRI_SHAPE_AC_OFFSET_VAR:
|
|
pos = (TRI_shape_size_t) (uintptr_t) *ops++; // offset is always smaller than 4 GByte
|
|
|
|
printf(" OP: variable offset at position %lu\n",
|
|
(unsigned long) pos);
|
|
break;
|
|
|
|
default:
|
|
printf(" OP: unknown op code\n");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @}
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Local Variables:
|
|
// mode: outline-minor
|
|
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}"
|
|
// End:
|