Beispiel #1
0
int TRI_InsertBlockerCompactorVocBase (TRI_vocbase_t* vocbase,
                                       double lifetime,
                                       TRI_voc_tick_t* id) {
  compaction_blocker_t blocker;
  int res;

  if (lifetime <= 0.0) {
    return TRI_ERROR_BAD_PARAMETER;
  }

  blocker._id      = TRI_NewTickServer();
  blocker._expires = TRI_microtime() + lifetime;

  LockCompaction(vocbase);

  res = TRI_PushBackVector(&vocbase->_compactionBlockers._data, &blocker);

  UnlockCompaction(vocbase);

  if (res != TRI_ERROR_NO_ERROR) {
    return res;
  }

  *id = blocker._id;
  
  return TRI_ERROR_NO_ERROR;
}
Beispiel #2
0
int TRI_TouchBlockerCompactorVocBase (TRI_vocbase_t* vocbase,
                                      TRI_voc_tick_t id,
                                      double lifetime) {
  size_t i, n;
  bool found;

  found = false;
  
  if (lifetime <= 0.0) {
    return TRI_ERROR_BAD_PARAMETER;
  }
  
  LockCompaction(vocbase);

  n = vocbase->_compactionBlockers._data._length;

  for (i = 0; i < n; ++i) {
    compaction_blocker_t* blocker = TRI_AtVector(&vocbase->_compactionBlockers._data, i);

    if (blocker->_id == id) {
      blocker->_expires = TRI_microtime() + lifetime;
      found = true;
      break;
    }
  }

  UnlockCompaction(vocbase);  

  if (! found) {
    return TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND;
  }

  return TRI_ERROR_NO_ERROR;
}
Beispiel #3
0
static bool CheckAndLockCompaction (TRI_vocbase_t* vocbase) {
  double now;
  size_t i, n;

  now = TRI_microtime();
 
  // check if we can acquire the write lock instantly
  if (! TryLockCompaction(vocbase)) {
    // couldn't acquire the write lock
    return false;
  }

  // we are now holding the write lock

  // check if we have a still-valid compaction blocker
  n = vocbase->_compactionBlockers._data._length;
  for (i = 0; i < n; ++i) {
    compaction_blocker_t* blocker = TRI_AtVector(&vocbase->_compactionBlockers._data, i);

    if (blocker->_expires > now) {
      // found a compaction blocker. unlock and return
      UnlockCompaction(vocbase);
      return false;
    }
  }

  return true;
}
Beispiel #4
0
bool TRI_CleanupCompactorVocBase (TRI_vocbase_t* vocbase) {
  double now;
  size_t i, n;

  now = TRI_microtime();
  
  // check if we can instantly acquire the lock
  if (! TryLockCompaction(vocbase)) {
    // couldn't acquire lock
    return false;
  }

  // we are now holding the write lock

  n = vocbase->_compactionBlockers._data._length;
 
  i = 0;
  while (i < n) {
    compaction_blocker_t* blocker = TRI_AtVector(&vocbase->_compactionBlockers._data, i);

    if (blocker->_expires < now) {
      TRI_RemoveVector(&vocbase->_compactionBlockers._data, i);
      n--;
    }
    else {
      i++;
    }
  }

  UnlockCompaction(vocbase);

  return true;
}
Beispiel #5
0
static bool CheckSyncCompactorDocumentCollection (TRI_document_collection_t* sim) {
  TRI_collection_t* base;
  TRI_datafile_t* journal;
  bool ok;
  bool worked;
  char const* synced;
  char* written;
  double ti;
  size_t i;
  size_t n;
  
  worked = false;
  base = &sim->base.base;

  // .............................................................................
  // the only thread MODIFYING the _compactors variable is this thread,
  // therefore no locking is required to access the _compactors
  // .............................................................................

  n = base->_compactors._length;

  for (i = 0;  i < n; ++i) {
    journal = base->_compactors._buffer[i];

    TRI_LOCK_JOURNAL_ENTRIES_DOC_COLLECTION(sim);

    synced = journal->_synced;
    written = journal->_written;

    TRI_UNLOCK_JOURNAL_ENTRIES_DOC_COLLECTION(sim);

    if (synced < written) {
      worked = true;
      ok = TRI_msync(journal->_fd, journal->_mmHandle, synced, written);
      ti = TRI_microtime();

      TRI_LOCK_JOURNAL_ENTRIES_DOC_COLLECTION(sim);

      if (ok) {
        journal->_synced = written;
        journal->_lastSynced = ti;
      }
      else {
        journal->_state = TRI_DF_STATE_WRITE_ERROR;
      }

      TRI_BROADCAST_JOURNAL_ENTRIES_DOC_COLLECTION(sim);
      TRI_UNLOCK_JOURNAL_ENTRIES_DOC_COLLECTION(sim);

      if (ok) {
        LOG_TRACE("msync succeeded %p, size %lu", synced, (unsigned long)(written - synced));
      }
      else {
        LOG_ERROR("msync failed with: %s", TRI_last_error());
      }
    }
  }

  return worked;
}
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;
}
Beispiel #7
0
static mrb_value MR_Time (mrb_state* mrb, mrb_value self) {
  return mrb_float_value(mrb, TRI_microtime());
}
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);
}
void TRI_PersistGeneralCursor (TRI_general_cursor_t* cursor,
                               double ttl) {
  cursor->_expires = TRI_microtime() + ttl;
}
Beispiel #10
0
    SimpleHttpResult* SimpleHttpClient::request (
      rest::HttpRequest::HttpRequestType method,
      std::string const& location,
      char const* body,
      size_t bodyLength,
      std::map<std::string, std::string> const& headerFields) {
      
      // ensure connection has not yet been invalidated
      TRI_ASSERT(_connection != nullptr);

      // ensure that result is empty
      TRI_ASSERT(_result == nullptr);

      // create a new result
      _result = new SimpleHttpResult;

      // reset error message
      _errorMessage = "";

      // set body
      setRequest(method, rewriteLocation(location), body, bodyLength, headerFields);

      // ensure state
      TRI_ASSERT(_state == IN_CONNECT || _state == IN_WRITE);

      // respect timeout
      double endTime = TRI_microtime() + _requestTimeout;
      double remainingTime = _requestTimeout;

      while (_state < FINISHED && remainingTime > 0.0) {
        // Note that this loop can either be left by timeout or because
        // a connect did not work (which sets the _state to DEAD). In all
        // other error conditions we call close() which resets the state
        // to IN_CONNECT and tries a reconnect. This is important because
        // it is always possible that we are called with a connection that
        // has already been closed by the other side. This leads to the
        // strange effect that the write (if it is small enough) proceeds
        // but the following read runs into an error. In that case we try
        // to reconnect one and then give up if this does not work.
        switch (_state) {
          case (IN_CONNECT): {
            handleConnect();
            // If this goes wrong, _state is set to DEAD
            break;
          }

          case (IN_WRITE): {
            size_t bytesWritten = 0;

            TRI_set_errno(TRI_ERROR_NO_ERROR);

            bool res = _connection->handleWrite(
              remainingTime, 
              static_cast<void const*>(_writeBuffer.c_str() + _written),
              _writeBuffer.length() - _written,
              &bytesWritten);

            if (! res) {
              setErrorMessage("Error writing to '" +
                              _connection->getEndpoint()->getSpecification() +
                              "' '" +
                              _connection->getErrorDetails() +
                              "'");
              this->close(); // this sets _state to IN_CONNECT for a retry
            }
            else {
              _written += bytesWritten;

              if (_written == _writeBuffer.length())  {
                _state = IN_READ_HEADER;
              }
            }

            break;
          }

          case (IN_READ_HEADER):
          case (IN_READ_BODY):
          case (IN_READ_CHUNKED_HEADER):
          case (IN_READ_CHUNKED_BODY): {
            TRI_set_errno(TRI_ERROR_NO_ERROR);

            // we need to notice if the other side has closed the connection:
            bool connectionClosed;

            bool res = _connection->handleRead(remainingTime,
                                               _readBuffer,
                                               connectionClosed);


            // If there was an error, then we are doomed:
            if (! res) {
              setErrorMessage("Error reading from: '" +
                              _connection->getEndpoint()->getSpecification() +
                              "' '" +
                              _connection->getErrorDetails() +
                              "'");
              this->close(); // this sets the state to IN_CONNECT for a retry
              break;
            }

            if (connectionClosed) {
              // write might have succeeded even if the server has closed 
              // the connection, this will then show up here with us being
              // in state IN_READ_HEADER but nothing read.
              if (_state == IN_READ_HEADER && 0 == _readBuffer.length()) {
                this->close(); // sets _state to IN_CONNECT again for a retry
                continue;
              }

              else if (_state == IN_READ_BODY && ! _result->hasContentLength()) {
                // If we are reading the body and no content length was
                // found in the header, then we must read until no more
                // progress is made (but without an error), this then means
                // that the server has closed the connection and we must
                // process the body one more time:
                _result->setContentLength(_readBuffer.length() - _readBufferOffset);
                processBody();

                if (_state != FINISHED) {
                  // If the body was not fully found we give up:
                  this->close(); // this sets the state IN_CONNECT to retry
                }

                break;
              }

              else {
                // In all other cases of closed connection, we are doomed:
                this->close(); // this sets the state to IN_CONNECT retry
                break;
              }
            }

            // the connection is still alive:
            switch (_state) {
              case (IN_READ_HEADER):
                processHeader();
                break;

              case (IN_READ_BODY):
                processBody();
                break;

              case (IN_READ_CHUNKED_HEADER):
                processChunkedHeader();
                break;

              case (IN_READ_CHUNKED_BODY):
                processChunkedBody();
                break;

              default:
                break;
            }

            break;
          }

          default:
            break;
        }

        remainingTime = endTime - TRI_microtime();
      }

      if (_state < FINISHED && _errorMessage.empty()) {
        setErrorMessage("Request timeout reached");
      }

      // set result type in getResult()
      SimpleHttpResult* result = getResult();

      _result = nullptr;

      return result;
    }
