void TRI_LockMutex (TRI_mutex_t* mutex) { // as of VS2013, exclusive SRWLocks tend to be faster than native mutexes #if TRI_WINDOWS_VISTA_LOCKS DWORD result = WaitForSingleObject(mutex->_mutex, INFINITE); switch (result) { case WAIT_ABANDONED: { LOG_FATAL_AND_EXIT("locks-win32.c:TRI_LockMutex:could not lock the condition --> WAIT_ABANDONED"); } case WAIT_OBJECT_0: { // everything ok break; } case WAIT_TIMEOUT: { LOG_FATAL_AND_EXIT("locks-win32.c:TRI_LockMutex:could not lock the condition --> WAIT_TIMEOUT"); } case WAIT_FAILED: { result = GetLastError(); LOG_FATAL_AND_EXIT("locks-win32.c:TRI_LockMutex:could not lock the condition --> WAIT_FAILED - reason -->%d",result); } } #else AcquireSRWLockExclusive(&mutex->_mutex); #endif }
bool TRI_TimedWaitCondition (TRI_condition_t* cond, uint64_t delay) { int rc; struct timespec ts; struct timeval tp; uint64_t x, y; rc = gettimeofday(&tp, NULL); if (rc != 0) { LOG_FATAL_AND_EXIT("could not get time of day for the condition: %s", strerror(rc)); } // Convert from timeval to timespec ts.tv_sec = tp.tv_sec; x = (tp.tv_usec * 1000) + (delay * 1000); y = (x % 1000000000); ts.tv_nsec = y; ts.tv_sec = ts.tv_sec + ((x - y) / 1000000000); // and wait rc = pthread_cond_timedwait(&cond->_cond, cond->_mutex, &ts); if (rc != 0) { if (rc == ETIMEDOUT) { return false; } LOG_FATAL_AND_EXIT("could not wait for the condition: %s", strerror(rc)); } return true; }
void TRI_WriteUnlockReadWriteLock (TRI_read_write_lock_t* lock) { #if TRI_WINDOWS_VISTA_LOCKS // ........................................................................... // Write lock this _lockReader so no other threads can access this // This will block this thread until it is released by the other thread // We do not need to lock the _lockWriter SINCE the TRI_WriteLockReadWriteLock // function above will lock (due to the ResetEvent(lock->_writerEvent); ) // ........................................................................... EnterCriticalSection(&lock->_lockReaders); // ........................................................................... // In the function TRI_WriteLockReadWriteLock we set the _writerEvent to // 'nonsignalled'. So if a write lock exists clear it by setting it to // 'signalled' // ........................................................................... if (WaitForSingleObject(lock->_writerEvent, 0) != WAIT_OBJECT_0) { SetEvent(lock->_writerEvent); } // ........................................................................... // Oops at least one reader exists - something terrible happened. // ........................................................................... else if (0 < lock->_readers) { LeaveCriticalSection(&lock->_lockReaders); LOG_FATAL_AND_EXIT("read lock, but trying to unlock write"); } // ........................................................................... // Oops we are trying to unlock a write lock, but there isn't one! Something // terrible happend. // ........................................................................... else { LeaveCriticalSection(&lock->_lockReaders); LOG_FATAL_AND_EXIT("no reader and no writer, but trying to unlock"); } // ........................................................................... // Allow read locks to be applied now. // ........................................................................... LeaveCriticalSection(&lock->_lockReaders); #else ReleaseSRWLockExclusive(&lock->_lock); #endif }
void TRI_UnlockMutex (TRI_mutex_t* mutex) { BOOL ok = ReleaseMutex(mutex->_mutex); if (! ok) { LOG_FATAL_AND_EXIT("could not unlock the mutex"); } }
void TRI_ReadLockReadWriteLock (TRI_read_write_lock_t* lock) { int rc; bool complained = false; again: rc = pthread_rwlock_rdlock(lock); if (rc != 0) { if (rc == EAGAIN) { // use busy waiting if we cannot acquire the read-lock in case of too many // concurrent read locks ("resource temporarily unavailable"). // in this case we'll wait in a busy loop until we can acquire the lock if (! complained) { LOG_WARNING("too many read-locks on read-write lock"); complained = true; } usleep(BUSY_LOCK_DELAY); #ifdef TRI_HAVE_SCHED_H // let other threads do things sched_yield(); #endif // ideal use case for goto :-) goto again; } if (rc == EDEADLK) { LOG_ERROR("rw-lock deadlock detected"); } LOG_FATAL_AND_EXIT("could not read-lock the read-write lock: %s", strerror(rc)); } }
void TRI_UnlockCondition (TRI_condition_t* cond) { int rc; rc = pthread_mutex_unlock(cond->_mutex); if (rc != 0) { LOG_FATAL_AND_EXIT("could not unlock the condition: %s", strerror(rc)); } }
int TRI_InitMutex (TRI_mutex_t* mutex) { mutex->_mutex = CreateMutex(NULL, FALSE, NULL); if (mutex->_mutex == NULL) { LOG_FATAL_AND_EXIT("cannot create the mutex"); } return TRI_ERROR_NO_ERROR; }
void TRI_WaitCondition (TRI_condition_t* cond) { int rc; rc = pthread_cond_wait(&cond->_cond, cond->_mutex); if (rc != 0) { LOG_FATAL_AND_EXIT("could not wait for the condition: %s", strerror(rc)); } }
void TRI_BroadcastCondition (TRI_condition_t* cond) { int rc; rc = pthread_cond_broadcast(&cond->_cond); if (rc != 0) { LOG_FATAL_AND_EXIT("could not croadcast the condition: %s", strerror(rc)); } }
void TRI_SignalCondition (TRI_condition_t* cond) { int rc; rc = pthread_cond_signal(&cond->_cond); if (rc != 0) { LOG_FATAL_AND_EXIT("could not signal the condition: %s", strerror(rc)); } }
int TRI_DestroyMutex (TRI_mutex_t* mutex) { if (CloseHandle(mutex->_mutex) == 0) { DWORD result = GetLastError(); LOG_FATAL_AND_EXIT("locks-win32.c:TRI_DestroyMutex:could not destroy the mutex -->%d",result); } return TRI_ERROR_NO_ERROR; }
void TRI_WriteUnlockReadWriteLock (TRI_read_write_lock_t* lock) { int rc; rc = pthread_rwlock_unlock(lock); if (rc != 0) { LOG_FATAL_AND_EXIT("could not read-unlock the read-write lock: %s", strerror(rc)); } }
void TRI_UnlockMutex (TRI_mutex_t* mutex) { int rc; rc = pthread_mutex_unlock(mutex); if (rc != 0) { LOG_FATAL_AND_EXIT("could not release the mutex: %s", strerror(rc)); } }
void TRI_UnlockSpin (TRI_spin_t* spinLock) { int rc; rc = pthread_spin_unlock(spinLock); if (rc != 0) { LOG_FATAL_AND_EXIT("could not release the spin-lock: %s", strerror(rc)); } }
void fillBuffer () { DWORD n = sizeof(buffer); BYTE* ptr = reinterpret_cast<BYTE*>(&buffer); // fill the buffer with random characters int result = CryptGenRandom(cryptoHandle, n, ptr); if (result == 0) { LOG_FATAL_AND_EXIT("read on random device failed: nothing read"); } pos = 0; }
void fillBuffer () { size_t n = sizeof(buffer); char* ptr = reinterpret_cast<char*>(&buffer); while (0 < n) { ssize_t r = TRI_READ(fd, ptr, (TRI_read_t) n); if (r == 0) { LOG_FATAL_AND_EXIT("read on random device failed: nothing read"); } else if (r < 0) { LOG_FATAL_AND_EXIT("read on random device failed: %s", strerror(errno)); } ptr += r; n -= r; } pos = 0; }
void TRI_InitCondition (TRI_condition_t* cond) { pthread_cond_init(&cond->_cond, 0); cond->_ownMutex = true; cond->_mutex = TRI_Allocate(TRI_CORE_MEM_ZONE, sizeof(pthread_mutex_t), false); if (cond->_mutex == NULL) { LOG_FATAL_AND_EXIT("could not allocate memory for condition variable mutex"); } pthread_mutex_init(cond->_mutex, 0); }
int TRI_DestroyMutex (TRI_mutex_t* mutex) { // as of VS2013, exclusive SRWLocks tend to be faster than native mutexes #if TRI_WINDOWS_VISTA_LOCKS if (CloseHandle(mutex->_mutex) == 0) { DWORD result = GetLastError(); LOG_FATAL_AND_EXIT("locks-win32.c:TRI_DestroyMutex:could not destroy the mutex -->%d",result); } #else #endif return TRI_ERROR_NO_ERROR; }
void TRI_UnlockMutex (TRI_mutex_t* mutex) { // as of VS2013, exclusive SRWLocks tend to be faster than native mutexes #if TRI_WINDOWS_VISTA_LOCKS BOOL ok = ReleaseMutex(mutex->_mutex); if (! ok) { LOG_FATAL_AND_EXIT("could not unlock the mutex"); } #else ReleaseSRWLockExclusive(&mutex->_mutex); #endif }
void TRI_WriteLockReadWriteLock (TRI_read_write_lock_t* lock) { int rc; rc = pthread_rwlock_wrlock(lock); if (rc != 0) { if (rc == EDEADLK) { LOG_ERROR("rw-lock deadlock detected"); } LOG_FATAL_AND_EXIT("could not write-lock the read-write lock: %s", strerror(rc)); } }
void TRI_LockSpin (TRI_spin_t* spinLock) { int rc; rc = pthread_spin_lock(spinLock); if (rc != 0) { if (rc == EDEADLK) { LOG_ERROR("spinlock deadlock detected"); } LOG_FATAL_AND_EXIT("could not lock the spin-lock: %s", strerror(rc)); } }
int TRI_InitMutex (TRI_mutex_t* mutex) { // as of VS2013, exclusive SRWLocks tend to be faster than native mutexes #if TRI_WINDOWS_VISTA_LOCKS mutex->_mutex = CreateMutex(nullptr, FALSE, nullptr); if (mutex->_mutex == nullptr) { LOG_FATAL_AND_EXIT("cannot create the mutex"); } #else InitializeSRWLock(&mutex->_mutex); #endif return TRI_ERROR_NO_ERROR; }
void fillBuffer () { size_t n = sizeof(buffer); char* ptr = reinterpret_cast<char*>(&buffer); while (0 < n) { ssize_t r = TRI_READ(fd, ptr, (TRI_read_t) n); if (r == 0) { LOG_FATAL_AND_EXIT("read on random device failed: nothing read"); } else if (errno == EWOULDBLOCK) { LOG_INFO("not enough entropy (got %d), switching to pseudo-random", (int) (sizeof(buffer) - n)); break; } else if (r < 0) { LOG_FATAL_AND_EXIT("read on random device failed: %s", strerror(errno)); } ptr += r; n -= r; rseed = buffer[0]; LOG_TRACE("using seed %lu", (long unsigned int) rseed); } if (0 < n) { std::mt19937 engine; unsigned long seed = RandomDevice::getSeed(); engine.seed((uint32_t) (rseed ^ (uint32_t) seed)); while (0 < n) { *ptr++ = engine(); --n; } } pos = 0; }
void TRI_LockMutex (TRI_mutex_t* mutex) { int rc; rc = pthread_mutex_lock(mutex); if (rc != 0) { if (rc == EDEADLK) { LOG_ERROR("mutex deadlock detected"); } LOG_FATAL_AND_EXIT("could not lock the mutex: %s", strerror(rc)); } }
void TRI_usleep (unsigned long waitTime) { int result; HANDLE hTimer = NULL; // stores the handle of the timer object LARGE_INTEGER wTime; // essentially a 64bit number wTime.QuadPart = waitTime * 10; // *10 to change to microseconds wTime.QuadPart = -wTime.QuadPart; // negative indicates relative time elapsed, // Create an unnamed waitable timer. hTimer = CreateWaitableTimer(NULL, 1, NULL); if (hTimer == NULL) { // not much we can do at this low level return; } if (GetLastError() == ERROR_ALREADY_EXISTS) { LOG_FATAL_AND_EXIT("internal error in TRI_usleep()"); } // Set timer to wait for indicated micro seconds. if (! SetWaitableTimer(hTimer, &wTime, 0, NULL, NULL, 0)) { // not much we can do at this low level CloseHandle(hTimer); return; } // Wait for the timer result = WaitForSingleObject(hTimer, INFINITE); if (result != WAIT_OBJECT_0) { CloseHandle(hTimer); LOG_FATAL_AND_EXIT("couldn't wait for timer in TRI_usleep()"); } CloseHandle(hTimer); // todo: go through what the result is e.g. WAIT_OBJECT_0 return; }
void TRI_LockMutex (TRI_mutex_t* mutex) { DWORD result = WaitForSingleObject(mutex->_mutex, INFINITE); switch (result) { case WAIT_ABANDONED: { LOG_FATAL_AND_EXIT("locks-win32.c:TRI_LockMutex:could not lock the condition --> WAIT_ABANDONED"); } case WAIT_OBJECT_0: { // everything ok break; } case WAIT_TIMEOUT: { LOG_FATAL_AND_EXIT("locks-win32.c:TRI_LockMutex:could not lock the condition --> WAIT_TIMEOUT"); } case WAIT_FAILED: { result = GetLastError(); LOG_FATAL_AND_EXIT("locks-win32.c:TRI_LockMutex:could not lock the condition --> WAIT_FAILED - reason -->%d",result); } } }
static void DecrementReaders (TRI_read_write_lock_t* lock) { // ........................................................................... // reduce the number of readers using the read_write lock by 1 // ........................................................................... lock->_readers--; // ........................................................................... // When the number of readers is 0, set the event to signalled which allows // a writer to use the read_write lock. // ........................................................................... if (lock->_readers == 0) { SetEvent(lock->_readersEvent); } else if (lock->_readers < 0) { LOG_FATAL_AND_EXIT("reader count is negative"); } }
void TRI_ReadUnlockReadWriteLock (TRI_read_write_lock_t* lock) { #if TRI_WINDOWS_VISTA_LOCKS EnterCriticalSection(&lock->_lockReaders); /* this is wrong since it is possible for the write locker to block this event // a write lock eists if (WaitForSingleObject(lock->_writerEvent, 0) != WAIT_OBJECT_0) { LOG_FATAL_AND_EXIT("write lock, but trying to unlock read"); } // at least one reader exists else if (0 < lock->_readers) { DecrementReaders(lock); } // ups, no writer and no reader else { LeaveCriticalSection(&lock->_lockReaders); LOG_FATAL_AND_EXIT("no reader and no writer, but trying to unlock"); } -*/ if (0 < lock->_readers) { DecrementReaders(lock); } // oops no reader else { LeaveCriticalSection(&lock->_lockReaders); LOG_FATAL_AND_EXIT("no reader, but trying to unlock read lock"); } LeaveCriticalSection(&lock->_lockReaders); #else ReleaseSRWLockShared(&lock->_lock); #endif }
static bool Compactifier (TRI_df_marker_t const* marker, void* data, TRI_datafile_t* datafile, bool journal) { TRI_df_marker_t* result; TRI_doc_mptr_t const* found; TRI_document_collection_t* document; TRI_primary_collection_t* primary; compaction_context_t* context; int res; context = data; document = context->_document; primary = &document->base; // new or updated document if (marker->_type == TRI_DOC_MARKER_KEY_DOCUMENT || marker->_type == TRI_DOC_MARKER_KEY_EDGE) { TRI_doc_document_key_marker_t const* d; TRI_doc_mptr_t* found2; TRI_voc_key_t key; bool deleted; d = (TRI_doc_document_key_marker_t const*) marker; key = (char*) d + d->_offsetKey; // check if the document is still active TRI_READ_LOCK_DOCUMENTS_INDEXES_PRIMARY_COLLECTION(primary); found = TRI_LookupByKeyAssociativePointer(&primary->_primaryIndex, key); deleted = (found == NULL || found->_rid > d->_rid); TRI_READ_UNLOCK_DOCUMENTS_INDEXES_PRIMARY_COLLECTION(primary); if (deleted) { LOG_TRACE("found a stale document: %s", key); return true; } context->_keepDeletions = true; // write to compactor files res = CopyMarker(document, context->_compactor, marker, &result); if (res != TRI_ERROR_NO_ERROR) { LOG_FATAL_AND_EXIT("cannot write compactor file: %s", TRI_last_error()); } // check if the document is still active TRI_WRITE_LOCK_DOCUMENTS_INDEXES_PRIMARY_COLLECTION(primary); found = TRI_LookupByKeyAssociativePointer(&primary->_primaryIndex, key); deleted = found == NULL; if (deleted) { context->_dfi._numberDead += 1; context->_dfi._sizeDead += (int64_t) marker->_size; TRI_WRITE_UNLOCK_DOCUMENTS_INDEXES_PRIMARY_COLLECTION(primary); LOG_DEBUG("found a stale document after copying: %s", key); return true; } found2 = CONST_CAST(found); assert(found2->_data != NULL); assert(((TRI_df_marker_t*) found2->_data)->_size > 0); // the fid might change if (found->_fid != context->_compactor->_fid) { // update old datafile's info TRI_doc_datafile_info_t* dfi = TRI_FindDatafileInfoPrimaryCollection(primary, found->_fid, false); if (dfi != NULL) { dfi->_numberDead += 1; dfi->_sizeDead += (int64_t) marker->_size; } found2->_fid = context->_compactor->_fid; } // let marker point to the new position found2->_data = result; // let _key point to the new key position found2->_key = ((char*) result) + (((TRI_doc_document_key_marker_t*) result)->_offsetKey); // update datafile info context->_dfi._numberAlive += 1; context->_dfi._sizeAlive += (int64_t) marker->_size; TRI_WRITE_UNLOCK_DOCUMENTS_INDEXES_PRIMARY_COLLECTION(primary); } // deletion else if (marker->_type == TRI_DOC_MARKER_KEY_DELETION && context->_keepDeletions) { // write to compactor files res = CopyMarker(document, context->_compactor, marker, &result); if (res != TRI_ERROR_NO_ERROR) { LOG_FATAL_AND_EXIT("cannot write compactor file: %s", TRI_last_error()); } // update datafile info context->_dfi._numberDeletion++; } else if (marker->_type == TRI_DOC_MARKER_BEGIN_TRANSACTION || marker->_type == TRI_DOC_MARKER_COMMIT_TRANSACTION || marker->_type == TRI_DOC_MARKER_ABORT_TRANSACTION || marker->_type == TRI_DOC_MARKER_PREPARE_TRANSACTION) { // write to compactor files res = CopyMarker(document, context->_compactor, marker, &result); if (res != TRI_ERROR_NO_ERROR) { LOG_FATAL_AND_EXIT("cannot write compactor file: %s", TRI_last_error()); } context->_dfi._numberTransaction++; context->_dfi._sizeTransaction += (int64_t) marker->_size; } return true; }
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; }