int TRI_StopReplicationApplier (TRI_replication_applier_t* applier, bool resetError) { int res; res = TRI_ERROR_NO_ERROR; LOG_TRACE("requesting replication applier stop"); TRI_WriteLockReadWriteLock(&applier->_statusLock); if (! applier->_state._active) { TRI_WriteUnlockReadWriteLock(&applier->_statusLock); return res; } res = StopApplier(applier, resetError); TRI_WriteUnlockReadWriteLock(&applier->_statusLock); // join the thread without the status lock (otherwise it would probably not join) if (res == TRI_ERROR_NO_ERROR) { res = TRI_JoinThread(&applier->_thread); } else { // keep original error code TRI_JoinThread(&applier->_thread); } SetTerminateFlag(applier, false); LOG_INFO("stopped replication applier for database '%s'", applier->_databaseName); return res; }
int TRI_ConfigureReplicationApplier (TRI_replication_applier_t* applier, TRI_replication_applier_configuration_t const* config) { int res; res = TRI_ERROR_NO_ERROR; if (config->_endpoint == NULL || strlen(config->_endpoint) == 0) { // no endpoint return TRI_ERROR_REPLICATION_INVALID_APPLIER_CONFIGURATION; } if (config->_database == NULL || strlen(config->_database) == 0) { // no database return TRI_ERROR_REPLICATION_INVALID_APPLIER_CONFIGURATION; } TRI_WriteLockReadWriteLock(&applier->_statusLock); if (applier->_state._active) { // cannot change the configuration while the replication is still running TRI_WriteUnlockReadWriteLock(&applier->_statusLock); return TRI_ERROR_REPLICATION_RUNNING; } res = TRI_SaveConfigurationReplicationApplier(applier->_vocbase, config, true); if (res == TRI_ERROR_NO_ERROR) { res = LoadConfiguration(applier->_vocbase, &applier->_configuration); } TRI_WriteUnlockReadWriteLock(&applier->_statusLock); return res; }
void* TRI_RemoveKeyAssociativeSynced (TRI_associative_synced_t* array, void const* key) { uint64_t hash; uint64_t i; uint64_t k; void* old; hash = array->hashKey(array, key); i = hash % array->_nrAlloc; #ifdef TRI_INTERNAL_STATS // update statistics array->_nrRems++; #endif // search the table TRI_WriteLockReadWriteLock(&array->_lock); while (array->_table[i] != NULL && ! array->isEqualKeyElement(array, key, array->_table[i])) { i = (i + 1) % array->_nrAlloc; #ifdef TRI_INTERNAL_STATS array->_nrProbesD++; #endif } // if we did not find such an item return false if (array->_table[i] == NULL) { TRI_WriteUnlockReadWriteLock(&array->_lock); return NULL; } // remove item old = array->_table[i]; array->_table[i] = NULL; array->_nrUsed--; // and now check the following places for items to move here k = (i + 1) % array->_nrAlloc; while (array->_table[k] != NULL) { uint64_t j = array->hashElement(array, array->_table[k]) % array->_nrAlloc; if ((i < k && !(i < j && j <= k)) || (k < i && !(i < j || j <= k))) { array->_table[i] = array->_table[k]; array->_table[k] = NULL; i = k; } k = (k + 1) % array->_nrAlloc; } // return success TRI_WriteUnlockReadWriteLock(&array->_lock); return old; }
void* TRI_InsertKeyAssociativeSynced (TRI_associative_synced_t* array, void const* key, void* element) { uint64_t hash; uint64_t i; void* old; // check for out-of-memory if (array->_nrAlloc == array->_nrUsed) { TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); return NULL; } // compute the hash hash = array->hashKey(array, key); i = hash % array->_nrAlloc; #ifdef TRI_INTERNAL_STATS // update statistics array->_nrAdds++; #endif // search the table TRI_WriteLockReadWriteLock(&array->_lock); while (array->_table[i] != NULL && ! array->isEqualKeyElement(array, key, array->_table[i])) { i = (i + 1) % array->_nrAlloc; #ifdef TRI_INTERNAL_STATS array->_nrProbesA++; #endif } old = array->_table[i]; // if we found an element, return if (old != NULL) { TRI_WriteUnlockReadWriteLock(&array->_lock); return old; } // add a new element to the associative array array->_table[i] = element; array->_nrUsed++; // if we were adding and the table is more than half full, extend it if (array->_nrAlloc < 2 * array->_nrUsed) { ResizeAssociativeSynced(array); } TRI_WriteUnlockReadWriteLock(&array->_lock); return NULL; }
int TRI_ShutdownReplicationApplier (TRI_replication_applier_t* applier) { if (applier == nullptr) { return TRI_ERROR_NO_ERROR; } LOG_TRACE("requesting replication applier shutdown"); if (applier->_vocbase->_type == TRI_VOCBASE_TYPE_COORDINATOR) { return TRI_ERROR_CLUSTER_UNSUPPORTED; } TRI_WriteLockReadWriteLock(&applier->_statusLock); if (! applier->_state._active) { TRI_WriteUnlockReadWriteLock(&applier->_statusLock); return TRI_ERROR_NO_ERROR; } int res = StopApplier(applier, true); TRI_WriteUnlockReadWriteLock(&applier->_statusLock); // join the thread without the status lock (otherwise it would probably not join) if (res == TRI_ERROR_NO_ERROR) { res = TRI_JoinThread(&applier->_thread); } else { // stop the thread but keep original error code int res2 = TRI_JoinThread(&applier->_thread); if (res2 != TRI_ERROR_NO_ERROR) { LOG_ERROR("could not join replication applier for database '%s': %s", applier->_databaseName, TRI_errno_string(res2)); } } SetTerminateFlag(applier, false); TRI_WriteLockReadWriteLock(&applier->_statusLock); // really abort all ongoing transactions applier->abortRunningRemoteTransactions(); TRI_WriteUnlockReadWriteLock(&applier->_statusLock); LOG_INFO("stopped replication applier for database '%s'", applier->_databaseName); return res; }
void* TRI_RemoveElementAssociativeSynced (TRI_associative_synced_t* array, void const* element) { uint64_t hash; uint64_t i; uint64_t k; union { void const* c; void* v; } old; hash = array->hashElement(array, element); i = hash % array->_nrAlloc; // update statistics array->_nrRems++; // search the table TRI_WriteLockReadWriteLock(&array->_lock); while (array->_table[i] != NULL && ! array->isEqualElementElement(array, element, array->_table[i])) { i = (i + 1) % array->_nrAlloc; array->_nrProbesD++; } // if we did not find such an item return 0 if (array->_table[i] == NULL) { TRI_WriteUnlockReadWriteLock(&array->_lock); return NULL; } // remove item old.c = array->_table[i]; array->_table[i] = NULL; array->_nrUsed--; // and now check the following places for items to move here k = (i + 1) % array->_nrAlloc; while (array->_table[k] != NULL) { uint64_t j = array->hashElement(array, array->_table[k]) % array->_nrAlloc; if ((i < k && !(i < j && j <= k)) || (k < i && !(i < j || j <= k))) { array->_table[i] = array->_table[k]; array->_table[k] = NULL; i = k; } k = (k + 1) % array->_nrAlloc; } // return success TRI_WriteUnlockReadWriteLock(&array->_lock); return old.v; }
void* TRI_InsertKeyAssociativeSynced (TRI_associative_synced_t* array, void const* key, void* element, bool overwrite) { uint64_t hash; uint64_t i; void* old; // compute the hash hash = array->hashKey(array, key); // search the table TRI_WriteLockReadWriteLock(&array->_lock); // check for out-of-memory if (array->_nrAlloc == array->_nrUsed && ! overwrite) { TRI_WriteUnlockReadWriteLock(&array->_lock); TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); return NULL; } i = hash % array->_nrAlloc; while (array->_table[i] != NULL && ! array->isEqualKeyElement(array, key, array->_table[i])) { i = TRI_IncModU64(i, array->_nrAlloc); } old = array->_table[i]; // if we found an element, return if (old != NULL) { if (overwrite) { array->_table[i] = element; } TRI_WriteUnlockReadWriteLock(&array->_lock); return old; } // add a new element to the associative array array->_table[i] = element; array->_nrUsed++; // if we were adding and the table is more than half full, extend it if (array->_nrAlloc < 2 * array->_nrUsed) { ResizeAssociativeSynced(array, (uint32_t) (2 * array->_nrAlloc + 1)); } TRI_WriteUnlockReadWriteLock(&array->_lock); return NULL; }
int TRI_StartReplicationApplier (TRI_replication_applier_t* applier, TRI_voc_tick_t initialTick, bool useTick) { LOG_TRACE("requesting replication applier start. initialTick: %llu, useTick: %d", (unsigned long long) initialTick, (int) useTick); if (applier->_vocbase->_type == TRI_VOCBASE_TYPE_COORDINATOR) { return TRI_ERROR_CLUSTER_UNSUPPORTED; } int res = TRI_ERROR_NO_ERROR; // wait until previous applier thread is shut down while (! TRI_WaitReplicationApplier(applier, 10 * 1000)); TRI_WriteLockReadWriteLock(&applier->_statusLock); if (! applier->_state._active) { res = StartApplier(applier, initialTick, useTick); } TRI_WriteUnlockReadWriteLock(&applier->_statusLock); return res; }
void TRI_SetProgressReplicationApplier (TRI_replication_applier_t* applier, char const* msg, bool lock) { char* copy; copy = TRI_DuplicateStringZ(TRI_CORE_MEM_ZONE, msg); if (copy == NULL) { return; } if (lock) { TRI_WriteLockReadWriteLock(&applier->_statusLock); } if (applier->_state._progressMsg != NULL) { TRI_FreeString(TRI_CORE_MEM_ZONE, applier->_state._progressMsg); } applier->_state._progressMsg = copy; // write time in buffer TRI_GetTimeStampReplication(applier->_state._progressTime, sizeof(applier->_state._progressTime) - 1); if (lock) { TRI_WriteUnlockReadWriteLock(&applier->_statusLock); } }
void* TRI_RemoveKeyAssociativeSynced (TRI_associative_synced_t* array, void const* key) { uint64_t hash; uint64_t i; uint64_t k; void* old; hash = array->hashKey(array, key); TRI_WriteLockReadWriteLock(&array->_lock); i = hash % array->_nrAlloc; // search the table while (array->_table[i] != NULL && ! array->isEqualKeyElement(array, key, array->_table[i])) { i = TRI_IncModU64(i, array->_nrAlloc); } // if we did not find such an item return false if (array->_table[i] == NULL) { TRI_WriteUnlockReadWriteLock(&array->_lock); return NULL; } // remove item old = array->_table[i]; array->_table[i] = NULL; array->_nrUsed--; // and now check the following places for items to move here k = TRI_IncModU64(i, array->_nrAlloc); while (array->_table[k] != NULL) { uint64_t j = array->hashElement(array, array->_table[k]) % array->_nrAlloc; if ((i < k && !(i < j && j <= k)) || (k < i && !(i < j || j <= k))) { array->_table[i] = array->_table[k]; array->_table[k] = NULL; i = k; } k = TRI_IncModU64(k, array->_nrAlloc); } // return success TRI_WriteUnlockReadWriteLock(&array->_lock); return old; }
int TRI_SetErrorReplicationApplier (TRI_replication_applier_t* applier, int errorCode, char const* msg) { TRI_WriteLockReadWriteLock(&applier->_statusLock); SetError(applier, errorCode, msg); TRI_WriteUnlockReadWriteLock(&applier->_statusLock); return errorCode; }
void* TRI_InsertKeyAssociativeSynced (TRI_associative_synced_t* array, void const* key, void* element) { uint64_t hash; uint64_t i; union { void const* c; void* v; } old; // compute the hash hash = array->hashKey(array, key); i = hash % array->_nrAlloc; // update statistics array->_nrAdds++; // search the table TRI_WriteLockReadWriteLock(&array->_lock); while (array->_table[i] != NULL && ! array->isEqualKeyElement(array, key, array->_table[i])) { i = (i + 1) % array->_nrAlloc; array->_nrProbesA++; } old.c = array->_table[i]; // if we found an element, return if (old.c != NULL) { TRI_WriteUnlockReadWriteLock(&array->_lock); return old.v; } // add a new element to the associative array array->_table[i] = element; array->_nrUsed++; // if we were adding and the table is more than half full, extend it if (array->_nrAlloc < 2 * array->_nrUsed) { ResizeAssociativeSynced(array); } TRI_WriteUnlockReadWriteLock(&array->_lock); return NULL; }
bool TRI_FlushAuthenticationAuthInfo () { bool res; TRI_ReadLockReadWriteLock(&DefaultAuthInfo->_authInfoLock); res = DefaultAuthInfo->_authInfoFlush; TRI_ReadUnlockReadWriteLock(&DefaultAuthInfo->_authInfoLock); if (res) { TRI_WriteLockReadWriteLock(&DefaultAuthInfo->_authInfoLock); DefaultAuthInfo->_authInfoFlush = false; TRI_WriteUnlockReadWriteLock(&DefaultAuthInfo->_authInfoLock); } return res; }
void TRI_DestroyAuthInfo (TRI_vocbase_t* vocbase) { void** beg; void** end; void** ptr; TRI_WriteLockReadWriteLock(&vocbase->_authInfoLock); beg = vocbase->_authInfo._table; end = vocbase->_authInfo._table + vocbase->_authInfo._nrAlloc; ptr = beg; for (; ptr < end; ++ptr) { if (*ptr) { TRI_vocbase_auth_t* auth = *ptr; FreeAuthInfo(auth); *ptr = NULL; } } vocbase->_authInfo._nrUsed = 0; TRI_WriteUnlockReadWriteLock(&vocbase->_authInfoLock); }
int TRI_StartReplicationApplier (TRI_replication_applier_t* applier, TRI_voc_tick_t initialTick, bool useTick) { int res; res = TRI_ERROR_NO_ERROR; LOG_TRACE("requesting replication applier start. initialTick: %llu, useTick: %d", (unsigned long long) initialTick, (int) useTick); // wait until previous applier thread is shut down while (! TRI_WaitReplicationApplier(applier, 10 * 1000)); TRI_WriteLockReadWriteLock(&applier->_statusLock); if (! applier->_state._active) { res = StartApplier(applier, initialTick, useTick); } TRI_WriteUnlockReadWriteLock(&applier->_statusLock); return res; }
bool TRI_LoadAuthInfo (TRI_vocbase_t* vocbase) { TRI_vocbase_col_t* collection; TRI_primary_collection_t* primary; void** beg; void** end; void** ptr; LOG_DEBUG("starting to load authentication and authorisation information"); collection = TRI_LookupCollectionByNameVocBase(vocbase, "_users"); if (collection == NULL) { LOG_INFO("collection '_users' does not exist, no authentication available"); return false; } TRI_UseCollectionVocBase(vocbase, collection); primary = collection->_collection; if (primary == NULL) { LOG_FATAL_AND_EXIT("collection '_users' cannot be loaded"); } if (! TRI_IS_DOCUMENT_COLLECTION(primary->base._info._type)) { TRI_ReleaseCollectionVocBase(vocbase, collection); LOG_FATAL_AND_EXIT("collection '_users' has an unknown collection type"); } TRI_WriteLockReadWriteLock(&vocbase->_authInfoLock); // ............................................................................. // inside a write transaction // ............................................................................. collection->_collection->beginWrite(collection->_collection); beg = primary->_primaryIndex._table; end = beg + primary->_primaryIndex._nrAlloc; ptr = beg; for (; ptr < end; ++ptr) { if (*ptr) { TRI_doc_mptr_t const* d; TRI_shaped_json_t shapedJson; d = (TRI_doc_mptr_t const*) *ptr; if (d->_validTo == 0) { TRI_vocbase_auth_t* auth; TRI_EXTRACT_SHAPED_JSON_MARKER(shapedJson, d->_data); auth = ConvertAuthInfo(vocbase, primary, &shapedJson); if (auth != NULL) { TRI_vocbase_auth_t* old; old = TRI_InsertKeyAssociativePointer(&vocbase->_authInfo, auth->_username, auth, true); if (old != NULL) { FreeAuthInfo(old); } } } } } collection->_collection->endWrite(collection->_collection); // ............................................................................. // outside a write transaction // ............................................................................. vocbase->_authInfoFlush = true; TRI_WriteUnlockReadWriteLock(&vocbase->_authInfoLock); TRI_ReleaseCollectionVocBase(vocbase, collection); return true; }
static void UnlockCompaction (TRI_vocbase_t* vocbase) { TRI_WriteUnlockReadWriteLock(&vocbase->_compactionBlockers._lock); }
void TRI_CompactorVocBase (void* data) { TRI_vocbase_t* vocbase; TRI_vector_pointer_t collections; vocbase = data; assert(vocbase->_state == 1); TRI_InitVectorPointer(&collections, TRI_UNKNOWN_MEM_ZONE); while (true) { int state; // keep initial _state value as vocbase->_state might change during compaction loop state = vocbase->_state; // check if compaction is currently disallowed if (CheckAndLockCompaction(vocbase)) { // compaction is currently allowed size_t i, n; // copy all collections TRI_READ_LOCK_COLLECTIONS_VOCBASE(vocbase); TRI_CopyDataVectorPointer(&collections, &vocbase->_collections); TRI_READ_UNLOCK_COLLECTIONS_VOCBASE(vocbase); n = collections._length; for (i = 0; i < n; ++i) { TRI_vocbase_col_t* collection; TRI_primary_collection_t* primary; TRI_col_type_e type; bool doCompact; bool worked; collection = collections._buffer[i]; if (! TRI_TRY_READ_LOCK_STATUS_VOCBASE_COL(collection)) { // if we can't acquire the read lock instantly, we continue directly // we don't want to stall here for too long continue; } primary = collection->_collection; if (primary == NULL) { TRI_READ_UNLOCK_STATUS_VOCBASE_COL(collection); continue; } worked = false; doCompact = primary->base._info._doCompact; type = primary->base._info._type; // for document collection, compactify datafiles if (TRI_IS_DOCUMENT_COLLECTION(type)) { if (collection->_status == TRI_VOC_COL_STATUS_LOADED && doCompact) { TRI_barrier_t* ce; // check whether someone else holds a read-lock on the compaction lock if (! TRI_TryWriteLockReadWriteLock(&primary->_compactionLock)) { // someone else is holding the compactor lock, we'll not compact TRI_READ_UNLOCK_STATUS_VOCBASE_COL(collection); continue; } ce = TRI_CreateBarrierCompaction(&primary->_barrierList); if (ce == NULL) { // out of memory LOG_WARNING("out of memory when trying to create a barrier element"); } else { worked = CompactifyDocumentCollection((TRI_document_collection_t*) primary); TRI_FreeBarrier(ce); } // read-unlock the compaction lock TRI_WriteUnlockReadWriteLock(&primary->_compactionLock); } } TRI_READ_UNLOCK_STATUS_VOCBASE_COL(collection); if (worked) { // signal the cleanup thread that we worked and that it can now wake up TRI_LockCondition(&vocbase->_cleanupCondition); TRI_SignalCondition(&vocbase->_cleanupCondition); TRI_UnlockCondition(&vocbase->_cleanupCondition); } } UnlockCompaction(vocbase); } if (state != 2 && vocbase->_state == 1) { // only sleep while server is still running TRI_LockCondition(&vocbase->_compactorCondition); TRI_TimedWaitCondition(&vocbase->_compactorCondition, (uint64_t) COMPACTOR_INTERVAL); TRI_UnlockCondition(&vocbase->_compactorCondition); } if (state == 2) { // server shutdown break; } } TRI_DestroyVectorPointer(&collections); LOG_TRACE("shutting down compactor thread"); }