VPackBuilder* TransactionContext::leaseBuilder() { if (_builders.empty()) { // create a new builder and return it return new VPackBuilder(); } // re-use an existing builder VPackBuilder* b = _builders.back(); b->clear(); _builders.pop_back(); return b; }
void arangodb::traverser::ShortestPath::vertexToVelocyPack(Transaction* trx, ManagedDocumentResult* mmdr, size_t position, VPackBuilder& builder) { TRI_ASSERT(position < length()); VPackSlice v = _vertices[position]; TRI_ASSERT(v.isString()); std::string collection = v.copyString(); size_t p = collection.find("/"); TRI_ASSERT(p != std::string::npos); TransactionBuilderLeaser searchBuilder(trx); searchBuilder->add(VPackValue(collection.substr(p + 1))); collection = collection.substr(0, p); int res = trx->documentFastPath(collection, mmdr, searchBuilder->slice(), builder, true); if (res != TRI_ERROR_NO_ERROR) { builder.clear(); // Just in case... builder.add(basics::VelocyPackHelper::NullValue()); } }
static void raceForClusterBootstrap() { AgencyComm agency; auto ci = ClusterInfo::instance(); while (true) { AgencyCommResult result = agency.getValues("Bootstrap"); if (!result.successful()) { // Error in communication, note that value not found is not an error LOG_TOPIC(TRACE, Logger::STARTUP) << "raceForClusterBootstrap: no agency communication"; sleep(1); continue; } VPackSlice value = result.slice()[0].get( std::vector<std::string>({agency.prefix(), "Bootstrap"})); if (value.isString()) { // key was found and is a string if (value.copyString().find("done") != std::string::npos) { // all done, let's get out of here: LOG_TOPIC(TRACE, Logger::STARTUP) << "raceForClusterBootstrap: bootstrap already done"; return; } LOG_TOPIC(DEBUG, Logger::STARTUP) << "raceForClusterBootstrap: somebody else does the bootstrap"; sleep(1); continue; } // No value set, we try to do the bootstrap ourselves: VPackBuilder b; b.add(VPackValue(arangodb::ServerState::instance()->getId())); result = agency.casValue("Bootstrap", b.slice(), false, 300, 15); if (!result.successful()) { LOG_TOPIC(DEBUG, Logger::STARTUP) << "raceForClusterBootstrap: lost race, somebody else will bootstrap"; // Cannot get foot into the door, try again later: sleep(1); continue; } // OK, we handle things now, let's see whether a DBserver is there: auto dbservers = ci->getCurrentDBServers(); if (dbservers.size() == 0) { LOG_TOPIC(TRACE, Logger::STARTUP) << "raceForClusterBootstrap: no DBservers, waiting"; agency.removeValues("Bootstrap", false); sleep(1); continue; } LOG_TOPIC(DEBUG, Logger::STARTUP) << "raceForClusterBootstrap: race won, we do the bootstrap"; auto vocbase = DatabaseFeature::DATABASE->systemDatabase(); V8DealerFeature::DEALER->loadJavascriptFiles(vocbase, "server/bootstrap/cluster-bootstrap.js", 0); LOG_TOPIC(DEBUG, Logger::STARTUP) << "raceForClusterBootstrap: bootstrap done"; b.clear(); b.add(VPackValue(arangodb::ServerState::instance()->getId() + ": done")); result = agency.setValue("Bootstrap", b.slice(), 0); if (result.successful()) { return; } LOG_TOPIC(TRACE, Logger::STARTUP) << "raceForClusterBootstrap: could not indicate success"; sleep(1); } }
int RocksDBFeature::dropPrefix(std::string const& prefix) { if (!isEnabled()) { return TRI_ERROR_NO_ERROR; } TRI_ASSERT(Instance != nullptr); try { VPackBuilder builder; // create lower and upper bound for deletion builder.openArray(); builder.add(VPackSlice::minKeySlice()); builder.close(); std::string l; l.reserve(prefix.size() + builder.slice().byteSize()); l.append(prefix); // extend the prefix to at least 24 bytes while (l.size() < RocksDBIndex::keyPrefixSize()) { uint64_t value = 0; l.append(reinterpret_cast<char const*>(&value), sizeof(uint64_t)); } l.append(builder.slice().startAs<char const>(), builder.slice().byteSize()); builder.clear(); builder.openArray(); builder.add(VPackSlice::maxKeySlice()); builder.close(); std::string u; u.reserve(prefix.size() + builder.slice().byteSize()); u.append(prefix); // extend the prefix to at least 24 bytes while (u.size() < RocksDBIndex::keyPrefixSize()) { uint64_t value = UINT64_MAX; u.append(reinterpret_cast<char const*>(&value), sizeof(uint64_t)); } u.append(builder.slice().startAs<char const>(), builder.slice().byteSize()); #if 0 for (size_t i = 0; i < prefix.size(); i += sizeof(TRI_idx_iid_t)) { char const* x = prefix.c_str() + i; size_t o; char* q = TRI_EncodeHexString(x, 8, &o); if (q != nullptr) { LOG(TRACE) << "RocksDB prefix part: " << q; TRI_FreeString(TRI_CORE_MEM_ZONE, q); } } LOG(TRACE) << "dropping RocksDB range: " << VPackSlice(l.c_str() + RocksDBIndex::keyPrefixSize()).toJson() << " - " << VPackSlice(u.c_str() + RocksDBIndex::keyPrefixSize()).toJson(); #endif // delete files in range lower..upper rocksdb::Slice lower(l.c_str(), l.size()); rocksdb::Slice upper(u.c_str(), u.size()); { rocksdb::Status status = rocksdb::DeleteFilesInRange(_db->GetBaseDB(), _db->GetBaseDB()->DefaultColumnFamily(), &lower, &upper); if (!status.ok()) { // if file deletion failed, we will still iterate over the remaining keys, so we // don't need to abort and raise an error here LOG(WARN) << "RocksDB file deletion failed"; } } // go on and delete the remaining keys (delete files in range does not necessarily // find them all, just complete files) auto comparator = RocksDBFeature::instance()->comparator(); rocksdb::DB* db = _db->GetBaseDB(); rocksdb::WriteBatch batch; std::unique_ptr<rocksdb::Iterator> it(db->NewIterator(rocksdb::ReadOptions())); it->Seek(lower); while (it->Valid()) { int res = comparator->Compare(it->key(), upper); if (res >= 0) { break; } batch.Delete(it->key()); it->Next(); } // now apply deletion batch rocksdb::Status status = db->Write(rocksdb::WriteOptions(), &batch); if (!status.ok()) { LOG(WARN) << "RocksDB key deletion failed: " << status.ToString(); return TRI_ERROR_INTERNAL; } return TRI_ERROR_NO_ERROR; } catch (arangodb::basics::Exception const& ex) { LOG(ERR) << "caught exception during RocksDB key prefix deletion: " << ex.what(); return ex.code(); } catch (std::exception const& ex) { LOG(ERR) << "caught exception during RocksDB key prefix deletion: " << ex.what(); return TRI_ERROR_INTERNAL; } catch (...) { LOG(ERR) << "caught unknown exception during RocksDB key prefix deletion"; return TRI_ERROR_INTERNAL; } }
AqlItemBlock* ShortestPathBlock::getSome(size_t, size_t atMost) { DEBUG_BEGIN_BLOCK(); if (_done) { return nullptr; } if (_buffer.empty()) { size_t toFetch = (std::min)(DefaultBatchSize(), atMost); if (!ExecutionBlock::getBlock(toFetch, toFetch)) { _done = true; return nullptr; } _pos = 0; // this is in the first block } // If we get here, we do have _buffer.front() AqlItemBlock* cur = _buffer.front(); size_t const curRegs = cur->getNrRegs(); // Collect the next path: if (_posInPath >= _pathLength) { if (!nextPath(cur)) { // This input does not have any path. maybe the next one has. // we can only return nullptr iff the buffer is empty. if (++_pos >= cur->size()) { _buffer.pop_front(); // does not throw delete cur; _pos = 0; } return getSome(atMost, atMost); } } size_t available = _pathLength - _posInPath; size_t toSend = (std::min)(atMost, available); RegisterId nrRegs = getPlanNode()->getRegisterPlan()->nrRegs[getPlanNode()->getDepth()]; std::unique_ptr<AqlItemBlock> res(requestBlock(toSend, nrRegs)); // automatically freed if we throw TRI_ASSERT(curRegs <= res->getNrRegs()); // only copy 1st row of registers inherited from previous frame(s) inheritRegisters(cur, res.get(), _pos); // TODO this might be optimized in favor of direct mptr. VPackBuilder resultBuilder; for (size_t j = 0; j < toSend; j++) { if (usesVertexOutput()) { // TODO this might be optimized in favor of direct mptr. resultBuilder.clear(); _path->vertexToVelocyPack(_trx, _posInPath, resultBuilder); res->setValue(j, _vertexReg, AqlValue(resultBuilder.slice())); } if (usesEdgeOutput()) { // TODO this might be optimized in favor of direct mptr. resultBuilder.clear(); _path->edgeToVelocyPack(_trx, _posInPath, resultBuilder); res->setValue(j, _edgeReg, AqlValue(resultBuilder.slice())); } if (j > 0) { // re-use already copied aqlvalues res->copyValuesFromFirstRow(j, static_cast<RegisterId>(curRegs)); } ++_posInPath; } if (_posInPath >= _pathLength) { // Advance read position for next call if (++_pos >= cur->size()) { _buffer.pop_front(); // does not throw delete cur; _pos = 0; } } // Clear out registers no longer needed later: clearRegisters(res.get()); return res.release(); DEBUG_END_BLOCK(); }
void ExportCursor::dump(arangodb::basics::StringBuffer& buffer) { auto transactionContext = std::make_shared<StandaloneTransactionContext>(_vocbase); VPackOptions* options = transactionContext->getVPackOptions(); TRI_ASSERT(_ex != nullptr); auto const restrictionType = _ex->_restrictions.type; buffer.appendText("\"result\":["); VPackBuilder result; size_t const n = batchSize(); for (size_t i = 0; i < n; ++i) { if (!hasNext()) { break; } if (i > 0) { buffer.appendChar(','); } VPackSlice const slice(reinterpret_cast<char const*>(_ex->_documents->at(_position++))); { result.clear(); VPackObjectBuilder b(&result); // Copy over shaped values for (auto const& entry : VPackObjectIterator(slice)) { std::string key(entry.key.copyString()); if (!IncludeAttribute(restrictionType, _ex->_restrictions.fields, key)) { // Ignore everything that should be excluded or not included continue; } // If we get here we need this entry in the final result if (entry.value.isCustom()) { result.add(key, VPackValue(options->customTypeHandler->toString(entry.value, options, slice))); } else { result.add(key, entry.value); } } } arangodb::basics::VPackStringBufferAdapter bufferAdapter(buffer.stringBuffer()); try { VPackDumper dumper(&bufferAdapter, options); dumper.dump(result.slice()); } catch (arangodb::basics::Exception const& ex) { THROW_ARANGO_EXCEPTION_MESSAGE(ex.code(), ex.what()); } catch (std::exception const& ex) { THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, ex.what()); } catch (...) { THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL); } } buffer.appendText("],\"hasMore\":"); buffer.appendText(hasNext() ? "true" : "false"); if (hasNext()) { // only return cursor id if there are more documents buffer.appendText(",\"id\":\""); buffer.appendInteger(id()); buffer.appendText("\""); } if (hasCount()) { buffer.appendText(",\"count\":"); buffer.appendInteger(static_cast<uint64_t>(count())); } if (!hasNext()) { delete _ex; _ex = nullptr; // mark the cursor as deleted this->deleted(); } }