1
0
Fork 0
arangodb/lib/ShapedJson/shape-accessor.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: