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; }
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; }
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; }
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; }
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; }
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; }
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; }
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); }
static inline void UpdateTimestampShadow (TRI_shadow_t* const shadow) { shadow->_timestamp = TRI_microtime(); }