bool TRI_StartScopeAql (TRI_aql_context_t* const context, const TRI_aql_scope_e type) { TRI_aql_scope_t* scope; TRI_aql_node_t* node; assert(context); scope = CreateScope(context, type); if (scope == NULL) { return false; } LOG_TRACE("starting scope of type %s", TRI_TypeNameScopeAql(scope->_type)); TRI_PushBackVectorPointer(&context->_memory._scopes, (void*) scope); TRI_PushBackVectorPointer(&context->_currentScopes, (void*) scope); node = TRI_CreateNodeScopeStartAql(context, scope); if (node == NULL) { return false; } if (! TRI_AppendStatementListAql(context->_statements, node)) { return false; } return true; }
static TRI_datafile_t* CreateCompactor (TRI_document_collection_t* document, TRI_voc_fid_t fid, TRI_voc_size_t maximalSize) { TRI_collection_t* collection; TRI_datafile_t* compactor; collection = &document->base.base; // reserve room for one additional entry if (TRI_ReserveVectorPointer(&collection->_compactors, 1) != TRI_ERROR_NO_ERROR) { // could not get memory, exit early return NULL; } TRI_LOCK_JOURNAL_ENTRIES_DOC_COLLECTION(document); compactor = TRI_CreateCompactorPrimaryCollection(&document->base, fid, maximalSize); if (compactor != NULL) { int res = TRI_PushBackVectorPointer(&collection->_compactors, compactor); // we have reserved space before, so we can be sure the push succeeds assert(res == TRI_ERROR_NO_ERROR); } // we still must wake up the other thread from time to time, otherwise we'll deadlock TRI_BROADCAST_JOURNAL_ENTRIES_DOC_COLLECTION(document); TRI_UNLOCK_JOURNAL_ENTRIES_DOC_COLLECTION(document); return compactor; }
static TRI_shape_t const* FindShapeShape (TRI_shaper_t* shaper, TRI_shape_t* shape) { TRI_shape_t const* l; array_shaper_t* s; int res; s = (array_shaper_t*) shaper; l = TRI_LookupByElementAssociativePointer(&s->_shapeDictionary, shape); if (l != NULL) { TRI_Free(shaper->_memoryZone, shape); return l; } shape->_sid = s->_shapes._length + 1; TRI_InsertElementAssociativePointer(&s->_shapeDictionary, shape, false); if (s->base._memoryZone->_failed) { TRI_Free(shaper->_memoryZone, shape); return NULL; } res = TRI_PushBackVectorPointer(&s->_shapes, shape); if (res != TRI_ERROR_NO_ERROR) { TRI_RemoveElementAssociativePointer(&s->_shapeDictionary, shape); TRI_Free(shaper->_memoryZone, shape); return NULL; } return shape; }
TRI_aql_node_t* TRI_CreateNodeReturnEmptyAql (void) { TRI_aql_node_t* node; TRI_aql_node_t* list; node = (TRI_aql_node_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_aql_node_t), false); if (node == NULL) { return NULL; } node->_type = TRI_AQL_NODE_RETURN_EMPTY; list = (TRI_aql_node_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_aql_node_t), false); if (list == NULL) { TRI_Free(TRI_UNKNOWN_MEM_ZONE, list); return NULL; } list->_type = TRI_AQL_NODE_LIST; TRI_InitVectorPointer(&list->_members, TRI_UNKNOWN_MEM_ZONE); TRI_InitVectorPointer(&node->_members, TRI_UNKNOWN_MEM_ZONE); TRI_PushBackVectorPointer(&node->_members, (void*) list); return node; }
TRI_vector_pointer_t TRI_LookupByKeyMultiPointer (TRI_memory_zone_t* zone, TRI_multi_pointer_t* array, void const* key) { TRI_vector_pointer_t result; uint64_t hash; uint64_t i; // initialises the result vector TRI_InitVectorPointer(&result, zone); // compute the hash hash = array->hashKey(array, key); i = hash % array->_nrAlloc; #ifdef TRI_INTERNAL_STATS // update statistics array->_nrFinds++; #endif // search the table while (array->_table[i] != NULL) { if (array->isEqualKeyElement(array, key, array->_table[i])) { TRI_PushBackVectorPointer(&result, array->_table[i]); } #ifdef TRI_INTERNAL_STATS else { array->_nrProbesF++; } #endif i = (i + 1) % array->_nrAlloc; } // return whatever we found return result; }
char* TRI_RegisterStringAql (TRI_aql_context_t* const context, const char* const value, const size_t length, const bool deescape) { char* copy; if (value == NULL) { ABORT_OOM } if (deescape && length > 0) { size_t outLength; copy = TRI_UnescapeUtf8StringZ(TRI_UNKNOWN_MEM_ZONE, value, length, &outLength); } else { copy = TRI_DuplicateString2Z(TRI_UNKNOWN_MEM_ZONE, value, length); } if (copy == NULL) { ABORT_OOM } if (TRI_PushBackVectorPointer(&context->_memory._strings, copy) != TRI_ERROR_NO_ERROR) { TRI_FreeString(TRI_UNKNOWN_MEM_ZONE, copy); ABORT_OOM }
static TRI_hash_index_element_multi_t* GetFromFreelist (TRI_hash_array_multi_t* array) { if (array->_freelist == nullptr) { size_t blockSize = GetBlockSize(array->_blocks._length); TRI_ASSERT(blockSize > 0); auto begin = static_cast<TRI_hash_index_element_multi_t*>(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, blockSize * OverflowEntrySize(), true)); if (begin == nullptr) { return nullptr; } auto ptr = begin; auto end = begin + (blockSize - 1); while (ptr < end) { ptr->_next = (ptr + 1); ++ptr; } array->_freelist = begin; TRI_PushBackVectorPointer(&array->_blocks, begin); array->_nrOverflowAlloc += blockSize; } auto next = array->_freelist; TRI_ASSERT(next != nullptr); array->_freelist = next->_next; array->_nrOverflowUsed++; return next; }
bool TRI_RegisterNodeContextAql (TRI_aql_context_t* const context, void* const node) { TRI_ASSERT_MAINTAINER(context != NULL); TRI_ASSERT_MAINTAINER(node != NULL); TRI_PushBackVectorPointer(&context->_memory._nodes, node); return true; }
TRI_vector_pointer_t TRI_LookupByElementHashArrayMulti (TRI_hash_array_t* array, TRI_hash_index_element_t* element) { TRI_vector_pointer_t result; uint64_t hash; uint64_t i; // ........................................................................... // initialise the vector which will hold the result if any // ........................................................................... TRI_InitVectorPointer(&result, TRI_UNKNOWN_MEM_ZONE); // ........................................................................... // compute the hash // ........................................................................... hash = HashElement(array, element); i = hash % array->_nrAlloc; // ........................................................................... // update statistics // ........................................................................... #ifdef TRI_INTERNAL_STATS array->_nrFinds++; #endif // ........................................................................... // search the table // ........................................................................... while (! IsEmptyElement(array, &array->_table[i])) { if (IsEqualElementElement(array, element, &array->_table[i])) { TRI_PushBackVectorPointer(&result, &array->_table[i]); } #ifdef TRI_INTERNAL_STATS else { array->_nrProbesF++; } #endif i = (i + 1) % array->_nrAlloc; } // ........................................................................... // return whatever we found -- which could be an empty vector list if nothing // matches. Note that we allow multiple elements (compare with pointer impl). // ........................................................................... return result; }
bool TRI_PushStackParseAql (TRI_aql_context_t* const context, const void* const value) { assert(context); if (value == NULL) { TRI_SetErrorContextAql(__FILE__, __LINE__, context, TRI_ERROR_OUT_OF_MEMORY, NULL); return false; } TRI_PushBackVectorPointer(&context->_parser->_stack, (void*) value); return true; }
TRI_vector_pointer_t TRI_LookupByKeyHashArrayMulti (TRI_hash_array_multi_t const* array, TRI_index_search_value_t const* key) { TRI_ASSERT_EXPENSIVE(array->_nrUsed < array->_nrAlloc); // ........................................................................... // initialise the vector which will hold the result if any // ........................................................................... TRI_vector_pointer_t result; TRI_InitVectorPointer(&result, TRI_UNKNOWN_MEM_ZONE); uint64_t const n = array->_nrAlloc; uint64_t i, k; i = k = HashKey(array, key) % n; for (; i < n && array->_table[i]._document != nullptr && ! IsEqualKeyElement(array, key, &array->_table[i]); ++i); if (i == n) { for (i = 0; i < k && array->_table[i]._document != nullptr && ! IsEqualKeyElement(array, key, &array->_table[i]); ++i); } TRI_ASSERT_EXPENSIVE(i < n); if (array->_table[i]._document != nullptr) { // add the element itself TRI_PushBackVectorPointer(&result, array->_table[i]._document); // add the overflow elements auto current = array->_table[i]._next; while (current != nullptr) { TRI_PushBackVectorPointer(&result, current->_document); current = current->_next; } } return result; }
static void RunWalk (TRI_aql_statement_walker_t* const walker) { size_t i, n; assert(walker); n = walker->_statements->_statements._length; for (i = 0; i < n; ++i) { TRI_aql_node_t* node; TRI_aql_node_type_e nodeType; node = (TRI_aql_node_t*) TRI_AtVectorPointer(&walker->_statements->_statements, i); if (!node) { continue; } nodeType = node->_type; // handle scopes if (nodeType == TRI_AQL_NODE_SCOPE_START) { TRI_PushBackVectorPointer(&walker->_currentScopes, TRI_AQL_NODE_DATA(node)); } // preprocess node if (walker->preVisitStatement != NULL) { // this might change the node ptr VisitStatement(walker, i, walker->preVisitStatement); node = walker->_statements->_statements._buffer[i]; } // process node's members if (walker->visitMember != NULL) { VisitMembers(walker, node); } // post process node if (walker->postVisitStatement != NULL) { VisitStatement(walker, i, walker->postVisitStatement); } if (nodeType == TRI_AQL_NODE_SCOPE_END) { size_t len = walker->_currentScopes._length; assert(len > 0); TRI_RemoveVectorPointer(&walker->_currentScopes, len - 1); } } }
static TRI_shape_aid_t FindAttributeNameArrayShaper (TRI_shaper_t* shaper, char const* name) { array_shaper_t* s; void const* p; s = (array_shaper_t*) shaper; p = TRI_LookupByKeyAssociativePointer(&s->_attributeNames, name); if (p == NULL) { size_t n; attribute_2_id_t* a2i; void* f; int res; n = strlen(name) + 1; a2i = TRI_Allocate(shaper->_memoryZone, sizeof(attribute_2_id_t) + n, false); if (a2i == NULL) { return 0; } a2i->_aid = 1 + s->_attributes._length; a2i->_size = n; memcpy(((char*) a2i) + sizeof(attribute_2_id_t), name, n); f = TRI_InsertKeyAssociativePointer(&s->_attributeNames, name, a2i, false); if (f == NULL) { TRI_Free(shaper->_memoryZone, a2i); return 0; } res = TRI_PushBackVectorPointer(&s->_attributes, a2i); if (res != TRI_ERROR_NO_ERROR) { TRI_RemoveKeyAssociativePointer(&s->_attributeNames, name); TRI_Free(shaper->_memoryZone, a2i); return 0; } return a2i->_aid; } else { attribute_2_id_t const* a2i = (attribute_2_id_t const*) p; return a2i->_aid; } }
static TRI_vocbase_col_t* AddCollection (TRI_vocbase_t* vocbase, TRI_col_type_t type, char const* name, TRI_voc_cid_t cid, char const* path) { void const* found; TRI_vocbase_col_t* col; // create a new proxy col = TRI_Allocate(sizeof(TRI_vocbase_col_t)); col->_vocbase = vocbase; col->_type = type; TRI_CopyString(col->_name, name, sizeof(col->_name)); col->_path = (path == NULL ? NULL : TRI_DuplicateString(path)); col->_collection = NULL; col->_newBorn = 0; col->_loaded = 0; col->_corrupted = 0; col->_cid = cid; // check name found = TRI_InsertKeyAssociativePointer(&vocbase->_collectionsByName, name, col, false); if (found != NULL) { TRI_Free(col); LOG_ERROR("duplicate entry for name '%s'", name); return NULL; } // check collection identifier if (cid != 0) { found = TRI_InsertKeyAssociativePointer(&vocbase->_collectionsById, &cid, col, false); if (found != NULL) { TRI_Free(col); LOG_ERROR("duplicate entry for identifier '%s'", cid); return NULL; } } TRI_PushBackVectorPointer(&vocbase->_collections, col); return col; }
TRI_vector_pointer_t TRI_LookupByElementMultiArray (TRI_memory_zone_t* zone, TRI_multi_array_t* array, void* element) { TRI_vector_pointer_t result; uint64_t hash; uint64_t i; // initialise the vector which will hold the result if any TRI_InitVectorPointer(&result, zone); // compute the hash hash = array->hashElement(array, element); i = hash % array->_nrAlloc; #ifdef TRI_INTERNAL_STATS // update statistics array->_nrFinds++; #endif // search the table while (! array->isEmptyElement(array, array->_table + i * array->_elementSize)) { if (array->isEqualElementElement(array, element, array->_table + i * array->_elementSize)) { TRI_PushBackVectorPointer(&result, array->_table + i * array->_elementSize); } #ifdef TRI_INTERNAL_STATS else { array->_nrProbesF++; } #endif i = (i + 1) % array->_nrAlloc; } // ........................................................................... // return whatever we found -- which could be an empty vector list if nothing // matches. Note that we allow multiple elements (compare with pointer // impl). If an out-of-memory occurred than the zone will have a suitable // marker. // ........................................................................... return result; }
static TRI_doc_mptr_t* RequestSimpleHeaders (TRI_headers_t* h) { simple_headers_t* headers = (simple_headers_t*) h; char const* header; union { TRI_doc_mptr_t const* c; TRI_doc_mptr_t* h; } c; if (headers->_freelist == NULL) { char* begin; char* ptr; size_t blockSize; blockSize = GetBlockSize(headers->_blocks._length); begin = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, blockSize * headers->_headerSize, false); // out of memory if (begin == NULL) { TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); return NULL; } ptr = begin + headers->_headerSize * (blockSize - 1); header = NULL; for (; begin <= ptr; ptr -= headers->_headerSize) { ClearSimpleHeaders((TRI_doc_mptr_t*) ptr, headers->_headerSize); ((TRI_doc_mptr_t*) ptr)->_data = header; header = ptr; } headers->_freelist = (TRI_doc_mptr_t*) header; TRI_PushBackVectorPointer(&headers->_blocks, begin); } c.c = headers->_freelist; headers->_freelist = c.c->_data; c.h->_data = NULL; return c.h; }
void TRI_CreateExternalProcess (const char* executable, const char** arguments, size_t n, bool usePipes, TRI_external_id_t* pid) { // create the external structure TRI_external_t* external = static_cast<TRI_external_t*>(TRI_Allocate(TRI_CORE_MEM_ZONE, sizeof(TRI_external_t), true)); external->_executable = TRI_DuplicateString(executable); external->_numberArguments = n + 1; external->_arguments = static_cast<char**>(TRI_Allocate(TRI_CORE_MEM_ZONE, (n + 2) * sizeof(char*), true)); external->_arguments[0] = TRI_DuplicateString(executable); for (size_t i = 0; i < n; ++i) { external->_arguments[i + 1] = TRI_DuplicateString(arguments[i]); } external->_arguments[n + 1] = nullptr; external->_status = TRI_EXT_NOT_STARTED; StartExternalProcess(external, usePipes); if (external->_status != TRI_EXT_RUNNING) { pid->_pid = TRI_INVALID_PROCESS_ID; FreeExternal(external); return; } LOG_DEBUG("adding process %d to list", (int) external->_pid); TRI_LockMutex(&ExternalProcessesLock); TRI_PushBackVectorPointer(&ExternalProcesses, external); // Note that the following deals with different types under windows, // however, this code here can be written in a platform-independent // way: pid->_pid = external->_pid; pid->_readPipe = external->_readPipe; pid->_writePipe = external->_writePipe; TRI_UnlockMutex(&ExternalProcessesLock); }
bool TRI_AppendStatementListAql (TRI_aql_statement_list_t* const list, TRI_aql_node_t* const node) { TRI_aql_node_type_e type; int result; assert(list); assert(node); type = node->_type; assert(TRI_IsTopLevelTypeAql(type)); if (type == TRI_AQL_NODE_SCOPE_START) { ++list->_currentLevel; } else if (type == TRI_AQL_NODE_SCOPE_END) { assert(list->_currentLevel > 0); --list->_currentLevel; } result = TRI_PushBackVectorPointer(&list->_statements, node); return result == TRI_ERROR_NO_ERROR; }
bool SetupCollections (TRI_aql_context_t* const context) { size_t i; size_t n; bool result = true; // each collection used is contained once in the assoc. array // so we do not have to care about duplicate names here n = context->_collectionNames._nrAlloc; for (i = 0; i < n; ++i) { char* name = context->_collectionNames._table[i]; TRI_aql_collection_t* collection; if (! name) { continue; } collection = CreateCollectionContainer(name); if (! collection) { result = false; TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); break; } TRI_PushBackVectorPointer(&context->_collections, (void*) collection); } if (result && n > 0) { qsort(context->_collections._buffer, context->_collections._length, sizeof(void*), &CollectionNameComparator); } // now collections contains the sorted list of collections return result; }
static void OptimisePaths (const TRI_aql_node_t* const fcallNode, TRI_aql_context_t* const context, TRI_aql_field_access_t* fieldAccess) { TRI_aql_node_t* args; TRI_aql_node_t* vertexCollection; TRI_aql_node_t* edgeCollection; TRI_aql_node_t* direction; char* directionValue; char* name; size_t n; args = TRI_AQL_NODE_MEMBER(fcallNode, 0); if (args == NULL) { return; } vertexCollection = TRI_AQL_NODE_MEMBER(args, 0); edgeCollection = TRI_AQL_NODE_MEMBER(args, 1); direction = TRI_AQL_NODE_MEMBER(args, 2); assert(vertexCollection); assert(edgeCollection); assert(direction); assert(fieldAccess); n = strlen(fieldAccess->_fullName); name = fieldAccess->_fullName + fieldAccess->_variableNameLength; directionValue = TRI_AQL_NODE_STRING(direction); // try to optimise the vertex collection access if (TRI_EqualString(directionValue, "outbound")) { CheckPathRestriction(fieldAccess, context, vertexCollection, ".source.", name, n); } else if (TRI_EqualString(directionValue, "inbound")) { CheckPathRestriction(fieldAccess, context, vertexCollection, ".source.", name, n); } else if (TRI_EqualString(directionValue, "any")) { // "any" cannot be optimised sanely becuase the conditions would be AND-combined // (but for "any", we'd need them OR-combined) // CheckPathRestriction(fieldAccess, context, vertexCollection, ".source.", name, n); // CheckPathRestriction(fieldAccess, context, vertexCollection, ".destination.", name, n); } // check if we have a filter on LENGTH(edges) if (args->_members._length <= 4 && TRI_EqualString(name, ".edges.LENGTH()")) { // length restriction, can only be applied if length parameters are not already set TRI_json_t* value; double minValue = 0.0; double maxValue = 0.0; bool useMin = false; bool useMax = false; if (fieldAccess->_type == TRI_AQL_ACCESS_EXACT) { value = fieldAccess->_value._value; if (value != NULL && value->_type == TRI_JSON_NUMBER) { // LENGTH(p.edges) == const minValue = maxValue = value->_value._number; useMin = useMax = true; } } else if (fieldAccess->_type == TRI_AQL_ACCESS_RANGE_SINGLE) { value = fieldAccess->_value._singleRange._value; if (value != NULL && value->_type == TRI_JSON_NUMBER) { // LENGTH(p.edges) operator const if (fieldAccess->_value._singleRange._type == TRI_AQL_RANGE_LOWER_INCLUDED) { minValue = value->_value._number; useMin = true; } else if (fieldAccess->_value._singleRange._type == TRI_AQL_RANGE_UPPER_INCLUDED) { maxValue = value->_value._number; useMax = true; } else if (fieldAccess->_value._singleRange._type == TRI_AQL_RANGE_LOWER_EXCLUDED) { if ((double) ((int) value->_value._number) == value->_value._number) { minValue = value->_value._number + 1.0; useMin = true; } } else if (fieldAccess->_value._singleRange._type == TRI_AQL_RANGE_UPPER_EXCLUDED) { if ((double) ((int) value->_value._number) == value->_value._number) { maxValue = value->_value._number - 1.0; useMax = true; } } } } else if (fieldAccess->_type == TRI_AQL_ACCESS_RANGE_DOUBLE) { // LENGTH(p.edges) > const && LENGTH(p.edges) < const value = fieldAccess->_value._between._lower._value; if (value != NULL && value->_type == TRI_JSON_NUMBER) { if (fieldAccess->_value._between._lower._type == TRI_AQL_RANGE_LOWER_INCLUDED) { minValue = value->_value._number; useMin = true; } else if (fieldAccess->_value._between._lower._type == TRI_AQL_RANGE_LOWER_EXCLUDED) { if ((double) ((int) value->_value._number) == value->_value._number) { minValue = value->_value._number + 1.0; useMin = true; } } } value = fieldAccess->_value._between._upper._value; if (value != NULL && value->_type == TRI_JSON_NUMBER) { if (fieldAccess->_value._between._upper._type == TRI_AQL_RANGE_UPPER_INCLUDED) { maxValue = value->_value._number; useMax = true; } else if (fieldAccess->_value._between._upper._type == TRI_AQL_RANGE_UPPER_EXCLUDED) { if ((double) ((int) value->_value._number) == value->_value._number) { maxValue = value->_value._number - 1.0; useMax = true; } } } } if (useMin || useMax) { TRI_aql_node_t* argNode; // minLength and maxLength are parameters 5 & 6 // add as many null value nodes as are missing while (args->_members._length < 4) { argNode = TRI_CreateNodeValueNullAql(context); if (argNode) { TRI_PushBackVectorPointer(&args->_members, (void*) argNode); } } // add min and max values to the function call argument list argNode = TRI_CreateNodeValueIntAql(context, useMin ? (int64_t) minValue : (int64_t) 0); if (argNode) { // min value node TRI_PushBackVectorPointer(&args->_members, (void*) argNode); argNode = TRI_CreateNodeValueIntAql(context, useMax ? (int64_t) maxValue : (int64_t) (1024 * 1024)); if (argNode) { // max value node TRI_PushBackVectorPointer(&args->_members, (void*) argNode); } } } } }
void TRI_RegisterNodeQuery (TRI_vector_pointer_t* memory, const TRI_query_node_t* const node) { TRI_PushBackVectorPointer(memory, (void*) node); }
void TRI_RegisterStringQuery (TRI_vector_pointer_t* memory, const char* const string) { TRI_PushBackVectorPointer(memory, (void*) string); }
static bool FindEdges (const TRI_edge_direction_e direction, TRI_multi_pointer_t* idx, TRI_vector_pointer_t* result, TRI_edge_header_t* entry, const int matchType) { TRI_vector_pointer_t found; TRI_edge_header_t* edge; entry->_flags = TRI_LookupFlagsEdge(direction); found = TRI_LookupByKeyMultiPointer(TRI_UNKNOWN_MEM_ZONE, idx, entry); if (found._length > 0) { size_t i; if (result->_capacity == 0) { int res; // if result vector is still empty and we have results, re-init the // result vector to a "good" size. this will save later reallocations res = TRI_InitVectorPointer2(result, TRI_UNKNOWN_MEM_ZONE, found._length); if (res != TRI_ERROR_NO_ERROR) { TRI_DestroyVectorPointer(&found); TRI_set_errno(res); return false; } } // add all results found for (i = 0; i < found._length; ++i) { edge = (TRI_edge_header_t*) found._buffer[i]; // the following queries will use the following sequences of matchTypes: // inEdges(): 1, 2, outEdges(): 1, 2, edges(): 1, 3 // if matchType is 1, we'll return all found edges without further filtering // // if matchType is 2 (inEdges or outEdges query), the direction is reversed. // We'll exclude all self-reflexive edges now (we already got them in iteration 1), // and alsoexclude all unidirectional edges // // if matchType is 3, the direction is also reversed. We'll exclude all // self-reflexive edges now (we already got them in iteration 1) if (matchType > 1) { // if the edge is self-reflexive, we have already found it in iteration 1 // we must skip it here, otherwise we would produce duplicates if (IsReflexive(edge)) { continue; } } TRI_PushBackVectorPointer(result, CONST_CAST(edge->_mptr)); } } TRI_DestroyVectorPointer(&found); return true; }
static bool CheckCollection (TRI_collection_t* collection) { TRI_datafile_t* datafile; TRI_vector_pointer_t all; TRI_vector_pointer_t compactors; TRI_vector_pointer_t datafiles; TRI_vector_pointer_t journals; TRI_vector_pointer_t sealed; TRI_vector_string_t files; bool stop; regex_t re; size_t i; size_t n; stop = false; // check files within the directory files = TRI_FilesDirectory(collection->_directory); n = files._length; regcomp(&re, "^(journal|datafile|index|compactor)-([0-9][0-9]*)\\.(db|json)$", REG_EXTENDED); TRI_InitVectorPointer(&journals, TRI_UNKNOWN_MEM_ZONE); TRI_InitVectorPointer(&compactors, TRI_UNKNOWN_MEM_ZONE); TRI_InitVectorPointer(&datafiles, TRI_UNKNOWN_MEM_ZONE); TRI_InitVectorPointer(&sealed, TRI_UNKNOWN_MEM_ZONE); TRI_InitVectorPointer(&all, TRI_UNKNOWN_MEM_ZONE); for (i = 0; i < n; ++i) { char const* file = files._buffer[i]; regmatch_t matches[4]; if (regexec(&re, file, sizeof(matches) / sizeof(matches[0]), matches, 0) == 0) { char const* first = file + matches[1].rm_so; size_t firstLen = matches[1].rm_eo - matches[1].rm_so; char const* third = file + matches[3].rm_so; size_t thirdLen = matches[3].rm_eo - matches[3].rm_so; // ............................................................................. // file is an index, just store the filename // ............................................................................. if (TRI_EqualString2("index", first, firstLen) && TRI_EqualString2("json", third, thirdLen)) { char* filename; filename = TRI_Concatenate2File(collection->_directory, file); TRI_PushBackVectorString(&collection->_indexFiles, filename); } // ............................................................................. // file is a journal or datafile, open the datafile // ............................................................................. else if (TRI_EqualString2("db", third, thirdLen)) { char* filename; char* ptr; TRI_col_header_marker_t* cm; filename = TRI_Concatenate2File(collection->_directory, file); datafile = TRI_OpenDatafile(filename); if (datafile == NULL) { collection->_lastError = TRI_errno(); stop = true; LOG_ERROR("cannot open datafile '%s': %s", filename, TRI_last_error()); break; } TRI_PushBackVectorPointer(&all, datafile); // check the document header ptr = datafile->_data; ptr += TRI_DF_ALIGN_BLOCK(sizeof(TRI_df_header_marker_t)); cm = (TRI_col_header_marker_t*) ptr; if (cm->base._type != TRI_COL_MARKER_HEADER) { LOG_ERROR("collection header mismatch in file '%s', expected TRI_COL_MARKER_HEADER, found %lu", filename, (unsigned long) cm->base._type); TRI_FreeString(TRI_CORE_MEM_ZONE, filename); stop = true; break; } if (cm->_cid != collection->_info._cid) { LOG_ERROR("collection identifier mismatch, expected %llu, found %llu", (unsigned long long) collection->_info._cid, (unsigned long long) cm->_cid); TRI_FreeString(TRI_CORE_MEM_ZONE, filename); stop = true; break; } // file is a journal if (TRI_EqualString2("journal", first, firstLen)) { if (datafile->_isSealed) { LOG_WARNING("strange, journal '%s' is already sealed; must be a left over; will use it as datafile", filename); TRI_PushBackVectorPointer(&sealed, datafile); } else { TRI_PushBackVectorPointer(&journals, datafile); } } // file is a compactor file else if (TRI_EqualString2("compactor", first, firstLen)) { if (datafile->_isSealed) { LOG_WARNING("strange, compactor journal '%s' is already sealed; must be a left over; will use it as datafile", filename); TRI_PushBackVectorPointer(&sealed, datafile); } else { TRI_PushBackVectorPointer(&compactors, datafile); } } // file is a datafile else if (TRI_EqualString2("datafile", first, firstLen)) { if (! datafile->_isSealed) { LOG_ERROR("datafile '%s' is not sealed, this should never happen", filename); collection->_lastError = TRI_set_errno(TRI_ERROR_ARANGO_CORRUPTED_DATAFILE); stop = true; break; } else { TRI_PushBackVectorPointer(&datafiles, datafile); } } else { LOG_ERROR("unknown datafile '%s'", file); } TRI_FreeString(TRI_CORE_MEM_ZONE, filename); } else { LOG_ERROR("unknown datafile '%s'", file); } } } TRI_DestroyVectorString(&files); regfree(&re); // convert the sealed journals into datafiles if (! stop) { n = sealed._length; for (i = 0; i < n; ++i) { char* number; char* dname; char* filename; bool ok; datafile = sealed._buffer[i]; number = TRI_StringUInt64(datafile->_fid); dname = TRI_Concatenate3String("datafile-", number, ".db"); filename = TRI_Concatenate2File(collection->_directory, dname); TRI_FreeString(TRI_CORE_MEM_ZONE, dname); TRI_FreeString(TRI_CORE_MEM_ZONE, number); ok = TRI_RenameDatafile(datafile, filename); if (ok) { TRI_PushBackVectorPointer(&datafiles, datafile); LOG_DEBUG("renamed sealed journal to '%s'", filename); } else { collection->_lastError = datafile->_lastError; stop = true; LOG_ERROR("cannot rename sealed log-file to %s, this should not happen: %s", filename, TRI_last_error()); break; } TRI_FreeString(TRI_CORE_MEM_ZONE, filename); } } TRI_DestroyVectorPointer(&sealed); // stop if necessary if (stop) { n = all._length; for (i = 0; i < n; ++i) { datafile = all._buffer[i]; LOG_TRACE("closing datafile '%s'", datafile->_filename); TRI_CloseDatafile(datafile); TRI_FreeDatafile(datafile); } TRI_DestroyVectorPointer(&all); TRI_DestroyVectorPointer(&datafiles); return false; } TRI_DestroyVectorPointer(&all); // add the datafiles and journals collection->_datafiles = datafiles; collection->_journals = journals; collection->_compactors = compactors; return true; }
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 == nullptr) { LOG_ERROR("unknown shape id %llu", (unsigned long long) accessor->_sid); #ifdef TRI_ENABLE_MAINTAINER_MODE TRI_ASSERT(false); #endif return false; } // find the attribute path path = shaper->lookupAttributePathByPid(shaper, accessor->_pid); if (path == nullptr) { LOG_ERROR("unknown attribute path %llu", (unsigned long long) accessor->_pid); #ifdef TRI_ENABLE_MAINTAINER_MODE TRI_ASSERT(false); #endif return false; } paids = (TRI_shape_aid_t*) (((char const*) path) + sizeof(TRI_shape_path_t)); // collect the bytecode // we need at least 2 entries in the vector to store an accessor TRI_InitVectorPointer2(&ops, shaper->_memoryZone, 2); // 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 == nullptr) { 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; } 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 == nullptr) { 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; } break; } } if (j < v) { continue; } LOG_TRACE("unknown attribute id '%ld'", (unsigned long) *paids); TRI_DestroyVectorPointer(&ops); accessor->_resultSid = TRI_SHAPE_ILLEGAL; accessor->_code = nullptr; return true; } else { TRI_DestroyVectorPointer(&ops); accessor->_resultSid = TRI_SHAPE_ILLEGAL; accessor->_code = nullptr; 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; } // remember resulting sid accessor->_resultSid = shape->_sid; // steal buffer from ops vector so we don't need to copy it accessor->_code = const_cast<void const**>(ops._buffer); // inform the vector that we took over ownership ops._buffer = nullptr; TRI_DestroyVectorPointer(&ops); return true; }
static TRI_datafile_t* CreateJournal (TRI_primary_collection_t* primary, TRI_voc_size_t maximalSize) { TRI_col_header_marker_t cm; TRI_collection_t* collection; TRI_datafile_t* journal; TRI_df_marker_t* position; TRI_voc_fid_t fid; int res; collection = &primary->base; fid = (TRI_voc_fid_t) TRI_NewTickServer(); if (collection->_info._isVolatile) { // in-memory collection journal = TRI_CreateDatafile(NULL, fid, maximalSize); } else { char* jname; char* number; char* filename; // construct a suitable filename (which is temporary at the beginning) number = TRI_StringUInt64(fid); jname = TRI_Concatenate3String("temp-", number, ".db"); filename = TRI_Concatenate2File(collection->_directory, jname); TRI_FreeString(TRI_CORE_MEM_ZONE, number); TRI_FreeString(TRI_CORE_MEM_ZONE, jname); journal = TRI_CreateDatafile(filename, fid, maximalSize); TRI_FreeString(TRI_CORE_MEM_ZONE, filename); } if (journal == NULL) { if (TRI_errno() == TRI_ERROR_OUT_OF_MEMORY_MMAP) { collection->_lastError = TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY_MMAP); collection->_state = TRI_COL_STATE_READ; } else { collection->_lastError = TRI_set_errno(TRI_ERROR_ARANGO_NO_JOURNAL); collection->_state = TRI_COL_STATE_WRITE_ERROR; } return NULL; } LOG_TRACE("created new journal '%s'", journal->getName(journal)); // create a collection header, still in the temporary file res = TRI_ReserveElementDatafile(journal, sizeof(TRI_col_header_marker_t), &position, maximalSize); if (res != TRI_ERROR_NO_ERROR) { collection->_lastError = journal->_lastError; LOG_ERROR("cannot create document header in journal '%s': %s", journal->getName(journal), TRI_last_error()); TRI_FreeDatafile(journal); return NULL; } TRI_InitMarker((char*) &cm, TRI_COL_MARKER_HEADER, sizeof(TRI_col_header_marker_t)); cm.base._tick = (TRI_voc_tick_t) fid; cm._type = (TRI_col_type_t) collection->_info._type; cm._cid = collection->_info._cid; res = TRI_WriteCrcElementDatafile(journal, position, &cm.base, sizeof(cm), true); if (res != TRI_ERROR_NO_ERROR) { collection->_lastError = journal->_lastError; LOG_ERROR("cannot create document header in journal '%s': %s", journal->getName(journal), TRI_last_error()); TRI_FreeDatafile(journal); return NULL; } assert(fid == journal->_fid); // if a physical file, we can rename it from the temporary name to the correct name if (journal->isPhysical(journal)) { char* jname; char* number; char* filename; bool ok; // and use the correct name number = TRI_StringUInt64(journal->_fid); jname = TRI_Concatenate3String("journal-", number, ".db"); filename = TRI_Concatenate2File(collection->_directory, jname); TRI_FreeString(TRI_CORE_MEM_ZONE, number); TRI_FreeString(TRI_CORE_MEM_ZONE, jname); ok = TRI_RenameDatafile(journal, filename); if (! ok) { LOG_ERROR("failed to rename the journal to '%s': %s", filename, TRI_last_error()); TRI_FreeDatafile(journal); TRI_FreeString(TRI_CORE_MEM_ZONE, filename); return NULL; } else { LOG_TRACE("renamed journal from %s to '%s'", journal->getName(journal), filename); } TRI_FreeString(TRI_CORE_MEM_ZONE, filename); } TRI_PushBackVectorPointer(&collection->_journals, journal); return journal; }
TRI_aql_index_t* TRI_DetermineIndexAql (TRI_aql_context_t* const context, const TRI_vector_pointer_t* const availableIndexes, const char* const collectionName, const TRI_vector_pointer_t* candidates) { TRI_aql_index_t* picked = NULL; TRI_vector_pointer_t matches; size_t i, n; TRI_InitVectorPointer(&matches, TRI_UNKNOWN_MEM_ZONE); assert(context); assert(collectionName); assert(candidates); n = availableIndexes->_length; for (i = 0; i < n; ++i) { TRI_index_t* idx = (TRI_index_t*) availableIndexes->_buffer[i]; size_t numIndexFields; bool lastTypeWasExact; size_t j; if (! CanUseIndex(idx)) { continue; } LogIndexString("checking", idx, collectionName); TRI_ClearVectorPointer(&matches); lastTypeWasExact = true; numIndexFields = idx->_fields._length; // now loop over all index fields, from left to right // index field order is important because skiplists can be used with leftmost prefixes as well, // but not with rightmost prefixes for (j = 0; j < numIndexFields; ++j) { char* indexedFieldName; char* fieldName; size_t k; indexedFieldName = idx->_fields._buffer[j]; if (indexedFieldName == NULL) { continue; } // now loop over all candidates for (k = 0; k < candidates->_length; ++k) { TRI_aql_field_access_t* candidate = (TRI_aql_field_access_t*) TRI_AtVectorPointer(candidates, k); if (candidate->_type == TRI_AQL_ACCESS_IMPOSSIBLE || candidate->_type == TRI_AQL_ACCESS_ALL) { // wrong index type, doesn't help us at all continue; } fieldName = candidate->_fullName + candidate->_variableNameLength + 1; if (idx->_type == TRI_IDX_TYPE_PRIMARY_INDEX) { // primary index key names must be treated differently. _id and _key are the same if (! TRI_EqualString("_id", fieldName) && ! TRI_EqualString(TRI_VOC_ATTRIBUTE_KEY, fieldName)) { continue; } } else if (idx->_type == TRI_IDX_TYPE_EDGE_INDEX) { // edge index key names must be treated differently. _from and _to can be used independently if (! TRI_EqualString(TRI_VOC_ATTRIBUTE_FROM, fieldName) && ! TRI_EqualString(TRI_VOC_ATTRIBUTE_TO, fieldName)) { continue; } } else if (! TRI_EqualString(indexedFieldName, fieldName)) { // different attribute, doesn't help continue; } // attribute is used in index if (idx->_type == TRI_IDX_TYPE_PRIMARY_INDEX || idx->_type == TRI_IDX_TYPE_EDGE_INDEX) { if (! IsExactCandidate(candidate)) { // wrong access type for primary index continue; } TRI_PushBackVectorPointer(&matches, candidate); } else if (idx->_type == TRI_IDX_TYPE_HASH_INDEX) { if (! IsExactCandidate(candidate)) { // wrong access type for hash index continue; } if (candidate->_type == TRI_AQL_ACCESS_LIST && numIndexFields != 1) { // we found a list, but the index covers multiple attributes. that means we cannot use list access continue; } TRI_PushBackVectorPointer(&matches, candidate); } else if (idx->_type == TRI_IDX_TYPE_BITARRAY_INDEX) { if (! IsExactCandidate(candidate)) { // wrong access type for hash index continue; } if (candidate->_type == TRI_AQL_ACCESS_LIST) { // we found a list, but the index covers multiple attributes. that means we cannot use list access continue; } TRI_PushBackVectorPointer(&matches, candidate); } else if (idx->_type == TRI_IDX_TYPE_SKIPLIST_INDEX) { bool candidateIsExact; if (candidate->_type != TRI_AQL_ACCESS_EXACT && candidate->_type != TRI_AQL_ACCESS_LIST && candidate->_type != TRI_AQL_ACCESS_RANGE_SINGLE && candidate->_type != TRI_AQL_ACCESS_RANGE_DOUBLE && candidate->_type != TRI_AQL_ACCESS_REFERENCE) { // wrong access type for skiplists continue; } if (candidate->_type == TRI_AQL_ACCESS_LIST && numIndexFields != 1) { // we found a list, but the index covers multiple attributes. that means we cannot use list access continue; } candidateIsExact = IsExactCandidate(candidate); if ((candidateIsExact && ! lastTypeWasExact) || (! candidateIsExact && ! lastTypeWasExact)) { // if we already had a range query, we cannot check for equality after that // if we already had a range query, we cannot check another range after that continue; } if (candidate->_type == TRI_AQL_ACCESS_RANGE_SINGLE) { // range type. check if the compare value is a list or an object TRI_json_t* value = candidate->_value._singleRange._value; if (TRI_IsListJson(value) || TRI_IsArrayJson(value)) { // list or object, we cannot use this for comparison in a skiplist continue; } } else if (candidate->_type == TRI_AQL_ACCESS_RANGE_DOUBLE) { // range type. check if the compare value is a list or an object TRI_json_t* value = candidate->_value._between._lower._value; if (TRI_IsListJson(value) || TRI_IsArrayJson(value)) { // list or object, we cannot use this for comparison in a skiplist continue; } value = candidate->_value._between._upper._value; if (TRI_IsListJson(value) || TRI_IsArrayJson(value)) { // list or object, we cannot use this for comparison in a skiplist continue; } } lastTypeWasExact = candidateIsExact; TRI_PushBackVectorPointer(&matches, candidate); } } // finished iterating over all candidates if (matches._length != j + 1) { // we already have picked less candidate fields than we should break; } } if (matches._length < 1) { // nothing found continue; } // we now do or don't have an index candidate in the matches vector if (matches._length < numIndexFields && TRI_NeedsFullCoverageIndex(idx->_type)) { // the matches vector does not fully cover the indexed fields, but the index requires it continue; } // if we can use the primary index, we'll use it picked = PickIndex(context, picked, idx, &matches); } TRI_DestroyVectorPointer(&matches); if (picked) { LogIndexString("using", picked->_idx, collectionName); } return picked; }
TRI_aql_node_t* TRI_JsonNodeAql (TRI_aql_context_t* const context, const TRI_json_t* const json) { TRI_aql_node_t* node = NULL; char* value; switch (json->_type) { case TRI_JSON_UNUSED: break; case TRI_JSON_NULL: node = TRI_CreateNodeValueNullAql(context); break; case TRI_JSON_BOOLEAN: node = TRI_CreateNodeValueBoolAql(context, json->_value._boolean); break; case TRI_JSON_NUMBER: node = TRI_CreateNodeValueDoubleAql(context, json->_value._number); break; case TRI_JSON_STRING: value = TRI_RegisterStringAql(context, json->_value._string.data, strlen(json->_value._string.data), true); node = TRI_CreateNodeValueStringAql(context, value); break; case TRI_JSON_LIST: { size_t i; size_t n; node = TRI_CreateNodeListAql(context); n = json->_value._objects._length; for (i = 0; i < n; ++i) { TRI_json_t* subJson; TRI_aql_node_t* member; subJson = (TRI_json_t*) TRI_AtVector(&json->_value._objects, i); assert(subJson); member = TRI_JsonNodeAql(context, subJson); if (member) { TRI_PushBackVectorPointer(&node->_members, (void*) member); } else { TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); return NULL; } } break; } case TRI_JSON_ARRAY: { size_t i; size_t n; node = TRI_CreateNodeArrayAql(context); n = json->_value._objects._length; for (i = 0; i < n; i += 2) { TRI_json_t* nameJson; TRI_json_t* valueJson; TRI_aql_node_t* member; TRI_aql_node_t* valueNode; char* name; // json_t containing the array element name nameJson = (TRI_json_t*) TRI_AtVector(&json->_value._objects, i); assert(nameJson); assert(nameJson->_value._string.data); name = TRI_RegisterStringAql(context, nameJson->_value._string.data, strlen(nameJson->_value._string.data), false); if (! name) { TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); return NULL; } // json_t containing the array element value valueJson = (TRI_json_t*) TRI_AtVector(&json->_value._objects, i + 1); assert(valueJson); valueNode = TRI_JsonNodeAql(context, valueJson); if (! valueNode) { TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); return NULL; } member = TRI_CreateNodeArrayElementAql(context, name, valueNode); if (member) { TRI_PushBackVectorPointer(&node->_members, (void*) member); } else { TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); return NULL; } } break; } } if (! node) { TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); } return node; }
static TRI_datafile_t* CreateJournal (TRI_primary_collection_t* primary, bool compactor) { TRI_col_header_marker_t cm; TRI_collection_t* collection; TRI_datafile_t* journal; TRI_df_marker_t* position; int res; char* filename; collection = &primary->base; if (collection->_info._isVolatile) { // in-memory collection filename = NULL; } else { char* jname; char* number; // construct a suitable filename number = TRI_StringUInt64(TRI_NewTickVocBase()); if (compactor) { jname = TRI_Concatenate3String("journal-", number, ".db"); } else { jname = TRI_Concatenate3String("compactor-", number, ".db"); } filename = TRI_Concatenate2File(collection->_directory, jname); TRI_FreeString(TRI_CORE_MEM_ZONE, number); TRI_FreeString(TRI_CORE_MEM_ZONE, jname); } // create journal file journal = TRI_CreateDatafile(filename, collection->_info._maximalSize); if (filename != NULL) { TRI_FreeString(TRI_CORE_MEM_ZONE, filename); } if (journal == NULL) { if (TRI_errno() == TRI_ERROR_OUT_OF_MEMORY_MMAP) { collection->_lastError = TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY_MMAP); collection->_state = TRI_COL_STATE_READ; } else { collection->_lastError = TRI_set_errno(TRI_ERROR_ARANGO_NO_JOURNAL); collection->_state = TRI_COL_STATE_WRITE_ERROR; } return NULL; } LOG_TRACE("created a new primary journal '%s'", journal->getName(journal)); if (journal->isPhysical(journal)) { char* jname; char* number; bool ok; // and use the correct name number = TRI_StringUInt64(journal->_fid); if (compactor) { jname = TRI_Concatenate3String("compactor-", number, ".db"); } else { jname = TRI_Concatenate3String("journal-", number, ".db"); } filename = TRI_Concatenate2File(collection->_directory, jname); TRI_FreeString(TRI_CORE_MEM_ZONE, number); TRI_FreeString(TRI_CORE_MEM_ZONE, jname); ok = TRI_RenameDatafile(journal, filename); if (! ok) { LOG_WARNING("failed to rename the journal to '%s': %s", filename, TRI_last_error()); } else { LOG_TRACE("renamed journal to '%s'", filename); } TRI_FreeString(TRI_CORE_MEM_ZONE, filename); } // create a collection header res = TRI_ReserveElementDatafile(journal, sizeof(TRI_col_header_marker_t), &position); if (res != TRI_ERROR_NO_ERROR) { collection->_lastError = journal->_lastError; LOG_ERROR("cannot create document header in journal '%s': %s", journal->getName(journal), TRI_last_error()); TRI_FreeDatafile(journal); return NULL; } memset(&cm, 0, sizeof(cm)); cm.base._size = sizeof(TRI_col_header_marker_t); cm.base._type = TRI_COL_MARKER_HEADER; cm.base._tick = TRI_NewTickVocBase(); cm._cid = collection->_info._cid; TRI_FillCrcMarkerDatafile(journal, &cm.base, sizeof(cm), 0, 0, 0, 0); res = TRI_WriteElementDatafile(journal, position, &cm.base, sizeof(cm), 0, 0, 0, 0, true); if (res != TRI_ERROR_NO_ERROR) { collection->_lastError = journal->_lastError; LOG_ERROR("cannot create document header in journal '%s': %s", journal->getName(journal), TRI_last_error()); TRI_FreeDatafile(journal); return NULL; } // that's it if (compactor) { TRI_PushBackVectorPointer(&collection->_compactors, journal); } else { TRI_PushBackVectorPointer(&collection->_journals, journal); } return journal; }
static bool CloseJournalPrimaryCollection (TRI_primary_collection_t* primary, size_t position, bool compactor) { TRI_datafile_t* journal; TRI_collection_t* collection; TRI_vector_pointer_t* vector; int res; collection = &primary->base; // either use a journal or a compactor if (compactor) { vector = &collection->_compactors; } else { vector = &collection->_journals; } // no journal at this position if (vector->_length <= position) { TRI_set_errno(TRI_ERROR_ARANGO_NO_JOURNAL); return false; } // seal and rename datafile journal = vector->_buffer[position]; res = TRI_SealDatafile(journal); if (res != TRI_ERROR_NO_ERROR) { LOG_ERROR("failed to seal datafile '%s': %s", journal->getName(journal), TRI_last_error()); TRI_RemoveVectorPointer(vector, position); TRI_PushBackVectorPointer(&collection->_datafiles, journal); return false; } if (journal->isPhysical(journal)) { // rename the file char* dname; char* filename; char* number; bool ok; number = TRI_StringUInt64(journal->_fid); dname = TRI_Concatenate3String("datafile-", number, ".db"); filename = TRI_Concatenate2File(collection->_directory, dname); TRI_FreeString(TRI_CORE_MEM_ZONE, dname); TRI_FreeString(TRI_CORE_MEM_ZONE, number); ok = TRI_RenameDatafile(journal, filename); if (! ok) { LOG_ERROR("failed to rename datafile '%s' to '%s': %s", journal->getName(journal), filename, TRI_last_error()); TRI_RemoveVectorPointer(vector, position); TRI_PushBackVectorPointer(&collection->_datafiles, journal); TRI_FreeString(TRI_CORE_MEM_ZONE, filename); return false; } TRI_FreeString(TRI_CORE_MEM_ZONE, filename); LOG_TRACE("closed journal '%s'", journal->getName(journal)); } TRI_RemoveVectorPointer(vector, position); TRI_PushBackVectorPointer(&collection->_datafiles, journal); return true; }