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;
}
Example #3
0
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;
}
Example #4
0
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;
}
Example #6
0
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;
}
Example #7
0
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);
  }
}
Example #10
0
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;
}
Example #11
0
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;
}
Example #12
0
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;
}
Example #13
0
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;
}
Example #14
0
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);
}
Example #15
0
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;
}
Example #16
0
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;
}
Example #17
0
static void UnlockCompaction (TRI_vocbase_t* vocbase) { 
  TRI_WriteUnlockReadWriteLock(&vocbase->_compactionBlockers._lock);
}
Example #18
0
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");
}