mirror of https://gitee.com/bigwinds/arangodb
issue #662: ArangoDB on Windows hanging
This commit is contained in:
parent
87aed55acf
commit
af6da9a652
22
CHANGELOG
22
CHANGELOG
|
@ -67,6 +67,28 @@ v1.5.x (XXXX-XX-XX)
|
||||||
v1.4.2 (XXXX-XX-XX)
|
v1.4.2 (XXXX-XX-XX)
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
|
* ported Windows version to use native Windows API SRWLocks (slim read-write locks)
|
||||||
|
and condition variables instead of homemade versions
|
||||||
|
|
||||||
|
MSDN states the following about the compatibility of SRWLocks and Condition Variables:
|
||||||
|
|
||||||
|
Minimum supported client:
|
||||||
|
Windows Server 2008 [desktop apps | Windows Store apps]
|
||||||
|
|
||||||
|
Minimum supported server:
|
||||||
|
Windows Vista [desktop apps | Windows Store apps]
|
||||||
|
|
||||||
|
* fixed issue #662: ArangoDB on Windows hanging
|
||||||
|
|
||||||
|
This fixes a deadlock issue that occurred on Windows when documents were written to
|
||||||
|
a collection at the same time when some other thread tried to drop the collection.
|
||||||
|
|
||||||
|
* fixed file-based logging in Windows
|
||||||
|
|
||||||
|
the logger complained on startup if the specified log file already existed
|
||||||
|
|
||||||
|
* fixed startup of server in daemon mode (`--daemon` startup option)
|
||||||
|
|
||||||
* fixed a segfault in the AQL optimiser
|
* fixed a segfault in the AQL optimiser
|
||||||
|
|
||||||
* issue #671: Method graph.measurement does not exist
|
* issue #671: Method graph.measurement does not exist
|
||||||
|
|
|
@ -213,8 +213,12 @@ static bool UnregisterCollection (TRI_vocbase_t* vocbase,
|
||||||
|
|
||||||
TRI_WRITE_LOCK_COLLECTIONS_VOCBASE(vocbase);
|
TRI_WRITE_LOCK_COLLECTIONS_VOCBASE(vocbase);
|
||||||
|
|
||||||
TRI_RemoveKeyAssociativePointer(&vocbase->_collectionsByName, collection->_name);
|
// only if we find the collection by its id, we can delete it by name
|
||||||
TRI_RemoveKeyAssociativePointer(&vocbase->_collectionsById, &collection->_cid);
|
if (TRI_RemoveKeyAssociativePointer(&vocbase->_collectionsById, &collection->_cid) != NULL) {
|
||||||
|
// this is because someone else might have created a new collection with the same name,
|
||||||
|
// but with a different id
|
||||||
|
TRI_RemoveKeyAssociativePointer(&vocbase->_collectionsByName, collection->_name);
|
||||||
|
}
|
||||||
|
|
||||||
TRI_ASSERT_MAINTAINER(vocbase->_collectionsByName._nrUsed == vocbase->_collectionsById._nrUsed);
|
TRI_ASSERT_MAINTAINER(vocbase->_collectionsByName._nrUsed == vocbase->_collectionsById._nrUsed);
|
||||||
|
|
||||||
|
@ -237,9 +241,9 @@ static bool UnloadCollectionCallback (TRI_collection_t* col, void* data) {
|
||||||
TRI_document_collection_t* document;
|
TRI_document_collection_t* document;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
collection = data;
|
collection = (TRI_vocbase_col_t*) data;
|
||||||
|
|
||||||
TRI_WRITE_LOCK_STATUS_VOCBASE_COL(collection);
|
TRI_EVENTUAL_WRITE_LOCK_STATUS_VOCBASE_COL(collection);
|
||||||
|
|
||||||
if (collection->_status != TRI_VOC_COL_STATUS_UNLOADING) {
|
if (collection->_status != TRI_VOC_COL_STATUS_UNLOADING) {
|
||||||
TRI_WRITE_UNLOCK_STATUS_VOCBASE_COL(collection);
|
TRI_WRITE_UNLOCK_STATUS_VOCBASE_COL(collection);
|
||||||
|
@ -328,7 +332,7 @@ static bool DropCollectionCallback (TRI_collection_t* col,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TRI_WRITE_LOCK_STATUS_VOCBASE_COL(collection);
|
TRI_EVENTUAL_WRITE_LOCK_STATUS_VOCBASE_COL(collection);
|
||||||
|
|
||||||
if (collection->_status != TRI_VOC_COL_STATUS_DELETED) {
|
if (collection->_status != TRI_VOC_COL_STATUS_DELETED) {
|
||||||
LOG_ERROR("someone resurrected the collection '%s'", collection->_name);
|
LOG_ERROR("someone resurrected the collection '%s'", collection->_name);
|
||||||
|
@ -559,7 +563,7 @@ static TRI_vocbase_col_t* AddCollection (TRI_vocbase_t* vocbase,
|
||||||
|
|
||||||
// check name
|
// check name
|
||||||
res = TRI_InsertKeyAssociativePointer2(&vocbase->_collectionsByName, name, collection, &found);
|
res = TRI_InsertKeyAssociativePointer2(&vocbase->_collectionsByName, name, collection, &found);
|
||||||
|
|
||||||
if (found != NULL) {
|
if (found != NULL) {
|
||||||
LOG_ERROR("duplicate entry for collection name '%s'", name);
|
LOG_ERROR("duplicate entry for collection name '%s'", name);
|
||||||
LOG_ERROR("collection id %llu has same name as already added collection %llu",
|
LOG_ERROR("collection id %llu has same name as already added collection %llu",
|
||||||
|
@ -582,8 +586,9 @@ static TRI_vocbase_col_t* AddCollection (TRI_vocbase_t* vocbase,
|
||||||
}
|
}
|
||||||
|
|
||||||
// check collection identifier
|
// check collection identifier
|
||||||
|
assert(collection->_cid == cid);
|
||||||
res = TRI_InsertKeyAssociativePointer2(&vocbase->_collectionsById, &cid, collection, &found);
|
res = TRI_InsertKeyAssociativePointer2(&vocbase->_collectionsById, &cid, collection, &found);
|
||||||
|
|
||||||
if (found != NULL) {
|
if (found != NULL) {
|
||||||
TRI_RemoveKeyAssociativePointer(&vocbase->_collectionsByName, name);
|
TRI_RemoveKeyAssociativePointer(&vocbase->_collectionsByName, name);
|
||||||
|
|
||||||
|
@ -601,7 +606,6 @@ static TRI_vocbase_col_t* AddCollection (TRI_vocbase_t* vocbase,
|
||||||
TRI_RemoveKeyAssociativePointer(&vocbase->_collectionsById, &cid);
|
TRI_RemoveKeyAssociativePointer(&vocbase->_collectionsById, &cid);
|
||||||
TRI_RemoveKeyAssociativePointer(&vocbase->_collectionsByName, name);
|
TRI_RemoveKeyAssociativePointer(&vocbase->_collectionsByName, name);
|
||||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, collection);
|
TRI_Free(TRI_UNKNOWN_MEM_ZONE, collection);
|
||||||
|
|
||||||
TRI_set_errno(res);
|
TRI_set_errno(res);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -720,8 +724,7 @@ static int RenameCollection (TRI_vocbase_t* vocbase,
|
||||||
void const* found;
|
void const* found;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
// lock collection because we are going to change the name
|
TRI_EVENTUAL_WRITE_LOCK_STATUS_VOCBASE_COL(collection);
|
||||||
TRI_WRITE_LOCK_STATUS_VOCBASE_COL(collection);
|
|
||||||
|
|
||||||
// this must be done after the collection lock
|
// this must be done after the collection lock
|
||||||
TRI_WRITE_LOCK_COLLECTIONS_VOCBASE(vocbase);
|
TRI_WRITE_LOCK_COLLECTIONS_VOCBASE(vocbase);
|
||||||
|
@ -815,7 +818,7 @@ static int RenameCollection (TRI_vocbase_t* vocbase,
|
||||||
|
|
||||||
TRI_RemoveKeyAssociativePointer(&vocbase->_collectionsByName, oldName);
|
TRI_RemoveKeyAssociativePointer(&vocbase->_collectionsByName, oldName);
|
||||||
TRI_CopyString(collection->_name, newName, sizeof(collection->_name) - 1);
|
TRI_CopyString(collection->_name, newName, sizeof(collection->_name) - 1);
|
||||||
|
|
||||||
// this shouldn't fail, as we removed an element above so adding one should be ok
|
// this shouldn't fail, as we removed an element above so adding one should be ok
|
||||||
found = TRI_InsertKeyAssociativePointer(&vocbase->_collectionsByName, newName, CONST_CAST(collection), false);
|
found = TRI_InsertKeyAssociativePointer(&vocbase->_collectionsByName, newName, CONST_CAST(collection), false);
|
||||||
assert(found == NULL);
|
assert(found == NULL);
|
||||||
|
@ -1090,7 +1093,7 @@ static int LoadCollectionVocBase (TRI_vocbase_t* vocbase,
|
||||||
// write lock
|
// write lock
|
||||||
// .............................................................................
|
// .............................................................................
|
||||||
|
|
||||||
TRI_WRITE_LOCK_STATUS_VOCBASE_COL(collection);
|
TRI_EVENTUAL_WRITE_LOCK_STATUS_VOCBASE_COL(collection);
|
||||||
|
|
||||||
// someone else loaded the collection, release the WRITE lock and try again
|
// someone else loaded the collection, release the WRITE lock and try again
|
||||||
if (collection->_status == TRI_VOC_COL_STATUS_LOADED) {
|
if (collection->_status == TRI_VOC_COL_STATUS_LOADED) {
|
||||||
|
@ -1980,7 +1983,7 @@ int TRI_UnloadCollectionVocBase (TRI_vocbase_t* vocbase,
|
||||||
return TRI_set_errno(TRI_ERROR_FORBIDDEN);
|
return TRI_set_errno(TRI_ERROR_FORBIDDEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
TRI_WRITE_LOCK_STATUS_VOCBASE_COL(collection);
|
TRI_EVENTUAL_WRITE_LOCK_STATUS_VOCBASE_COL(collection);
|
||||||
|
|
||||||
// cannot unload a corrupted collection
|
// cannot unload a corrupted collection
|
||||||
if (collection->_status == TRI_VOC_COL_STATUS_CORRUPTED) {
|
if (collection->_status == TRI_VOC_COL_STATUS_CORRUPTED) {
|
||||||
|
@ -2065,14 +2068,14 @@ int TRI_DropCollectionVocBase (TRI_vocbase_t* vocbase,
|
||||||
|
|
||||||
TRI_ReadLockReadWriteLock(&vocbase->_inventoryLock);
|
TRI_ReadLockReadWriteLock(&vocbase->_inventoryLock);
|
||||||
|
|
||||||
// mark collection as deleted
|
TRI_EVENTUAL_WRITE_LOCK_STATUS_VOCBASE_COL(collection);
|
||||||
TRI_WRITE_LOCK_STATUS_VOCBASE_COL(collection);
|
|
||||||
|
|
||||||
// .............................................................................
|
// .............................................................................
|
||||||
// collection already deleted
|
// collection already deleted
|
||||||
// .............................................................................
|
// .............................................................................
|
||||||
|
|
||||||
if (collection->_status == TRI_VOC_COL_STATUS_DELETED) {
|
if (collection->_status == TRI_VOC_COL_STATUS_DELETED) {
|
||||||
|
// mark collection as deleted
|
||||||
UnregisterCollection(vocbase, collection, generatingServer);
|
UnregisterCollection(vocbase, collection, generatingServer);
|
||||||
|
|
||||||
TRI_WRITE_UNLOCK_STATUS_VOCBASE_COL(collection);
|
TRI_WRITE_UNLOCK_STATUS_VOCBASE_COL(collection);
|
||||||
|
@ -2101,7 +2104,7 @@ int TRI_DropCollectionVocBase (TRI_vocbase_t* vocbase,
|
||||||
|
|
||||||
// remove dangling .json.tmp file if it exists
|
// remove dangling .json.tmp file if it exists
|
||||||
tmpFile = TRI_Concatenate4String(collection->_path, TRI_DIR_SEPARATOR_STR, TRI_VOC_PARAMETER_FILE, ".tmp");
|
tmpFile = TRI_Concatenate4String(collection->_path, TRI_DIR_SEPARATOR_STR, TRI_VOC_PARAMETER_FILE, ".tmp");
|
||||||
|
|
||||||
if (tmpFile != NULL) {
|
if (tmpFile != NULL) {
|
||||||
if (TRI_ExistsFile(tmpFile)) {
|
if (TRI_ExistsFile(tmpFile)) {
|
||||||
TRI_UnlinkFile(tmpFile);
|
TRI_UnlinkFile(tmpFile);
|
||||||
|
@ -2125,7 +2128,6 @@ int TRI_DropCollectionVocBase (TRI_vocbase_t* vocbase,
|
||||||
}
|
}
|
||||||
|
|
||||||
collection->_status = TRI_VOC_COL_STATUS_DELETED;
|
collection->_status = TRI_VOC_COL_STATUS_DELETED;
|
||||||
|
|
||||||
UnregisterCollection(vocbase, collection, generatingServer);
|
UnregisterCollection(vocbase, collection, generatingServer);
|
||||||
|
|
||||||
TRI_WRITE_UNLOCK_STATUS_VOCBASE_COL(collection);
|
TRI_WRITE_UNLOCK_STATUS_VOCBASE_COL(collection);
|
||||||
|
@ -2180,6 +2182,7 @@ int TRI_DropCollectionVocBase (TRI_vocbase_t* vocbase,
|
||||||
}
|
}
|
||||||
|
|
||||||
collection->_status = TRI_VOC_COL_STATUS_DELETED;
|
collection->_status = TRI_VOC_COL_STATUS_DELETED;
|
||||||
|
|
||||||
UnregisterCollection(vocbase, collection, generatingServer);
|
UnregisterCollection(vocbase, collection, generatingServer);
|
||||||
|
|
||||||
TRI_WRITE_UNLOCK_STATUS_VOCBASE_COL(collection);
|
TRI_WRITE_UNLOCK_STATUS_VOCBASE_COL(collection);
|
||||||
|
|
|
@ -114,6 +114,13 @@ struct TRI_vocbase_defaults_s;
|
||||||
#define TRI_READ_UNLOCK_STATUS_VOCBASE_COL(a) \
|
#define TRI_READ_UNLOCK_STATUS_VOCBASE_COL(a) \
|
||||||
TRI_ReadUnlockReadWriteLock(&(a)->_lock)
|
TRI_ReadUnlockReadWriteLock(&(a)->_lock)
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief tries to write lock the vocbase collection status
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#define TRI_TRY_WRITE_LOCK_STATUS_VOCBASE_COL(a) \
|
||||||
|
TRI_TryWriteLockReadWriteLock(&(a)->_lock)
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief write locks the vocbase collection status
|
/// @brief write locks the vocbase collection status
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -128,6 +135,15 @@ struct TRI_vocbase_defaults_s;
|
||||||
#define TRI_WRITE_UNLOCK_STATUS_VOCBASE_COL(a) \
|
#define TRI_WRITE_UNLOCK_STATUS_VOCBASE_COL(a) \
|
||||||
TRI_WriteUnlockReadWriteLock(&(a)->_lock)
|
TRI_WriteUnlockReadWriteLock(&(a)->_lock)
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief write locks the vocbase collection status using spinning
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#define TRI_EVENTUAL_WRITE_LOCK_STATUS_VOCBASE_COL(a) \
|
||||||
|
while (! TRI_TRY_WRITE_LOCK_STATUS_VOCBASE_COL(a)) { \
|
||||||
|
usleep(1000); \
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief locks the synchroniser waiters
|
/// @brief locks the synchroniser waiters
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -208,43 +208,7 @@ void TRI_UnlockSpin (TRI_spin_t* spin) {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void TRI_InitReadWriteLock (TRI_read_write_lock_t* lock) {
|
void TRI_InitReadWriteLock (TRI_read_write_lock_t* lock) {
|
||||||
|
InitializeSRWLock(&lock->_lock);
|
||||||
// ...........................................................................
|
|
||||||
// set the number of readers reading on the read_write lock to 0
|
|
||||||
// ...........................................................................
|
|
||||||
|
|
||||||
lock->_readers = 0;
|
|
||||||
|
|
||||||
|
|
||||||
// ...........................................................................
|
|
||||||
// Signaled: writer has no access
|
|
||||||
// Non-Signaled: writer has access, block readers
|
|
||||||
// Creates an event which allows a thread to wait on it (perhaps should use
|
|
||||||
// a mutux rather than an event here). The writer event is set to signalled
|
|
||||||
// when CreateEvent is called with these parameters.
|
|
||||||
// ...........................................................................
|
|
||||||
|
|
||||||
lock->_writerEvent = CreateEvent(0, TRUE, TRUE, 0);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ...........................................................................
|
|
||||||
// Signaled: no readers
|
|
||||||
// Non-Signaled: some readers have access, block writer
|
|
||||||
// Same as the writer event above except this is the reader event
|
|
||||||
// ...........................................................................
|
|
||||||
|
|
||||||
lock->_readersEvent = CreateEvent(0, TRUE, TRUE, 0);
|
|
||||||
|
|
||||||
|
|
||||||
// ...........................................................................
|
|
||||||
// Creates critical sections for writer and readers.
|
|
||||||
// Waits for ownership of the specified critical section object.
|
|
||||||
// The function returns when the calling thread is granted ownership.
|
|
||||||
// ...........................................................................
|
|
||||||
|
|
||||||
InitializeCriticalSection(&lock->_lockWriter);
|
|
||||||
InitializeCriticalSection(&lock->_lockReaders);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -252,11 +216,6 @@ void TRI_InitReadWriteLock (TRI_read_write_lock_t* lock) {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void TRI_DestroyReadWriteLock (TRI_read_write_lock_t* lock) {
|
void TRI_DestroyReadWriteLock (TRI_read_write_lock_t* lock) {
|
||||||
DeleteCriticalSection(&lock->_lockWriter);
|
|
||||||
DeleteCriticalSection(&lock->_lockReaders);
|
|
||||||
|
|
||||||
CloseHandle(lock->_writerEvent);
|
|
||||||
CloseHandle(lock->_readersEvent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -272,56 +231,6 @@ void TRI_DestroyReadWriteLock (TRI_read_write_lock_t* lock) {
|
||||||
/// @{
|
/// @{
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief increments readers
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
static void IncrementReaders (TRI_read_write_lock_t* lock) {
|
|
||||||
|
|
||||||
// ...........................................................................
|
|
||||||
// increment the number of readers we have on the read_write lock
|
|
||||||
// ...........................................................................
|
|
||||||
|
|
||||||
lock->_readers++;
|
|
||||||
|
|
||||||
|
|
||||||
// ...........................................................................
|
|
||||||
// Since the number of readers must be positive, set the readers event to
|
|
||||||
// non-signalled so that any write event will have to wait.
|
|
||||||
// ...........................................................................
|
|
||||||
ResetEvent(lock->_readersEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief decrements readers
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @}
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- public functions
|
// --SECTION-- public functions
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
@ -336,20 +245,7 @@ static void DecrementReaders (TRI_read_write_lock_t* lock) {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
bool TRI_TryReadLockReadWriteLock (TRI_read_write_lock_t* lock) {
|
bool TRI_TryReadLockReadWriteLock (TRI_read_write_lock_t* lock) {
|
||||||
WaitForSingleObject(lock->_writerEvent, 10); // 10 millis timeout
|
return (TryAcquireSRWLockShared(&lock->_lock) != 0);
|
||||||
|
|
||||||
EnterCriticalSection(&lock->_lockReaders);
|
|
||||||
IncrementReaders(lock);
|
|
||||||
LeaveCriticalSection(&lock->_lockReaders);
|
|
||||||
|
|
||||||
if (WaitForSingleObject(lock->_writerEvent, 0) != WAIT_OBJECT_0) {
|
|
||||||
EnterCriticalSection(&lock->_lockReaders);
|
|
||||||
DecrementReaders(lock);
|
|
||||||
LeaveCriticalSection(&lock->_lockReaders);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -357,43 +253,7 @@ bool TRI_TryReadLockReadWriteLock (TRI_read_write_lock_t* lock) {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void TRI_ReadLockReadWriteLock (TRI_read_write_lock_t* lock) {
|
void TRI_ReadLockReadWriteLock (TRI_read_write_lock_t* lock) {
|
||||||
|
AcquireSRWLockShared(&lock->_lock);
|
||||||
while (true) {
|
|
||||||
|
|
||||||
// ........................................................................
|
|
||||||
// Waits for a writer to finish if there is one. This function only
|
|
||||||
// returns when the writer event is in a signalled state
|
|
||||||
// ........................................................................
|
|
||||||
|
|
||||||
WaitForSingleObject(lock->_writerEvent, INFINITE);
|
|
||||||
|
|
||||||
|
|
||||||
// .........................................................................
|
|
||||||
// This thread will wait here until this resource becomes excusively available
|
|
||||||
// .........................................................................
|
|
||||||
|
|
||||||
EnterCriticalSection(&lock->_lockReaders);
|
|
||||||
IncrementReaders(lock);
|
|
||||||
|
|
||||||
// .........................................................................
|
|
||||||
// allows some other thread to use this resource
|
|
||||||
// .........................................................................
|
|
||||||
|
|
||||||
LeaveCriticalSection(&lock->_lockReaders);
|
|
||||||
|
|
||||||
|
|
||||||
// it could have happened that the writer event is no longer in a signalled
|
|
||||||
// state. Between leaving the crtical section and here a writer sneaked in.
|
|
||||||
//
|
|
||||||
if (WaitForSingleObject(lock->_writerEvent, 0) != WAIT_OBJECT_0) {
|
|
||||||
EnterCriticalSection(&lock->_lockReaders);
|
|
||||||
DecrementReaders(lock);
|
|
||||||
LeaveCriticalSection(&lock->_lockReaders);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -401,98 +261,15 @@ void TRI_ReadLockReadWriteLock (TRI_read_write_lock_t* lock) {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void TRI_ReadUnlockReadWriteLock (TRI_read_write_lock_t* lock) {
|
void TRI_ReadUnlockReadWriteLock (TRI_read_write_lock_t* lock) {
|
||||||
EnterCriticalSection(&lock->_lockReaders);
|
ReleaseSRWLockShared(&lock->_lock);
|
||||||
|
|
||||||
/* 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief tries to write lock a read-write lock
|
/// @brief tries to write lock a read-write lock
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
bool TRI_TryWriteLockReadWriteLock (TRI_read_write_lock_t* lock) {
|
bool TRI_TryWriteLockReadWriteLock (TRI_read_write_lock_t* lock) {
|
||||||
|
return (TryAcquireSRWLockExclusive(&lock->_lock) != 0);
|
||||||
BOOL result;
|
|
||||||
// ...........................................................................
|
|
||||||
// Here we use TryEnterCriticalSection instead of EnterCriticalSection
|
|
||||||
// There could already be a write lock - which will actuall block from this
|
|
||||||
// point on.
|
|
||||||
// ...........................................................................
|
|
||||||
|
|
||||||
result = TryEnterCriticalSection(&lock->_lockWriter);
|
|
||||||
|
|
||||||
if (result == 0) {
|
|
||||||
// appears some other writer is writing
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ...........................................................................
|
|
||||||
// Wait until the lock->_writerEvent is in a 'signalled' state
|
|
||||||
// This might fail because a reader is just about to read
|
|
||||||
// ...........................................................................
|
|
||||||
|
|
||||||
if (WaitForSingleObject(lock->_writerEvent, 0) != WAIT_OBJECT_0) {
|
|
||||||
LeaveCriticalSection(&lock->_lockWriter);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ...........................................................................
|
|
||||||
// Set _writeEvent as nonsignalled -- this will block other read/write
|
|
||||||
// lockers
|
|
||||||
// ...........................................................................
|
|
||||||
|
|
||||||
ResetEvent(lock->_writerEvent);
|
|
||||||
|
|
||||||
|
|
||||||
// ...........................................................................
|
|
||||||
// If there are ANY read locks outstanding, leave
|
|
||||||
// ...........................................................................
|
|
||||||
|
|
||||||
if (WaitForSingleObject(lock->_readersEvent, 0) != WAIT_OBJECT_0) {
|
|
||||||
LeaveCriticalSection(&lock->_lockWriter);
|
|
||||||
SetEvent(lock->_writerEvent);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ...........................................................................
|
|
||||||
// Allow other threads to access this function
|
|
||||||
// ...........................................................................
|
|
||||||
|
|
||||||
LeaveCriticalSection(&lock->_lockWriter);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -500,99 +277,15 @@ bool TRI_TryWriteLockReadWriteLock (TRI_read_write_lock_t* lock) {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void TRI_WriteLockReadWriteLock (TRI_read_write_lock_t* lock) {
|
void TRI_WriteLockReadWriteLock (TRI_read_write_lock_t* lock) {
|
||||||
|
AcquireSRWLockExclusive(&lock->_lock);
|
||||||
// ...........................................................................
|
|
||||||
// Lock so no other thread can access this
|
|
||||||
// EnterCriticalSection(&lock->_lockWriter) will block this thread until
|
|
||||||
// it has been released by the other thread.
|
|
||||||
// ...........................................................................
|
|
||||||
|
|
||||||
EnterCriticalSection(&lock->_lockWriter);
|
|
||||||
|
|
||||||
|
|
||||||
// ...........................................................................
|
|
||||||
// Wait until the lock->_writerEvent is in a 'signalled' state
|
|
||||||
// ...........................................................................
|
|
||||||
|
|
||||||
WaitForSingleObject(lock->_writerEvent, INFINITE);
|
|
||||||
|
|
||||||
|
|
||||||
// ...........................................................................
|
|
||||||
// Set _writeEvent as nonsignalled -- this will block other read/write
|
|
||||||
// lockers
|
|
||||||
// ...........................................................................
|
|
||||||
|
|
||||||
ResetEvent(lock->_writerEvent);
|
|
||||||
|
|
||||||
|
|
||||||
// ...........................................................................
|
|
||||||
// If there are ANY read locks outstanding, then wait until these are cleared
|
|
||||||
// ...........................................................................
|
|
||||||
|
|
||||||
WaitForSingleObject(lock->_readersEvent, INFINITE);
|
|
||||||
|
|
||||||
|
|
||||||
// ...........................................................................
|
|
||||||
// Allow other threads to access this function
|
|
||||||
// ...........................................................................
|
|
||||||
|
|
||||||
LeaveCriticalSection(&lock->_lockWriter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief write unlocks read-write lock
|
/// @brief write unlocks read-write lock
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void TRI_WriteUnlockReadWriteLock (TRI_read_write_lock_t* lock) {
|
void TRI_WriteUnlockReadWriteLock (TRI_read_write_lock_t* lock) {
|
||||||
|
ReleaseSRWLockExclusive(&lock->_lock);
|
||||||
// ...........................................................................
|
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -715,7 +408,6 @@ void TRI_UnlockCondition (TRI_condition_t* cond) {
|
||||||
LeaveCriticalSection(&cond->_lockWaiters);
|
LeaveCriticalSection(&cond->_lockWaiters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// COMPARE & SWAP operations below for windows
|
// COMPARE & SWAP operations below for windows
|
||||||
// Note that for the MAC OS we use the 'barrier' functions which ensure that
|
// Note that for the MAC OS we use the 'barrier' functions which ensure that
|
||||||
|
|
|
@ -65,13 +65,7 @@ TRI_mutex_t;
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
typedef struct TRI_read_write_lock_s {
|
typedef struct TRI_read_write_lock_s {
|
||||||
HANDLE _writerEvent;
|
SRWLOCK _lock;
|
||||||
HANDLE _readersEvent;
|
|
||||||
|
|
||||||
int _readers;
|
|
||||||
|
|
||||||
CRITICAL_SECTION _lockWriter;
|
|
||||||
CRITICAL_SECTION _lockReaders;
|
|
||||||
}
|
}
|
||||||
TRI_read_write_lock_t;
|
TRI_read_write_lock_t;
|
||||||
|
|
||||||
|
|
|
@ -57,16 +57,15 @@ _invalid_parameter_handler newInvalidHandleHandler;
|
||||||
/// @{
|
/// @{
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
int ftruncate(int fd, long newSize) {
|
int ftruncate (int fd, long newSize) {
|
||||||
int result = _chsize(fd, newSize);
|
int result = _chsize(fd, newSize);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getpagesize (void) {
|
||||||
int getpagesize(void) {
|
|
||||||
static int pageSize = 0; // only define it once
|
static int pageSize = 0; // only define it once
|
||||||
|
|
||||||
if (!pageSize) {
|
if (! pageSize) {
|
||||||
// first time, so call the system info function
|
// first time, so call the system info function
|
||||||
SYSTEM_INFO systemInfo;
|
SYSTEM_INFO systemInfo;
|
||||||
GetSystemInfo (&systemInfo);
|
GetSystemInfo (&systemInfo);
|
||||||
|
@ -76,22 +75,20 @@ int getpagesize(void) {
|
||||||
return pageSize;
|
return pageSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Calls the windows Sleep function which always sleeps for milliseconds
|
// Calls the windows Sleep function which always sleeps for milliseconds
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void TRI_sleep(unsigned long waitTime) {
|
void TRI_sleep (unsigned long waitTime) {
|
||||||
Sleep(waitTime * 1000);
|
Sleep(waitTime * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Calls a timer which waits for a signal after the elapsed time.
|
// Calls a timer which waits for a signal after the elapsed time.
|
||||||
// The timer is acurate to 100nanoseconds
|
// The timer is accurate to 100nanoseconds
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void TRI_usleep(unsigned long waitTime) {
|
void TRI_usleep (unsigned long waitTime) {
|
||||||
int result;
|
int result;
|
||||||
HANDLE hTimer = NULL; // stores the handle of the timer object
|
HANDLE hTimer = NULL; // stores the handle of the timer object
|
||||||
LARGE_INTEGER wTime; // essentially a 64bit number
|
LARGE_INTEGER wTime; // essentially a 64bit number
|
||||||
|
@ -109,7 +106,7 @@ void TRI_usleep(unsigned long waitTime) {
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
// Set timer to wait for indicated micro seconds.
|
// Set timer to wait for indicated micro seconds.
|
||||||
if (!SetWaitableTimer(hTimer, &wTime, 0, NULL, NULL, 0)) {
|
if (! SetWaitableTimer(hTimer, &wTime, 0, NULL, NULL, 0)) {
|
||||||
// not much we can do at this low level
|
// not much we can do at this low level
|
||||||
CloseHandle(hTimer);
|
CloseHandle(hTimer);
|
||||||
return;
|
return;
|
||||||
|
@ -135,14 +132,13 @@ void TRI_usleep(unsigned long waitTime) {
|
||||||
// for now is to ignore error and hope it goes away!
|
// for now is to ignore error and hope it goes away!
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static void InvalidParameterHandler(const wchar_t* expression, // expression sent to function - NULL
|
static void InvalidParameterHandler (const wchar_t* expression, // expression sent to function - NULL
|
||||||
const wchar_t* function, // name of function - NULL
|
const wchar_t* function, // name of function - NULL
|
||||||
const wchar_t* file, // file where code resides - NULL
|
const wchar_t* file, // file where code resides - NULL
|
||||||
unsigned int line, // line within file - NULL
|
unsigned int line, // line within file - NULL
|
||||||
uintptr_t pReserved) { // in case microsoft forget something
|
uintptr_t pReserved) { // in case microsoft forget something
|
||||||
LOG_ERROR("Invalid handle parameter passed");
|
LOG_ERROR("Invalid handle parameter passed");
|
||||||
|
/*
|
||||||
/* start oreste -debug */
|
|
||||||
if (expression != 0) {
|
if (expression != 0) {
|
||||||
wprintf(L"win-utils.c:InvalidParameterHandler:EXPRESSION = %s\n",expression);
|
wprintf(L"win-utils.c:InvalidParameterHandler:EXPRESSION = %s\n",expression);
|
||||||
}
|
}
|
||||||
|
@ -161,14 +157,12 @@ static void InvalidParameterHandler(const wchar_t* expression, // expression sen
|
||||||
else {
|
else {
|
||||||
wprintf(L"win-utils.c:InvalidParameterHandler:FILE = NULL\n");
|
wprintf(L"win-utils.c:InvalidParameterHandler:FILE = NULL\n");
|
||||||
}
|
}
|
||||||
printf("oreste:win-utils.c:InvalidParameterHandler:LINE = %ud\n",line);
|
*/
|
||||||
/* end oreste -debug */
|
|
||||||
//abort();
|
//abort();
|
||||||
// TODO: use the wcstombs_s function to convert wchar to char - since all the above
|
// TODO: use the wcstombs_s function to convert wchar to char - since all the above
|
||||||
// wchar never will contain 2 byte chars
|
// wchar never will contain 2 byte chars
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Called from the 'main' and performs any initialisation requirements which
|
// Called from the 'main' and performs any initialisation requirements which
|
||||||
// are specific to windows.
|
// are specific to windows.
|
||||||
|
@ -178,8 +172,8 @@ static void InvalidParameterHandler(const wchar_t* expression, // expression sen
|
||||||
// calling function should decide what to do.
|
// calling function should decide what to do.
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
int finaliseWindows (const TRI_win_finalise_e finaliseWhat,
|
||||||
int finaliseWindows(const TRI_win_finalise_e finaliseWhat, const char* data) {
|
const char* data) {
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
// ............................................................................
|
// ............................................................................
|
||||||
|
@ -209,10 +203,8 @@ int finaliseWindows(const TRI_win_finalise_e finaliseWhat, const char* data) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int initialiseWindows (const TRI_win_initialise_e initialiseWhat,
|
||||||
|
const char* data) {
|
||||||
int initialiseWindows(const TRI_win_initialise_e initialiseWhat, const char* data) {
|
|
||||||
|
|
||||||
|
|
||||||
// ............................................................................
|
// ............................................................................
|
||||||
// The data is used to transport information from the calling function to here
|
// The data is used to transport information from the calling function to here
|
||||||
|
@ -273,7 +265,6 @@ int initialiseWindows(const TRI_win_initialise_e initialiseWhat, const char* dat
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int TRI_createFile (const char* filename, int openFlags, int modeFlags) {
|
int TRI_createFile (const char* filename, int openFlags, int modeFlags) {
|
||||||
HANDLE fileHandle;
|
HANDLE fileHandle;
|
||||||
int fileDescriptor;
|
int fileDescriptor;
|
||||||
|
@ -282,11 +273,10 @@ int TRI_createFile (const char* filename, int openFlags, int modeFlags) {
|
||||||
GENERIC_READ | GENERIC_WRITE,
|
GENERIC_READ | GENERIC_WRITE,
|
||||||
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
|
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
NULL,
|
NULL,
|
||||||
CREATE_NEW,
|
(openFlags & O_APPEND) ? OPEN_ALWAYS : CREATE_NEW,
|
||||||
0,
|
0,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
|
|
||||||
if (fileHandle == INVALID_HANDLE_VALUE) {
|
if (fileHandle == INVALID_HANDLE_VALUE) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,14 +106,14 @@ int TRI_openFile (const char* filename, int openFlags);
|
||||||
// this provides a translation
|
// this provides a translation
|
||||||
// .............................................................................
|
// .............................................................................
|
||||||
|
|
||||||
void TRI_sleep(unsigned long);
|
void TRI_sleep (unsigned long);
|
||||||
|
|
||||||
|
|
||||||
// .............................................................................
|
// .............................................................................
|
||||||
// there is no usleep (micro sleep) in windows, so we create one here
|
// there is no usleep (micro sleep) in windows, so we create one here
|
||||||
// .............................................................................
|
// .............................................................................
|
||||||
|
|
||||||
void TRI_usleep(unsigned long);
|
void TRI_usleep (unsigned long);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @}
|
/// @}
|
||||||
|
|
Loading…
Reference in New Issue