Example #1
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 #2
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
  }
}