static void LinkBarrierElement (TRI_barrier_t* element, TRI_barrier_list_t* container) { assert(container != NULL); element->_container = container; TRI_LockSpin(&container->_lock); // empty list if (container->_end == NULL) { element->_next = NULL; element->_prev = NULL; container->_begin = element; container->_end = element; } // add to the end else { element->_next = NULL; element->_prev = container->_end; container->_end->_next = element; container->_end = element; } if (element->_type == TRI_BARRIER_ELEMENT) { // increase counter for barrier elements ++container->_numBarrierElements; } TRI_UnlockSpin(&container->_lock); }
static void LinkBarrierElement (TRI_barrier_t* element, TRI_barrier_list_t* container) { element->_container = container; TRI_LockSpin(&container->_lock); // empty list if (container->_end == NULL) { element->_next = NULL; element->_prev = NULL; container->_begin = element; container->_end = element; } // add to the end else { element->_next = NULL; element->_prev = container->_end; container->_end->_next = element; container->_end = element; } TRI_UnlockSpin(&container->_lock); }
bool TRI_ContainsBarrierList (TRI_barrier_list_t* container, TRI_barrier_type_e type) { TRI_LockSpin(&container->_lock); if (type == TRI_BARRIER_ELEMENT) { // shortcut bool hasBarriers = (container->_numBarrierElements > 0); TRI_UnlockSpin(&container->_lock); return hasBarriers; } TRI_barrier_t* ptr = container->_begin; while (ptr != NULL) { if (ptr->_type == type) { TRI_UnlockSpin(&container->_lock); return true; } ptr = ptr->_next; } TRI_UnlockSpin(&container->_lock); return false; }
void TRI_FreeBarrier (TRI_barrier_t* element) { TRI_barrier_list_t* container; container = element->_container; TRI_LockSpin(&container->_lock); // element is at the beginning of the chain if (element->_prev == NULL) { container->_begin = element->_next; } else { element->_prev->_next = element->_next; } // element is at the end of the chain if (element->_next == NULL) { container->_end = element->_prev; } else { element->_next->_prev = element->_prev; } TRI_UnlockSpin(&container->_lock); // free data contained in the element // currently, only barriers of type ELEMENT contain data that needs freeing FreeDataBarrier(element); // free the element TRI_Free(TRI_UNKNOWN_MEM_ZONE, element); }
void TRI_FreeBarrier (TRI_barrier_t* element) { TRI_barrier_list_t* container; assert(element != NULL); container = element->_container; assert(container != NULL); TRI_LockSpin(&container->_lock); // element is at the beginning of the chain if (element->_prev == NULL) { container->_begin = element->_next; } else { element->_prev->_next = element->_next; } // element is at the end of the chain if (element->_next == NULL) { container->_end = element->_prev; } else { element->_next->_prev = element->_prev; } if (element->_type == TRI_BARRIER_ELEMENT) { // decrease counter for barrier elements --container->_numBarrierElements; } TRI_UnlockSpin(&container->_lock); // free the element TRI_Free(TRI_UNKNOWN_MEM_ZONE, element); }
static bool CheckTerminateFlag (TRI_replication_applier_t* applier) { TRI_LockSpin(&applier->_threadLock); bool result = applier->_terminateThread; TRI_UnlockSpin(&applier->_threadLock); return result; }
void TRI_FreeBarrier (TRI_barrier_t* element) { TRI_barrier_list_t* container; container = element->_container; TRI_LockSpin(&container->_lock); // element is at the beginning of the chain if (element->_prev == NULL) { container->_begin = element->_next; } else { element->_prev->_next = element->_next; } // element is at the end of the chain if (element->_next == NULL) { container->_end = element->_prev; } else { element->_next->_prev = element->_prev; } TRI_UnlockSpin(&container->_lock); // free the element TRI_Free(TRI_UNKNOWN_MEM_ZONE, element); }
void TRI_ReleaseGeneralCursor (TRI_general_cursor_t* cursor) { TRI_general_cursor_store_t* store = cursor->_store; TRI_LockSpin(&store->_lock); cursor = static_cast<TRI_general_cursor_t*>(TRI_LookupByKeyAssociativePointer(&store->_ids, &cursor->_id)); if (cursor != NULL) { --cursor->_usage._refCount; } TRI_UnlockSpin(&store->_lock); }
TRI_voc_tick_t TRI_NewTickVocBase () { uint64_t tick = ServerIdentifier; TRI_LockSpin(&TickLock); tick |= (++CurrentTick) << 16; TRI_UnlockSpin(&TickLock); return tick; }
TRI_general_cursor_t* TRI_FindGeneralCursor (TRI_vocbase_t* vocbase, TRI_voc_tick_t id) { TRI_general_cursor_store_t* store = vocbase->_cursors; TRI_LockSpin(&store->_lock); TRI_general_cursor_t* cursor = static_cast<TRI_general_cursor_t*>(TRI_LookupByKeyAssociativePointer(&store->_ids, &id)); if (cursor == NULL || cursor->_usage._isDeleted) { cursor = NULL; } TRI_UnlockSpin(&store->_lock); return cursor; }
TRI_general_cursor_t* TRI_CreateGeneralCursor (TRI_vocbase_t* vocbase, TRI_general_cursor_result_t* result, const bool doCount, const TRI_general_cursor_length_t batchSize, TRI_json_t* extra) { TRI_general_cursor_t* cursor; TRI_ASSERT(vocbase != NULL); cursor = (TRI_general_cursor_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_general_cursor_t), false); if (cursor == NULL) { return NULL; } cursor->_vocbase = vocbase; cursor->_store = vocbase->_cursors; cursor->_result = result; cursor->_extra = extra; // might be NULL cursor->_expires = TRI_microtime() + 3600; // default lifetime: 1h cursor->_id = TRI_NewTickServer(); // state cursor->_currentRow = 0; cursor->_length = result->getLength(result); cursor->_hasCount = doCount; cursor->_batchSize = batchSize; cursor->_usage._refCount = 0; cursor->_usage._isDeleted = false; // assign functions cursor->next = NextGeneralCursor; cursor->hasNext = HasNextGeneralCursor; cursor->hasCount = HasCountGeneralCursor; cursor->getBatchSize = GetBatchSizeGeneralCursor; cursor->getExtra = GetExtraGeneralCursor; cursor->free = TRI_FreeGeneralCursor; TRI_InitSpin(&cursor->_lock); TRI_LockSpin(&vocbase->_cursors->_lock); // TODO: check for errors here TRI_InsertKeyAssociativePointer(&vocbase->_cursors->_ids, &cursor->_id, cursor, true); TRI_UnlockSpin(&vocbase->_cursors->_lock); LOG_TRACE("created general cursor"); return cursor; }
bool TRI_RemoveGeneralCursor (TRI_vocbase_t* vocbase, TRI_voc_tick_t id) { TRI_general_cursor_store_t* store = vocbase->_cursors; bool result; TRI_LockSpin(&store->_lock); TRI_general_cursor_t* cursor = static_cast<TRI_general_cursor_t*>(TRI_LookupByKeyAssociativePointer(&store->_ids, &id)); if (cursor == NULL || cursor->_usage._isDeleted) { result = false; } else { cursor->_usage._isDeleted = true; result = true; } TRI_UnlockSpin(&store->_lock); return result; }
bool TRI_DropGeneralCursor (TRI_general_cursor_t* cursor) { TRI_general_cursor_store_t* store = cursor->_store; bool result; TRI_LockSpin(&store->_lock); cursor = static_cast<TRI_general_cursor_t*>(TRI_LookupByKeyAssociativePointer(&store->_ids, &cursor->_id)); if (cursor != NULL && ! cursor->_usage._isDeleted) { cursor->_usage._isDeleted = true; result = true; } else { result = false; } TRI_UnlockSpin(&store->_lock); return result; }
TRI_general_cursor_t* TRI_UseGeneralCursor (TRI_general_cursor_t* cursor) { TRI_general_cursor_store_t* store = cursor->_store; TRI_LockSpin(&store->_lock); cursor = static_cast<TRI_general_cursor_t*>(TRI_LookupByKeyAssociativePointer(&store->_ids, &cursor->_id)); if (cursor != NULL) { if (cursor->_usage._isDeleted) { cursor = NULL; } else { ++cursor->_usage._refCount; } } TRI_UnlockSpin(&store->_lock); return cursor; }
bool TRI_ContainsBarrierList (TRI_barrier_list_t* container, TRI_barrier_type_e type) { TRI_barrier_t* ptr; TRI_LockSpin(&container->_lock); ptr = container->_begin; while (ptr != NULL) { if (ptr->_type == type) { TRI_UnlockSpin(&container->_lock); return true; } ptr = ptr->_next; } TRI_UnlockSpin(&container->_lock); return false; }
static void CleanupSimCollection (TRI_sim_collection_t* sim) { // loop until done while (true) { TRI_barrier_list_t* container; TRI_barrier_t* element; bool hasUnloaded = false; container = &sim->base._barrierList; element = NULL; // check and remove a callback elements at the beginning of the list TRI_LockSpin(&container->_lock); if (container->_begin == NULL || container->_begin->_type == TRI_BARRIER_ELEMENT) { // did not find anything on top of the barrier list or found an element marker // this means we must exit TRI_UnlockSpin(&container->_lock); return; } element = container->_begin; assert(element); // found an element to go on with container->_begin = element->_next; if (element->_next == NULL) { container->_end = NULL; } else { element->_next->_prev = NULL; } TRI_UnlockSpin(&container->_lock); // execute callback, sone of the callbacks might delete or free our collection if (element->_type == TRI_BARRIER_DATAFILE_CALLBACK) { TRI_barrier_datafile_cb_t* de; de = (TRI_barrier_datafile_cb_t*) element; de->callback(de->_datafile, de->_data); TRI_Free(TRI_UNKNOWN_MEM_ZONE, element); // next iteration } else if (element->_type == TRI_BARRIER_COLLECTION_UNLOAD_CALLBACK) { // collection is unloaded TRI_barrier_collection_cb_t* ce; ce = (TRI_barrier_collection_cb_t*) element; hasUnloaded = ce->callback(ce->_collection, ce->_data); TRI_Free(TRI_UNKNOWN_MEM_ZONE, element); if (hasUnloaded) { // this has unloaded and freed the collection return; } } else if (element->_type == TRI_BARRIER_COLLECTION_DROP_CALLBACK) { // collection is dropped TRI_barrier_collection_cb_t* ce; ce = (TRI_barrier_collection_cb_t*) element; hasUnloaded = ce->callback(ce->_collection, ce->_data); TRI_Free(TRI_UNKNOWN_MEM_ZONE, element); if (hasUnloaded) { // this has dropped the collection return; } } else { // unknown type LOG_FATAL("unknown barrier type '%d'", (int) element->_type); TRI_Free(TRI_UNKNOWN_MEM_ZONE, element); } // next iteration } }
void TRI_CleanupGeneralCursor (TRI_general_cursor_store_t* store, bool force) { double compareStamp = TRI_microtime(); size_t deleteCount = 0; // we need an exclusive lock on the index TRI_LockSpin(&store->_lock); if (store->_ids._nrUsed == 0) { // store is empty, nothing to do! TRI_UnlockSpin(&store->_lock); return; } LOG_TRACE("cleaning shadows. in store: %ld", (unsigned long) store->_ids._nrUsed); // loop until there's nothing to delete or // we have deleted CURSOR_MAX_DELETE elements while (deleteCount++ < CURSOR_MAX_DELETE || force) { bool deleted = false; size_t i; for (i = 0; i < store->_ids._nrAlloc; i++) { // enum all cursors TRI_general_cursor_t* cursor = (TRI_general_cursor_t*) store->_ids._table[i]; if (cursor == NULL) { continue; } TRI_LockSpin(&cursor->_lock); if (force || (cursor->_usage._refCount == 0 && (cursor->_usage._isDeleted || cursor->_expires < compareStamp))) { LOG_TRACE("cleaning cursor %p, id: %llu, rc: %d, expires: %d, deleted: %d", cursor, (unsigned long long) cursor->_id, (int) cursor->_usage._refCount, (int) cursor->_expires, (int) cursor->_usage._isDeleted); TRI_RemoveKeyAssociativePointer(&store->_ids, &cursor->_id); TRI_UnlockSpin(&cursor->_lock); TRI_FreeGeneralCursor(cursor); deleted = true; // the remove might reposition elements in the container. // therefore break here and start iteration anew break; } TRI_UnlockSpin(&cursor->_lock); } if (! deleted) { // we did not find anything to delete, so give up break; } } // release lock TRI_UnlockSpin(&store->_lock); }
void TRI_LockGeneralCursor (TRI_general_cursor_t* const cursor) { TRI_LockSpin(&cursor->_lock); }
static void CleanupDocumentCollection (TRI_document_collection_t* document) { // loop until done while (true) { TRI_barrier_list_t* container; TRI_barrier_t* element; bool hasUnloaded = false; container = &document->base._barrierList; element = NULL; // check and remove all callback elements at the beginning of the list TRI_LockSpin(&container->_lock); // check the element on top of the barrier list // if it is a TRI_BARRIER_ELEMENT, it means that there is still a reference held // to document data in a datafile. We must then not unload or remove a file if (container->_begin == NULL || container->_begin->_type == TRI_BARRIER_ELEMENT || container->_begin->_type == TRI_BARRIER_COLLECTION_REPLICATION || container->_begin->_type == TRI_BARRIER_COLLECTION_COMPACTION) { // did not find anything at the head of the barrier list or found an element marker // this means we must exit and cannot throw away datafiles and can unload collections TRI_UnlockSpin(&container->_lock); return; } // no TRI_BARRIER_ELEMENT at the head of the barrier list. This means that there is // some other action we can perform (i.e. unloading a datafile or a collection) // note that there is no need to check the entire list for a TRI_BARRIER_ELEMENT as // the list is filled up in chronological order. New barriers are always added to the // tail of the list, and if we have the following list // HEAD -> TRI_BARRIER_DATAFILE_CALLBACK -> TRI_BARRIER_ELEMENT // then it is still safe to execute the datafile callback operation, even if there // is a TRI_BARRIER_ELEMENT after it. // This is the case because the TRI_BARRIER_DATAFILE_CALLBACK is only put into the // barrier list after changing the pointers in all headers. After the pointers are // changed, it is safe to unload/remove an old datafile (that noone points to). And // any newer TRI_BARRIER_ELEMENTS will always reference data inside other datafiles. element = container->_begin; assert(element); // found an element to go on with container->_begin = element->_next; if (element->_next == NULL) { container->_end = NULL; } else { element->_next->_prev = NULL; } // yes, we can release the lock here TRI_UnlockSpin(&container->_lock); // someone else might now insert a new TRI_BARRIER_ELEMENT here, but it will // always refer to a different datafile than the one that we will now unload // execute callback, sone of the callbacks might delete or free our collection if (element->_type == TRI_BARRIER_DATAFILE_DROP_CALLBACK) { TRI_barrier_datafile_drop_cb_t* de; de = (TRI_barrier_datafile_drop_cb_t*) element; de->callback(de->_datafile, de->_data); TRI_Free(TRI_UNKNOWN_MEM_ZONE, element); // next iteration } else if (element->_type == TRI_BARRIER_DATAFILE_RENAME_CALLBACK) { TRI_barrier_datafile_rename_cb_t* de; de = (TRI_barrier_datafile_rename_cb_t*) element; de->callback(de->_datafile, de->_data); TRI_Free(TRI_UNKNOWN_MEM_ZONE, element); // next iteration } else if (element->_type == TRI_BARRIER_COLLECTION_UNLOAD_CALLBACK) { // collection is unloaded TRI_barrier_collection_cb_t* ce; ce = (TRI_barrier_collection_cb_t*) element; hasUnloaded = ce->callback(ce->_collection, ce->_data); TRI_Free(TRI_UNKNOWN_MEM_ZONE, element); if (hasUnloaded) { // this has unloaded and freed the collection return; } } else if (element->_type == TRI_BARRIER_COLLECTION_DROP_CALLBACK) { // collection is dropped TRI_barrier_collection_cb_t* ce; ce = (TRI_barrier_collection_cb_t*) element; hasUnloaded = ce->callback(ce->_collection, ce->_data); TRI_Free(TRI_UNKNOWN_MEM_ZONE, element); if (hasUnloaded) { // this has dropped the collection return; } } else { // unknown type LOG_FATAL_AND_EXIT("unknown barrier type '%d'", (int) element->_type); } // next iteration } }