Example #1
0
static void LinkBarrierElement (TRI_barrier_t* element, 
                                TRI_barrier_list_t* container) {
  assert(container != NULL);

  element->_container = container;

  TRI_LockSpin(&container->_lock);

  // empty list
  if (container->_end == NULL) {
    element->_next = NULL;
    element->_prev = NULL;

    container->_begin = element;
    container->_end = element;
  }

  // add to the end
  else {
    element->_next = NULL;
    element->_prev = container->_end;

    container->_end->_next = element;
    container->_end = element;
  }

  if (element->_type == TRI_BARRIER_ELEMENT) {
    // increase counter for barrier elements
    ++container->_numBarrierElements;
  }

  TRI_UnlockSpin(&container->_lock);
}
Example #2
0
static void LinkBarrierElement (TRI_barrier_t* element, TRI_barrier_list_t* container) {
  element->_container = container;

  TRI_LockSpin(&container->_lock);

  // empty list
  if (container->_end == NULL) {
    element->_next = NULL;
    element->_prev = NULL;

    container->_begin = element;
    container->_end = element;
  }

  // add to the end
  else {
    element->_next = NULL;
    element->_prev = container->_end;

    container->_end->_next = element;
    container->_end = element;
  }

  TRI_UnlockSpin(&container->_lock);
}
Example #3
0
bool TRI_ContainsBarrierList (TRI_barrier_list_t* container,  
                              TRI_barrier_type_e type) {
  TRI_LockSpin(&container->_lock);
  
  if (type == TRI_BARRIER_ELEMENT) {
    // shortcut
    bool hasBarriers = (container->_numBarrierElements > 0);
    TRI_UnlockSpin(&container->_lock);

    return hasBarriers;
  }

  TRI_barrier_t* ptr = container->_begin;

  while (ptr != NULL) {
    if (ptr->_type == type) {
      TRI_UnlockSpin(&container->_lock);

      return true;
    }

    ptr = ptr->_next;
  }

  TRI_UnlockSpin(&container->_lock);

  return false;
}
Example #4
0
void TRI_FreeBarrier (TRI_barrier_t* element) {
  TRI_barrier_list_t* container;

  container = element->_container;

  TRI_LockSpin(&container->_lock);

  // element is at the beginning of the chain
  if (element->_prev == NULL) {
    container->_begin = element->_next;
  }
  else {
    element->_prev->_next = element->_next;
  }

  // element is at the end of the chain
  if (element->_next == NULL) {
    container->_end = element->_prev;
  }
  else {
    element->_next->_prev = element->_prev;
  }

  TRI_UnlockSpin(&container->_lock);
  
  // free data contained in the element
  // currently, only barriers of type ELEMENT contain data that needs freeing
  FreeDataBarrier(element);

  // free the element
  TRI_Free(TRI_UNKNOWN_MEM_ZONE, element);
}
Example #5
0
void TRI_FreeBarrier (TRI_barrier_t* element) {
  TRI_barrier_list_t* container;

  assert(element != NULL);
  container = element->_container;
  assert(container != NULL);

  TRI_LockSpin(&container->_lock);

  // element is at the beginning of the chain
  if (element->_prev == NULL) {
    container->_begin = element->_next;
  }
  else {
    element->_prev->_next = element->_next;
  }

  // element is at the end of the chain
  if (element->_next == NULL) {
    container->_end = element->_prev;
  }
  else {
    element->_next->_prev = element->_prev;
  }
  
  if (element->_type == TRI_BARRIER_ELEMENT) {
    // decrease counter for barrier elements
    --container->_numBarrierElements;
  }

  TRI_UnlockSpin(&container->_lock);
  
  // free the element
  TRI_Free(TRI_UNKNOWN_MEM_ZONE, element);
}
static bool CheckTerminateFlag (TRI_replication_applier_t* applier) {
  TRI_LockSpin(&applier->_threadLock);
  bool result = applier->_terminateThread;
  TRI_UnlockSpin(&applier->_threadLock);

  return result;
}
Example #7
0
void TRI_FreeBarrier (TRI_barrier_t* element) {
  TRI_barrier_list_t* container;

  container = element->_container;

  TRI_LockSpin(&container->_lock);

  // element is at the beginning of the chain
  if (element->_prev == NULL) {
    container->_begin = element->_next;
  }
  else {
    element->_prev->_next = element->_next;
  }

  // element is at the end of the chain
  if (element->_next == NULL) {
    container->_end = element->_prev;
  }
  else {
    element->_next->_prev = element->_prev;
  }

  TRI_UnlockSpin(&container->_lock);

  // free the element
  TRI_Free(TRI_UNKNOWN_MEM_ZONE, element);
}
void TRI_ReleaseGeneralCursor (TRI_general_cursor_t* cursor) {
  TRI_general_cursor_store_t* store = cursor->_store;

  TRI_LockSpin(&store->_lock);
  cursor = static_cast<TRI_general_cursor_t*>(TRI_LookupByKeyAssociativePointer(&store->_ids, &cursor->_id));
  if (cursor != NULL) {
    --cursor->_usage._refCount;
  }
  TRI_UnlockSpin(&store->_lock);
}
Example #9
0
TRI_voc_tick_t TRI_NewTickVocBase () {
  uint64_t tick = ServerIdentifier;

  TRI_LockSpin(&TickLock);

  tick |= (++CurrentTick) << 16;

  TRI_UnlockSpin(&TickLock);

  return tick;
}
Example #10
0
TRI_general_cursor_t* TRI_FindGeneralCursor (TRI_vocbase_t* vocbase,
                                             TRI_voc_tick_t id) {
  TRI_general_cursor_store_t* store = vocbase->_cursors;

  TRI_LockSpin(&store->_lock);
  TRI_general_cursor_t* cursor = static_cast<TRI_general_cursor_t*>(TRI_LookupByKeyAssociativePointer(&store->_ids, &id));
  if (cursor == NULL || cursor->_usage._isDeleted) {
    cursor = NULL;
  }
  TRI_UnlockSpin(&store->_lock);

  return cursor;
}
Example #11
0
TRI_general_cursor_t* TRI_CreateGeneralCursor (TRI_vocbase_t* vocbase,
                                               TRI_general_cursor_result_t* result,
                                               const bool doCount,
                                               const TRI_general_cursor_length_t batchSize,
                                               TRI_json_t* extra) {
  TRI_general_cursor_t* cursor;

  TRI_ASSERT(vocbase != NULL);

  cursor = (TRI_general_cursor_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_general_cursor_t), false);

  if (cursor == NULL) {
    return NULL;
  }

  cursor->_vocbase     = vocbase;
  cursor->_store       = vocbase->_cursors;

  cursor->_result      = result;
  cursor->_extra       = extra; // might be NULL

  cursor->_expires     = TRI_microtime() + 3600; // default lifetime: 1h
  cursor->_id          = TRI_NewTickServer();

  // state
  cursor->_currentRow  = 0;
  cursor->_length      = result->getLength(result);
  cursor->_hasCount    = doCount;
  cursor->_batchSize   = batchSize;
  cursor->_usage._refCount  = 0;
  cursor->_usage._isDeleted = false;

  // assign functions
  cursor->next         = NextGeneralCursor;
  cursor->hasNext      = HasNextGeneralCursor;
  cursor->hasCount     = HasCountGeneralCursor;
  cursor->getBatchSize = GetBatchSizeGeneralCursor;
  cursor->getExtra     = GetExtraGeneralCursor;
  cursor->free         = TRI_FreeGeneralCursor;

  TRI_InitSpin(&cursor->_lock);

  TRI_LockSpin(&vocbase->_cursors->_lock);
  // TODO: check for errors here
  TRI_InsertKeyAssociativePointer(&vocbase->_cursors->_ids, &cursor->_id, cursor, true);
  TRI_UnlockSpin(&vocbase->_cursors->_lock);

  LOG_TRACE("created general cursor");

  return cursor;
}
Example #12
0
bool TRI_RemoveGeneralCursor (TRI_vocbase_t* vocbase,
                              TRI_voc_tick_t id) {
  TRI_general_cursor_store_t* store = vocbase->_cursors;
  bool result;

  TRI_LockSpin(&store->_lock);
  TRI_general_cursor_t* cursor = static_cast<TRI_general_cursor_t*>(TRI_LookupByKeyAssociativePointer(&store->_ids, &id));
  if (cursor == NULL || cursor->_usage._isDeleted) {
    result = false;
  }
  else {
    cursor->_usage._isDeleted = true;
    result = true;
  }
  TRI_UnlockSpin(&store->_lock);

  return result;
}
Example #13
0
bool TRI_DropGeneralCursor (TRI_general_cursor_t* cursor) {
  TRI_general_cursor_store_t* store = cursor->_store;
  bool result;

  TRI_LockSpin(&store->_lock);
  cursor = static_cast<TRI_general_cursor_t*>(TRI_LookupByKeyAssociativePointer(&store->_ids, &cursor->_id));

  if (cursor != NULL && ! cursor->_usage._isDeleted) {
    cursor->_usage._isDeleted = true;
    result = true;
  }
  else {
    result = false;
  }
  TRI_UnlockSpin(&store->_lock);

  return result;
}
Example #14
0
TRI_general_cursor_t* TRI_UseGeneralCursor (TRI_general_cursor_t* cursor) {
  TRI_general_cursor_store_t* store = cursor->_store;

  TRI_LockSpin(&store->_lock);
  cursor = static_cast<TRI_general_cursor_t*>(TRI_LookupByKeyAssociativePointer(&store->_ids, &cursor->_id));

  if (cursor != NULL) {
    if (cursor->_usage._isDeleted) {
      cursor = NULL;
    }
    else {
      ++cursor->_usage._refCount;
    }
  }
  TRI_UnlockSpin(&store->_lock);

  return cursor;
}
Example #15
0
bool TRI_ContainsBarrierList (TRI_barrier_list_t* container, TRI_barrier_type_e type) {
  TRI_barrier_t* ptr;

  TRI_LockSpin(&container->_lock);

  ptr = container->_begin;

  while (ptr != NULL) {
    if (ptr->_type == type) {
      TRI_UnlockSpin(&container->_lock);
      return true;
    }
    ptr = ptr->_next;
  }

  TRI_UnlockSpin(&container->_lock);

  return false;
}
Example #16
0
static void CleanupSimCollection (TRI_sim_collection_t* sim) {
  // loop until done
  while (true) {
    TRI_barrier_list_t* container;
    TRI_barrier_t* element;
    bool hasUnloaded = false;

    container = &sim->base._barrierList;
    element = NULL;

    // check and remove a callback elements at the beginning of the list
    TRI_LockSpin(&container->_lock);

    if (container->_begin == NULL || container->_begin->_type == TRI_BARRIER_ELEMENT) {
      // did not find anything on top of the barrier list or found an element marker
      // this means we must exit
      TRI_UnlockSpin(&container->_lock);
      return;
    }

    element = container->_begin;
    assert(element);

    // found an element to go on with
    container->_begin = element->_next;

    if (element->_next == NULL) {
      container->_end = NULL;
    }
    else {
      element->_next->_prev = NULL;
    }

    TRI_UnlockSpin(&container->_lock);

    // execute callback, sone of the callbacks might delete or free our collection
    if (element->_type == TRI_BARRIER_DATAFILE_CALLBACK) {
      TRI_barrier_datafile_cb_t* de;

      de = (TRI_barrier_datafile_cb_t*) element;

      de->callback(de->_datafile, de->_data);
      TRI_Free(TRI_UNKNOWN_MEM_ZONE, element);
      // next iteration
    }
    else if (element->_type == TRI_BARRIER_COLLECTION_UNLOAD_CALLBACK) {
      // collection is unloaded
      TRI_barrier_collection_cb_t* ce;

      ce = (TRI_barrier_collection_cb_t*) element;
      hasUnloaded = ce->callback(ce->_collection, ce->_data);
      TRI_Free(TRI_UNKNOWN_MEM_ZONE, element);
      
      if (hasUnloaded) {
        // this has unloaded and freed the collection
        return;
      }
    }
    else if (element->_type == TRI_BARRIER_COLLECTION_DROP_CALLBACK) {
      // collection is dropped
      TRI_barrier_collection_cb_t* ce;

      ce = (TRI_barrier_collection_cb_t*) element;
      hasUnloaded = ce->callback(ce->_collection, ce->_data);
      TRI_Free(TRI_UNKNOWN_MEM_ZONE, element);

      if (hasUnloaded) {
        // this has dropped the collection
        return;
      }
    }
    else {
      // unknown type
      LOG_FATAL("unknown barrier type '%d'", (int) element->_type);
      TRI_Free(TRI_UNKNOWN_MEM_ZONE, element);
    }

    // next iteration
  }
}
Example #17
0
void TRI_CleanupGeneralCursor (TRI_general_cursor_store_t* store,
                               bool force) {
  double compareStamp = TRI_microtime();
  size_t deleteCount = 0;

  // we need an exclusive lock on the index
  TRI_LockSpin(&store->_lock);

  if (store->_ids._nrUsed == 0) {
    // store is empty, nothing to do!
    TRI_UnlockSpin(&store->_lock);
    return;
  }

  LOG_TRACE("cleaning shadows. in store: %ld", (unsigned long) store->_ids._nrUsed);

  // loop until there's nothing to delete or
  // we have deleted CURSOR_MAX_DELETE elements
  while (deleteCount++ < CURSOR_MAX_DELETE || force) {
    bool deleted = false;
    size_t i;

    for (i = 0; i < store->_ids._nrAlloc; i++) {
      // enum all cursors
      TRI_general_cursor_t* cursor = (TRI_general_cursor_t*) store->_ids._table[i];

      if (cursor == NULL) {
        continue;
      }

      TRI_LockSpin(&cursor->_lock);

      if (force ||
          (cursor->_usage._refCount == 0 &&
           (cursor->_usage._isDeleted || cursor->_expires < compareStamp))) {
        LOG_TRACE("cleaning cursor %p, id: %llu, rc: %d, expires: %d, deleted: %d",
                  cursor,
                  (unsigned long long) cursor->_id,
                  (int) cursor->_usage._refCount,
                  (int) cursor->_expires,
                  (int) cursor->_usage._isDeleted);

        TRI_RemoveKeyAssociativePointer(&store->_ids, &cursor->_id);
        TRI_UnlockSpin(&cursor->_lock);
        TRI_FreeGeneralCursor(cursor);
        deleted = true;

        // the remove might reposition elements in the container.
        // therefore break here and start iteration anew
        break;
      }

      TRI_UnlockSpin(&cursor->_lock);
    }

    if (! deleted) {
      // we did not find anything to delete, so give up
      break;
    }
  }

  // release lock
  TRI_UnlockSpin(&store->_lock);
}
Example #18
0
void TRI_LockGeneralCursor (TRI_general_cursor_t* const cursor) {
  TRI_LockSpin(&cursor->_lock);
}
Example #19
0
static void CleanupDocumentCollection (TRI_document_collection_t* document) {
  // loop until done
  while (true) {
    TRI_barrier_list_t* container;
    TRI_barrier_t* element;
    bool hasUnloaded = false;

    container = &document->base._barrierList;
    element = NULL;

    // check and remove all callback elements at the beginning of the list
    TRI_LockSpin(&container->_lock);

    // check the element on top of the barrier list
    // if it is a TRI_BARRIER_ELEMENT, it means that there is still a reference held
    // to document data in a datafile. We must then not unload or remove a file

    if (container->_begin == NULL ||
        container->_begin->_type == TRI_BARRIER_ELEMENT ||
        container->_begin->_type == TRI_BARRIER_COLLECTION_REPLICATION ||
        container->_begin->_type == TRI_BARRIER_COLLECTION_COMPACTION) {
      // did not find anything at the head of the barrier list or found an element marker
      // this means we must exit and cannot throw away datafiles and can unload collections
      TRI_UnlockSpin(&container->_lock);
      return;
    }

    // no TRI_BARRIER_ELEMENT at the head of the barrier list. This means that there is
    // some other action we can perform (i.e. unloading a datafile or a collection)

    // note that there is no need to check the entire list for a TRI_BARRIER_ELEMENT as
    // the list is filled up in chronological order. New barriers are always added to the
    // tail of the list, and if we have the following list
    // HEAD -> TRI_BARRIER_DATAFILE_CALLBACK -> TRI_BARRIER_ELEMENT
    // then it is still safe to execute the datafile callback operation, even if there
    // is a TRI_BARRIER_ELEMENT after it.
    // This is the case because the TRI_BARRIER_DATAFILE_CALLBACK is only put into the
    // barrier list after changing the pointers in all headers. After the pointers are
    // changed, it is safe to unload/remove an old datafile (that noone points to). And
    // any newer TRI_BARRIER_ELEMENTS will always reference data inside other datafiles.

    element = container->_begin;
    assert(element);

    // found an element to go on with
    container->_begin = element->_next;

    if (element->_next == NULL) {
      container->_end = NULL;
    }
    else {
      element->_next->_prev = NULL;
    }

    // yes, we can release the lock here
    TRI_UnlockSpin(&container->_lock);

    // someone else might now insert a new TRI_BARRIER_ELEMENT here, but it will
    // always refer to a different datafile than the one that we will now unload

    // execute callback, sone of the callbacks might delete or free our collection
    if (element->_type == TRI_BARRIER_DATAFILE_DROP_CALLBACK) {
      TRI_barrier_datafile_drop_cb_t* de;

      de = (TRI_barrier_datafile_drop_cb_t*) element;

      de->callback(de->_datafile, de->_data);
      TRI_Free(TRI_UNKNOWN_MEM_ZONE, element);
      // next iteration
    }
    else if (element->_type == TRI_BARRIER_DATAFILE_RENAME_CALLBACK) {
      TRI_barrier_datafile_rename_cb_t* de;

      de = (TRI_barrier_datafile_rename_cb_t*) element;

      de->callback(de->_datafile, de->_data);
      TRI_Free(TRI_UNKNOWN_MEM_ZONE, element);
      // next iteration
    }
    else if (element->_type == TRI_BARRIER_COLLECTION_UNLOAD_CALLBACK) {
      // collection is unloaded
      TRI_barrier_collection_cb_t* ce;

      ce = (TRI_barrier_collection_cb_t*) element;
      hasUnloaded = ce->callback(ce->_collection, ce->_data);
      TRI_Free(TRI_UNKNOWN_MEM_ZONE, element);

      if (hasUnloaded) {
        // this has unloaded and freed the collection
        return;
      }
    }
    else if (element->_type == TRI_BARRIER_COLLECTION_DROP_CALLBACK) {
      // collection is dropped
      TRI_barrier_collection_cb_t* ce;

      ce = (TRI_barrier_collection_cb_t*) element;
      hasUnloaded = ce->callback(ce->_collection, ce->_data);
      TRI_Free(TRI_UNKNOWN_MEM_ZONE, element);

      if (hasUnloaded) {
        // this has dropped the collection
        return;
      }
    }
    else {
      // unknown type
      LOG_FATAL_AND_EXIT("unknown barrier type '%d'", (int) element->_type);
    }

    // next iteration
  }
}