Beispiel #11
0
void TRI_CleanupShadowData (TRI_shadow_store_t* const store,
                            const double maxAge,
                            const bool force) {
  double compareStamp = TRI_microtime() - maxAge; // age must be specified in secs
  size_t deleteCount = 0;

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

  if (store->_ids._nrUsed == 0) {
    // store is empty, nothing to do!
    TRI_UnlockMutex(&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 SHADOW_MAX_DELETE elements
  while (deleteCount++ < SHADOW_MAX_DELETE || force) {
    bool deleted = false;
    size_t i;

    for (i = 0; i < store->_ids._nrAlloc; i++) {
      // enum all shadows
      TRI_shadow_t* shadow = (TRI_shadow_t*) store->_ids._table[i];

      if (shadow == NULL) {
        continue;
      }
          
      // check if shadow is unused and expired
      if (shadow->_rc < 1 || force) {
        if (shadow->_type == SHADOW_TRANSIENT ||
            shadow->_timestamp < compareStamp ||
            shadow->_deleted ||
            force) {
          LOG_TRACE("cleaning shadow %p, id: %llu, rc: %d, expired: %d, deleted: %d",
                    shadow,
                    (unsigned long long) shadow->_id,
                    (int) shadow->_rc,
                    (int) (shadow->_timestamp < compareStamp),
                    (int) shadow->_deleted);

          TRI_RemoveKeyAssociativePointer(&store->_ids, &shadow->_id);
          TRI_RemoveKeyAssociativePointer(&store->_pointers, shadow->_data);
          store->destroyShadow(shadow->_data);
          TRI_Free(TRI_UNKNOWN_MEM_ZONE, shadow);

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

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

  // release lock
  TRI_UnlockMutex(&store->_lock);
}
Beispiel #12
0
static inline void UpdateTimestampShadow (TRI_shadow_t* const shadow) {
  shadow->_timestamp = TRI_microtime();
}