From ac2c4f8f6b8d37660fc477138879e7436b6d4727 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Fri, 4 Dec 2020 20:30:48 -0800 Subject: [PATCH 001/740] first attempt at implementing streaming replies, everything is implemented besides NativeAPI --- fdbclient/NativeAPI.actor.cpp | 284 +++++++++++++++++++++++++ fdbclient/NativeAPI.actor.h | 16 ++ fdbclient/StorageServerInterface.h | 40 ++++ fdbrpc/FlowTransport.h | 2 +- fdbrpc/fdbrpc.h | 329 ++++++++++++++++++++++++++++- fdbrpc/genericactors.actor.h | 23 +- fdbserver/storageserver.actor.cpp | 255 +++++++++++++++++++--- flow/flow.h | 23 +- flow/genericactors.actor.h | 10 + 9 files changed, 945 insertions(+), 37 deletions(-) diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index e537e17c6e7..0383ae9378b 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -1700,6 +1700,17 @@ Future> getRange( TransactionInfo const& info, TagSet const& tags); +Future getRangeStream( + PromiseStream> const& results, + Database const& cx, + Future const& fVersion, + KeySelector const& begin, + KeySelector const& end, + GetRangeLimits const& limits, + bool const& reverse, + TransactionInfo const& info, + TagSet const& tags); + ACTOR Future> getValue(Future version, Key key, Database cx, TransactionInfo info, Reference trLogInfo, TagSet tags); @@ -2658,6 +2669,224 @@ ACTOR Future> getRange( Database cx, Reference getRangeStream( PromiseStream> results, Database cx, Reference trLogInfo, Future fVersion, + KeySelector begin, KeySelector end, GetRangeLimits limits, Promise> conflictRange, bool snapshot, bool reverse, + TransactionInfo info, TagSet tags ) +{ + state GetRangeLimits originalLimits( limits ); + state KeySelector originalBegin = begin; + state KeySelector originalEnd = end; + state Standalone output; + state Span span("NAPI:getRange"_loc, info.spanID); + + try { + state Version version = wait( fVersion ); + cx->validateVersion(version); + + state double startTime = now(); + state Version readVersion = version; // Needed for latestVersion requests; if more, make future requests at the version that the first one completed + // FIXME: Is this really right? Weaken this and see if there is a problem; if so maybe there is a much subtler problem even with this. + + if( begin.getKey() == allKeys.begin && begin.offset < 1 ) { + output.readToBegin = true; + begin = KeySelector(firstGreaterOrEqual( begin.getKey() ), begin.arena()); + } + + ASSERT( !limits.isReached() ); + ASSERT( (!limits.hasRowLimit() || limits.rows >= limits.minRows) && limits.minRows >= 0 ); + + loop { + if( end.getKey() == allKeys.begin && (end.offset < 1 || end.isFirstGreaterOrEqual()) ) { + getRangeFinished(cx, trLogInfo, startTime, originalBegin, originalEnd, snapshot, conflictRange, reverse, output); + return output; + } + + Key locationKey = reverse ? Key(end.getKey(), end.arena()) : Key(begin.getKey(), begin.arena()); + bool locationBackward = reverse ? (end-1).isBackward() : begin.isBackward(); + state pair> beginServer = wait( getKeyLocation( cx, locationKey, &StorageServerInterface::getKeyValues, info, locationBackward ) ); + state KeyRange shard = beginServer.first; + state bool modifiedSelectors = false; + state GetKeyValuesRequest req; + + req.isFetchKeys = (info.taskID == TaskPriority::FetchKeys); + req.version = readVersion; + + if( reverse && (begin-1).isDefinitelyLess(shard.begin) && + ( !begin.isFirstGreaterOrEqual() || begin.getKey() != shard.begin ) ) { //In this case we would be setting modifiedSelectors to true, but not modifying anything + + req.begin = firstGreaterOrEqual( shard.begin ); + modifiedSelectors = true; + } + else req.begin = begin; + + if( !reverse && end.isDefinitelyGreater(shard.end) ) { + req.end = firstGreaterOrEqual( shard.end ); + modifiedSelectors = true; + } + else req.end = end; + + transformRangeLimits(limits, reverse, req); + ASSERT(req.limitBytes > 0 && req.limit != 0 && req.limit < 0 == reverse); + + req.tags = cx->sampleReadTags() ? tags : Optional(); + req.debugID = info.debugID; + req.spanContext = span.context; + try { + if( info.debugID.present() ) { + g_traceBatch.addEvent("TransactionDebug", info.debugID.get().first(), "NativeAPI.getRange.Before"); + /*TraceEvent("TransactionDebugGetRangeInfo", info.debugID.get()) + .detail("ReqBeginKey", req.begin.getKey()) + .detail("ReqEndKey", req.end.getKey()) + .detail("OriginalBegin", originalBegin.toString()) + .detail("OriginalEnd", originalEnd.toString()) + .detail("Begin", begin.toString()) + .detail("End", end.toString()) + .detail("Shard", shard) + .detail("ReqLimit", req.limit) + .detail("ReqLimitBytes", req.limitBytes) + .detail("ReqVersion", req.version) + .detail("Reverse", reverse) + .detail("ModifiedSelectors", modifiedSelectors) + .detail("Servers", beginServer.second->description());*/ + } + + ++cx->transactionPhysicalReads; + ++cx->transactionGetRangeRequests; + state GetKeyValuesReply rep; + if (CLIENT_BUGGIFY) { + throw deterministicRandom()->randomChoice(std::vector{ + transaction_too_old(), future_version() + }); + } + //FIXME: load balance requests + if(beginServer.second->size() == 0) { + wait(Future(Never())); + } + state FutureStream repStream = beginServer.second->getInterface(0).getKeyValuesStream.getReplyStream(req); + loop { + GetKeyValuesStreamReply rep = waitNext(repStream); + + if( info.debugID.present() ) { + g_traceBatch.addEvent("TransactionDebug", info.debugID.get().first(), "NativeAPI.getRange.After");//.detail("SizeOf", rep.data.size()); + /*TraceEvent("TransactionDebugGetRangeDone", info.debugID.get()) + .detail("ReqBeginKey", req.begin.getKey()) + .detail("ReqEndKey", req.end.getKey()) + .detail("RepIsMore", rep.more) + .detail("VersionReturned", rep.version) + .detail("RowsReturned", rep.data.size());*/ + } + + ASSERT( !rep.more || rep.data.size() ); + ASSERT( !limits.hasRowLimit() || rep.data.size() <= limits.rows ); + + limits.decrement( rep.data ); + + if(reverse && begin.isLastLessOrEqual() && rep.data.size() && rep.data.end()[-1].key == begin.getKey()) { + modifiedSelectors = false; + } + + bool finished = limits.isReached() || ( !modifiedSelectors && !rep.more ) || limits.hasSatisfiedMinRows(); + bool readThrough = modifiedSelectors && !rep.more; + + // optimization: first request got all data--just return it + if( finished && !output.size() ) { + bool readToBegin = output.readToBegin; + bool readThroughEnd = output.readThroughEnd; + + output = Standalone( RangeResultRef( rep.data, modifiedSelectors || limits.isReached() || rep.more ), rep.arena ); + output.readToBegin = readToBegin; + output.readThroughEnd = readThroughEnd; + + if( BUGGIFY && limits.hasByteLimit() && output.size() > std::max(1, originalLimits.minRows) ) { + output.more = true; + output.resize(output.arena(), deterministicRandom()->randomInt(std::max(1,originalLimits.minRows),output.size())); + getRangeFinished(cx, trLogInfo, startTime, originalBegin, originalEnd, snapshot, conflictRange, reverse, output); + return output; + } + + if( readThrough ) { + output.arena().dependsOn( shard.arena() ); + output.readThrough = reverse ? shard.begin : shard.end; + } + + getRangeFinished(cx, trLogInfo, startTime, originalBegin, originalEnd, snapshot, conflictRange, reverse, output); + return output; + } + + output.arena().dependsOn( rep.arena ); + output.append(output.arena(), rep.data.begin(), rep.data.size()); + + if( finished ) { + if( readThrough ) { + output.arena().dependsOn( shard.arena() ); + output.readThrough = reverse ? shard.begin : shard.end; + } + output.more = modifiedSelectors || limits.isReached() || rep.more; + + getRangeFinished(cx, trLogInfo, startTime, originalBegin, originalEnd, snapshot, conflictRange, reverse, output); + return output; + } + + readVersion = rep.version; // see above comment + + if( !rep.more ) { + ASSERT( modifiedSelectors ); + TEST(true); // !GetKeyValuesReply.more and modifiedSelectors in getRange + + if( !rep.data.size() ) { + Standalone result = wait( getRangeFallback(cx, version, originalBegin, originalEnd, originalLimits, reverse, info, tags ) ); + getRangeFinished(cx, trLogInfo, startTime, originalBegin, originalEnd, snapshot, conflictRange, reverse, result); + return result; + } + + if( reverse ) + end = firstGreaterOrEqual( shard.begin ); + else + begin = firstGreaterOrEqual( shard.end ); + } else { + TEST(true); // GetKeyValuesReply.more in getRange + if( reverse ) + end = firstGreaterOrEqual( output[output.size()-1].key ); + else + begin = firstGreaterThan( output[output.size()-1].key ); + } + } + + } catch ( Error& e ) { + if( info.debugID.present() ) { + g_traceBatch.addEvent("TransactionDebug", info.debugID.get().first(), "NativeAPI.getRange.Error"); + TraceEvent("TransactionDebugError", info.debugID.get()).error(e); + } + if (e.code() == error_code_wrong_shard_server || e.code() == error_code_all_alternatives_failed || + (e.code() == error_code_transaction_too_old && readVersion == latestVersion)) + { + cx->invalidateCache( reverse ? end.getKey() : begin.getKey(), reverse ? (end-1).isBackward() : begin.isBackward() ); + + if (e.code() == error_code_wrong_shard_server) { + Standalone result = wait( getRangeFallback(cx, version, originalBegin, originalEnd, originalLimits, reverse, info, tags ) ); + getRangeFinished(cx, trLogInfo, startTime, originalBegin, originalEnd, snapshot, conflictRange, reverse, result); + return result; + } + + wait(delay(CLIENT_KNOBS->WRONG_SHARD_SERVER_DELAY, info.taskID)); + } else { + if (trLogInfo) + trLogInfo->addLog(FdbClientLogEvents::EventGetRangeError(startTime, cx->clientLocality.dcId(), static_cast(e.code()), begin.getKey(), end.getKey())); + + throw e; + } + } + } + } + catch(Error &e) { + if(conflictRange.canBeSet()) { + conflictRange.send(std::make_pair(Key(), Key())); + } + + throw; + } +} + Future> getRange( Database const& cx, Future const& fVersion, KeySelector const& begin, KeySelector const& end, GetRangeLimits const& limits, bool const& reverse, TransactionInfo const& info, TagSet const& tags ) { @@ -2967,6 +3196,61 @@ Future< Standalone > Transaction::getRange( return getRange( begin, end, GetRangeLimits( limit ), snapshot, reverse ); } +Future Transaction::getRangeStream( + const PromiseStream>& results, + const KeySelector& begin, + const KeySelector& end, + GetRangeLimits limits, + bool snapshot, + bool reverse ) +{ + ++cx->transactionLogicalReads; + ++cx->transactionGetRangeRequests; + + if( limits.isReached() ) + return Standalone(); + + if( !limits.isValid() ) + return range_limits_invalid(); + + ASSERT(limits.rows != 0); + + KeySelector b = begin; + if( b.orEqual ) { + TEST(true); // Native begin orEqual==true + b.removeOrEqual(b.arena()); + } + + KeySelector e = end; + if( e.orEqual ) { + TEST(true); // Native end orEqual==true + e.removeOrEqual(e.arena()); + } + + if( b.offset >= e.offset && b.getKey() >= e.getKey() ) { + TEST(true); // Native range inverted + return Standalone(); + } + + Promise> conflictRange; + if(!snapshot) { + extraConflictRanges.push_back( conflictRange.getFuture() ); + } + + return forwardErrors(::getRangeStream(results, cx, trLogInfo, getReadVersion(), b, e, limits, conflictRange, snapshot, reverse, info, options.readTags), results); +} + +Future Transaction::getRangeStream( + const PromiseStream>& results, + const KeySelector& begin, + const KeySelector& end, + int limit, + bool snapshot, + bool reverse ) +{ + return getRangeStream( results, begin, end, GetRangeLimits( limit ), snapshot, reverse ); +} + void Transaction::addReadConflictRange( KeyRangeRef const& keys ) { ASSERT( !keys.empty() ); diff --git a/fdbclient/NativeAPI.actor.h b/fdbclient/NativeAPI.actor.h index 323d5af550f..10802ccfff5 100644 --- a/fdbclient/NativeAPI.actor.h +++ b/fdbclient/NativeAPI.actor.h @@ -253,6 +253,22 @@ class Transaction : NonCopyable { KeySelector(firstGreaterOrEqual(keys.end), keys.arena()), limits, snapshot, reverse); } + [[nodiscard]] Future getRangeStream(const PromiseStream>& results, const KeySelector& begin, const KeySelector& end, + int limit, bool snapshot = false, bool reverse = false); + [[nodiscard]] Future getRangeStream(const PromiseStream>& results, const KeySelector& begin, const KeySelector& end, + GetRangeLimits limits, bool snapshot = false, + bool reverse = false); + [[nodiscard]] Future getRangeStream(const PromiseStream>& results, const KeyRange& keys, int limit, bool snapshot = false, + bool reverse = false) { + return getRangeStream(results, KeySelector(firstGreaterOrEqual(keys.begin), keys.arena()), + KeySelector(firstGreaterOrEqual(keys.end), keys.arena()), limit, snapshot, reverse); + } + [[nodiscard]] Future getRangeStream(const PromiseStream>& results, const KeyRange& keys, GetRangeLimits limits, + bool snapshot = false, bool reverse = false) { + return getRangeStream(results, KeySelector(firstGreaterOrEqual(keys.begin), keys.arena()), + KeySelector(firstGreaterOrEqual(keys.end), keys.arena()), limits, snapshot, reverse); + } + [[nodiscard]] Future>> getAddressesForKey(const Key& key); void enableCheckWrites(); diff --git a/fdbclient/StorageServerInterface.h b/fdbclient/StorageServerInterface.h index bc340727fd7..f10c573bf3a 100644 --- a/fdbclient/StorageServerInterface.h +++ b/fdbclient/StorageServerInterface.h @@ -73,6 +73,7 @@ struct StorageServerInterface { RequestStream watchValue; RequestStream getReadHotRanges; RequestStream getRangeSplitPoints; + RequestStream getKeyValuesStream; explicit StorageServerInterface(UID uid) : uniqueID( uid ) {} StorageServerInterface() : uniqueID( deterministicRandom()->randomUniqueID() ) {} @@ -101,6 +102,7 @@ struct StorageServerInterface { watchValue = RequestStream( getValue.getEndpoint().getAdjustedEndpoint(10) ); getReadHotRanges = RequestStream( getValue.getEndpoint().getAdjustedEndpoint(11) ); getRangeSplitPoints = RequestStream(getValue.getEndpoint().getAdjustedEndpoint(12)); + getKeyValuesStream = RequestStream(getValue.getEndpoint().getAdjustedEndpoint(13)); } } else { ASSERT(Ar::isDeserializing); @@ -129,6 +131,7 @@ struct StorageServerInterface { streams.push_back(watchValue.getReceiver()); streams.push_back(getReadHotRanges.getReceiver()); streams.push_back(getRangeSplitPoints.getReceiver()); + streams.push_back(getKeyValuesStrean.getReceiver(TaskPriority::LoadBalancedEndpoint)); FlowTransport::transport().addEndpoints(streams); } }; @@ -260,6 +263,43 @@ struct GetKeyValuesRequest : TimedRequest { } }; +struct GetKeyValuesStreamReply : public ReplyPromiseStreamReply { + constexpr static FileIdentifier file_identifier = 1783066; + Arena arena; + VectorRef data; + Version version; // useful when latestVersion was requested + bool more; + bool cached = false; + + GetKeyValuesStreamReply() : version(invalidVersion), more(false), cached(false) {} + + int expectedSize() const { return sizeof(GetKeyValuesStreamReply) + data.expectedSize(); } + + template + void serialize( Ar& ar ) { + serializer(ar, ReplyPromiseStreamReply::acknowledgeEndpoint, data, version, more, cached, arena); + } +}; + +struct GetKeyValuesStreamRequest { + constexpr static FileIdentifier file_identifier = 6795746; + SpanID spanContext; + Arena arena; + KeySelectorRef begin, end; + Version version; // or latestVersion + int limit, limitBytes; + bool isFetchKeys; + Optional tags; + Optional debugID; + ReplyPromiseStream reply; + + GetKeyValuesStreamRequest() : isFetchKeys(false) {} + template + void serialize( Ar& ar ) { + serializer(ar, begin, end, version, limit, limitBytes, isFetchKeys, tags, debugID, reply, spanContext, arena); + } +}; + struct GetKeyReply : public LoadBalancedReply { constexpr static FileIdentifier file_identifier = 11226513; KeySelector sel; diff --git a/fdbrpc/FlowTransport.h b/fdbrpc/FlowTransport.h index 58b67e5d696..62bcd65a583 100644 --- a/fdbrpc/FlowTransport.h +++ b/fdbrpc/FlowTransport.h @@ -66,7 +66,7 @@ class Endpoint { return addresses.getTLSAddress(); } - Endpoint getAdjustedEndpoint( uint32_t index ) { + Endpoint getAdjustedEndpoint( uint32_t index ) const { uint32_t newIndex = token.second(); newIndex += index; return Endpoint( addresses, UID(token.first()+(uint64_t(index)<<32), (token.second()&0xffffffff00000000LL) | newIndex) ); diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index 489cd6617f9..6096b9a4733 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -73,6 +73,10 @@ struct FlowReceiver : public NetworkMessageReceiver { FlowTransport::transport().addWellKnownEndpoint(endpoint, this, taskID); } + const Endpoint& getRawEndpoint() { + return endpoint; + } + private: Endpoint endpoint; bool m_isLocalEndpoint; @@ -96,6 +100,9 @@ struct NetSAV final : SAV, FlowReceiver, FastAllocated> { ErrorOr> message; reader.deserialize(message); if (message.isError()) { + if(message.getError().code() == error_code_broken_promise) { + IFailureMonitor::failureMonitor().endpointNotFound( getRawEndpoint() ); + } SAV::sendErrorAndDelPromiseRef(message.getError()); } else { SAV::sendAndDelPromiseRef(message.get().asUnderlyingType()); @@ -189,8 +196,6 @@ struct serializable_traits> : std::true_type { template ReplyPromise const& getReplyPromise(ReplyPromise const& p) { return p; } - - template void resetReply(Request& r) { r.reply.reset(); } @@ -212,6 +217,283 @@ void setReplyPriority(ReplyPromise & p, TaskPriority taskID) { p.getEndpo template void setReplyPriority(const ReplyPromise & p, TaskPriority taskID) { p.getEndpoint(taskID); } +struct ReplyPromiseStreamReply { + Optional acknowledgeEndpoint; + ReplyPromiseStreamReply() {} +}; + +struct AcknowledgementReply { + constexpr static FileIdentifier file_identifier = 1378929; + int64_t bytes; + + AcknowledgementReply() : bytes(0) {} + explicit AcknowledgementReply(int64_t bytes) : bytes(bytes) {} + + template + void serialize( Ar& ar ) { + serializer(ar, bytes); + } +}; + +struct AcknowledgementReceiver final : FlowReceiver, FastAllocated { + using FastAllocated::operator new; + using FastAllocated::operator delete; + + int64_t bytesSent; + int64_t bytesAcknowledged; + Promise ready; + + AcknowledgementReceiver() : bytesSent(0), bytesAcknowledged(0), ready(nullptr) {} + AcknowledgementReceiver(const Endpoint& remoteEndpoint) : FlowReceiver(remoteEndpoint, false), + bytesSent(0), bytesAcknowledged(0), ready(nullptr) {} + + void receive(ArenaObjectReader& reader) override { + ErrorOr> message; + reader.deserialize(message); + ASSERT(!message.isError() && message.get().asUnderlyingType().bytes > bytesAcknowledged); + bytesAcknowledged = message.get().asUnderlyingType().bytes; + if(queue->acknowledgements.bytesSent - queue->acknowledgements.bytesAcknowledged < 2e6) { + queue->acknowledgements.ready.send(Void()); + } + } +}; + +template +struct NetNotifiedQueueWithErrors final : private SingleCallback, public FlowReceiver, FastAllocated> { + using FastAllocated>::operator new; + using FastAllocated>::operator delete; + + int promises; // one for each promise (and one for an active actor if this is an actor) + int futures; // one for each future and one more if there are any callbacks + + // Invariant: SingleCallback::next==this || (queue.empty() && !error.isValid()) + std::queue> queue; + Error error; + AcknowledgementReceiver acknowledgements; + + NetNotifiedQueueWithErrors(int futures, int promises) : futures(futures), promises(promises), { + SingleCallback::next = this; + } + NetNotifiedQueueWithErrors(int futures, int promises, const Endpoint& remoteEndpoint) + : futures(futures), promises(promises), FlowReceiver(remoteEndpoint, false) { + SingleCallback::next = this; + } + + void receive(ArenaObjectReader& reader) override { + this->addPromiseRef(); + ErrorOr> message; + reader.deserialize(message); + + if (message.isError()) { + if(message.getError().code() == error_code_broken_promise) { + IFailureMonitor::failureMonitor().endpointNotFound( getRawEndpoint() ); + } + this->sendError(message.getError()); + } else { + if(message.get().asUnderlyingType().acknowledgeEndpoint.present()) { + acknowledgements = AcknowledgementReceiver(message.get().asUnderlyingType().acknowledgeEndpoint.get()); + } + this->send(std::move(message.get().asUnderlyingType())); + } + this->delPromiseRef(); + } + + bool isReady() const { return !queue.empty() || error.isValid(); } + bool isError() const { return queue.empty() && error.isValid(); } // the *next* thing queued is an error + uint32_t size() const { return queue.size(); } + + T pop() { + if (queue.empty()) { + if (error.isValid()) throw error; + throw internal_error(); + } + auto copy = std::move(queue.front()); + if(acknowledgements.getRawEndpoint().isValid()) { + acknowledgements.bytesAcknowledged += copy.expectedSize(); + FlowTransport::transport().sendUnreliable(SerializeSource(AcknowledgementReply(acknowledgements.bytesAcknowledged)), acknowledgements.getEndpoint(), true); + } + queue.pop(); + return copy; + } + + template + void send(U && value) { + if (error.isValid()) return; + + if (SingleCallback::next != this) { + SingleCallback::next->fire(std::forward(value)); + } + else { + queue.emplace(std::forward(value)); + } + } + + void sendError(Error err) { + if (error.isValid()) return; + + this->error = err; + if (SingleCallback::next != this) + SingleCallback::next->error(err); + } + + void addPromiseRef() { promises++; } + void addFutureRef() { futures++; } + + void delPromiseRef() { + if (!--promises) { + if (futures) { + sendError(broken_promise()); + } + else + destroy(); + } + } + void delFutureRef() { + if (!--futures) { + if (promises) + cancel(); + else + destroy(); + } + } + + int getFutureReferenceCount() const { return futures; } + int getPromiseReferenceCount() const { return promises; } + + virtual void destroy() { delete this; } + virtual void cancel() {} + + void addCallbackAndDelFutureRef(SingleCallback* cb) { + ASSERT(SingleCallback::next == this); + cb->insert(this); + } + virtual void unwait() override { delFutureRef(); } + virtual void fire(T const&) override { ASSERT(false); } + virtual void fire(T&&) override { ASSERT(false); } +}; + +template +class ReplyPromiseStream { +public: + // stream.send( request ) + // Unreliable at most once delivery: Delivers request unless there is a connection failure (zero or one times) + + template + void send(U && value) const { + if (queue->isRemoteEndpoint()) { + if(!queue->acknowledgements.getRawEndpoint().isValid()) { + value.acknowledgeEndpoint = queue->acknowledgements.getEndpoint(); + } + queue->acknowledgements.bytesSent += value.expectedSize(); + if((!queue->acknowledgements.ready.isValid() || queue->acknowledgements.ready.isSet()) && queue->acknowledgements.bytesSent - queue->acknowledgements.bytesAcknowledged >= 2e6) { + queue->acknowledgements.ready = Promise(); + } + FlowTransport::transport().sendUnreliable(SerializeSource(std::forward(value)), getEndpoint(), true); + } + else + queue->send(std::forward(value)); + } + + template + void sendError(const E& exc) const { + queue->sendError(exc); + if(errors && errors->canBeSet()) { + errors->sendError(exc); + } + } + + FutureStream getFuture() const { queue->addFutureRef(); return FutureStream(queue); } + ReplyPromiseStream() : queue(new NetNotifiedQueueWithErrors(0, 1)), errors(new SAV(0, 1)) {} + ReplyPromiseStream(const ReplyPromiseStream& rhs) : queue(rhs.queue), errors(rhs.errors) { + queue->addPromiseRef(); + if(errors) { + errors->addPromiseRef(); + } + } + ReplyPromiseStream(ReplyPromiseStream&& rhs) noexcept : queue(rhs.queue), errors(rhs.errors) { rhs.queue = nullptr; rhs.errors = nullptr; } + explicit ReplyPromiseStream(const Endpoint& endpoint) : queue(new NetNotifiedQueueWithErrors(0, 1, endpoint)), errors(nullptr) {} + + Future getErrorFutureAndDelPromiseRef() { + ASSERT(errors && errors->getPromiseReferenceCount() > 1); + errors->addFutureRef(); + errors->delPromiseRef(); + return Future(errors); + } + + ~ReplyPromiseStream() { + if (queue) + queue->delPromiseRef(); + if (errors) + errors->delPromiseRef(); + } + + const Endpoint& getEndpoint(TaskPriority taskID = TaskPriority::DefaultEndpoint) const { return queue->getEndpoint(taskID); } + + bool operator == (const ReplyPromiseStream& rhs) const { return queue == rhs.queue; } + bool isEmpty() const { return !queue->isReady(); } + uint32_t size() const { return queue->size(); } + + Future onReady() { + if(queue->acknowledgements.bytesSent - queue->acknowledgements.bytesAcknowledged < 2e6) { + return Void(); + } + return queue->acknowledgements.ready.getFuture(); + } + + void operator=(const ReplyPromiseStream& rhs) { + rhs.queue->addPromiseRef(); + if (queue) queue->delPromiseRef(); + queue = rhs.queue; + if(rhs.errors) rhs.errors->addPromiseRef(); + if (errors) errors->delPromiseRef(); + errors = rhs.errors; + } + void operator=(ReplyPromiseStream&& rhs) noexcept { + if (queue != rhs.queue) { + if (queue) queue->delPromiseRef(); + queue = rhs.queue; + rhs.queue = 0; + } + if (errors != rhs.errors) { + if (errors) errors->delPromiseRef(); + errors = rhs.errors; + rhs.errors = 0; + } + } + +private: + NetNotifiedQueueWithErrors* queue; + SAV* errors; +}; + +template +void save(Ar& ar, const ReplyPromiseStream& value) { + auto const& ep = value.getEndpoint(); + ar << ep; +} + +template +void load(Ar& ar, ReplyPromiseStream& value) { + Endpoint endpoint; + ar >> endpoint; + value = ReplyPromiseStream(endpoint); +} + +template +struct serializable_traits> : std::true_type { + template + static void serialize(Archiver& ar, ReplyPromiseStream& stream) { + if constexpr (Archiver::isDeserializing) { + Endpoint endpoint; + serializer(ar, endpoint); + stream = ReplyPromiseStream(endpoint); + } else { + const auto& ep = stream.getEndpoint(); + serializer(ar, ep); + } + } +}; + template struct NetNotifiedQueue final : NotifiedQueue, FlowReceiver, FastAllocated> { using FastAllocated>::operator new; @@ -322,6 +604,47 @@ class RequestStream { } } + //FIXME comment + + template + FutureStream getReplyStream(const X& value, TaskPriority taskID) const { + setReplyPriority(value, taskID); + if (queue->isRemoteEndpoint()) { + Future disc = makeDependent(IFailureMonitor::failureMonitor()).onDisconnectOrFailure(getEndpoint(taskID)); + auto& p = getReplyPromiseStream(value); + if (disc.isReady()) { + p.sendError(request_maybe_delivered()); + return p.getFuture(); + } + Reference peer = FlowTransport::transport().sendUnreliable(SerializeSource(value), getEndpoint(taskID), true); + endStreamOnDisconnect(disc, p, peer); + return p.getFuture(); + } + send(value); + auto& p = getReplyPromiseStream(value); + return p.getFuture(); + } + + template + FutureStream getReplyStream(const X& value) const { + if (queue->isRemoteEndpoint()) { + Future disc = makeDependent(IFailureMonitor::failureMonitor()).onDisconnectOrFailure(getEndpoint()); + auto& p = getReplyPromiseStream(value); + if (disc.isReady()) { + p.sendError(request_maybe_delivered()); + return p.getFuture(); + } + Reference peer = FlowTransport::transport().sendUnreliable(SerializeSource(value), getEndpoint(), true); + endStreamOnDisconnect(disc, p, peer) + return p.getFuture(); + } + else { + send(value); + auto& p = getReplyPromiseStream(value); + return p.getFuture(); + } + } + // stream.getReplyUnlessFailedFor( request, double sustainedFailureDuration, double sustainedFailureSlope ) // Reliable at least once delivery: Like getReply, delivers request at least once and returns one of the replies. However, if // the failure detector considers the endpoint failed permanently or for the given amount of time, returns failure instead. @@ -374,7 +697,7 @@ class RequestStream { //queue = (NetNotifiedQueue*)0xdeadbeef; } - Endpoint getEndpoint(TaskPriority taskID = TaskPriority::DefaultEndpoint) const { return queue->getEndpoint(taskID); } + const Endpoint& getEndpoint(TaskPriority taskID = TaskPriority::DefaultEndpoint) const { return queue->getEndpoint(taskID); } void makeWellKnownEndpoint(Endpoint::Token token, TaskPriority taskID) { queue->makeWellKnownEndpoint(token, taskID); } diff --git a/fdbrpc/genericactors.actor.h b/fdbrpc/genericactors.actor.h index d5c39df1a48..d3e6dd9ab46 100644 --- a/fdbrpc/genericactors.actor.h +++ b/fdbrpc/genericactors.actor.h @@ -192,6 +192,21 @@ struct PeerHolder { } }; +// Implements getRepyStream +ACTOR template +void endStreamOnDisconnect( Future signal, ReplyPromiseStream stream, Reference peer = Reference() ) { + state PeerHolder holder = PeerHolder(peer); + choose { + when(wait(signal)) { + stream.sendError(request_maybe_delivered()); + } + when(wait(stream.getErrorFutureAndDelPromiseRef())) {} + } + return Void(); +} + + + // Implements tryGetReply, getReplyUnlessFailedFor ACTOR template Future> waitValueOrSignal( Future value, Future signal, Endpoint endpoint, ReplyPromise holdme = ReplyPromise(), Reference peer = Reference() ) { @@ -211,12 +226,8 @@ Future> waitValueOrSignal( Future value, Future signal, Endp if( e.code() == error_code_actor_cancelled ) throw e; - // broken_promise error normally means an endpoint failure, which in tryGetReply has the same semantics as receiving the failure signal - if (e.code() != error_code_broken_promise || signal.isError()) - return ErrorOr(e); - - IFailureMonitor::failureMonitor().endpointNotFound( endpoint ); - value = Never(); + ASSERT(e.code() != error_code_broken_promise); + return ErrorOr(e); } } } diff --git a/fdbserver/storageserver.actor.cpp b/fdbserver/storageserver.actor.cpp index 3b1866a581b..e8fda37615c 100644 --- a/fdbserver/storageserver.actor.cpp +++ b/fdbserver/storageserver.actor.cpp @@ -531,7 +531,7 @@ struct StorageServer { struct Counters { CounterCollection cc; - Counter allQueries, getKeyQueries, getValueQueries, getRangeQueries, finishedQueries, rowsQueried, bytesQueried, watchQueries, emptyQueries; + Counter allQueries, getKeyQueries, getValueQueries, getRangeQueries, getRangeStreamQueries, finishedQueries, rowsQueried, bytesQueried, watchQueries, emptyQueries; Counter bytesInput, bytesDurable, bytesFetched, mutationBytes; // Like bytesInput but without MVCC accounting Counter sampledBytesCleared; @@ -549,6 +549,7 @@ struct StorageServer { getKeyQueries("GetKeyQueries", cc), getValueQueries("GetValueQueries",cc), getRangeQueries("GetRangeQueries", cc), + getRangeStreamQueries("GetRangeStreamQueries", cc), allQueries("QueryQueue", cc), finishedQueries("FinishedQueries", cc), rowsQueried("RowsQueried", cc), @@ -1640,6 +1641,195 @@ ACTOR Future getKeyValuesQ( StorageServer* data, GetKeyValuesRequest req ) return Void(); } +ACTOR Future getKeyValuesStreamQ( StorageServer* data, GetKeyValuesStreamRequest req ) +{ + Future disc = IFailureMonitor::failureMonitor().onDisconnectOrFailure(req.reply.getEndpoint()); + Future work = getKeyValuesStreamWork( data, req ); + choose { + when(wait(disc)) { + req.reply.sendError(end_of_stream()); + } + when(wait(work)) {} + } + return Void(); +} + +ACTOR Future getKeyValuesStreamWork( StorageServer* data, GetKeyValuesStreamRequest req ) +// Throws a wrong_shard_server if the keys in the request or result depend on data outside this server OR if a large selector offset prevents +// all data from being read in one range read +{ + state Span span("SS:getKeyValuesStream"_loc, { req.spanContext }); + state int64_t resultSize = 0; + + ++data->counters.getRangeStreamQueries; + ++data->counters.allQueries; + ++data->readQueueSizeMetric; + data->maxQueryQueue = std::max( data->maxQueryQueue, data->counters.allQueries.getValue() - data->counters.finishedQueries.getValue()); + + // Active load balancing runs at a very high priority (to obtain accurate queue lengths) + // so we need to downgrade here + if (SERVER_KNOBS->FETCH_KEYS_LOWER_PRIORITY && req.isFetchKeys) { + wait( delay(0, TaskPriority::FetchKeys) ); + } else { + wait( delay(0, TaskPriority::DefaultEndpoint) ); + } + + try { + if( req.debugID.present() ) + g_traceBatch.addEvent("TransactionDebug", req.debugID.get().first(), "storageserver.getKeyValues.Before"); + state Version version = wait( waitForVersion( data, req.version, span.context ) ); + + state uint64_t changeCounter = data->shardChangeCounter; +// try { + state KeyRange shard = getShardKeyRange( data, req.begin ); + + if( req.debugID.present() ) + g_traceBatch.addEvent("TransactionDebug", req.debugID.get().first(), "storageserver.getKeyValues.AfterVersion"); + //.detail("ShardBegin", shard.begin).detail("ShardEnd", shard.end); + //} catch (Error& e) { TraceEvent("WrongShardServer", data->thisServerID).detail("Begin", req.begin.toString()).detail("End", req.end.toString()).detail("Version", version).detail("Shard", "None").detail("In", "getKeyValues>getShardKeyRange"); throw e; } + + if ( !selectorInRange(req.end, shard) && !(req.end.isFirstGreaterOrEqual() && req.end.getKey() == shard.end) ) { +// TraceEvent("WrongShardServer1", data->thisServerID).detail("Begin", req.begin.toString()).detail("End", req.end.toString()).detail("Version", version).detail("ShardBegin", shard.begin).detail("ShardEnd", shard.end).detail("In", "getKeyValues>checkShardExtents"); + throw wrong_shard_server(); + } + + state int offset1; + state int offset2; + state Future fBegin = req.begin.isFirstGreaterOrEqual() + ? Future(req.begin.getKey()) + : findKey(data, req.begin, version, shard, &offset1, span.context); + state Future fEnd = req.end.isFirstGreaterOrEqual() + ? Future(req.end.getKey()) + : findKey(data, req.end, version, shard, &offset2, span.context); + state Key begin = wait(fBegin); + state Key end = wait(fEnd); + if( req.debugID.present() ) + g_traceBatch.addEvent("TransactionDebug", req.debugID.get().first(), "storageserver.getKeyValues.AfterKeys"); + //.detail("Off1",offset1).detail("Off2",offset2).detail("ReqBegin",req.begin.getKey()).detail("ReqEnd",req.end.getKey()); + + // Offsets of zero indicate begin/end keys in this shard, which obviously means we can answer the query + // An end offset of 1 is also OK because the end key is exclusive, so if the first key of the next shard is the end the last actual key returned must be from this shard. + // A begin offset of 1 is also OK because then either begin is past end or equal to end (so the result is definitely empty) + if ((offset1 && offset1!=1) || (offset2 && offset2!=1)) { + TEST(true); // wrong_shard_server due to offset + // We could detect when offset1 takes us off the beginning of the database or offset2 takes us off the end, and return a clipped range rather + // than an error (since that is what the NativeAPI.getRange will do anyway via its "slow path"), but we would have to add some flags to the response + // to encode whether we went off the beginning and the end, since it needs that information. + //TraceEvent("WrongShardServer2", data->thisServerID).detail("Begin", req.begin.toString()).detail("End", req.end.toString()).detail("Version", version).detail("ShardBegin", shard.begin).detail("ShardEnd", shard.end).detail("In", "getKeyValues>checkOffsets").detail("BeginKey", begin).detail("EndKey", end).detail("BeginOffset", offset1).detail("EndOffset", offset2); + throw wrong_shard_server(); + } + + if (begin >= end) { + if( req.debugID.present() ) + g_traceBatch.addEvent("TransactionDebug", req.debugID.get().first(), "storageserver.getKeyValues.Send"); + //.detail("Begin",begin).detail("End",end); + + GetKeyValuesReply none; + none.version = version; + none.more = false; + + data->checkChangeCounter( changeCounter, KeyRangeRef( std::min(req.begin.getKey(), req.end.getKey()), std::max(req.begin.getKey(), req.end.getKey()) ) ); + req.reply.send( none ); + req.reply.sendError( end_of_stream() ); + } else { + state int remainingLimitBytes = req.limitBytes; + loop { + wait(req.reply.onReady()); + GetKeyValuesReply _r = wait( readRange(data, version, KeyRangeRef(begin, end), req.limit, &remainingLimitBytes, span.context) ); + GetKeyValuesReply r = _r; + + if( req.debugID.present() ) + g_traceBatch.addEvent("TransactionDebug", req.debugID.get().first(), "storageserver.getKeyValues.AfterReadRange"); + //.detail("Begin",begin).detail("End",end).detail("SizeOf",r.data.size()); + data->checkChangeCounter( changeCounter, KeyRangeRef( std::min(begin, std::min(req.begin.getKey(), req.end.getKey())), std::max(end, std::max(req.begin.getKey(), req.end.getKey())) ) ); + if (EXPENSIVE_VALIDATION) { + for (int i = 0; i < r.data.size(); i++) + ASSERT(r.data[i].key >= begin && r.data[i].key < end); + ASSERT(r.data.size() <= std::abs(req.limit)); + } + + /*for( int i = 0; i < r.data.size(); i++ ) { + StorageMetrics m; + m.bytesPerKSecond = r.data[i].expectedSize(); + m.iosPerKSecond = 1; //FIXME: this should be 1/r.data.size(), but we cannot do that because it is an int + data->metrics.notify(r.data[i].key, m); + }*/ + + // For performance concerns, the cost of a range read is billed to the start key and end key of the range. + int64_t totalByteSize = 0; + for (int i = 0; i < r.data.size(); i++) { + totalByteSize += r.data[i].expectedSize(); + } + if (totalByteSize > 0 && SERVER_KNOBS->READ_SAMPLING_ENABLED) { + int64_t bytesReadPerKSecond = std::max(totalByteSize, SERVER_KNOBS->EMPTY_READ_PENALTY) / 2; + data->metrics.notifyBytesReadPerKSecond(r.data[0].key, bytesReadPerKSecond); + data->metrics.notifyBytesReadPerKSecond(r.data[r.data.size() - 1].key, bytesReadPerKSecond); + } + + r.penalty = data->getPenalty(); + req.reply.send( r ); + + resultSize = req.limitBytes - remainingLimitBytes; + data->counters.bytesQueried += resultSize; + data->counters.rowsQueried += r.data.size(); + if(r.data.size() == 0) { + ++data->counters.emptyQueries; + } + if(!r.more) { + req.reply.sendError(end_of_stream()); + break; + } + + if(req.limit >= 0) { + begin = keyAfter(r.data.back().key); + } else { + end = r.data.back(); + } + + if (SERVER_KNOBS->FETCH_KEYS_LOWER_PRIORITY && req.isFetchKeys) { + wait( delay(0, TaskPriority::FetchKeys) ); + } else { + wait( delay(0, TaskPriority::DefaultEndpoint) ); + } + + data->transactionTagCounter.addRequest(req.tags, resultSize); + + //FIXME: figure out what to do with latency measurements + //double duration = g_network->timer() - req.requestTime(); + //data->counters.readLatencySample.addMeasurement(duration); + //if(data->latencyBandConfig.present()) { + // int maxReadBytes = data->latencyBandConfig.get().readConfig.maxReadBytes.orDefault(std::numeric_limits::max()); + // int maxSelectorOffset = data->latencyBandConfig.get().readConfig.maxKeySelectorOffset.orDefault(std::numeric_limits::max()); + // data->counters.readLatencyBands.addMeasurement( + // duration, resultSize > maxReadBytes || abs(req.begin.offset) > maxSelectorOffset || + // abs(req.end.offset) > maxSelectorOffset); + //} + } + } + } catch (Error& e) { + if(!canReplyWith(e)) + throw; + req.reply.sendError(e); + } + + data->transactionTagCounter.addRequest(req.tags, resultSize); + ++data->counters.finishedQueries; + --data->readQueueSizeMetric; + + //FIXME: figure out what to do with latency measurements + //double duration = g_network->timer() - req.requestTime(); + //data->counters.readLatencySample.addMeasurement(duration); + //if(data->latencyBandConfig.present()) { + // int maxReadBytes = data->latencyBandConfig.get().readConfig.maxReadBytes.orDefault(std::numeric_limits::max()); + // int maxSelectorOffset = data->latencyBandConfig.get().readConfig.maxKeySelectorOffset.orDefault(std::numeric_limits::max()); + // data->counters.readLatencyBands.addMeasurement( + // duration, resultSize > maxReadBytes || abs(req.begin.offset) > maxSelectorOffset || + // abs(req.end.offset) > maxSelectorOffset); + //} + + return Void(); +} + ACTOR Future getKeyQ( StorageServer* data, GetKeyRequest req ) { state Span span("SS:getKey"_loc, { req.spanContext }); state int64_t resultSize = 0; @@ -2057,35 +2247,39 @@ ACTOR Future> tryGetRange( Database cx, Version versi try { loop { - Standalone rep = wait( tr.getRange( begin, end, limits, true ) ); - limits.decrement( rep ); + state PromiseStream> results; + state Future hold = tr.getRangeStream(results, begin, end, limits, true); + loop { + Standalone rep = waitNext( results.getFuture() ); + limits.decrement( rep ); + + if( limits.isReached() || !rep.more ) { + if( output.size() ) { + output.arena().dependsOn( rep.arena() ); + output.append( output.arena(), rep.begin(), rep.size() ); + if( limits.isReached() && rep.readThrough.present() ) + output.readThrough = rep.readThrough.get(); + } else { + output = rep; + } - if( limits.isReached() || !rep.more ) { - if( output.size() ) { + output.more = limits.isReached(); + + return output; + } else if( rep.readThrough.present() ) { output.arena().dependsOn( rep.arena() ); - output.append( output.arena(), rep.begin(), rep.size() ); - if( limits.isReached() && rep.readThrough.present() ) - output.readThrough = rep.readThrough.get(); + if( rep.size() ) { + output.append( output.arena(), rep.begin(), rep.size() ); + ASSERT( rep.readThrough.get() > rep.end()[-1].key ); + } else { + ASSERT( rep.readThrough.get() > keys.begin ); + } + begin = firstGreaterOrEqual( rep.readThrough.get() ); } else { - output = rep; - } - - output.more = limits.isReached(); - - return output; - } else if( rep.readThrough.present() ) { - output.arena().dependsOn( rep.arena() ); - if( rep.size() ) { + output.arena().dependsOn( rep.arena() ); output.append( output.arena(), rep.begin(), rep.size() ); - ASSERT( rep.readThrough.get() > rep.end()[-1].key ); - } else { - ASSERT( rep.readThrough.get() > keys.begin ); + begin = firstGreaterThan( output.end()[-1].key ); } - begin = firstGreaterOrEqual( rep.readThrough.get() ); - } else { - output.arena().dependsOn( rep.arena() ); - output.append( output.arena(), rep.begin(), rep.size() ); - begin = firstGreaterThan( output.end()[-1].key ); } } } catch( Error &e ) { @@ -2217,6 +2411,7 @@ ACTOR Future fetchKeys( StorageServer *data, AddingShard* shard ) { try { TEST(true); // Fetching keys for transferred shard + //FIXME: this is inefficient because we are restarting the getRangeStreaming for every block state Standalone this_block = wait(tryGetRange(data->cx, fetchVersion, keys, GetRangeLimits(GetRangeLimits::ROW_LIMIT_UNLIMITED, fetchBlockBytes), &isTooOld)); @@ -3771,6 +3966,15 @@ ACTOR Future serveGetKeyValuesRequests( StorageServer* self, FutureStream< } } +ACTOR Future serveGetKeyValuesStreamRequests( StorageServer* self, FutureStream getKeyValuesStream ) { + loop { + GetKeyValuesStreamRequest req = waitNext(getKeyValuesStream); + // Warning: This code is executed at extremely high priority (TaskPriority::LoadBalancedEndpoint), so downgrade before doing real work + //FIXME: add readGuard again + self->actors.add(getKeyValuesStreamQ(self, req)); + } +} + ACTOR Future serveGetKeyRequests( StorageServer* self, FutureStream getKey ) { loop { GetKeyRequest req = waitNext(getKey); @@ -3805,6 +4009,7 @@ ACTOR Future storageServerCore( StorageServer* self, StorageServerInterfac self->actors.add(checkBehind(self)); self->actors.add(serveGetValueRequests(self, ssi.getValue.getFuture())); self->actors.add(serveGetKeyValuesRequests(self, ssi.getKeyValues.getFuture())); + self->actors.add(serveGetKeyValuesStreamRequests(self, ssi.getKeyValuesStream.getFuture())); self->actors.add(serveGetKeyRequests(self, ssi.getKey.getFuture())); self->actors.add(serveWatchValueRequests(self, ssi.watchValue.getFuture())); self->actors.add(traceRole(Role::STORAGE_SERVER, ssi.id())); diff --git a/flow/flow.h b/flow/flow.h index a72465143d4..b33d525fdc1 100644 --- a/flow/flow.h +++ b/flow/flow.h @@ -884,6 +884,11 @@ decltype(std::declval().reply) const& getReplyPromise(Request const& r) return r.reply; } +template +decltype(std::declval().reply) const& getReplyPromiseStream(Request const& r) { + return r.reply; +} + // Neither of these implementations of REPLY_TYPE() works on both MSVC and g++, so... #ifdef __GNUG__ #define REPLY_TYPE(RequestType) decltype(getReplyPromise(std::declval()).getFuture().getValue()) @@ -903,8 +908,22 @@ struct ReplyType> { #define REPLY_TYPE(RequestType) typename ReplyType::Type #endif - - +// Neither of these implementations of REPLY_TYPE() works on both MSVC and g++, so... +#ifdef __GNUG__ +#define REPLYSTREAM_TYPE(RequestType) decltype(getReplyPromiseStream(std::declval()).getFuture().getValue()) +#else +template +struct ReplyStreamType { + // Doing this calculation directly in the return value declaration for PromiseStream::getReply() + // breaks IntelliSense in VS2010; this is a workaround. + typedef decltype(std::declval().reply.getFuture().getValue()) Type; +}; +template class ReplyPromiseStream; +template +struct ReplyStreamType> { + typedef T Type; +}; +#define REPLYSTREAM_TYPE(RequestType) typename ReplyStreamType::Type template class PromiseStream { diff --git a/flow/genericactors.actor.h b/flow/genericactors.actor.h index 3fcab1f7dd5..cb2f502e529 100644 --- a/flow/genericactors.actor.h +++ b/flow/genericactors.actor.h @@ -1233,6 +1233,16 @@ ACTOR template Future waitOrError(Future f, Future errorSi } } +ACTOR template Future forwardErrors(Future f, PromiseStream output) { + try { + T val = wait(f); + return val; + } catch (Error& e) { + output.sendError(e); + throw; + } +} + struct FlowLock : NonCopyable, public ReferenceCounted { // FlowLock implements a nonblocking critical section: there can be only a limited number of clients executing code between // wait(take()) and release(). Not thread safe. take() returns only when the number of holders of the lock is fewer than the From 91b4ee6d94df44b3f3d8fb66cb833c1aa4e7cb51 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Fri, 4 Dec 2020 20:51:10 -0800 Subject: [PATCH 002/740] fixed compile error --- fdbclient/NativeAPI.actor.cpp | 2 +- fdbrpc/genericactors.actor.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index 0383ae9378b..b8bf5a9bf00 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -2677,7 +2677,7 @@ ACTOR Future getRangeStream( PromiseStream> res state KeySelector originalBegin = begin; state KeySelector originalEnd = end; state Standalone output; - state Span span("NAPI:getRange"_loc, info.spanID); + state Span span("NAPI:getRangeStream"_loc, info.spanID); try { state Version version = wait( fVersion ); diff --git a/fdbrpc/genericactors.actor.h b/fdbrpc/genericactors.actor.h index d3e6dd9ab46..73b9c2712fe 100644 --- a/fdbrpc/genericactors.actor.h +++ b/fdbrpc/genericactors.actor.h @@ -202,7 +202,6 @@ void endStreamOnDisconnect( Future signal, ReplyPromiseStream stream, R } when(wait(stream.getErrorFutureAndDelPromiseRef())) {} } - return Void(); } From 1d28619e27d616bba9539d06a259bd8398ba6198 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Fri, 4 Dec 2020 20:55:41 -0800 Subject: [PATCH 003/740] commented out the NativeAPI getRangeStream actor while getting the rest of the code to compile --- fdbclient/NativeAPI.actor.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index b8bf5a9bf00..83103f4dbd8 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -1700,6 +1700,7 @@ Future> getRange( TransactionInfo const& info, TagSet const& tags); +/* Future getRangeStream( PromiseStream> const& results, Database const& cx, @@ -1710,6 +1711,7 @@ Future getRangeStream( bool const& reverse, TransactionInfo const& info, TagSet const& tags); +*/ ACTOR Future> getValue(Future version, Key key, Database cx, TransactionInfo info, Reference trLogInfo, TagSet tags); @@ -2669,6 +2671,7 @@ ACTOR Future> getRange( Database cx, Reference getRangeStream( PromiseStream> results, Database cx, Reference trLogInfo, Future fVersion, KeySelector begin, KeySelector end, GetRangeLimits limits, Promise> conflictRange, bool snapshot, bool reverse, TransactionInfo info, TagSet tags ) @@ -2747,7 +2750,7 @@ ACTOR Future getRangeStream( PromiseStream> res .detail("ReqVersion", req.version) .detail("Reverse", reverse) .detail("ModifiedSelectors", modifiedSelectors) - .detail("Servers", beginServer.second->description());*/ + .detail("Servers", beginServer.second->description());/ } ++cx->transactionPhysicalReads; @@ -2773,7 +2776,7 @@ ACTOR Future getRangeStream( PromiseStream> res .detail("ReqEndKey", req.end.getKey()) .detail("RepIsMore", rep.more) .detail("VersionReturned", rep.version) - .detail("RowsReturned", rep.data.size());*/ + .detail("RowsReturned", rep.data.size());/ } ASSERT( !rep.more || rep.data.size() ); @@ -2886,6 +2889,7 @@ ACTOR Future getRangeStream( PromiseStream> res throw; } } +*/ Future> getRange( Database const& cx, Future const& fVersion, KeySelector const& begin, KeySelector const& end, GetRangeLimits const& limits, bool const& reverse, TransactionInfo const& info, TagSet const& tags ) @@ -3204,6 +3208,9 @@ Future Transaction::getRangeStream( bool snapshot, bool reverse ) { + return Void(); + + /* ++cx->transactionLogicalReads; ++cx->transactionGetRangeRequests; @@ -3238,6 +3245,7 @@ Future Transaction::getRangeStream( } return forwardErrors(::getRangeStream(results, cx, trLogInfo, getReadVersion(), b, e, limits, conflictRange, snapshot, reverse, info, options.readTags), results); + */ } Future Transaction::getRangeStream( From 481795fde9d966dbcaf88aa015fcf3e399d48691 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Fri, 4 Dec 2020 20:59:03 -0800 Subject: [PATCH 004/740] fixed test macros --- fdbclient/NativeAPI.actor.cpp | 10 +++++----- fdbserver/storageserver.actor.cpp | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index 83103f4dbd8..5fdd2f55817 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -2834,7 +2834,7 @@ ACTOR Future getRangeStream( PromiseStream> res if( !rep.more ) { ASSERT( modifiedSelectors ); - TEST(true); // !GetKeyValuesReply.more and modifiedSelectors in getRange + TEST(true); // !GetKeyValuesReply.more and modifiedSelectors in getRangeStream if( !rep.data.size() ) { Standalone result = wait( getRangeFallback(cx, version, originalBegin, originalEnd, originalLimits, reverse, info, tags ) ); @@ -2847,7 +2847,7 @@ ACTOR Future getRangeStream( PromiseStream> res else begin = firstGreaterOrEqual( shard.end ); } else { - TEST(true); // GetKeyValuesReply.more in getRange + TEST(true); // GetKeyValuesReply.more in getRangeStream if( reverse ) end = firstGreaterOrEqual( output[output.size()-1].key ); else @@ -3224,18 +3224,18 @@ Future Transaction::getRangeStream( KeySelector b = begin; if( b.orEqual ) { - TEST(true); // Native begin orEqual==true + TEST(true); // Native stream begin orEqual==true b.removeOrEqual(b.arena()); } KeySelector e = end; if( e.orEqual ) { - TEST(true); // Native end orEqual==true + TEST(true); // Native stream end orEqual==true e.removeOrEqual(e.arena()); } if( b.offset >= e.offset && b.getKey() >= e.getKey() ) { - TEST(true); // Native range inverted + TEST(true); // Native stream range inverted return Standalone(); } diff --git a/fdbserver/storageserver.actor.cpp b/fdbserver/storageserver.actor.cpp index e8fda37615c..587fa0e9898 100644 --- a/fdbserver/storageserver.actor.cpp +++ b/fdbserver/storageserver.actor.cpp @@ -1711,7 +1711,7 @@ ACTOR Future getKeyValuesStreamWork( StorageServer* data, GetKeyValuesStre // An end offset of 1 is also OK because the end key is exclusive, so if the first key of the next shard is the end the last actual key returned must be from this shard. // A begin offset of 1 is also OK because then either begin is past end or equal to end (so the result is definitely empty) if ((offset1 && offset1!=1) || (offset2 && offset2!=1)) { - TEST(true); // wrong_shard_server due to offset + TEST(true); // wrong_shard_server due to offset in rangeStream // We could detect when offset1 takes us off the beginning of the database or offset2 takes us off the end, and return a clipped range rather // than an error (since that is what the NativeAPI.getRange will do anyway via its "slow path"), but we would have to add some flags to the response // to encode whether we went off the beginning and the end, since it needs that information. From ad9ea11ddca125546b6b3a9a29d68a7e12f3f0c3 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Fri, 4 Dec 2020 21:00:55 -0800 Subject: [PATCH 005/740] missing #endif --- flow/flow.h | 1 + 1 file changed, 1 insertion(+) diff --git a/flow/flow.h b/flow/flow.h index b33d525fdc1..306f04837e3 100644 --- a/flow/flow.h +++ b/flow/flow.h @@ -924,6 +924,7 @@ struct ReplyStreamType> { typedef T Type; }; #define REPLYSTREAM_TYPE(RequestType) typename ReplyStreamType::Type +#endif template class PromiseStream { From d39eb5427dbc6393bf16eebf635acc5cfa3b2cd0 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Fri, 4 Dec 2020 21:04:24 -0800 Subject: [PATCH 006/740] directly reference local variables --- fdbrpc/fdbrpc.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index 6096b9a4733..d1a77c2835f 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -252,8 +252,8 @@ struct AcknowledgementReceiver final : FlowReceiver, FastAllocated bytesAcknowledged); bytesAcknowledged = message.get().asUnderlyingType().bytes; - if(queue->acknowledgements.bytesSent - queue->acknowledgements.bytesAcknowledged < 2e6) { - queue->acknowledgements.ready.send(Void()); + if(bytesSent - bytesAcknowledged < 2e6) { + ready.send(Void()); } } }; From 33d2c60b8c9edceff21dc3672e0b784f44176276 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Fri, 4 Dec 2020 21:07:12 -0800 Subject: [PATCH 007/740] removed extra comma --- fdbrpc/fdbrpc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index d1a77c2835f..9b0c8bc695b 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -271,7 +271,7 @@ struct NetNotifiedQueueWithErrors final : private SingleCallback, public Flow Error error; AcknowledgementReceiver acknowledgements; - NetNotifiedQueueWithErrors(int futures, int promises) : futures(futures), promises(promises), { + NetNotifiedQueueWithErrors(int futures, int promises) : futures(futures), promises(promises) { SingleCallback::next = this; } NetNotifiedQueueWithErrors(int futures, int promises, const Endpoint& remoteEndpoint) From e9336c363354a8c714b5195251898b90b3f1d81a Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Fri, 4 Dec 2020 21:09:49 -0800 Subject: [PATCH 008/740] more fixes --- fdbclient/StorageServerInterface.h | 2 +- fdbrpc/fdbrpc.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fdbclient/StorageServerInterface.h b/fdbclient/StorageServerInterface.h index f10c573bf3a..7efab1fd20b 100644 --- a/fdbclient/StorageServerInterface.h +++ b/fdbclient/StorageServerInterface.h @@ -131,7 +131,7 @@ struct StorageServerInterface { streams.push_back(watchValue.getReceiver()); streams.push_back(getReadHotRanges.getReceiver()); streams.push_back(getRangeSplitPoints.getReceiver()); - streams.push_back(getKeyValuesStrean.getReceiver(TaskPriority::LoadBalancedEndpoint)); + streams.push_back(getKeyValuesStream.getReceiver(TaskPriority::LoadBalancedEndpoint)); FlowTransport::transport().addEndpoints(streams); } }; diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index 9b0c8bc695b..69b25093cca 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -310,7 +310,7 @@ struct NetNotifiedQueueWithErrors final : private SingleCallback, public Flow auto copy = std::move(queue.front()); if(acknowledgements.getRawEndpoint().isValid()) { acknowledgements.bytesAcknowledged += copy.expectedSize(); - FlowTransport::transport().sendUnreliable(SerializeSource(AcknowledgementReply(acknowledgements.bytesAcknowledged)), acknowledgements.getEndpoint(), true); + FlowTransport::transport().sendUnreliable(SerializeSource(AcknowledgementReply(acknowledgements.bytesAcknowledged)), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint), true); } queue.pop(); return copy; @@ -635,7 +635,7 @@ class RequestStream { return p.getFuture(); } Reference peer = FlowTransport::transport().sendUnreliable(SerializeSource(value), getEndpoint(), true); - endStreamOnDisconnect(disc, p, peer) + endStreamOnDisconnect(disc, p, peer); return p.getFuture(); } else { From 43c1822563dbd06badd5210296d5521846cb61a9 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Fri, 4 Dec 2020 21:14:20 -0800 Subject: [PATCH 009/740] fixed definition order --- fdbserver/storageserver.actor.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/fdbserver/storageserver.actor.cpp b/fdbserver/storageserver.actor.cpp index 587fa0e9898..9c6d15a240f 100644 --- a/fdbserver/storageserver.actor.cpp +++ b/fdbserver/storageserver.actor.cpp @@ -1641,19 +1641,6 @@ ACTOR Future getKeyValuesQ( StorageServer* data, GetKeyValuesRequest req ) return Void(); } -ACTOR Future getKeyValuesStreamQ( StorageServer* data, GetKeyValuesStreamRequest req ) -{ - Future disc = IFailureMonitor::failureMonitor().onDisconnectOrFailure(req.reply.getEndpoint()); - Future work = getKeyValuesStreamWork( data, req ); - choose { - when(wait(disc)) { - req.reply.sendError(end_of_stream()); - } - when(wait(work)) {} - } - return Void(); -} - ACTOR Future getKeyValuesStreamWork( StorageServer* data, GetKeyValuesStreamRequest req ) // Throws a wrong_shard_server if the keys in the request or result depend on data outside this server OR if a large selector offset prevents // all data from being read in one range read @@ -1830,6 +1817,19 @@ ACTOR Future getKeyValuesStreamWork( StorageServer* data, GetKeyValuesStre return Void(); } +ACTOR Future getKeyValuesStreamQ( StorageServer* data, GetKeyValuesStreamRequest req ) +{ + Future disc = IFailureMonitor::failureMonitor().onDisconnectOrFailure(req.reply.getEndpoint()); + Future work = getKeyValuesStreamWork( data, req ); + choose { + when(wait(disc)) { + req.reply.sendError(end_of_stream()); + } + when(wait(work)) {} + } + return Void(); +} + ACTOR Future getKeyQ( StorageServer* data, GetKeyRequest req ) { state Span span("SS:getKey"_loc, { req.spanContext }); state int64_t resultSize = 0; From 5179e42d135e13a1d55522aab4ac2287352f34f8 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Fri, 4 Dec 2020 21:19:11 -0800 Subject: [PATCH 010/740] allow begin and end variables to be modified --- fdbserver/storageserver.actor.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fdbserver/storageserver.actor.cpp b/fdbserver/storageserver.actor.cpp index 9c6d15a240f..0d980da9f44 100644 --- a/fdbserver/storageserver.actor.cpp +++ b/fdbserver/storageserver.actor.cpp @@ -1688,8 +1688,9 @@ ACTOR Future getKeyValuesStreamWork( StorageServer* data, GetKeyValuesStre state Future fEnd = req.end.isFirstGreaterOrEqual() ? Future(req.end.getKey()) : findKey(data, req.end, version, shard, &offset2, span.context); - state Key begin = wait(fBegin); - state Key end = wait(fEnd); + wait(success(fBegin) && success(fEnd)); + state Key begin = fBegin.get(); + state Key end = fEnd.get(); if( req.debugID.present() ) g_traceBatch.addEvent("TransactionDebug", req.debugID.get().first(), "storageserver.getKeyValues.AfterKeys"); //.detail("Off1",offset1).detail("Off2",offset2).detail("ReqBegin",req.begin.getKey()).detail("ReqEnd",req.end.getKey()); From 492ec2f348df2f1c5b07c595c9a8fded4af816d9 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Fri, 4 Dec 2020 21:30:07 -0800 Subject: [PATCH 011/740] misdiagnosed the previous compile error --- fdbserver/storageserver.actor.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fdbserver/storageserver.actor.cpp b/fdbserver/storageserver.actor.cpp index 0d980da9f44..91c67a8b4d7 100644 --- a/fdbserver/storageserver.actor.cpp +++ b/fdbserver/storageserver.actor.cpp @@ -1688,9 +1688,8 @@ ACTOR Future getKeyValuesStreamWork( StorageServer* data, GetKeyValuesStre state Future fEnd = req.end.isFirstGreaterOrEqual() ? Future(req.end.getKey()) : findKey(data, req.end, version, shard, &offset2, span.context); - wait(success(fBegin) && success(fEnd)); - state Key begin = fBegin.get(); - state Key end = fEnd.get(); + state Key begin = wait(fBegin); + state Key end = wait(fEnd); if( req.debugID.present() ) g_traceBatch.addEvent("TransactionDebug", req.debugID.get().first(), "storageserver.getKeyValues.AfterKeys"); //.detail("Off1",offset1).detail("Off2",offset2).detail("ReqBegin",req.begin.getKey()).detail("ReqEnd",req.end.getKey()); @@ -1771,7 +1770,7 @@ ACTOR Future getKeyValuesStreamWork( StorageServer* data, GetKeyValuesStre if(req.limit >= 0) { begin = keyAfter(r.data.back().key); } else { - end = r.data.back(); + end = r.data.back().key; } if (SERVER_KNOBS->FETCH_KEYS_LOWER_PRIORITY && req.isFetchKeys) { From 52448b0077c3a984ef6e8173093511942e3ffb69 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Fri, 4 Dec 2020 21:40:42 -0800 Subject: [PATCH 012/740] sent the wrong reply type --- fdbclient/StorageServerInterface.h | 1 + fdbserver/storageserver.actor.cpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/fdbclient/StorageServerInterface.h b/fdbclient/StorageServerInterface.h index 7efab1fd20b..447013311e1 100644 --- a/fdbclient/StorageServerInterface.h +++ b/fdbclient/StorageServerInterface.h @@ -272,6 +272,7 @@ struct GetKeyValuesStreamReply : public ReplyPromiseStreamReply { bool cached = false; GetKeyValuesStreamReply() : version(invalidVersion), more(false), cached(false) {} + GetKeyValuesStreamReply(GetKeyValuesReply r) : arena(r.arena), data(r.data), version(r.version), more(r.more), cached(r.cached) {} int expectedSize() const { return sizeof(GetKeyValuesStreamReply) + data.expectedSize(); } diff --git a/fdbserver/storageserver.actor.cpp b/fdbserver/storageserver.actor.cpp index 91c67a8b4d7..d6e99c3cdc6 100644 --- a/fdbserver/storageserver.actor.cpp +++ b/fdbserver/storageserver.actor.cpp @@ -1711,7 +1711,7 @@ ACTOR Future getKeyValuesStreamWork( StorageServer* data, GetKeyValuesStre g_traceBatch.addEvent("TransactionDebug", req.debugID.get().first(), "storageserver.getKeyValues.Send"); //.detail("Begin",begin).detail("End",end); - GetKeyValuesReply none; + GetKeyValuesStreamReply none; none.version = version; none.more = false; @@ -1723,7 +1723,7 @@ ACTOR Future getKeyValuesStreamWork( StorageServer* data, GetKeyValuesStre loop { wait(req.reply.onReady()); GetKeyValuesReply _r = wait( readRange(data, version, KeyRangeRef(begin, end), req.limit, &remainingLimitBytes, span.context) ); - GetKeyValuesReply r = _r; + GetKeyValuesStreamReply r(_r); if( req.debugID.present() ) g_traceBatch.addEvent("TransactionDebug", req.debugID.get().first(), "storageserver.getKeyValues.AfterReadRange"); From 12502289c0ed1a3ff8b3516509d930602ab9fc19 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Fri, 4 Dec 2020 21:56:11 -0800 Subject: [PATCH 013/740] more fixes --- fdbrpc/fdbrpc.h | 2 +- fdbserver/storageserver.actor.cpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index 69b25093cca..d5dc9011cae 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -382,7 +382,7 @@ class ReplyPromiseStream { void send(U && value) const { if (queue->isRemoteEndpoint()) { if(!queue->acknowledgements.getRawEndpoint().isValid()) { - value.acknowledgeEndpoint = queue->acknowledgements.getEndpoint(); + value.acknowledgeEndpoint = queue->acknowledgements.getEndpoint(TaskPriority::DefaultEndpoint); } queue->acknowledgements.bytesSent += value.expectedSize(); if((!queue->acknowledgements.ready.isValid() || queue->acknowledgements.ready.isSet()) && queue->acknowledgements.bytesSent - queue->acknowledgements.bytesAcknowledged >= 2e6) { diff --git a/fdbserver/storageserver.actor.cpp b/fdbserver/storageserver.actor.cpp index d6e99c3cdc6..65c00ded0ad 100644 --- a/fdbserver/storageserver.actor.cpp +++ b/fdbserver/storageserver.actor.cpp @@ -1753,7 +1753,6 @@ ACTOR Future getKeyValuesStreamWork( StorageServer* data, GetKeyValuesStre data->metrics.notifyBytesReadPerKSecond(r.data[r.data.size() - 1].key, bytesReadPerKSecond); } - r.penalty = data->getPenalty(); req.reply.send( r ); resultSize = req.limitBytes - remainingLimitBytes; From 5b54dd08ae60cd3e81a2c2990199b47a30e91b83 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Wed, 9 Dec 2020 11:18:03 -0800 Subject: [PATCH 014/740] added NativeAPI changes back --- fdbclient/DatabaseContext.h | 1 + fdbclient/NativeAPI.actor.cpp | 14 +++++--------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/fdbclient/DatabaseContext.h b/fdbclient/DatabaseContext.h index 5652ae7a14b..0dd7ada5adc 100644 --- a/fdbclient/DatabaseContext.h +++ b/fdbclient/DatabaseContext.h @@ -289,6 +289,7 @@ class DatabaseContext : public ReferenceCounted, public FastAll Counter transactionGetKeyRequests; Counter transactionGetValueRequests; Counter transactionGetRangeRequests; + Counter transactionGetRangeStreamRequests; Counter transactionWatchRequests; Counter transactionGetAddressesForKeyRequests; Counter transactionBytesRead; diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index 5fdd2f55817..68794bf8edc 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -859,7 +859,8 @@ DatabaseContext::DatabaseContext(Reference> getRange( Database cx, ReferencetransactionPhysicalReads; - ++cx->transactionGetRangeRequests; state GetKeyValuesReply rep; try { if (CLIENT_BUGGIFY) { @@ -2754,7 +2755,6 @@ ACTOR Future getRangeStream( PromiseStream> res } ++cx->transactionPhysicalReads; - ++cx->transactionGetRangeRequests; state GetKeyValuesReply rep; if (CLIENT_BUGGIFY) { throw deterministicRandom()->randomChoice(std::vector{ @@ -3208,11 +3208,8 @@ Future Transaction::getRangeStream( bool snapshot, bool reverse ) { - return Void(); - - /* ++cx->transactionLogicalReads; - ++cx->transactionGetRangeRequests; + ++cx->transactionGetRangeStreamRequests; if( limits.isReached() ) return Standalone(); @@ -3245,7 +3242,6 @@ Future Transaction::getRangeStream( } return forwardErrors(::getRangeStream(results, cx, trLogInfo, getReadVersion(), b, e, limits, conflictRange, snapshot, reverse, info, options.readTags), results); - */ } Future Transaction::getRangeStream( From a4b6136ea00523db0cdad580b2bba33cb3dbc458 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Sun, 13 Dec 2020 21:52:55 -0800 Subject: [PATCH 015/740] based getRangeStream only on getExactRange for now to handle less special cases --- fdbclient/NativeAPI.actor.cpp | 256 ++++++++++++++++++++++++++++------ 1 file changed, 214 insertions(+), 42 deletions(-) diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index 68794bf8edc..f5a43e883bb 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -1702,19 +1702,6 @@ Future> getRange( TransactionInfo const& info, TagSet const& tags); -/* -Future getRangeStream( - PromiseStream> const& results, - Database const& cx, - Future const& fVersion, - KeySelector const& begin, - KeySelector const& end, - GetRangeLimits const& limits, - bool const& reverse, - TransactionInfo const& info, - TagSet const& tags); -*/ - ACTOR Future> getValue(Future version, Key key, Database cx, TransactionInfo info, Reference trLogInfo, TagSet tags); @@ -2672,10 +2659,209 @@ ACTOR Future> getRange( Database cx, Reference getRangeStream( PromiseStream> results, Database cx, Reference trLogInfo, Future fVersion, KeySelector begin, KeySelector end, GetRangeLimits limits, Promise> conflictRange, bool snapshot, bool reverse, TransactionInfo info, TagSet tags ) +{ + //FIXME: better handling to disable row limits + ASSERT(!limits.hasRowLimit()); + state Span span("NAPI:getRangeStream"_loc, info.spanID); + + state Version version = wait( fVersion ); + cx->validateVersion(version); + + Future fb = resolveKey(cx, begin, version, info, tags); + state Future fe = resolveKey(cx, end, version, info, tags); + + state Key b = wait(fb); + state Key e = wait(fe); + + if( !snapshot ) { + //FIXME: this conflict range is too large, and should be updated continously as results are returned + conflictRange.send(std::make_pair(std::min(b, begin.getKey()), std::max(e, end.getKey()))); + } + + if (b >= e) { + results.send(end_of_stream()); + return Void(); + } + + state KeyRangeRef keys(b, e); + + //if e is allKeys.end, we have read through the end of the database + //if b is allKeys.begin, we have either read through the beginning of the database, + //or allKeys.begin exists in the database and will be part of the conflict range anyways + + loop { + state vector< pair> > locations = wait( getKeyRangeLocations( cx, keys, CLIENT_KNOBS->GET_RANGE_SHARD_LIMIT, reverse, &StorageServerInterface::getKeyValues, info ) ); + ASSERT( locations.size() ); + state int shard = 0; + loop { + const KeyRangeRef& range = locations[shard].first; + + GetKeyValuesStreamRequest req; + req.version = version; + req.begin = firstGreaterOrEqual( range.begin ); + req.end = firstGreaterOrEqual( range.end ); + req.spanContext = span.context; + + transformRangeLimits(limits, reverse, req); + ASSERT(req.limitBytes > 0 && req.limit != 0 && req.limit < 0 == reverse); + + //FIXME: buggify byte limits on internal functions that use them, instead of globally + req.tags = cx->sampleReadTags() ? tags : Optional(); + req.debugID = info.debugID; + + try { + if( info.debugID.present() ) { + g_traceBatch.addEvent("TransactionDebug", info.debugID.get().first(), "NativeAPI.RangeStream.Before"); + } + ++cx->transactionPhysicalReads; + state GetKeyValuesStreamReply rep; + + if( locations[shard].second->size() == 0 ) { + wait(cx->connectionFileChanged()); + results.sendError( transaction_too_old() ); + return Void(); + } + + //FIXME: add load balancing + state FutureStream replyStream = locations[shard].second->getInterface(0).getKeyValuesStream.getReplyStream(req); + loop { + try { + choose { + when(wait(cx->connectionFileChanged())) { + results.sendError( transaction_too_old() ); + return Void(); + } + + when(GetKeyValuesStreamReply _rep = waitNext(replyStream) { + rep = _rep; + } + } + ++cx->transactionPhysicalReadsCompleted; + } catch(Error&) { + ++cx->transactionPhysicalReadsCompleted; + throw; + } + if( info.debugID.present() ) + g_traceBatch.addEvent("TransactionDebug", info.debugID.get().first(), "NativeAPI.getExactRange.After"); + Standalone output = rep.data; + + bool more = rep.more; + // If the reply says there is more but we know that we finished the shard, then fix rep.more + if( reverse && more && rep.data.size() > 0 && output[output.size()-1].key == locations[shard].first.begin ) { + more = false; + } + + if (more) { + if( !rep.data.size() ) { + TraceEvent(SevError, "GetRangeStreamError").detail("Reason", "More data indicated but no rows present") + .detail("LimitBytes", limits.bytes).detail("LimitRows", limits.rows) + .detail("OutputSize", output.size()).detail("OutputBytes", output.expectedSize()) + .detail("BlockSize", rep.data.size()).detail("BlockBytes", rep.data.expectedSize()); + ASSERT( false ); + } + TEST(true); // GetKeyValuesStreamReply.more in getRangeStream + // Make next request to the same shard with a beginning key just after the last key returned + if( reverse ) + locations[shard].first = KeyRangeRef( locations[shard].first.begin, output[output.size()-1].key ); + else + locations[shard].first = KeyRangeRef( keyAfter( output[output.size()-1].key ), locations[shard].first.end ); + } + + if (!more || locations[shard].first.empty()) { + TEST(true); // getRangeStream (!more || locations[shard].first.empty()) + if(shard == locations.size()-1) { + const KeyRangeRef& range = locations[shard].first; + KeyRef begin = reverse ? keys.begin : range.end; + KeyRef end = reverse ? range.begin : keys.end; + + if(begin >= end) { + output.more = false; + if(b == allKeys.begin) { + r.readToBegin = true; + } + if(e == allKeys.end) { + r.readThroughEnd = true; + } + int64_t bytes = 0; + for(const KeyValueRef &kv : result) { + bytes += kv.key.size() + kv.value.size(); + } + + cx->transactionBytesRead += bytes; + cx->transactionKeysRead += result.size(); + + //FIXME: figure out appropriate metrics for the client event log + //if( trLogInfo ) { + // trLogInfo->addLog(FdbClientLogEvents::EventGetRange(startTime, cx->clientLocality.dcId(), now()-startTime, bytes, begin.getKey(), end.getKey())); + //} + + results.send(output); + results.sendError(end_of_stream()); + return Void(); + } + + keys = KeyRangeRef(begin, end); + break; + } + + ++shard; + } + + if(output.size() > 0) { + output.more = true; + if(b == allKeys.begin && !reverse) { + r.readToBegin = true; + } + if(e == allKeys.end && reverse) { + r.readThroughEnd = true; + } + int64_t bytes = 0; + for(const KeyValueRef &kv : result) { + bytes += kv.key.size() + kv.value.size(); + } + + cx->transactionBytesRead += bytes; + cx->transactionKeysRead += result.size(); + + //FIXME: figure out appropriate metrics for the client event log + //if( trLogInfo ) { + // trLogInfo->addLog(FdbClientLogEvents::EventGetRange(startTime, cx->clientLocality.dcId(), now()-startTime, bytes, begin.getKey(), end.getKey())); + //} + results.send(output); + } + } + } catch (Error& e) { + if (e.code() == error_code_actor_cancelled) { + throw; + } + if (e.code() == error_code_wrong_shard_server || e.code() == error_code_all_alternatives_failed) { + const KeyRangeRef& range = locations[shard].first; + + if( reverse ) + keys = KeyRangeRef( keys.begin, range.end ); + else + keys = KeyRangeRef( range.begin, keys.end ); + + cx->invalidateCache( keys ); + wait( delay(CLIENT_KNOBS->WRONG_SHARD_SERVER_DELAY, info.taskID )); + break; + } else { + results.sendError(e); + return Void(); + } + } + } + } +} + + +/* +ACTOR Future getRangeStreamSingleShard( PromiseStream> results, Database cx, Reference trLogInfo, Future fVersion, + KeySelector begin, KeySelector end, GetRangeLimits limits, Promise> conflictRange, bool snapshot, bool reverse, + TransactionInfo info, TagSet tags ) { state GetRangeLimits originalLimits( limits ); state KeySelector originalBegin = begin; @@ -2702,7 +2888,9 @@ ACTOR Future getRangeStream( PromiseStream> res loop { if( end.getKey() == allKeys.begin && (end.offset < 1 || end.isFirstGreaterOrEqual()) ) { getRangeFinished(cx, trLogInfo, startTime, originalBegin, originalEnd, snapshot, conflictRange, reverse, output); - return output; + results.send(output); + results.send(end_of_stream()); + return Void(); } Key locationKey = reverse ? Key(end.getKey(), end.arena()) : Key(begin.getKey(), begin.arena()); @@ -2738,20 +2926,6 @@ ACTOR Future getRangeStream( PromiseStream> res try { if( info.debugID.present() ) { g_traceBatch.addEvent("TransactionDebug", info.debugID.get().first(), "NativeAPI.getRange.Before"); - /*TraceEvent("TransactionDebugGetRangeInfo", info.debugID.get()) - .detail("ReqBeginKey", req.begin.getKey()) - .detail("ReqEndKey", req.end.getKey()) - .detail("OriginalBegin", originalBegin.toString()) - .detail("OriginalEnd", originalEnd.toString()) - .detail("Begin", begin.toString()) - .detail("End", end.toString()) - .detail("Shard", shard) - .detail("ReqLimit", req.limit) - .detail("ReqLimitBytes", req.limitBytes) - .detail("ReqVersion", req.version) - .detail("Reverse", reverse) - .detail("ModifiedSelectors", modifiedSelectors) - .detail("Servers", beginServer.second->description());/ } ++cx->transactionPhysicalReads; @@ -2771,12 +2945,6 @@ ACTOR Future getRangeStream( PromiseStream> res if( info.debugID.present() ) { g_traceBatch.addEvent("TransactionDebug", info.debugID.get().first(), "NativeAPI.getRange.After");//.detail("SizeOf", rep.data.size()); - /*TraceEvent("TransactionDebugGetRangeDone", info.debugID.get()) - .detail("ReqBeginKey", req.begin.getKey()) - .detail("ReqEndKey", req.end.getKey()) - .detail("RepIsMore", rep.more) - .detail("VersionReturned", rep.version) - .detail("RowsReturned", rep.data.size());/ } ASSERT( !rep.more || rep.data.size() ); @@ -2888,8 +3056,7 @@ ACTOR Future getRangeStream( PromiseStream> res throw; } -} -*/ +}*/ Future> getRange( Database const& cx, Future const& fVersion, KeySelector const& begin, KeySelector const& end, GetRangeLimits const& limits, bool const& reverse, TransactionInfo const& info, TagSet const& tags ) @@ -3211,11 +3378,15 @@ Future Transaction::getRangeStream( ++cx->transactionLogicalReads; ++cx->transactionGetRangeStreamRequests; - if( limits.isReached() ) - return Standalone(); + if( limits.isReached() ) { + results.send(end_of_stream()); + return Void(); + } - if( !limits.isValid() ) - return range_limits_invalid(); + if( !limits.isValid() ) { + results.send(range_limits_invalid()); + return Void(); + } ASSERT(limits.rows != 0); @@ -3233,7 +3404,8 @@ Future Transaction::getRangeStream( if( b.offset >= e.offset && b.getKey() >= e.getKey() ) { TEST(true); // Native stream range inverted - return Standalone(); + results.send(end_of_stream()); + return Void(); } Promise> conflictRange; From 42070809eeb5dc95c8fd2a2ca9c5f2acde997f57 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Sun, 13 Dec 2020 21:55:39 -0800 Subject: [PATCH 016/740] missing paratheses --- fdbclient/NativeAPI.actor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index f5a43e883bb..f257dc2997b 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -2735,7 +2735,7 @@ ACTOR Future getRangeStream( PromiseStream> res return Void(); } - when(GetKeyValuesStreamReply _rep = waitNext(replyStream) { + when(GetKeyValuesStreamReply _rep = waitNext(replyStream)) { rep = _rep; } } From e838398dc1a7d6d9342543f74eb5b9cc692d3998 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Sun, 13 Dec 2020 22:07:27 -0800 Subject: [PATCH 017/740] fixed a lot of compile errors --- fdbclient/NativeAPI.actor.cpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index f257dc2997b..762793cf5d8 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -2678,11 +2678,11 @@ ACTOR Future getRangeStream( PromiseStream> res if( !snapshot ) { //FIXME: this conflict range is too large, and should be updated continously as results are returned - conflictRange.send(std::make_pair(std::min(b, begin.getKey()), std::max(e, end.getKey()))); + conflictRange.send(std::make_pair(std::min(b, Key(begin.getKey(),begin.arena)), std::max(e, Key(end.getKey(),end.arena)))); } if (b >= e) { - results.send(end_of_stream()); + results.sendError(end_of_stream()); return Void(); } @@ -2699,13 +2699,14 @@ ACTOR Future getRangeStream( PromiseStream> res loop { const KeyRangeRef& range = locations[shard].first; - GetKeyValuesStreamRequest req; + state GetKeyValuesStreamRequest req; req.version = version; req.begin = firstGreaterOrEqual( range.begin ); req.end = firstGreaterOrEqual( range.end ); req.spanContext = span.context; + req.limit = reverse ? -CLIENT_KNOBS->REPLY_BYTE_LIMIT : CLIENT_KNOBS->REPLY_BYTE_LIMIT; + req.limitBytes = CLIENT_KNOBS->REPLY_BYTE_LIMIT; - transformRangeLimits(limits, reverse, req); ASSERT(req.limitBytes > 0 && req.limit != 0 && req.limit < 0 == reverse); //FIXME: buggify byte limits on internal functions that use them, instead of globally @@ -2746,7 +2747,7 @@ ACTOR Future getRangeStream( PromiseStream> res } if( info.debugID.present() ) g_traceBatch.addEvent("TransactionDebug", info.debugID.get().first(), "NativeAPI.getExactRange.After"); - Standalone output = rep.data; + Standalone output( rep.data, rep.arena ); bool more = rep.more; // If the reply says there is more but we know that we finished the shard, then fix rep.more @@ -2780,13 +2781,13 @@ ACTOR Future getRangeStream( PromiseStream> res if(begin >= end) { output.more = false; if(b == allKeys.begin) { - r.readToBegin = true; + output.readToBegin = true; } if(e == allKeys.end) { - r.readThroughEnd = true; + output.readThroughEnd = true; } int64_t bytes = 0; - for(const KeyValueRef &kv : result) { + for(const KeyValueRef &kv : output) { bytes += kv.key.size() + kv.value.size(); } @@ -2813,13 +2814,13 @@ ACTOR Future getRangeStream( PromiseStream> res if(output.size() > 0) { output.more = true; if(b == allKeys.begin && !reverse) { - r.readToBegin = true; + output.readToBegin = true; } if(e == allKeys.end && reverse) { - r.readThroughEnd = true; + output.readThroughEnd = true; } int64_t bytes = 0; - for(const KeyValueRef &kv : result) { + for(const KeyValueRef &kv : output) { bytes += kv.key.size() + kv.value.size(); } From 3fa3442b8a2d6f2bbf90ba239b5aa6222f72c5c8 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Sun, 13 Dec 2020 22:13:27 -0800 Subject: [PATCH 018/740] fixed more compile errors --- fdbclient/NativeAPI.actor.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index 762793cf5d8..ce311448d0f 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -2678,7 +2678,7 @@ ACTOR Future getRangeStream( PromiseStream> res if( !snapshot ) { //FIXME: this conflict range is too large, and should be updated continously as results are returned - conflictRange.send(std::make_pair(std::min(b, Key(begin.getKey(),begin.arena)), std::max(e, Key(end.getKey(),end.arena)))); + conflictRange.send(std::make_pair(std::min(b, Key(begin.getKey(),begin.arena())), std::max(e, Key(end.getKey(),end.arena())))); } if (b >= e) { @@ -2747,7 +2747,7 @@ ACTOR Future getRangeStream( PromiseStream> res } if( info.debugID.present() ) g_traceBatch.addEvent("TransactionDebug", info.debugID.get().first(), "NativeAPI.getExactRange.After"); - Standalone output( rep.data, rep.arena ); + Standalone output( RangeResultRef(rep.data, rep.more), rep.arena ); bool more = rep.more; // If the reply says there is more but we know that we finished the shard, then fix rep.more @@ -2792,7 +2792,7 @@ ACTOR Future getRangeStream( PromiseStream> res } cx->transactionBytesRead += bytes; - cx->transactionKeysRead += result.size(); + cx->transactionKeysRead += output.size(); //FIXME: figure out appropriate metrics for the client event log //if( trLogInfo ) { @@ -2825,7 +2825,7 @@ ACTOR Future getRangeStream( PromiseStream> res } cx->transactionBytesRead += bytes; - cx->transactionKeysRead += result.size(); + cx->transactionKeysRead += output.size(); //FIXME: figure out appropriate metrics for the client event log //if( trLogInfo ) { From dc2bf7e987618a09e657e1fdc9476ddfa2042c96 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Sun, 13 Dec 2020 22:21:58 -0800 Subject: [PATCH 019/740] more compiler fixes --- fdbclient/NativeAPI.actor.cpp | 6 +++--- flow/flow.h | 35 +++++++++++++++++------------------ 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index ce311448d0f..0291d952d5b 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -2890,7 +2890,7 @@ ACTOR Future getRangeStreamSingleShard( PromiseStream Transaction::getRangeStream( ++cx->transactionGetRangeStreamRequests; if( limits.isReached() ) { - results.send(end_of_stream()); + results.sendError(end_of_stream()); return Void(); } @@ -3405,7 +3405,7 @@ Future Transaction::getRangeStream( if( b.offset >= e.offset && b.getKey() >= e.getKey() ) { TEST(true); // Native stream range inverted - results.send(end_of_stream()); + results.sendError(end_of_stream()); return Void(); } diff --git a/flow/flow.h b/flow/flow.h index 306f04837e3..8454b2647eb 100644 --- a/flow/flow.h +++ b/flow/flow.h @@ -908,24 +908,6 @@ struct ReplyType> { #define REPLY_TYPE(RequestType) typename ReplyType::Type #endif -// Neither of these implementations of REPLY_TYPE() works on both MSVC and g++, so... -#ifdef __GNUG__ -#define REPLYSTREAM_TYPE(RequestType) decltype(getReplyPromiseStream(std::declval()).getFuture().getValue()) -#else -template -struct ReplyStreamType { - // Doing this calculation directly in the return value declaration for PromiseStream::getReply() - // breaks IntelliSense in VS2010; this is a workaround. - typedef decltype(std::declval().reply.getFuture().getValue()) Type; -}; -template class ReplyPromiseStream; -template -struct ReplyStreamType> { - typedef T Type; -}; -#define REPLYSTREAM_TYPE(RequestType) typename ReplyStreamType::Type -#endif - template class PromiseStream { public: @@ -998,6 +980,23 @@ class PromiseStream { NotifiedQueue* queue; }; +// Neither of these implementations of REPLY_TYPE() works on both MSVC and g++, so... +#ifdef __GNUG__ +#define REPLYSTREAM_TYPE(RequestType) decltype(getReplyPromiseStream(std::declval()).getFuture().pop()) +#else +template +struct ReplyStreamType { + // Doing this calculation directly in the return value declaration for PromiseStream::getReply() + // breaks IntelliSense in VS2010; this is a workaround. + typedef decltype(std::declval().reply.getFuture().pop()) Type; +}; +template class ReplyPromiseStream; +template +struct ReplyStreamType> { + typedef T Type; +}; +#define REPLYSTREAM_TYPE(RequestType) typename ReplyStreamType::Type +#endif //extern int actorCount; From a92d6f5a47806d707337f95867cf26917c6a59a5 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Sun, 13 Dec 2020 22:30:09 -0800 Subject: [PATCH 020/740] one more wrong send instead of sendError --- fdbclient/NativeAPI.actor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index 0291d952d5b..ee09452cf3c 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -3385,7 +3385,7 @@ Future Transaction::getRangeStream( } if( !limits.isValid() ) { - results.send(range_limits_invalid()); + results.sendError(range_limits_invalid()); return Void(); } From cc14329f8c113b38edd98b3a66e9548084f80277 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 10:59:56 -0800 Subject: [PATCH 021/740] refactored NetNotifiedQueueWithErrors to inherit from NotifiedQueue and override the pop method --- fdbrpc/fdbrpc.h | 89 +++---------------------------- fdbrpc/genericactors.actor.h | 6 ++- fdbserver/storageserver.actor.cpp | 2 +- flow/flow.h | 14 ++++- 4 files changed, 27 insertions(+), 84 deletions(-) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index d5dc9011cae..31be9281bf7 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -259,26 +259,17 @@ struct AcknowledgementReceiver final : FlowReceiver, FastAllocated -struct NetNotifiedQueueWithErrors final : private SingleCallback, public FlowReceiver, FastAllocated> { +struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAllocated> { using FastAllocated>::operator new; using FastAllocated>::operator delete; - int promises; // one for each promise (and one for an active actor if this is an actor) - int futures; // one for each future and one more if there are any callbacks - - // Invariant: SingleCallback::next==this || (queue.empty() && !error.isValid()) - std::queue> queue; - Error error; AcknowledgementReceiver acknowledgements; - NetNotifiedQueueWithErrors(int futures, int promises) : futures(futures), promises(promises) { - SingleCallback::next = this; - } + NetNotifiedQueueWithErrors(int futures, int promises) : NotifiedQueue(futures, promises) {} NetNotifiedQueueWithErrors(int futures, int promises, const Endpoint& remoteEndpoint) - : futures(futures), promises(promises), FlowReceiver(remoteEndpoint, false) { - SingleCallback::next = this; - } + : NotifiedQueue(futures, promises), FlowReceiver(remoteEndpoint, false) {} + void destroy() override { delete this; } void receive(ArenaObjectReader& reader) override { this->addPromiseRef(); ErrorOr> message; @@ -298,78 +289,14 @@ struct NetNotifiedQueueWithErrors final : private SingleCallback, public Flow this->delPromiseRef(); } - bool isReady() const { return !queue.empty() || error.isValid(); } - bool isError() const { return queue.empty() && error.isValid(); } // the *next* thing queued is an error - uint32_t size() const { return queue.size(); } - - T pop() { - if (queue.empty()) { - if (error.isValid()) throw error; - throw internal_error(); - } - auto copy = std::move(queue.front()); + T pop() override { + T res = popImpl(); if(acknowledgements.getRawEndpoint().isValid()) { acknowledgements.bytesAcknowledged += copy.expectedSize(); FlowTransport::transport().sendUnreliable(SerializeSource(AcknowledgementReply(acknowledgements.bytesAcknowledged)), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint), true); } - queue.pop(); - return copy; - } - - template - void send(U && value) { - if (error.isValid()) return; - - if (SingleCallback::next != this) { - SingleCallback::next->fire(std::forward(value)); - } - else { - queue.emplace(std::forward(value)); - } - } - - void sendError(Error err) { - if (error.isValid()) return; - - this->error = err; - if (SingleCallback::next != this) - SingleCallback::next->error(err); - } - - void addPromiseRef() { promises++; } - void addFutureRef() { futures++; } - - void delPromiseRef() { - if (!--promises) { - if (futures) { - sendError(broken_promise()); - } - else - destroy(); - } - } - void delFutureRef() { - if (!--futures) { - if (promises) - cancel(); - else - destroy(); - } - } - - int getFutureReferenceCount() const { return futures; } - int getPromiseReferenceCount() const { return promises; } - - virtual void destroy() { delete this; } - virtual void cancel() {} - - void addCallbackAndDelFutureRef(SingleCallback* cb) { - ASSERT(SingleCallback::next == this); - cb->insert(this); + return res; } - virtual void unwait() override { delFutureRef(); } - virtual void fire(T const&) override { ASSERT(false); } - virtual void fire(T&&) override { ASSERT(false); } }; template @@ -437,7 +364,7 @@ class ReplyPromiseStream { if(queue->acknowledgements.bytesSent - queue->acknowledgements.bytesAcknowledged < 2e6) { return Void(); } - return queue->acknowledgements.ready.getFuture(); + return queue->acknowledgements.ready.getFuture() || tagError(makeDependent(IFailureMonitor::failureMonitor()).onDisconnectOrFailure(getEndpoint(taskID)), request_maybe_delivered()); } void operator=(const ReplyPromiseStream& rhs) { diff --git a/fdbrpc/genericactors.actor.h b/fdbrpc/genericactors.actor.h index 73b9c2712fe..3b75d243b10 100644 --- a/fdbrpc/genericactors.actor.h +++ b/fdbrpc/genericactors.actor.h @@ -192,7 +192,11 @@ struct PeerHolder { } }; -// Implements getRepyStream +// Implements getRepyStream, this a void actor with the same lifetime as the input ReplyPromiseStream. +// Because this actor holds a reference to the stream, normally it would be impossible to know when there are no other references. +// To get around this, there is a SAV inside the stream that has one less promise reference than +// it should (caused by getErrorFutureAndDelPromiseRef()). When that SAV gets a broken promise because no one besides this void actor +// is referencing it, this void actor will get a broken_promise dropping the final reference to the full ReplyPromiseStream ACTOR template void endStreamOnDisconnect( Future signal, ReplyPromiseStream stream, Reference peer = Reference() ) { state PeerHolder holder = PeerHolder(peer); diff --git a/fdbserver/storageserver.actor.cpp b/fdbserver/storageserver.actor.cpp index 65c00ded0ad..30d7049e845 100644 --- a/fdbserver/storageserver.actor.cpp +++ b/fdbserver/storageserver.actor.cpp @@ -2251,7 +2251,7 @@ ACTOR Future> tryGetRange( Database cx, Version versi loop { Standalone rep = waitNext( results.getFuture() ); limits.decrement( rep ); - + //FIXME: this is only returning the first result from the stream and then cancelling the stream if( limits.isReached() || !rep.more ) { if( output.size() ) { output.arena().dependsOn( rep.arena() ); diff --git a/flow/flow.h b/flow/flow.h index 8454b2647eb..6c66c03791e 100644 --- a/flow/flow.h +++ b/flow/flow.h @@ -580,7 +580,8 @@ struct NotifiedQueue : private SingleCallback, FastAllocated bool isError() const { return queue.empty() && error.isValid(); } // the *next* thing queued is an error uint32_t size() const { return queue.size(); } - T pop() { + virtual T pop() { + return popImpl(); if (queue.empty()) { if (error.isValid()) throw error; throw internal_error(); @@ -644,6 +645,17 @@ struct NotifiedQueue : private SingleCallback, FastAllocated virtual void unwait() override { delFutureRef(); } virtual void fire(T const&) override { ASSERT(false); } virtual void fire(T&&) override { ASSERT(false); } + + protected: + T popImpl() { + if (queue.empty()) { + if (error.isValid()) throw error; + throw internal_error(); + } + auto copy = std::move(queue.front()); + queue.pop(); + return copy; + } }; From 0ff68756c1508174e25b59b2b13fc9afb80a2ec4 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 11:01:27 -0800 Subject: [PATCH 022/740] fix compile errors --- fdbrpc/fdbrpc.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index 31be9281bf7..3e333396564 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -259,7 +259,7 @@ struct AcknowledgementReceiver final : FlowReceiver, FastAllocated -struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAllocated> { +struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAllocated> { using FastAllocated>::operator new; using FastAllocated>::operator delete; @@ -292,7 +292,7 @@ struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAlloc T pop() override { T res = popImpl(); if(acknowledgements.getRawEndpoint().isValid()) { - acknowledgements.bytesAcknowledged += copy.expectedSize(); + acknowledgements.bytesAcknowledged += res.expectedSize(); FlowTransport::transport().sendUnreliable(SerializeSource(AcknowledgementReply(acknowledgements.bytesAcknowledged)), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint), true); } return res; From c35482639ad8a02d74dcd78702cb32131ff7e1a3 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 11:04:12 -0800 Subject: [PATCH 023/740] more fixes --- fdbrpc/fdbrpc.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index 3e333396564..34b598d8ec8 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -290,7 +290,7 @@ struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAl } T pop() override { - T res = popImpl(); + T res = this->popImpl(); if(acknowledgements.getRawEndpoint().isValid()) { acknowledgements.bytesAcknowledged += res.expectedSize(); FlowTransport::transport().sendUnreliable(SerializeSource(AcknowledgementReply(acknowledgements.bytesAcknowledged)), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint), true); @@ -364,7 +364,8 @@ class ReplyPromiseStream { if(queue->acknowledgements.bytesSent - queue->acknowledgements.bytesAcknowledged < 2e6) { return Void(); } - return queue->acknowledgements.ready.getFuture() || tagError(makeDependent(IFailureMonitor::failureMonitor()).onDisconnectOrFailure(getEndpoint(taskID)), request_maybe_delivered()); + return queue->acknowledgements.ready.getFuture() || + tagError(makeDependent(IFailureMonitor::failureMonitor()).onDisconnectOrFailure(queue->acknowledgements.getEndpoint(TaskPriority::DefaultEndpoint)), request_maybe_delivered()); } void operator=(const ReplyPromiseStream& rhs) { From f843325eec69679b56f959fee5e20500713bb986 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 11:12:06 -0800 Subject: [PATCH 024/740] added missing include --- fdbrpc/fdbrpc.h | 1 + 1 file changed, 1 insertion(+) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index 34b598d8ec8..5b683213622 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -24,6 +24,7 @@ #include "flow/flow.h" #include "flow/serialize.h" +#include "flow/genericactors.actor.h" #include "fdbrpc/FlowTransport.h" // NetworkMessageReceiver Endpoint #include "fdbrpc/FailureMonitor.h" #include "fdbrpc/networksender.actor.h" From f3196ea4bdae4768e07df637cac35dc1a48eb6c1 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 11:18:10 -0800 Subject: [PATCH 025/740] fixed tag error call --- fdbrpc/fdbrpc.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index 5b683213622..39d18442084 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -24,7 +24,6 @@ #include "flow/flow.h" #include "flow/serialize.h" -#include "flow/genericactors.actor.h" #include "fdbrpc/FlowTransport.h" // NetworkMessageReceiver Endpoint #include "fdbrpc/FailureMonitor.h" #include "fdbrpc/networksender.actor.h" @@ -366,7 +365,7 @@ class ReplyPromiseStream { return Void(); } return queue->acknowledgements.ready.getFuture() || - tagError(makeDependent(IFailureMonitor::failureMonitor()).onDisconnectOrFailure(queue->acknowledgements.getEndpoint(TaskPriority::DefaultEndpoint)), request_maybe_delivered()); + tagError(makeDependent(IFailureMonitor::failureMonitor()).onDisconnectOrFailure(queue->acknowledgements.getEndpoint(TaskPriority::DefaultEndpoint)), request_maybe_delivered()); } void operator=(const ReplyPromiseStream& rhs) { From d27ae116758ed9a5cb9fe8893fb22e4cae1eb994 Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Mon, 14 Dec 2020 19:28:11 +0000 Subject: [PATCH 026/740] Basic test of ReplyPromiseStream --- fdbserver/NetworkTest.h | 26 +++++++++++++++++++++++++- fdbserver/networktest.actor.cpp | 26 +++++++++++++++++++++----- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/fdbserver/NetworkTest.h b/fdbserver/NetworkTest.h index b68c7952150..98fc6c8e969 100644 --- a/fdbserver/NetworkTest.h +++ b/fdbserver/NetworkTest.h @@ -27,7 +27,8 @@ #include "flow/FileIdentifier.h" struct NetworkTestInterface { - RequestStream< struct NetworkTestRequest > test; + // RequestStream< struct NetworkTestRequest > test; + RequestStream test; NetworkTestInterface() {} NetworkTestInterface( NetworkAddress remote ); NetworkTestInterface( INetwork* local ); @@ -57,6 +58,29 @@ struct NetworkTestRequest { } }; +struct NetworkTestStreamingReply : ReplyPromiseStreamReply { + constexpr static FileIdentifier file_identifier = 3726830; + + int index = 0; + NetworkTestStreamingReply() = default; + explicit NetworkTestStreamingReply(int index) : index(index) {} + size_t expectedSize() const { return sizeof(*this); } + + template + void serialize(Ar& ar) { + serializer(ar, ReplyPromiseStreamReply::acknowledgeEndpoint, index); + } +}; + +struct NetworkTestStreamingRequest { + constexpr static FileIdentifier file_identifier = 2794452; + ReplyPromiseStream reply; + template + void serialize(Ar& ar) { + serializer(ar, reply); + } +}; + Future networkTestServer(); Future networkTestClient( std:: string const& testServers ); diff --git a/fdbserver/networktest.actor.cpp b/fdbserver/networktest.actor.cpp index 573dfa72ccd..abc7bb84712 100644 --- a/fdbserver/networktest.actor.cpp +++ b/fdbserver/networktest.actor.cpp @@ -74,9 +74,13 @@ ACTOR Future networkTestServer() { loop { choose { - when( NetworkTestRequest req = waitNext( interf.test.getFuture() ) ) { + when(NetworkTestStreamingRequest req = waitNext(interf.test.getFuture())) { LatencyStats::sample sample = latency.tick(); - req.reply.send( NetworkTestReply( Value( std::string( req.replySize, '.' ) ) ) ); + for (int i = 0; i < 1e6; ++i) { + wait(req.reply.onReady()); + req.reply.send(NetworkTestStreamingReply{ i }); + } + req.reply.sendError(end_of_stream()); latency.tock(sample); sent++; } @@ -121,9 +125,21 @@ ACTOR Future testClient(std::vector interfs, int* se while (moreRequestsPending(*sent)) { (*sent)++; sample = latency->tick(); - NetworkTestReply rep = wait( - retryBrokenPromise(interfs[deterministicRandom()->randomInt(0, interfs.size())].test, - NetworkTestRequest(StringRef(request_payload), FLOW_KNOBS->NETWORK_TEST_REPLY_SIZE))); + state FutureStream stream = + interfs[deterministicRandom()->randomInt(0, interfs.size())].test.getReplyStream( + NetworkTestStreamingRequest{}); + state int j = 0; + try { + loop { + NetworkTestStreamingReply rep = waitNext(stream); + ASSERT(rep.index == j++); + if (rep.index % 100000 == 0) { + printf("%d\n", rep.index); + } + } + } catch (Error& e) { + ASSERT(e.code() == error_code_end_of_stream); + } latency->tock(sample); (*completed)++; } From e45da7609690b7051251aba7f03fa0e581a7833a Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Mon, 14 Dec 2020 19:32:11 +0000 Subject: [PATCH 027/740] Fix compilation --- fdbserver/networktest.actor.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fdbserver/networktest.actor.cpp b/fdbserver/networktest.actor.cpp index abc7bb84712..27773df761c 100644 --- a/fdbserver/networktest.actor.cpp +++ b/fdbserver/networktest.actor.cpp @@ -74,9 +74,10 @@ ACTOR Future networkTestServer() { loop { choose { - when(NetworkTestStreamingRequest req = waitNext(interf.test.getFuture())) { - LatencyStats::sample sample = latency.tick(); - for (int i = 0; i < 1e6; ++i) { + when(state NetworkTestStreamingRequest req = waitNext(interf.test.getFuture())) { + state LatencyStats::sample sample = latency.tick(); + state int i = 0; + for (; i < 1e6; ++i) { wait(req.reply.onReady()); req.reply.send(NetworkTestStreamingReply{ i }); } From bb1c5f3aa500cab58006b96b849151e783f60828 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 11:54:36 -0800 Subject: [PATCH 028/740] added debugging --- fdbserver/networktest.actor.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fdbserver/networktest.actor.cpp b/fdbserver/networktest.actor.cpp index 27773df761c..7b953a827ca 100644 --- a/fdbserver/networktest.actor.cpp +++ b/fdbserver/networktest.actor.cpp @@ -126,10 +126,12 @@ ACTOR Future testClient(std::vector interfs, int* se while (moreRequestsPending(*sent)) { (*sent)++; sample = latency->tick(); + fprintf(stderr, "Before getReplyStream\n"); state FutureStream stream = interfs[deterministicRandom()->randomInt(0, interfs.size())].test.getReplyStream( NetworkTestStreamingRequest{}); state int j = 0; + fprintf(stderr, "Starting waitNext\n"); try { loop { NetworkTestStreamingReply rep = waitNext(stream); @@ -139,6 +141,7 @@ ACTOR Future testClient(std::vector interfs, int* se } } } catch (Error& e) { + fprintf(stderr, "Error: %s\n", e.what()); ASSERT(e.code() == error_code_end_of_stream); } latency->tock(sample); From d661badcc1b3b3da0745bc3adc97666a4df9d488 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 12:10:50 -0800 Subject: [PATCH 029/740] getReplyStream must return the replyPromiseStream to avoid broken_promise errors --- fdbclient/NativeAPI.actor.cpp | 8 ++++---- fdbrpc/fdbrpc.h | 16 ++++++++-------- fdbserver/networktest.actor.cpp | 7 ++----- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index ee09452cf3c..ffd13613419 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -2727,7 +2727,7 @@ ACTOR Future getRangeStream( PromiseStream> res } //FIXME: add load balancing - state FutureStream replyStream = locations[shard].second->getInterface(0).getKeyValuesStream.getReplyStream(req); + state ReplyPromiseStream replyStream = locations[shard].second->getInterface(0).getKeyValuesStream.getReplyStream(req); loop { try { choose { @@ -2736,7 +2736,7 @@ ACTOR Future getRangeStream( PromiseStream> res return Void(); } - when(GetKeyValuesStreamReply _rep = waitNext(replyStream)) { + when(GetKeyValuesStreamReply _rep = waitNext(replyStream.getFuture())) { rep = _rep; } } @@ -2940,9 +2940,9 @@ ACTOR Future getRangeStreamSingleShard( PromiseStreamsize() == 0) { wait(Future(Never())); } - state FutureStream repStream = beginServer.second->getInterface(0).getKeyValuesStream.getReplyStream(req); + state ReplyPromiseStream repStream = beginServer.second->getInterface(0).getKeyValuesStream.getReplyStream(req); loop { - GetKeyValuesStreamReply rep = waitNext(repStream); + GetKeyValuesStreamReply rep = waitNext(repStream.getFuture()); if( info.debugID.present() ) { g_traceBatch.addEvent("TransactionDebug", info.debugID.get().first(), "NativeAPI.getRange.After");//.detail("SizeOf", rep.data.size()); diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index 39d18442084..992066debc1 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -535,41 +535,41 @@ class RequestStream { //FIXME comment template - FutureStream getReplyStream(const X& value, TaskPriority taskID) const { + ReplyPromiseStream getReplyStream(const X& value, TaskPriority taskID) const { setReplyPriority(value, taskID); if (queue->isRemoteEndpoint()) { Future disc = makeDependent(IFailureMonitor::failureMonitor()).onDisconnectOrFailure(getEndpoint(taskID)); auto& p = getReplyPromiseStream(value); if (disc.isReady()) { p.sendError(request_maybe_delivered()); - return p.getFuture(); + return p; } Reference peer = FlowTransport::transport().sendUnreliable(SerializeSource(value), getEndpoint(taskID), true); endStreamOnDisconnect(disc, p, peer); - return p.getFuture(); + return p; } send(value); auto& p = getReplyPromiseStream(value); - return p.getFuture(); + return p; } template - FutureStream getReplyStream(const X& value) const { + ReplyPromiseStream getReplyStream(const X& value) const { if (queue->isRemoteEndpoint()) { Future disc = makeDependent(IFailureMonitor::failureMonitor()).onDisconnectOrFailure(getEndpoint()); auto& p = getReplyPromiseStream(value); if (disc.isReady()) { p.sendError(request_maybe_delivered()); - return p.getFuture(); + return p; } Reference peer = FlowTransport::transport().sendUnreliable(SerializeSource(value), getEndpoint(), true); endStreamOnDisconnect(disc, p, peer); - return p.getFuture(); + return p; } else { send(value); auto& p = getReplyPromiseStream(value); - return p.getFuture(); + return p; } } diff --git a/fdbserver/networktest.actor.cpp b/fdbserver/networktest.actor.cpp index 7b953a827ca..19eee019374 100644 --- a/fdbserver/networktest.actor.cpp +++ b/fdbserver/networktest.actor.cpp @@ -126,22 +126,19 @@ ACTOR Future testClient(std::vector interfs, int* se while (moreRequestsPending(*sent)) { (*sent)++; sample = latency->tick(); - fprintf(stderr, "Before getReplyStream\n"); - state FutureStream stream = + state ReplyPromiseStream stream = interfs[deterministicRandom()->randomInt(0, interfs.size())].test.getReplyStream( NetworkTestStreamingRequest{}); state int j = 0; - fprintf(stderr, "Starting waitNext\n"); try { loop { - NetworkTestStreamingReply rep = waitNext(stream); + NetworkTestStreamingReply rep = waitNext(stream.getFuture()); ASSERT(rep.index == j++); if (rep.index % 100000 == 0) { printf("%d\n", rep.index); } } } catch (Error& e) { - fprintf(stderr, "Error: %s\n", e.what()); ASSERT(e.code() == error_code_end_of_stream); } latency->tock(sample); From cc3e7f8806ef8f79ee007f94009b66bc6e4be0a1 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 12:41:04 -0800 Subject: [PATCH 030/740] getReplyStream should not fail immediately if it cannot communicate with the endpoint --- fdbrpc/FailureMonitor.actor.cpp | 9 +++++++++ fdbrpc/FailureMonitor.h | 6 +++++- fdbrpc/fdbrpc.h | 4 ++-- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/fdbrpc/FailureMonitor.actor.cpp b/fdbrpc/FailureMonitor.actor.cpp index 36600a44f69..2897b9f441d 100644 --- a/fdbrpc/FailureMonitor.actor.cpp +++ b/fdbrpc/FailureMonitor.actor.cpp @@ -144,6 +144,15 @@ Future SimpleFailureMonitor::onDisconnectOrFailure(Endpoint const& endpoin return endpointKnownFailed.onChange(endpoint); } +Future SimpleFailureMonitor::onDisconnect(Endpoint const& endpoint) { + // If the endpoint is permanently failed, return right away + if (failedEndpoints.count(endpoint)) { + TraceEvent("AlreadyDisconnected").detail("Addr", endpoint.getPrimaryAddress()).detail("Tok", endpoint.token); + return Void(); + } + return endpointKnownFailed.onChange(endpoint); +} + Future SimpleFailureMonitor::onStateChanged(Endpoint const& endpoint) { // Wait on endpointKnownFailed if it is false, to pick up both endpointNotFound errors (which set it to true) // and changes to addressStatus (which trigger a range). Don't wait on endpointKnownFailed if it is true, because diff --git a/fdbrpc/FailureMonitor.h b/fdbrpc/FailureMonitor.h index f31b7a2d84f..637394b66aa 100644 --- a/fdbrpc/FailureMonitor.h +++ b/fdbrpc/FailureMonitor.h @@ -98,9 +98,12 @@ class IFailureMonitor { // The next time the known status for the endpoint changes, returns the new status. virtual Future onStateChanged(Endpoint const& endpoint) = 0; - // Returns when onFailed(endpoint) || transport().onDisconnect( endpoint.getPrimaryAddress() ), but more efficiently + // Returns when onFailed(endpoint) || transport().onDisconnect( endpoint.getPrimaryAddress() ) virtual Future onDisconnectOrFailure(Endpoint const& endpoint) = 0; + // Returns when transport().onDisconnect( endpoint.getPrimaryAddress() ) or the endpoint is permanently failed + virtual Future onDisconnect(Endpoint const& endpoint) = 0; + // Returns true if the endpoint is failed but the address of the endpoint is not failed. virtual bool onlyEndpointFailed(Endpoint const& endpoint) const = 0; @@ -146,6 +149,7 @@ class SimpleFailureMonitor : public IFailureMonitor { FailureStatus getState(Endpoint const& endpoint) const override; FailureStatus getState(NetworkAddress const& address) const override; Future onDisconnectOrFailure(Endpoint const& endpoint) override; + Future onDisconnect(Endpoint const& endpoint) override; bool onlyEndpointFailed(Endpoint const& endpoint) const override; bool permanentlyFailed(Endpoint const& endpoint) const override; diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index 992066debc1..849751be9bb 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -538,7 +538,7 @@ class RequestStream { ReplyPromiseStream getReplyStream(const X& value, TaskPriority taskID) const { setReplyPriority(value, taskID); if (queue->isRemoteEndpoint()) { - Future disc = makeDependent(IFailureMonitor::failureMonitor()).onDisconnectOrFailure(getEndpoint(taskID)); + Future disc = makeDependent(IFailureMonitor::failureMonitor()).onDisconnect(getEndpoint(taskID)); auto& p = getReplyPromiseStream(value); if (disc.isReady()) { p.sendError(request_maybe_delivered()); @@ -556,7 +556,7 @@ class RequestStream { template ReplyPromiseStream getReplyStream(const X& value) const { if (queue->isRemoteEndpoint()) { - Future disc = makeDependent(IFailureMonitor::failureMonitor()).onDisconnectOrFailure(getEndpoint()); + Future disc = makeDependent(IFailureMonitor::failureMonitor()).onDisconnect(getEndpoint()); auto& p = getReplyPromiseStream(value); if (disc.isReady()) { p.sendError(request_maybe_delivered()); From e1dbebfba68b0389c51e679e3ddaa97b0e7e6c6f Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 13:06:14 -0800 Subject: [PATCH 031/740] added debugging --- fdbserver/networktest.actor.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/fdbserver/networktest.actor.cpp b/fdbserver/networktest.actor.cpp index 19eee019374..62062e7c91e 100644 --- a/fdbserver/networktest.actor.cpp +++ b/fdbserver/networktest.actor.cpp @@ -77,10 +77,13 @@ ACTOR Future networkTestServer() { when(state NetworkTestStreamingRequest req = waitNext(interf.test.getFuture())) { state LatencyStats::sample sample = latency.tick(); state int i = 0; - for (; i < 1e6; ++i) { + for (; i < 100; ++i) { + fprintf(stderr, "Wait onReady %d\n", i); wait(req.reply.onReady()); + fprintf(stderr, "Send reply %d\n", i); req.reply.send(NetworkTestStreamingReply{ i }); } + fprintf(stderr, "Send end_of_stream\n"); req.reply.sendError(end_of_stream()); latency.tock(sample); sent++; @@ -134,9 +137,7 @@ ACTOR Future testClient(std::vector interfs, int* se loop { NetworkTestStreamingReply rep = waitNext(stream.getFuture()); ASSERT(rep.index == j++); - if (rep.index % 100000 == 0) { - printf("%d\n", rep.index); - } + printf("Result: %d\n", rep.index); } } catch (Error& e) { ASSERT(e.code() == error_code_end_of_stream); From 8bffc60d3f0ac45e224c64e25e65eb513fa2b110 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 13:17:45 -0800 Subject: [PATCH 032/740] more debugging --- fdbserver/networktest.actor.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fdbserver/networktest.actor.cpp b/fdbserver/networktest.actor.cpp index 62062e7c91e..aed98051f84 100644 --- a/fdbserver/networktest.actor.cpp +++ b/fdbserver/networktest.actor.cpp @@ -135,11 +135,13 @@ ACTOR Future testClient(std::vector interfs, int* se state int j = 0; try { loop { + printf("Wait for result\n", rep.index); NetworkTestStreamingReply rep = waitNext(stream.getFuture()); ASSERT(rep.index == j++); printf("Result: %d\n", rep.index); } } catch (Error& e) { + printf("Error: %s\n", e.what()); ASSERT(e.code() == error_code_end_of_stream); } latency->tock(sample); From 7987c99e15687cf9b1cc5bcd816ad2bd63d89cdb Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 13:18:45 -0800 Subject: [PATCH 033/740] compiler fix --- fdbserver/networktest.actor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdbserver/networktest.actor.cpp b/fdbserver/networktest.actor.cpp index aed98051f84..8a3e2ce8378 100644 --- a/fdbserver/networktest.actor.cpp +++ b/fdbserver/networktest.actor.cpp @@ -135,7 +135,7 @@ ACTOR Future testClient(std::vector interfs, int* se state int j = 0; try { loop { - printf("Wait for result\n", rep.index); + printf("Wait for result\n"); NetworkTestStreamingReply rep = waitNext(stream.getFuture()); ASSERT(rep.index == j++); printf("Result: %d\n", rep.index); From 3b317b6c7967408e8997ace807fad879a93e1bc7 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 13:39:36 -0800 Subject: [PATCH 034/740] fixed how messages were being sent and added logging --- fdbrpc/fdbrpc.h | 40 ++++++++++++++++++++++++--------- fdbserver/networktest.actor.cpp | 2 +- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index 849751be9bb..f92cd30e5c3 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -267,10 +267,13 @@ struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAl NetNotifiedQueueWithErrors(int futures, int promises) : NotifiedQueue(futures, promises) {} NetNotifiedQueueWithErrors(int futures, int promises, const Endpoint& remoteEndpoint) - : NotifiedQueue(futures, promises), FlowReceiver(remoteEndpoint, false) {} + : NotifiedQueue(futures, promises), FlowReceiver(remoteEndpoint, false) { + printf("NetNotified create with remote endpoint: %s\n", remoteEndpoint.token.toString().c_str()); + } void destroy() override { delete this; } void receive(ArenaObjectReader& reader) override { + printf("NetNotifiedReceived\n"); this->addPromiseRef(); ErrorOr> message; reader.deserialize(message); @@ -297,6 +300,10 @@ struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAl } return res; } + + ~NetNotifiedQueueWithErrors() { + printf("NetNotifiedQueue destructor\n"); + } }; template @@ -315,17 +322,22 @@ class ReplyPromiseStream { if((!queue->acknowledgements.ready.isValid() || queue->acknowledgements.ready.isSet()) && queue->acknowledgements.bytesSent - queue->acknowledgements.bytesAcknowledged >= 2e6) { queue->acknowledgements.ready = Promise(); } - FlowTransport::transport().sendUnreliable(SerializeSource(std::forward(value)), getEndpoint(), true); + FlowTransport::transport().sendUnreliable(SerializeSource>>(value), getEndpoint(), false); } - else + else { queue->send(std::forward(value)); + } } template void sendError(const E& exc) const { - queue->sendError(exc); - if(errors && errors->canBeSet()) { - errors->sendError(exc); + if (queue->isRemoteEndpoint()) { + FlowTransport::transport().sendUnreliable(SerializeSource>>(exc), getEndpoint(), false); + } else { + queue->sendError(exc); + if(errors && errors->canBeSet()) { + errors->sendError(exc); + } } } @@ -354,7 +366,14 @@ class ReplyPromiseStream { errors->delPromiseRef(); } - const Endpoint& getEndpoint(TaskPriority taskID = TaskPriority::DefaultEndpoint) const { return queue->getEndpoint(taskID); } + const Endpoint& getEndpoint(TaskPriority taskID = TaskPriority::DefaultEndpoint) const { + if(!queue->getRawEndpoint().isValid()) { + Endpoint res = queue->getEndpoint(taskID); + printf("Registered Endpoint: %s\n", res.token.toString()); + return res; + } + return queue->getEndpoint(taskID); + } bool operator == (const ReplyPromiseStream& rhs) const { return queue == rhs.queue; } bool isEmpty() const { return !queue->isReady(); } @@ -396,14 +415,15 @@ class ReplyPromiseStream { template void save(Ar& ar, const ReplyPromiseStream& value) { - auto const& ep = value.getEndpoint(); + auto const& ep = value.getEndpoint().token; ar << ep; } template void load(Ar& ar, ReplyPromiseStream& value) { - Endpoint endpoint; - ar >> endpoint; + UID token; + ar >> token; + Endpoint endpoint = FlowTransport::transport().loadedEndpoint(token); value = ReplyPromiseStream(endpoint); } diff --git a/fdbserver/networktest.actor.cpp b/fdbserver/networktest.actor.cpp index 8a3e2ce8378..be13891d273 100644 --- a/fdbserver/networktest.actor.cpp +++ b/fdbserver/networktest.actor.cpp @@ -248,7 +248,7 @@ ACTOR Future networkTestClient( std:: string testServers ) { } state std::vector> clients; - for (int i = 0; i < FLOW_KNOBS->NETWORK_TEST_CLIENT_COUNT; i++) { + for (int i = 0; i < 1; i++) { clients.push_back(testClient(interfs, &sent, &completed, &latency)); } clients.push_back(logger(&sent, &completed, &latency)); From b3d6f5037c6cd24b467325bb4c711ad63ffdfc86 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 13:41:29 -0800 Subject: [PATCH 035/740] fixed warnings --- fdbrpc/fdbrpc.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index f92cd30e5c3..2aacb9df2eb 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -368,9 +368,7 @@ class ReplyPromiseStream { const Endpoint& getEndpoint(TaskPriority taskID = TaskPriority::DefaultEndpoint) const { if(!queue->getRawEndpoint().isValid()) { - Endpoint res = queue->getEndpoint(taskID); - printf("Registered Endpoint: %s\n", res.token.toString()); - return res; + printf("Registered Endpoint: %s\n", queue->getEndpoint(taskID).token.toString()); } return queue->getEndpoint(taskID); } From 810d0d3e47ff9bf9201b57de45fc3dc6d0d164f7 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 13:44:25 -0800 Subject: [PATCH 036/740] fixed compile error --- fdbrpc/fdbrpc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index 2aacb9df2eb..49fae130954 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -368,7 +368,7 @@ class ReplyPromiseStream { const Endpoint& getEndpoint(TaskPriority taskID = TaskPriority::DefaultEndpoint) const { if(!queue->getRawEndpoint().isValid()) { - printf("Registered Endpoint: %s\n", queue->getEndpoint(taskID).token.toString()); + printf("Registered Endpoint: %s\n", queue->getEndpoint(taskID).token.toString().c_str()); } return queue->getEndpoint(taskID); } From d9a9180fa25f894fb18dffad78605440b4f0b33f Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 13:53:18 -0800 Subject: [PATCH 037/740] avoid an assertion error where sending a broken_promise causes the object to be destroyed --- fdbrpc/genericactors.actor.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/fdbrpc/genericactors.actor.h b/fdbrpc/genericactors.actor.h index 3b75d243b10..799118db993 100644 --- a/fdbrpc/genericactors.actor.h +++ b/fdbrpc/genericactors.actor.h @@ -200,11 +200,15 @@ struct PeerHolder { ACTOR template void endStreamOnDisconnect( Future signal, ReplyPromiseStream stream, Reference peer = Reference() ) { state PeerHolder holder = PeerHolder(peer); - choose { - when(wait(signal)) { - stream.sendError(request_maybe_delivered()); + try { + choose { + when(wait(signal)) { + stream.sendError(request_maybe_delivered()); + } + when(wait(stream.getErrorFutureAndDelPromiseRef())) {} } - when(wait(stream.getErrorFutureAndDelPromiseRef())) {} + } catch (Error &e) { + wait(delay(0)); } } From 12b14ead8c56c51740ee84f8e879ccbd597dfc31 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 13:58:18 -0800 Subject: [PATCH 038/740] fixed an assert --- fdbserver/networktest.actor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdbserver/networktest.actor.cpp b/fdbserver/networktest.actor.cpp index be13891d273..5fd903741b7 100644 --- a/fdbserver/networktest.actor.cpp +++ b/fdbserver/networktest.actor.cpp @@ -142,7 +142,7 @@ ACTOR Future testClient(std::vector interfs, int* se } } catch (Error& e) { printf("Error: %s\n", e.what()); - ASSERT(e.code() == error_code_end_of_stream); + ASSERT(e.code() == error_code_end_of_stream || e.code() == error_code_request_maybe_delivered); } latency->tock(sample); (*completed)++; From 1c0d6aee803bb6a71e9d19e52a2a5cc1b4edb79d Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 14:03:20 -0800 Subject: [PATCH 039/740] added more logging --- fdbrpc/FailureMonitor.actor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdbrpc/FailureMonitor.actor.cpp b/fdbrpc/FailureMonitor.actor.cpp index 2897b9f441d..c9652cb6c0d 100644 --- a/fdbrpc/FailureMonitor.actor.cpp +++ b/fdbrpc/FailureMonitor.actor.cpp @@ -126,7 +126,7 @@ void SimpleFailureMonitor::endpointNotFound(Endpoint const& endpoint) { } void SimpleFailureMonitor::notifyDisconnect(NetworkAddress const& address) { - //TraceEvent("NotifyDisconnect").detail("Address", address); + TraceEvent("NotifyDisconnect").detail("Address", address); endpointKnownFailed.triggerRange(Endpoint({ address }, UID()), Endpoint({ address }, UID(-1, -1))); } From 12c8b2a3e314b8c8d918b17f7e3d1a6932b34bd6 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 14:08:09 -0800 Subject: [PATCH 040/740] more logging --- fdbrpc/FlowTransport.actor.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fdbrpc/FlowTransport.actor.cpp b/fdbrpc/FlowTransport.actor.cpp index 0a54f57a1fa..0bba1ce410c 100644 --- a/fdbrpc/FlowTransport.actor.cpp +++ b/fdbrpc/FlowTransport.actor.cpp @@ -89,6 +89,7 @@ void EndpointMap::realloc() { } void EndpointMap::insert( NetworkMessageReceiver* r, Endpoint::Token& token, TaskPriority priority ) { + printf("Endpoint Map Insert: %s\n", token.toString().c_str()); if (firstFree == uint32_t(-1)) realloc(); int index = firstFree; firstFree = data[index].nextFree; @@ -148,6 +149,7 @@ TaskPriority EndpointMap::getPriority( Endpoint::Token const& token ) { } void EndpointMap::remove( Endpoint::Token const& token, NetworkMessageReceiver* r ) { + printf("Endpoint Map Remove: %s\n", token.toString().c_str()); uint32_t index = token.second(); if ( index < data.size() && data[index].token().first() == token.first() && ((data[index].token().second()&0xffffffff00000000LL)|index)==token.second() && data[index].receiver == r ) { data[index].receiver = 0; From ead866f1ca4cd656f3e22024e1356866ee7717a3 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 14:09:11 -0800 Subject: [PATCH 041/740] more logging --- fdbrpc/fdbrpc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index 49fae130954..6c490ee399b 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -302,7 +302,7 @@ struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAl } ~NetNotifiedQueueWithErrors() { - printf("NetNotifiedQueue destructor\n"); + printf("NetNotifiedQueue destructor %s\n", getRawEndpoint().token.toString().c_str()); } }; From c3a8220b90df89f52aa00f89bcabb78cc05cbe75 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 14:35:09 -0800 Subject: [PATCH 042/740] more logging --- fdbrpc/FlowTransport.actor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/fdbrpc/FlowTransport.actor.cpp b/fdbrpc/FlowTransport.actor.cpp index 0bba1ce410c..4221d2f4ccf 100644 --- a/fdbrpc/FlowTransport.actor.cpp +++ b/fdbrpc/FlowTransport.actor.cpp @@ -1497,6 +1497,7 @@ void FlowTransport::cancelReliable( ReliablePacket* p ) { } Reference FlowTransport::sendUnreliable( ISerializeSource const& what, const Endpoint& destination, bool openConnection ) { + printf("Send Unreliable: %s %s\n", destination.getPrimaryAddress().toString().c_str(), destination.token.toString().c_str()); if (self->isLocalAddress(destination.getPrimaryAddress())) { sendLocal( self, what, destination ); return Reference(); From 235b01fbc49ce6e5bf3f449269e8869af4e49df2 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 14:41:34 -0800 Subject: [PATCH 043/740] fixed serialization of replyPromiseStream --- fdbrpc/fdbrpc.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index 6c490ee399b..c3aff7317f3 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -427,14 +427,15 @@ void load(Ar& ar, ReplyPromiseStream& value) { template struct serializable_traits> : std::true_type { - template - static void serialize(Archiver& ar, ReplyPromiseStream& stream) { + template + static void serialize(Archiver& ar, ReplyPromiseStream& p) { if constexpr (Archiver::isDeserializing) { - Endpoint endpoint; - serializer(ar, endpoint); - stream = ReplyPromiseStream(endpoint); + UID token; + serializer(ar, token); + auto endpoint = FlowTransport::transport().loadedEndpoint(token); + p = ReplyPromiseStream(endpoint); } else { - const auto& ep = stream.getEndpoint(); + const auto& ep = p.getEndpoint().token; serializer(ar, ep); } } From 014ca6eb2267daf6d64bd8b923258344de7ce178 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 14:42:07 -0800 Subject: [PATCH 044/740] solved error broken_promise better --- fdbrpc/fdbrpc.h | 4 +++- fdbrpc/genericactors.actor.h | 12 ++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index c3aff7317f3..c56abc54b1a 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -356,7 +356,9 @@ class ReplyPromiseStream { ASSERT(errors && errors->getPromiseReferenceCount() > 1); errors->addFutureRef(); errors->delPromiseRef(); - return Future(errors); + Future res(errors); + errors = nullptr; + return res; } ~ReplyPromiseStream() { diff --git a/fdbrpc/genericactors.actor.h b/fdbrpc/genericactors.actor.h index 799118db993..3b75d243b10 100644 --- a/fdbrpc/genericactors.actor.h +++ b/fdbrpc/genericactors.actor.h @@ -200,15 +200,11 @@ struct PeerHolder { ACTOR template void endStreamOnDisconnect( Future signal, ReplyPromiseStream stream, Reference peer = Reference() ) { state PeerHolder holder = PeerHolder(peer); - try { - choose { - when(wait(signal)) { - stream.sendError(request_maybe_delivered()); - } - when(wait(stream.getErrorFutureAndDelPromiseRef())) {} + choose { + when(wait(signal)) { + stream.sendError(request_maybe_delivered()); } - } catch (Error &e) { - wait(delay(0)); + when(wait(stream.getErrorFutureAndDelPromiseRef())) {} } } From c181a6768d9ed701b865bde517f77e89a576434c Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 15:09:17 -0800 Subject: [PATCH 045/740] test acknowledgements --- fdbserver/NetworkTest.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdbserver/NetworkTest.h b/fdbserver/NetworkTest.h index 98fc6c8e969..bf46c8e6d9d 100644 --- a/fdbserver/NetworkTest.h +++ b/fdbserver/NetworkTest.h @@ -64,7 +64,7 @@ struct NetworkTestStreamingReply : ReplyPromiseStreamReply { int index = 0; NetworkTestStreamingReply() = default; explicit NetworkTestStreamingReply(int index) : index(index) {} - size_t expectedSize() const { return sizeof(*this); } + size_t expectedSize() const { return 4e6;/*sizeof(*this);*/ } template void serialize(Ar& ar) { From a7eed27d7d34820048fe909c673e96c947cf331b Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Mon, 14 Dec 2020 23:21:37 +0000 Subject: [PATCH 046/740] Use tutorial binary for faster compilation --- documentation/tutorial/tutorial.actor.cpp | 49 ++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/documentation/tutorial/tutorial.actor.cpp b/documentation/tutorial/tutorial.actor.cpp index 16904dc163e..df9116e2592 100644 --- a/documentation/tutorial/tutorial.actor.cpp +++ b/documentation/tutorial/tutorial.actor.cpp @@ -100,10 +100,11 @@ struct EchoServerInterface { RequestStream getInterface; RequestStream echo; RequestStream reverse; + RequestStream stream; template void serialize(Ar& ar) { - serializer(ar, echo, reverse); + serializer(ar, echo, reverse, stream); } }; @@ -141,6 +142,31 @@ struct ReverseRequest { } }; +struct StreamReply : ReplyPromiseStreamReply { + constexpr static FileIdentifier file_identifier = 440804; + + int index = 0; + StreamReply() = default; + explicit StreamReply(int index) : index(index) {} + + size_t expectedSize() const { return 2e6; } + + template + void serialize(Ar& ar) { + serializer(ar, ReplyPromiseStreamReply::acknowledgeEndpoint, index); + } +}; + +struct StreamRequest { + constexpr static FileIdentifier file_identifier = 5410805; + ReplyPromiseStream reply; + + template + void serialize(Ar& ar) { + serializer(ar, reply); + } +}; + uint64_t tokenCounter = 1; ACTOR Future echoServer() { @@ -155,6 +181,15 @@ ACTOR Future echoServer() { when(ReverseRequest req = waitNext(echoServer.reverse.getFuture())) { req.reply.send(std::string(req.message.rbegin(), req.message.rend())); } + when(state StreamRequest req = waitNext(echoServer.stream.getFuture())) { + state int i = 0; + for (; i < 100; ++i) { + wait(req.reply.onReady()); + std::cout << "Send " << i << std::endl; + req.reply.send(StreamReply{ i }); + } + req.reply.sendError(end_of_stream()); + } } } } @@ -172,6 +207,18 @@ ACTOR Future echoClient() { reverseRequest.message = "Hello World"; std::string reverseString = wait(server.reverse.getReply(reverseRequest)); std::cout << format("Sent %s to reverse, received %s\n", "Hello World", reverseString.c_str()); + + state ReplyPromiseStream stream = server.stream.getReplyStream(StreamRequest{}); + state int j = 0; + try { + loop { + StreamReply rep = waitNext(stream.getFuture()); + std::cout << "Rep: " << rep.index << std::endl; + ASSERT(rep.index == j++); + } + } catch (Error& e) { + ASSERT(e.code() == error_code_end_of_stream || e.code() == error_code_request_maybe_delivered); + } return Void(); } From ad39cf1d348e0d97152d73300fe3494e3af23510 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 15:24:48 -0800 Subject: [PATCH 047/740] added ack logging --- fdbrpc/fdbrpc.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index c56abc54b1a..0180a2bef55 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -248,6 +248,7 @@ struct AcknowledgementReceiver final : FlowReceiver, FastAllocated> message; reader.deserialize(message); ASSERT(!message.isError() && message.get().asUnderlyingType().bytes > bytesAcknowledged); @@ -286,6 +287,7 @@ struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAl } else { if(message.get().asUnderlyingType().acknowledgeEndpoint.present()) { acknowledgements = AcknowledgementReceiver(message.get().asUnderlyingType().acknowledgeEndpoint.get()); + printf("Acknowledgements create with remote endpoint: %s %s\n", acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).getPrimaryAddress().toString().c_str(), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).token.toString().c_str()); } this->send(std::move(message.get().asUnderlyingType())); } @@ -296,7 +298,8 @@ struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAl T res = this->popImpl(); if(acknowledgements.getRawEndpoint().isValid()) { acknowledgements.bytesAcknowledged += res.expectedSize(); - FlowTransport::transport().sendUnreliable(SerializeSource(AcknowledgementReply(acknowledgements.bytesAcknowledged)), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint), true); + printf("Sending acknowledgement to endpoint: %d %s %s\n", acknowledgements.bytesAcknowledged, acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).getPrimaryAddress().toString().c_str(), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).token.toString().c_str()); + FlowTransport::transport().sendUnreliable(SerializeSource(AcknowledgementReply(acknowledgements.bytesAcknowledged)), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint), false); } return res; } @@ -317,6 +320,7 @@ class ReplyPromiseStream { if (queue->isRemoteEndpoint()) { if(!queue->acknowledgements.getRawEndpoint().isValid()) { value.acknowledgeEndpoint = queue->acknowledgements.getEndpoint(TaskPriority::DefaultEndpoint); + printf("Registered Ack Endpoint: %s\n", queue->acknowledgements.getEndpoint(TaskPriority::DefaultEndpoint).token.toString().c_str()); } queue->acknowledgements.bytesSent += value.expectedSize(); if((!queue->acknowledgements.ready.isValid() || queue->acknowledgements.ready.isSet()) && queue->acknowledgements.bytesSent - queue->acknowledgements.bytesAcknowledged >= 2e6) { From 50a3372155a0371b11a911e1df4fd8022a1290e4 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 15:51:20 -0800 Subject: [PATCH 048/740] use loadedEndpoint for acknowledgement --- documentation/tutorial/tutorial.actor.cpp | 2 +- fdbclient/StorageServerInterface.h | 2 +- fdbrpc/fdbrpc.h | 8 ++++---- fdbserver/NetworkTest.h | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/documentation/tutorial/tutorial.actor.cpp b/documentation/tutorial/tutorial.actor.cpp index df9116e2592..34515dacaf7 100644 --- a/documentation/tutorial/tutorial.actor.cpp +++ b/documentation/tutorial/tutorial.actor.cpp @@ -153,7 +153,7 @@ struct StreamReply : ReplyPromiseStreamReply { template void serialize(Ar& ar) { - serializer(ar, ReplyPromiseStreamReply::acknowledgeEndpoint, index); + serializer(ar, ReplyPromiseStreamReply::acknowledgeToken, index); } }; diff --git a/fdbclient/StorageServerInterface.h b/fdbclient/StorageServerInterface.h index 447013311e1..b285ae6d187 100644 --- a/fdbclient/StorageServerInterface.h +++ b/fdbclient/StorageServerInterface.h @@ -278,7 +278,7 @@ struct GetKeyValuesStreamReply : public ReplyPromiseStreamReply { template void serialize( Ar& ar ) { - serializer(ar, ReplyPromiseStreamReply::acknowledgeEndpoint, data, version, more, cached, arena); + serializer(ar, ReplyPromiseStreamReply::acknowledgeToken, data, version, more, cached, arena); } }; diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index 0180a2bef55..58a8bf2d760 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -218,7 +218,7 @@ template void setReplyPriority(const ReplyPromise & p, TaskPriority taskID) { p.getEndpoint(taskID); } struct ReplyPromiseStreamReply { - Optional acknowledgeEndpoint; + Optional acknowledgeToken; ReplyPromiseStreamReply() {} }; @@ -285,8 +285,8 @@ struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAl } this->sendError(message.getError()); } else { - if(message.get().asUnderlyingType().acknowledgeEndpoint.present()) { - acknowledgements = AcknowledgementReceiver(message.get().asUnderlyingType().acknowledgeEndpoint.get()); + if(message.get().asUnderlyingType().acknowledgeToken.present()) { + acknowledgements = AcknowledgementReceiver(FlowTransport::transport().loadedEndpoint(message.get().asUnderlyingType().acknowledgeToken.get())); printf("Acknowledgements create with remote endpoint: %s %s\n", acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).getPrimaryAddress().toString().c_str(), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).token.toString().c_str()); } this->send(std::move(message.get().asUnderlyingType())); @@ -319,7 +319,7 @@ class ReplyPromiseStream { void send(U && value) const { if (queue->isRemoteEndpoint()) { if(!queue->acknowledgements.getRawEndpoint().isValid()) { - value.acknowledgeEndpoint = queue->acknowledgements.getEndpoint(TaskPriority::DefaultEndpoint); + value.acknowledgeToken = queue->acknowledgements.getEndpoint(TaskPriority::DefaultEndpoint).token; printf("Registered Ack Endpoint: %s\n", queue->acknowledgements.getEndpoint(TaskPriority::DefaultEndpoint).token.toString().c_str()); } queue->acknowledgements.bytesSent += value.expectedSize(); diff --git a/fdbserver/NetworkTest.h b/fdbserver/NetworkTest.h index bf46c8e6d9d..7e5cd30411b 100644 --- a/fdbserver/NetworkTest.h +++ b/fdbserver/NetworkTest.h @@ -68,7 +68,7 @@ struct NetworkTestStreamingReply : ReplyPromiseStreamReply { template void serialize(Ar& ar) { - serializer(ar, ReplyPromiseStreamReply::acknowledgeEndpoint, index); + serializer(ar, ReplyPromiseStreamReply::acknowledgeToken, index); } }; From 3b618fdd177b8c9df4aa0e1f58c26f35b28a277d Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 16:10:06 -0800 Subject: [PATCH 049/740] more logging --- fdbrpc/FlowTransport.actor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/fdbrpc/FlowTransport.actor.cpp b/fdbrpc/FlowTransport.actor.cpp index 4221d2f4ccf..81891b66269 100644 --- a/fdbrpc/FlowTransport.actor.cpp +++ b/fdbrpc/FlowTransport.actor.cpp @@ -1136,6 +1136,7 @@ ACTOR static Future connectionReader( } } if (compatible) { + printf("Peer Addr: %s\n", peerAddress.toString().c_str()); scanPackets( transport, unprocessed_begin, unprocessed_end, arena, peerAddress, peerProtocolVersion ); } else if(!expectConnectPacket) { From 312467bbf8868715149e1cdd369b4fad7513cbd6 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 16:14:19 -0800 Subject: [PATCH 050/740] more logging --- fdbrpc/FlowTransport.actor.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fdbrpc/FlowTransport.actor.cpp b/fdbrpc/FlowTransport.actor.cpp index 81891b66269..ae1f47a2599 100644 --- a/fdbrpc/FlowTransport.actor.cpp +++ b/fdbrpc/FlowTransport.actor.cpp @@ -1009,6 +1009,7 @@ ACTOR static Future connectionReader( state ProtocolVersion peerProtocolVersion; peerAddress = conn->getPeerAddress(); + printf("Peer Add1: %s\n", peerAddress.toString().c_str()); if (!peer) { ASSERT( !peerAddress.isPublic() ); } @@ -1122,6 +1123,7 @@ ACTOR static Future connectionReader( if (pkt.canonicalRemotePort) { peerAddress = NetworkAddress(pkt.canonicalRemoteIp(), pkt.canonicalRemotePort, true, peerAddress.isTLS()); + printf("Peer Addr2: %s\n", peerAddress.toString().c_str()); } peer = transport->getOrOpenPeer(peerAddress, false); peer->compatible = compatible; @@ -1136,7 +1138,7 @@ ACTOR static Future connectionReader( } } if (compatible) { - printf("Peer Addr: %s\n", peerAddress.toString().c_str()); + printf("Peer Addr3: %s\n", peerAddress.toString().c_str()); scanPackets( transport, unprocessed_begin, unprocessed_end, arena, peerAddress, peerProtocolVersion ); } else if(!expectConnectPacket) { From 9c16acbef00eb90f824ece43e2e679e1339cc77a Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 16:26:08 -0800 Subject: [PATCH 051/740] more logging --- fdbrpc/FlowTransport.actor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdbrpc/FlowTransport.actor.cpp b/fdbrpc/FlowTransport.actor.cpp index ae1f47a2599..5d1d8f6e0b2 100644 --- a/fdbrpc/FlowTransport.actor.cpp +++ b/fdbrpc/FlowTransport.actor.cpp @@ -1009,7 +1009,7 @@ ACTOR static Future connectionReader( state ProtocolVersion peerProtocolVersion; peerAddress = conn->getPeerAddress(); - printf("Peer Add1: %s\n", peerAddress.toString().c_str()); + printf("Peer Add1: %d %s\n", (bool) peer, peerAddress.toString().c_str()); if (!peer) { ASSERT( !peerAddress.isPublic() ); } From 117c063fbc9e3d258cd0db60ddad48810ca7507c Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 16:30:00 -0800 Subject: [PATCH 052/740] more logging --- flow/Net2.actor.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/flow/Net2.actor.cpp b/flow/Net2.actor.cpp index 6cf1037908b..17ed6d81b93 100644 --- a/flow/Net2.actor.cpp +++ b/flow/Net2.actor.cpp @@ -372,6 +372,7 @@ class Connection : public IConnection, ReferenceCounted { state Reference self( new Connection(*ios) ); self->peer_address = addr; + printf("Updating peer_addr1: %s\n", addr.toString().c_str()); try { auto to = tcpEndpoint(addr); BindPromise p("N2_ConnectError", self->id); @@ -390,6 +391,7 @@ class Connection : public IConnection, ReferenceCounted { // This is not part of the IConnection interface, because it is wrapped by IListener::accept() void accept(NetworkAddress peerAddr) { + printf("Updating peer_addr2: %s\n", peerAddr.toString().c_str()); this->peer_address = peerAddr; init(); } From 197987aa66197d36d2e15a926d049b7c63d59a02 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 16:36:38 -0800 Subject: [PATCH 053/740] more logging --- fdbrpc/FlowTransport.actor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdbrpc/FlowTransport.actor.cpp b/fdbrpc/FlowTransport.actor.cpp index 5d1d8f6e0b2..3d74eed7208 100644 --- a/fdbrpc/FlowTransport.actor.cpp +++ b/fdbrpc/FlowTransport.actor.cpp @@ -579,7 +579,7 @@ ACTOR Future connectionKeeper( Reference self, ? "OK" : "FAILED"); ++self->connectOutgoingCount; - + printf("FlowTransport connect: %s\n", self->destination.toString()); try { choose { when(Reference _conn = From 2fbcb7a44981fe8c1ef4377aef06b3decca4d25d Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 16:37:25 -0800 Subject: [PATCH 054/740] fixed logging --- fdbrpc/FlowTransport.actor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdbrpc/FlowTransport.actor.cpp b/fdbrpc/FlowTransport.actor.cpp index 3d74eed7208..8f166592184 100644 --- a/fdbrpc/FlowTransport.actor.cpp +++ b/fdbrpc/FlowTransport.actor.cpp @@ -579,7 +579,7 @@ ACTOR Future connectionKeeper( Reference self, ? "OK" : "FAILED"); ++self->connectOutgoingCount; - printf("FlowTransport connect: %s\n", self->destination.toString()); + printf("FlowTransport connect: %s\n", self->destination.toString().c_str()); try { choose { when(Reference _conn = From e54aaf8a7763349cc6c3d8c7ffec264cd3d5edee Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 16:44:13 -0800 Subject: [PATCH 055/740] more debugging --- fdbrpc/FlowTransport.actor.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fdbrpc/FlowTransport.actor.cpp b/fdbrpc/FlowTransport.actor.cpp index 8f166592184..ce81f4c1780 100644 --- a/fdbrpc/FlowTransport.actor.cpp +++ b/fdbrpc/FlowTransport.actor.cpp @@ -1225,6 +1225,10 @@ Reference TransportData::getOrOpenPeer( NetworkAddress const& address, boo if(!peer) { peer = makeReference(this, address); if(startConnectionKeeper && !isLocalAddress(address)) { + fprintf("getOrOpen %s\n", address.toString().c_str()); + if(!address.ip.isValid()) { + crashAndDie(); + } peer->connect = connectionKeeper(peer); } peers[address] = peer; From 2354d93030aff7d95d25bd6bd10ff2235645b466 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 16:44:49 -0800 Subject: [PATCH 056/740] fixed logging --- fdbrpc/FlowTransport.actor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdbrpc/FlowTransport.actor.cpp b/fdbrpc/FlowTransport.actor.cpp index ce81f4c1780..154a7336a94 100644 --- a/fdbrpc/FlowTransport.actor.cpp +++ b/fdbrpc/FlowTransport.actor.cpp @@ -1225,7 +1225,7 @@ Reference TransportData::getOrOpenPeer( NetworkAddress const& address, boo if(!peer) { peer = makeReference(this, address); if(startConnectionKeeper && !isLocalAddress(address)) { - fprintf("getOrOpen %s\n", address.toString().c_str()); + printf("getOrOpen %s\n", address.toString().c_str()); if(!address.ip.isValid()) { crashAndDie(); } From 63d5cead644bd0d894d2efe6f858c9c267dbcf7d Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 16:53:51 -0800 Subject: [PATCH 057/740] do not open connections to invalid IP addresses --- fdbrpc/FlowTransport.actor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdbrpc/FlowTransport.actor.cpp b/fdbrpc/FlowTransport.actor.cpp index 154a7336a94..96fc38fd037 100644 --- a/fdbrpc/FlowTransport.actor.cpp +++ b/fdbrpc/FlowTransport.actor.cpp @@ -1323,7 +1323,7 @@ Endpoint FlowTransport::loadedEndpoint( const UID& token ) { } void FlowTransport::addPeerReference(const Endpoint& endpoint, bool isStream) { - if (!isStream || !endpoint.getPrimaryAddress().isValid()) + if (!isStream || !endpoint.getPrimaryAddress().ip.isValid()) return; Reference peer = self->getOrOpenPeer(endpoint.getPrimaryAddress()); From 9bc30d85afdd0a109790b9727d9cb80c1d84a411 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 17:06:27 -0800 Subject: [PATCH 058/740] revert changes --- fdbrpc/FlowTransport.actor.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/fdbrpc/FlowTransport.actor.cpp b/fdbrpc/FlowTransport.actor.cpp index 96fc38fd037..9de88a5bfd6 100644 --- a/fdbrpc/FlowTransport.actor.cpp +++ b/fdbrpc/FlowTransport.actor.cpp @@ -1226,9 +1226,6 @@ Reference TransportData::getOrOpenPeer( NetworkAddress const& address, boo peer = makeReference(this, address); if(startConnectionKeeper && !isLocalAddress(address)) { printf("getOrOpen %s\n", address.toString().c_str()); - if(!address.ip.isValid()) { - crashAndDie(); - } peer->connect = connectionKeeper(peer); } peers[address] = peer; @@ -1323,7 +1320,7 @@ Endpoint FlowTransport::loadedEndpoint( const UID& token ) { } void FlowTransport::addPeerReference(const Endpoint& endpoint, bool isStream) { - if (!isStream || !endpoint.getPrimaryAddress().ip.isValid()) + if (!isStream || !endpoint.getPrimaryAddress().isValid()) return; Reference peer = self->getOrOpenPeer(endpoint.getPrimaryAddress()); From 4911a66cb1d12cecddfe1bfe430b0406e5b26dae Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 17:27:13 -0800 Subject: [PATCH 059/740] experiment with pop override --- fdbrpc/fdbrpc.h | 8 +++----- flow/flow.h | 17 ++++------------- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index 58a8bf2d760..cee3e8bf8cb 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -294,16 +294,14 @@ struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAl this->delPromiseRef(); } - T pop() override { - T res = this->popImpl(); + void popAction() override { if(acknowledgements.getRawEndpoint().isValid()) { - acknowledgements.bytesAcknowledged += res.expectedSize(); + acknowledgements.bytesAcknowledged++; printf("Sending acknowledgement to endpoint: %d %s %s\n", acknowledgements.bytesAcknowledged, acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).getPrimaryAddress().toString().c_str(), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).token.toString().c_str()); FlowTransport::transport().sendUnreliable(SerializeSource(AcknowledgementReply(acknowledgements.bytesAcknowledged)), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint), false); } - return res; } - + ~NetNotifiedQueueWithErrors() { printf("NetNotifiedQueue destructor %s\n", getRawEndpoint().token.toString().c_str()); } diff --git a/flow/flow.h b/flow/flow.h index 6c66c03791e..25f2537edbe 100644 --- a/flow/flow.h +++ b/flow/flow.h @@ -580,17 +580,19 @@ struct NotifiedQueue : private SingleCallback, FastAllocated bool isError() const { return queue.empty() && error.isValid(); } // the *next* thing queued is an error uint32_t size() const { return queue.size(); } - virtual T pop() { - return popImpl(); + T pop() { if (queue.empty()) { if (error.isValid()) throw error; throw internal_error(); } auto copy = std::move(queue.front()); queue.pop(); + popAction(); return copy; } + virtual void popAction() {} + template void send(U && value) { if (error.isValid()) return; @@ -645,17 +647,6 @@ struct NotifiedQueue : private SingleCallback, FastAllocated virtual void unwait() override { delFutureRef(); } virtual void fire(T const&) override { ASSERT(false); } virtual void fire(T&&) override { ASSERT(false); } - - protected: - T popImpl() { - if (queue.empty()) { - if (error.isValid()) throw error; - throw internal_error(); - } - auto copy = std::move(queue.front()); - queue.pop(); - return copy; - } }; From c03ffd6db4bf76037ce573f95d00cadf42f3a00c Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 17:49:05 -0800 Subject: [PATCH 060/740] send acks when someone is waiting on the stream already --- fdbrpc/fdbrpc.h | 18 ++++++++++++++---- flow/flow.h | 24 +++++++++++++----------- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index cee3e8bf8cb..9277208e477 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -289,19 +289,29 @@ struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAl acknowledgements = AcknowledgementReceiver(FlowTransport::transport().loadedEndpoint(message.get().asUnderlyingType().acknowledgeToken.get())); printf("Acknowledgements create with remote endpoint: %s %s\n", acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).getPrimaryAddress().toString().c_str(), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).token.toString().c_str()); } + if(SingleCallback::next != this) { + if(acknowledgements.getRawEndpoint().isValid()) { + acknowledgements.bytesAcknowledged += res.expectedSize(); + printf("Sending acknowledgement1 to endpoint: %d %s %s\n", acknowledgements.bytesAcknowledged, acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).getPrimaryAddress().toString().c_str(), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).token.toString().c_str()); + FlowTransport::transport().sendUnreliable(SerializeSource(AcknowledgementReply(acknowledgements.bytesAcknowledged)), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint), false); + } + } + this->send(std::move(message.get().asUnderlyingType())); } this->delPromiseRef(); } - void popAction() override { + T pop() override { + T res = this->popImpl(); if(acknowledgements.getRawEndpoint().isValid()) { - acknowledgements.bytesAcknowledged++; - printf("Sending acknowledgement to endpoint: %d %s %s\n", acknowledgements.bytesAcknowledged, acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).getPrimaryAddress().toString().c_str(), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).token.toString().c_str()); + acknowledgements.bytesAcknowledged += res.expectedSize(); + printf("Sending acknowledgement2 to endpoint: %d %s %s\n", acknowledgements.bytesAcknowledged, acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).getPrimaryAddress().toString().c_str(), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).token.toString().c_str()); FlowTransport::transport().sendUnreliable(SerializeSource(AcknowledgementReply(acknowledgements.bytesAcknowledged)), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint), false); } + return res; } - + ~NetNotifiedQueueWithErrors() { printf("NetNotifiedQueue destructor %s\n", getRawEndpoint().token.toString().c_str()); } diff --git a/flow/flow.h b/flow/flow.h index 25f2537edbe..67593c4115a 100644 --- a/flow/flow.h +++ b/flow/flow.h @@ -580,19 +580,10 @@ struct NotifiedQueue : private SingleCallback, FastAllocated bool isError() const { return queue.empty() && error.isValid(); } // the *next* thing queued is an error uint32_t size() const { return queue.size(); } - T pop() { - if (queue.empty()) { - if (error.isValid()) throw error; - throw internal_error(); - } - auto copy = std::move(queue.front()); - queue.pop(); - popAction(); - return copy; + virtual T pop() { + return popImpl(); } - virtual void popAction() {} - template void send(U && value) { if (error.isValid()) return; @@ -647,6 +638,17 @@ struct NotifiedQueue : private SingleCallback, FastAllocated virtual void unwait() override { delFutureRef(); } virtual void fire(T const&) override { ASSERT(false); } virtual void fire(T&&) override { ASSERT(false); } + + protected: + T popImpl() { + if (queue.empty()) { + if (error.isValid()) throw error; + throw internal_error(); + } + auto copy = std::move(queue.front()); + queue.pop(); + return copy; + } }; From 5251010f22c619424e7f310ac2a1c8fc24d9400e Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 17:50:57 -0800 Subject: [PATCH 061/740] fixed compiler error --- fdbrpc/fdbrpc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index 9277208e477..d85b31e4179 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -291,7 +291,7 @@ struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAl } if(SingleCallback::next != this) { if(acknowledgements.getRawEndpoint().isValid()) { - acknowledgements.bytesAcknowledged += res.expectedSize(); + acknowledgements.bytesAcknowledged += message.get().asUnderlyingType().expectedSize(); printf("Sending acknowledgement1 to endpoint: %d %s %s\n", acknowledgements.bytesAcknowledged, acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).getPrimaryAddress().toString().c_str(), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).token.toString().c_str()); FlowTransport::transport().sendUnreliable(SerializeSource(AcknowledgementReply(acknowledgements.bytesAcknowledged)), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint), false); } From 5fddfb84a023b538006f997f9e42f597e7bb7bbe Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 17:53:31 -0800 Subject: [PATCH 062/740] compile fix --- fdbrpc/fdbrpc.h | 2 +- flow/flow.h | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index d85b31e4179..5ae105def4e 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -289,7 +289,7 @@ struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAl acknowledgements = AcknowledgementReceiver(FlowTransport::transport().loadedEndpoint(message.get().asUnderlyingType().acknowledgeToken.get())); printf("Acknowledgements create with remote endpoint: %s %s\n", acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).getPrimaryAddress().toString().c_str(), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).token.toString().c_str()); } - if(SingleCallback::next != this) { + if(this->shouldFireImmediately()) { if(acknowledgements.getRawEndpoint().isValid()) { acknowledgements.bytesAcknowledged += message.get().asUnderlyingType().expectedSize(); printf("Sending acknowledgement1 to endpoint: %d %s %s\n", acknowledgements.bytesAcknowledged, acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).getPrimaryAddress().toString().c_str(), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).token.toString().c_str()); diff --git a/flow/flow.h b/flow/flow.h index 67593c4115a..c0a57e1d612 100644 --- a/flow/flow.h +++ b/flow/flow.h @@ -600,7 +600,7 @@ struct NotifiedQueue : private SingleCallback, FastAllocated if (error.isValid()) return; this->error = err; - if (SingleCallback::next != this) + if (shouldFireImmediately()) SingleCallback::next->error(err); } @@ -649,6 +649,10 @@ struct NotifiedQueue : private SingleCallback, FastAllocated queue.pop(); return copy; } + + bool shouldFireImmediately() { + return SingleCallback::next != this; + } }; From 94ab2620d5500c7c66be22e1214f1e75efbd44ed Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Mon, 14 Dec 2020 18:03:17 -0800 Subject: [PATCH 063/740] update logging for a failed assert --- fdbrpc/fdbrpc.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index 5ae105def4e..453f62d9559 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -248,10 +248,14 @@ struct AcknowledgementReceiver final : FlowReceiver, FastAllocated> message; reader.deserialize(message); - ASSERT(!message.isError() && message.get().asUnderlyingType().bytes > bytesAcknowledged); + if(message.isError()) { + printf("AcknowledgementReceived Error\n"); + } else { + printf("AcknowledgementReceived %d %d\n", message.get().asUnderlyingType().bytes, bytesAcknowledged); + } + ASSERT(!message.isError() && message.get().asUnderlyingType().bytes >= bytesAcknowledged); bytesAcknowledged = message.get().asUnderlyingType().bytes; if(bytesSent - bytesAcknowledged < 2e6) { ready.send(Void()); From 7f8465af2c5e3336c5f5f5a4539a518f814b32c3 Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Tue, 15 Dec 2020 02:09:11 +0000 Subject: [PATCH 064/740] AcknowledgementReply is not wrapped in ErrorOr --- fdbrpc/fdbrpc.h | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index 453f62d9559..94b83111506 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -248,15 +248,11 @@ struct AcknowledgementReceiver final : FlowReceiver, FastAllocated> message; + printf("AcknowledgementReceived\n"); + AcknowledgementReply message; reader.deserialize(message); - if(message.isError()) { - printf("AcknowledgementReceived Error\n"); - } else { - printf("AcknowledgementReceived %d %d\n", message.get().asUnderlyingType().bytes, bytesAcknowledged); - } - ASSERT(!message.isError() && message.get().asUnderlyingType().bytes >= bytesAcknowledged); - bytesAcknowledged = message.get().asUnderlyingType().bytes; + ASSERT(message.bytes > bytesAcknowledged); + bytesAcknowledged = message.bytes; if(bytesSent - bytesAcknowledged < 2e6) { ready.send(Void()); } From 048782bc7e53a5cb20dddce364854b8f00b4f80e Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Tue, 15 Dec 2020 02:32:26 +0000 Subject: [PATCH 065/740] Fix printf format overflow --- fdbrpc/fdbrpc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index 94b83111506..3428668fac3 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -292,7 +292,7 @@ struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAl if(this->shouldFireImmediately()) { if(acknowledgements.getRawEndpoint().isValid()) { acknowledgements.bytesAcknowledged += message.get().asUnderlyingType().expectedSize(); - printf("Sending acknowledgement1 to endpoint: %d %s %s\n", acknowledgements.bytesAcknowledged, acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).getPrimaryAddress().toString().c_str(), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).token.toString().c_str()); + printf("Sending acknowledgement1 to endpoint: %ld %s %s\n", acknowledgements.bytesAcknowledged, acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).getPrimaryAddress().toString().c_str(), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).token.toString().c_str()); FlowTransport::transport().sendUnreliable(SerializeSource(AcknowledgementReply(acknowledgements.bytesAcknowledged)), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint), false); } } From 343e29cd01742a3837dfd7259eb51faacaba14fa Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Tue, 15 Dec 2020 02:39:55 +0000 Subject: [PATCH 066/740] Only set ready promise if it can be set --- fdbrpc/fdbrpc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index 3428668fac3..246a589aa8e 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -253,7 +253,7 @@ struct AcknowledgementReceiver final : FlowReceiver, FastAllocated bytesAcknowledged); bytesAcknowledged = message.bytes; - if(bytesSent - bytesAcknowledged < 2e6) { + if (bytesSent - bytesAcknowledged < 2e6 && ready.isValid() && ready.canBeSet()) { ready.send(Void()); } } From aca2e057723ba6d96ad697e46b42be8c2cafb5bb Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Tue, 15 Dec 2020 10:50:15 -0800 Subject: [PATCH 067/740] fix: make sure the server does not miss a client failure --- fdbrpc/fdbrpc.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index 246a589aa8e..fbdd9f01261 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -242,6 +242,7 @@ struct AcknowledgementReceiver final : FlowReceiver, FastAllocated ready; + Future failures; AcknowledgementReceiver() : bytesSent(0), bytesAcknowledged(0), ready(nullptr) {} AcknowledgementReceiver(const Endpoint& remoteEndpoint) : FlowReceiver(remoteEndpoint, false), @@ -269,6 +270,7 @@ struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAl NetNotifiedQueueWithErrors(int futures, int promises) : NotifiedQueue(futures, promises) {} NetNotifiedQueueWithErrors(int futures, int promises, const Endpoint& remoteEndpoint) : NotifiedQueue(futures, promises), FlowReceiver(remoteEndpoint, false) { + acknowledgements.failures = tagError(makeDependent(IFailureMonitor::failureMonitor()).onDisconnectOrFailure(remoteEndpoint), request_maybe_delivered()); printf("NetNotified create with remote endpoint: %s\n", remoteEndpoint.token.toString().c_str()); } @@ -395,8 +397,7 @@ class ReplyPromiseStream { if(queue->acknowledgements.bytesSent - queue->acknowledgements.bytesAcknowledged < 2e6) { return Void(); } - return queue->acknowledgements.ready.getFuture() || - tagError(makeDependent(IFailureMonitor::failureMonitor()).onDisconnectOrFailure(queue->acknowledgements.getEndpoint(TaskPriority::DefaultEndpoint)), request_maybe_delivered()); + return queue->acknowledgements.ready.getFuture() || queue->acknowledgements.failures; } void operator=(const ReplyPromiseStream& rhs) { From 9b327046275a5e5507fbce7fed22c8ce55379bca Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Tue, 15 Dec 2020 11:40:44 -0800 Subject: [PATCH 068/740] added error handling for request_maybe_delivered --- fdbserver/networktest.actor.cpp | 55 +++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/fdbserver/networktest.actor.cpp b/fdbserver/networktest.actor.cpp index 5fd903741b7..0e79f87f9a2 100644 --- a/fdbserver/networktest.actor.cpp +++ b/fdbserver/networktest.actor.cpp @@ -73,32 +73,39 @@ ACTOR Future networkTestServer() { state LatencyStats latency; loop { - choose { - when(state NetworkTestStreamingRequest req = waitNext(interf.test.getFuture())) { - state LatencyStats::sample sample = latency.tick(); - state int i = 0; - for (; i < 100; ++i) { - fprintf(stderr, "Wait onReady %d\n", i); - wait(req.reply.onReady()); - fprintf(stderr, "Send reply %d\n", i); - req.reply.send(NetworkTestStreamingReply{ i }); + try { + choose { + when(state NetworkTestStreamingRequest req = waitNext(interf.test.getFuture())) { + state LatencyStats::sample sample = latency.tick(); + state int i = 0; + for (; i < 100; ++i) { + fprintf(stderr, "Wait onReady %d\n", i); + wait(req.reply.onReady()); + fprintf(stderr, "Send reply %d\n", i); + req.reply.send(NetworkTestStreamingReply{ i }); + } + fprintf(stderr, "Send end_of_stream\n"); + req.reply.sendError(end_of_stream()); + latency.tock(sample); + sent++; } - fprintf(stderr, "Send end_of_stream\n"); - req.reply.sendError(end_of_stream()); - latency.tock(sample); - sent++; - } - when( wait( logging ) ) { - auto spd = sent / (now() - lastTime); - if (FLOW_KNOBS->NETWORK_TEST_SCRIPT_MODE) { - fprintf(stderr, "%f\t%.3f\t%.3f\n", spd, latency.mean() * 1e6, latency.stddev() * 1e6); - } else { - fprintf(stderr, "responses per second: %f (%f us)\n", spd, latency.mean() * 1e6); + when( wait( logging ) ) { + auto spd = sent / (now() - lastTime); + if (FLOW_KNOBS->NETWORK_TEST_SCRIPT_MODE) { + fprintf(stderr, "%f\t%.3f\t%.3f\n", spd, latency.mean() * 1e6, latency.stddev() * 1e6); + } else { + fprintf(stderr, "responses per second: %f (%f us)\n", spd, latency.mean() * 1e6); + } + latency.reset(); + lastTime = now(); + sent = 0; + logging = delay( 1.0 ); } - latency.reset(); - lastTime = now(); - sent = 0; - logging = delay( 1.0 ); + } + } catch (Error &e) { + if(e.code() != error_code_request_maybe_delivered) { + fprintf(stderr, "Error: %s\n", e.what()); + throw e; } } } From 806af6469b1a2998e57c538ea82949f96326f279 Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Tue, 15 Dec 2020 21:22:46 +0000 Subject: [PATCH 069/740] Add client that uses getRangeStream --- documentation/tutorial/tutorial.actor.cpp | 34 +++++++++-------------- fdbclient/NativeAPI.actor.cpp | 9 ++++-- fdbrpc/FlowTransport.actor.cpp | 8 ------ fdbserver/storageserver.actor.cpp | 9 +++++- flow/Net2.actor.cpp | 2 -- 5 files changed, 28 insertions(+), 34 deletions(-) diff --git a/documentation/tutorial/tutorial.actor.cpp b/documentation/tutorial/tutorial.actor.cpp index 34515dacaf7..d7502040d28 100644 --- a/documentation/tutorial/tutorial.actor.cpp +++ b/documentation/tutorial/tutorial.actor.cpp @@ -395,36 +395,28 @@ ACTOR Future multipleClients() { std::string clusterFile = "fdb.cluster"; ACTOR Future fdbClient() { - wait(delay(30)); state Database db = Database::createDatabase(clusterFile, 300); state Transaction tx(db); - state std::string keyPrefix = "/tut/"; - state Key startKey; - state KeyRef endKey = LiteralStringRef("/tut0"); - state int beginIdx = 0; + state PromiseStream> results; + state Key next; loop { try { - tx.reset(); - // this workload is stupidly simple: - // 1. select a random key between 1 - // and 1e8 - // 2. select this key plus the 100 - // next ones - // 3. write 10 values in [k, k+100] - beginIdx = deterministicRandom()->randomInt(0, 1e8 - 100); - startKey = keyPrefix + std::to_string(beginIdx); - Standalone range = wait(tx.getRange(KeyRangeRef(startKey, endKey), 100)); - for (int i = 0; i < 10; ++i) { - Key k = Key(keyPrefix + std::to_string(beginIdx + deterministicRandom()->randomInt(0, 100))); - tx.set(k, LiteralStringRef("foo")); + state Future stream = + tx.getRangeStream(results, KeySelector(firstGreaterOrEqual(next), next.arena()), + KeySelector(firstGreaterOrEqual(normalKeys.end)), GetRangeLimits()); + loop { + Standalone range = waitNext(results.getFuture()); + std::cout << "Got " << range.expectedSize() << std::endl; + next = keyAfter(range.back().key); } - wait(tx.commit()); - std::cout << "Committed\n"; - wait(delay(2.0)); } catch (Error& e) { + if (e.code() == error_code_end_of_stream) { + break; + } wait(tx.onError(e)); } } + return Void(); } ACTOR Future fdbStatusStresser() { diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index ffd13613419..e7c24c12fff 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -2705,7 +2705,11 @@ ACTOR Future getRangeStream( PromiseStream> res req.end = firstGreaterOrEqual( range.end ); req.spanContext = span.context; req.limit = reverse ? -CLIENT_KNOBS->REPLY_BYTE_LIMIT : CLIENT_KNOBS->REPLY_BYTE_LIMIT; - req.limitBytes = CLIENT_KNOBS->REPLY_BYTE_LIMIT; + if (limits.hasByteLimit()) { + req.limitBytes = limits.bytes; + } else { + req.limitBytes = std::numeric_limits::max(); + } ASSERT(req.limitBytes > 0 && req.limit != 0 && req.limit < 0 == reverse); @@ -2738,6 +2742,7 @@ ACTOR Future getRangeStream( PromiseStream> res when(GetKeyValuesStreamReply _rep = waitNext(replyStream.getFuture())) { rep = _rep; + limits.decrement(rep.data); } } ++cx->transactionPhysicalReadsCompleted; @@ -2771,7 +2776,7 @@ ACTOR Future getRangeStream( PromiseStream> res locations[shard].first = KeyRangeRef( keyAfter( output[output.size()-1].key ), locations[shard].first.end ); } - if (!more || locations[shard].first.empty()) { + if (!more || locations[shard].first.empty() || limits.isReached()) { TEST(true); // getRangeStream (!more || locations[shard].first.empty()) if(shard == locations.size()-1) { const KeyRangeRef& range = locations[shard].first; diff --git a/fdbrpc/FlowTransport.actor.cpp b/fdbrpc/FlowTransport.actor.cpp index 9de88a5bfd6..ff9f71b070c 100644 --- a/fdbrpc/FlowTransport.actor.cpp +++ b/fdbrpc/FlowTransport.actor.cpp @@ -89,7 +89,6 @@ void EndpointMap::realloc() { } void EndpointMap::insert( NetworkMessageReceiver* r, Endpoint::Token& token, TaskPriority priority ) { - printf("Endpoint Map Insert: %s\n", token.toString().c_str()); if (firstFree == uint32_t(-1)) realloc(); int index = firstFree; firstFree = data[index].nextFree; @@ -149,7 +148,6 @@ TaskPriority EndpointMap::getPriority( Endpoint::Token const& token ) { } void EndpointMap::remove( Endpoint::Token const& token, NetworkMessageReceiver* r ) { - printf("Endpoint Map Remove: %s\n", token.toString().c_str()); uint32_t index = token.second(); if ( index < data.size() && data[index].token().first() == token.first() && ((data[index].token().second()&0xffffffff00000000LL)|index)==token.second() && data[index].receiver == r ) { data[index].receiver = 0; @@ -579,7 +577,6 @@ ACTOR Future connectionKeeper( Reference self, ? "OK" : "FAILED"); ++self->connectOutgoingCount; - printf("FlowTransport connect: %s\n", self->destination.toString().c_str()); try { choose { when(Reference _conn = @@ -1009,7 +1006,6 @@ ACTOR static Future connectionReader( state ProtocolVersion peerProtocolVersion; peerAddress = conn->getPeerAddress(); - printf("Peer Add1: %d %s\n", (bool) peer, peerAddress.toString().c_str()); if (!peer) { ASSERT( !peerAddress.isPublic() ); } @@ -1123,7 +1119,6 @@ ACTOR static Future connectionReader( if (pkt.canonicalRemotePort) { peerAddress = NetworkAddress(pkt.canonicalRemoteIp(), pkt.canonicalRemotePort, true, peerAddress.isTLS()); - printf("Peer Addr2: %s\n", peerAddress.toString().c_str()); } peer = transport->getOrOpenPeer(peerAddress, false); peer->compatible = compatible; @@ -1138,7 +1133,6 @@ ACTOR static Future connectionReader( } } if (compatible) { - printf("Peer Addr3: %s\n", peerAddress.toString().c_str()); scanPackets( transport, unprocessed_begin, unprocessed_end, arena, peerAddress, peerProtocolVersion ); } else if(!expectConnectPacket) { @@ -1225,7 +1219,6 @@ Reference TransportData::getOrOpenPeer( NetworkAddress const& address, boo if(!peer) { peer = makeReference(this, address); if(startConnectionKeeper && !isLocalAddress(address)) { - printf("getOrOpen %s\n", address.toString().c_str()); peer->connect = connectionKeeper(peer); } peers[address] = peer; @@ -1501,7 +1494,6 @@ void FlowTransport::cancelReliable( ReliablePacket* p ) { } Reference FlowTransport::sendUnreliable( ISerializeSource const& what, const Endpoint& destination, bool openConnection ) { - printf("Send Unreliable: %s %s\n", destination.getPrimaryAddress().toString().c_str(), destination.token.toString().c_str()); if (self->isLocalAddress(destination.getPrimaryAddress())) { sendLocal( self, what, destination ); return Reference(); diff --git a/fdbserver/storageserver.actor.cpp b/fdbserver/storageserver.actor.cpp index 30d7049e845..eac398e6a29 100644 --- a/fdbserver/storageserver.actor.cpp +++ b/fdbserver/storageserver.actor.cpp @@ -1722,8 +1722,14 @@ ACTOR Future getKeyValuesStreamWork( StorageServer* data, GetKeyValuesStre state int remainingLimitBytes = req.limitBytes; loop { wait(req.reply.onReady()); - GetKeyValuesReply _r = wait( readRange(data, version, KeyRangeRef(begin, end), req.limit, &remainingLimitBytes, span.context) ); + printf("Issuing getRange for stream impl. begin: %s end: %s limit: %d limitBytes: %d\n", + printable(begin).c_str(), printable(end).c_str(), req.limit, remainingLimitBytes); + state int byteLimit = std::min(remainingLimitBytes, CLIENT_KNOBS->REPLY_BYTE_LIMIT); + state int byteLimitBefore = byteLimit; + GetKeyValuesReply _r = wait( readRange(data, version, KeyRangeRef(begin, end), req.limit, &byteLimit, span.context) ); + remainingLimitBytes -= byteLimitBefore - byteLimit; GetKeyValuesStreamReply r(_r); + printf("Result. size: %d more: %d \n", int(r.data.expectedSize()), int(r.more)); if( req.debugID.present() ) g_traceBatch.addEvent("TransactionDebug", req.debugID.get().first(), "storageserver.getKeyValues.AfterReadRange"); @@ -1765,6 +1771,7 @@ ACTOR Future getKeyValuesStreamWork( StorageServer* data, GetKeyValuesStre req.reply.sendError(end_of_stream()); break; } + ASSERT(r.data.size()); if(req.limit >= 0) { begin = keyAfter(r.data.back().key); diff --git a/flow/Net2.actor.cpp b/flow/Net2.actor.cpp index 17ed6d81b93..6cf1037908b 100644 --- a/flow/Net2.actor.cpp +++ b/flow/Net2.actor.cpp @@ -372,7 +372,6 @@ class Connection : public IConnection, ReferenceCounted { state Reference self( new Connection(*ios) ); self->peer_address = addr; - printf("Updating peer_addr1: %s\n", addr.toString().c_str()); try { auto to = tcpEndpoint(addr); BindPromise p("N2_ConnectError", self->id); @@ -391,7 +390,6 @@ class Connection : public IConnection, ReferenceCounted { // This is not part of the IConnection interface, because it is wrapped by IListener::accept() void accept(NetworkAddress peerAddr) { - printf("Updating peer_addr2: %s\n", peerAddr.toString().c_str()); this->peer_address = peerAddr; init(); } From aaf4249b0c52cd19b128376cf079ab870893d9be Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Tue, 15 Dec 2020 14:06:38 -0800 Subject: [PATCH 070/740] temporarily allow endpoint_not_found on ReplyPromiseStream endpoints. If we know cancel a ReplyPromiseStream before consuming the whole stream, send an error to the server --- fdbrpc/fdbrpc.h | 33 +++++++++++++++++++++++---------- flow/flow.h | 4 ++++ 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index fbdd9f01261..13c29cc86e5 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -250,12 +250,19 @@ struct AcknowledgementReceiver final : FlowReceiver, FastAllocated message; reader.deserialize(message); - ASSERT(message.bytes > bytesAcknowledged); - bytesAcknowledged = message.bytes; - if (bytesSent - bytesAcknowledged < 2e6 && ready.isValid() && ready.canBeSet()) { - ready.send(Void()); + if(message.isError()) { + if(ready.isSet()) { + ready = Promise(); + } + ready.sendError(message.getError()); + } else { + ASSERT(message.get().bytes > bytesAcknowledged); + bytesAcknowledged = message.get().bytes; + if (bytesSent - bytesAcknowledged < 2e6 && ready.isValid() && ready.canBeSet()) { + ready.send(Void()); + } } } }; @@ -269,7 +276,8 @@ struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAl NetNotifiedQueueWithErrors(int futures, int promises) : NotifiedQueue(futures, promises) {} NetNotifiedQueueWithErrors(int futures, int promises, const Endpoint& remoteEndpoint) - : NotifiedQueue(futures, promises), FlowReceiver(remoteEndpoint, false) { + : NotifiedQueue(futures, promises), FlowReceiver(remoteEndpoint, true) { + //FIXME: creating the FlowReceiver as a stream will mean that every cancelled read will lead to a permanent endpoint in the failed endpoints map acknowledgements.failures = tagError(makeDependent(IFailureMonitor::failureMonitor()).onDisconnectOrFailure(remoteEndpoint), request_maybe_delivered()); printf("NetNotified create with remote endpoint: %s\n", remoteEndpoint.token.toString().c_str()); } @@ -295,7 +303,7 @@ struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAl if(acknowledgements.getRawEndpoint().isValid()) { acknowledgements.bytesAcknowledged += message.get().asUnderlyingType().expectedSize(); printf("Sending acknowledgement1 to endpoint: %ld %s %s\n", acknowledgements.bytesAcknowledged, acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).getPrimaryAddress().toString().c_str(), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).token.toString().c_str()); - FlowTransport::transport().sendUnreliable(SerializeSource(AcknowledgementReply(acknowledgements.bytesAcknowledged)), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint), false); + FlowTransport::transport().sendUnreliable(SerializeSource>(AcknowledgementReply(acknowledgements.bytesAcknowledged)), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint), false); } } @@ -309,13 +317,18 @@ struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAl if(acknowledgements.getRawEndpoint().isValid()) { acknowledgements.bytesAcknowledged += res.expectedSize(); printf("Sending acknowledgement2 to endpoint: %d %s %s\n", acknowledgements.bytesAcknowledged, acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).getPrimaryAddress().toString().c_str(), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).token.toString().c_str()); - FlowTransport::transport().sendUnreliable(SerializeSource(AcknowledgementReply(acknowledgements.bytesAcknowledged)), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint), false); + FlowTransport::transport().sendUnreliable(SerializeSource>(AcknowledgementReply(acknowledgements.bytesAcknowledged)), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint), false); } return res; } ~NetNotifiedQueueWithErrors() { - printf("NetNotifiedQueue destructor %s\n", getRawEndpoint().token.toString().c_str()); + if(acknowledgements.getRawEndpoint().isValid() && acknowledgements.isRemoteEndpoint() && !this->hasError()) { + FlowTransport::transport().sendUnreliable(SerializeSource>(request_maybe_delivered()), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint), false); + printf("NetNotifiedQueue destructor with error %s\n", getRawEndpoint().token.toString().c_str()); + } else { + printf("NetNotifiedQueue destructor %s\n", getRawEndpoint().token.toString().c_str()); + } } }; @@ -333,7 +346,7 @@ class ReplyPromiseStream { printf("Registered Ack Endpoint: %s\n", queue->acknowledgements.getEndpoint(TaskPriority::DefaultEndpoint).token.toString().c_str()); } queue->acknowledgements.bytesSent += value.expectedSize(); - if((!queue->acknowledgements.ready.isValid() || queue->acknowledgements.ready.isSet()) && queue->acknowledgements.bytesSent - queue->acknowledgements.bytesAcknowledged >= 2e6) { + if((queue->acknowledgements.ready.isSet() && !queue->acknowledgements.ready.isError()) && queue->acknowledgements.bytesSent - queue->acknowledgements.bytesAcknowledged >= 2e6) { queue->acknowledgements.ready = Promise(); } FlowTransport::transport().sendUnreliable(SerializeSource>>(value), getEndpoint(), false); diff --git a/flow/flow.h b/flow/flow.h index c0a57e1d612..a993fa4061a 100644 --- a/flow/flow.h +++ b/flow/flow.h @@ -653,6 +653,10 @@ struct NotifiedQueue : private SingleCallback, FastAllocated bool shouldFireImmediately() { return SingleCallback::next != this; } + + bool hasError() { + return error.isValid(); + } }; From 6da9856ff23ad22a9b1150e7db144dabff8fc0df Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Tue, 15 Dec 2020 14:10:22 -0800 Subject: [PATCH 071/740] fix compile error --- fdbrpc/fdbrpc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index 13c29cc86e5..f0fdc5558cd 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -346,7 +346,7 @@ class ReplyPromiseStream { printf("Registered Ack Endpoint: %s\n", queue->acknowledgements.getEndpoint(TaskPriority::DefaultEndpoint).token.toString().c_str()); } queue->acknowledgements.bytesSent += value.expectedSize(); - if((queue->acknowledgements.ready.isSet() && !queue->acknowledgements.ready.isError()) && queue->acknowledgements.bytesSent - queue->acknowledgements.bytesAcknowledged >= 2e6) { + if((queue->acknowledgements.ready.isSet() && !queue->acknowledgements.ready.getFuture().isError()) && queue->acknowledgements.bytesSent - queue->acknowledgements.bytesAcknowledged >= 2e6) { queue->acknowledgements.ready = Promise(); } FlowTransport::transport().sendUnreliable(SerializeSource>>(value), getEndpoint(), false); From 5a3d72f36f840b63bcb6092cccf34df74102c835 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Tue, 15 Dec 2020 14:28:37 -0800 Subject: [PATCH 072/740] fix: onReady must return errors when possible --- fdbrpc/fdbrpc.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index f0fdc5558cd..ada87d3fb13 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -323,11 +323,10 @@ struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAl } ~NetNotifiedQueueWithErrors() { + printf("NetNotifiedQueue destructor %s\n", getRawEndpoint().token.toString().c_str()); if(acknowledgements.getRawEndpoint().isValid() && acknowledgements.isRemoteEndpoint() && !this->hasError()) { FlowTransport::transport().sendUnreliable(SerializeSource>(request_maybe_delivered()), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint), false); printf("NetNotifiedQueue destructor with error %s\n", getRawEndpoint().token.toString().c_str()); - } else { - printf("NetNotifiedQueue destructor %s\n", getRawEndpoint().token.toString().c_str()); } } }; @@ -407,7 +406,13 @@ class ReplyPromiseStream { uint32_t size() const { return queue->size(); } Future onReady() { + printf("OnReady Start\n"); + if(queue->acknowledgements.failures.isError() || (queue->acknowledgements.ready.isSet() && queue->acknowledgements.ready.getFuture().isError()) { + printf("OnReady Error\n"); + return queue->acknowledgements.ready.getFuture() || queue->acknowledgements.failures; + } if(queue->acknowledgements.bytesSent - queue->acknowledgements.bytesAcknowledged < 2e6) { + printf("OnReady Skip\n"); return Void(); } return queue->acknowledgements.ready.getFuture() || queue->acknowledgements.failures; From e9d0bc891ac2c83dd3edc44ca0373938d1dc49d8 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Tue, 15 Dec 2020 14:29:46 -0800 Subject: [PATCH 073/740] fix compile error --- fdbrpc/fdbrpc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index ada87d3fb13..a6b71bb9120 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -407,7 +407,7 @@ class ReplyPromiseStream { Future onReady() { printf("OnReady Start\n"); - if(queue->acknowledgements.failures.isError() || (queue->acknowledgements.ready.isSet() && queue->acknowledgements.ready.getFuture().isError()) { + if(queue->acknowledgements.failures.isError() || (queue->acknowledgements.ready.isSet() && queue->acknowledgements.ready.getFuture().isError())) { printf("OnReady Error\n"); return queue->acknowledgements.ready.getFuture() || queue->acknowledgements.failures; } From 15434cfd0ed70ee0e8a5b3253933f1d83d62eced Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Tue, 15 Dec 2020 14:47:09 -0800 Subject: [PATCH 074/740] added checks for ready being invalid --- fdbrpc/fdbrpc.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index a6b71bb9120..2d99b3df064 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -253,7 +253,7 @@ struct AcknowledgementReceiver final : FlowReceiver, FastAllocated message; reader.deserialize(message); if(message.isError()) { - if(ready.isSet()) { + if(!ready.isValid() || ready.isSet()) { ready = Promise(); } ready.sendError(message.getError()); @@ -345,7 +345,7 @@ class ReplyPromiseStream { printf("Registered Ack Endpoint: %s\n", queue->acknowledgements.getEndpoint(TaskPriority::DefaultEndpoint).token.toString().c_str()); } queue->acknowledgements.bytesSent += value.expectedSize(); - if((queue->acknowledgements.ready.isSet() && !queue->acknowledgements.ready.getFuture().isError()) && queue->acknowledgements.bytesSent - queue->acknowledgements.bytesAcknowledged >= 2e6) { + if((!queue->acknowledgements.ready.isValid() || (queue->acknowledgements.ready.isSet() && !queue->acknowledgements.ready.getFuture().isError())) && queue->acknowledgements.bytesSent - queue->acknowledgements.bytesAcknowledged >= 2e6) { queue->acknowledgements.ready = Promise(); } FlowTransport::transport().sendUnreliable(SerializeSource>>(value), getEndpoint(), false); @@ -407,7 +407,8 @@ class ReplyPromiseStream { Future onReady() { printf("OnReady Start\n"); - if(queue->acknowledgements.failures.isError() || (queue->acknowledgements.ready.isSet() && queue->acknowledgements.ready.getFuture().isError())) { + if(queue->acknowledgements.failures.isError() || + (queue->acknowledgements.ready.isValid() && queue->acknowledgements.ready.isSet() && queue->acknowledgements.ready.getFuture().isError())) { printf("OnReady Error\n"); return queue->acknowledgements.ready.getFuture() || queue->acknowledgements.failures; } From f543188d66b8d32be865e7d587b879d5d54ca55a Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Tue, 15 Dec 2020 15:02:50 -0800 Subject: [PATCH 075/740] more logging --- fdbrpc/FailureMonitor.actor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/fdbrpc/FailureMonitor.actor.cpp b/fdbrpc/FailureMonitor.actor.cpp index c9652cb6c0d..4bdb9f83e4d 100644 --- a/fdbrpc/FailureMonitor.actor.cpp +++ b/fdbrpc/FailureMonitor.actor.cpp @@ -109,6 +109,7 @@ void SimpleFailureMonitor::setStatus(NetworkAddress const& address, FailureStatu void SimpleFailureMonitor::endpointNotFound(Endpoint const& endpoint) { // SOMEDAY: Expiration (this "leaks" memory) + printf("endpointNotFound %s\n", endpoint.token.toString().c_str()); if (endpoint.token.first() == -1) { TraceEvent("WellKnownEndpointNotFound") .suppressFor(1.0) From 8817ca9faf2069abac457440926ad8cc643a59be Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Tue, 15 Dec 2020 15:18:35 -0800 Subject: [PATCH 076/740] fix: do not attempt to use ready when it is invalid --- fdbrpc/FlowTransport.actor.cpp | 1 + fdbrpc/fdbrpc.h | 13 +++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/fdbrpc/FlowTransport.actor.cpp b/fdbrpc/FlowTransport.actor.cpp index ff9f71b070c..f8ef9bc335f 100644 --- a/fdbrpc/FlowTransport.actor.cpp +++ b/fdbrpc/FlowTransport.actor.cpp @@ -843,6 +843,7 @@ ACTOR static void deliver(TransportData* self, Endpoint destination, ArenaReader } auto receiver = self->endpoints.get(destination.token); + printf("Deliver %d %s\n", (bool)receiver, destination.token.toString().c_str()); if (receiver) { try { g_currentDeliveryPeerAddress = destination.addresses; diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index 2d99b3df064..514702b4cc9 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -407,10 +407,13 @@ class ReplyPromiseStream { Future onReady() { printf("OnReady Start\n"); - if(queue->acknowledgements.failures.isError() || - (queue->acknowledgements.ready.isValid() && queue->acknowledgements.ready.isSet() && queue->acknowledgements.ready.getFuture().isError())) { - printf("OnReady Error\n"); - return queue->acknowledgements.ready.getFuture() || queue->acknowledgements.failures; + if(queue->acknowledgements.failures.isError()) { + printf("OnReady Error1\n"); + return queue->acknowledgements.failures.getError(); + } + if(queue->acknowledgements.ready.isValid() && queue->acknowledgements.ready.isSet() && queue->acknowledgements.ready.getFuture().isError())) { + printf("OnReady Error2\n"); + return queue->acknowledgements.ready.getFuture().getError(); } if(queue->acknowledgements.bytesSent - queue->acknowledgements.bytesAcknowledged < 2e6) { printf("OnReady Skip\n"); @@ -598,6 +601,7 @@ class RequestStream { return p; } Reference peer = FlowTransport::transport().sendUnreliable(SerializeSource(value), getEndpoint(taskID), true); + //FIXME: defer sending the message until we know the connection is established endStreamOnDisconnect(disc, p, peer); return p; } @@ -616,6 +620,7 @@ class RequestStream { return p; } Reference peer = FlowTransport::transport().sendUnreliable(SerializeSource(value), getEndpoint(), true); + //FIXME: defer sending the message until we know the connection is established endStreamOnDisconnect(disc, p, peer); return p; } From 9de0c857ea54430765581905c97564f0dc7864a9 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Tue, 15 Dec 2020 15:19:25 -0800 Subject: [PATCH 077/740] fix compiler error --- fdbrpc/fdbrpc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index 514702b4cc9..efe4b672023 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -411,7 +411,7 @@ class ReplyPromiseStream { printf("OnReady Error1\n"); return queue->acknowledgements.failures.getError(); } - if(queue->acknowledgements.ready.isValid() && queue->acknowledgements.ready.isSet() && queue->acknowledgements.ready.getFuture().isError())) { + if(queue->acknowledgements.ready.isValid() && queue->acknowledgements.ready.isSet() && queue->acknowledgements.ready.getFuture().isError()) { printf("OnReady Error2\n"); return queue->acknowledgements.ready.getFuture().getError(); } From a674cd01e1ab93e7e1f642ad7c44b4811df15935 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Tue, 15 Dec 2020 15:38:24 -0800 Subject: [PATCH 078/740] fix: did not change the endpoint to a stream is all places --- fdbrpc/fdbrpc.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index efe4b672023..919eaaf923d 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -329,6 +329,9 @@ struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAl printf("NetNotifiedQueue destructor with error %s\n", getRawEndpoint().token.toString().c_str()); } } + + //FIXME: creating the FlowReceiver as a stream will mean that every cancelled read will lead to a permanent endpoint in the failed endpoints map + bool isStream() const override { return true; } }; template From 061883e5e10e1fa94a7f755f00c24629cee42ea6 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Tue, 15 Dec 2020 15:56:26 -0800 Subject: [PATCH 079/740] more logging --- fdbrpc/FailureMonitor.actor.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fdbrpc/FailureMonitor.actor.cpp b/fdbrpc/FailureMonitor.actor.cpp index 4bdb9f83e4d..a227e073d23 100644 --- a/fdbrpc/FailureMonitor.actor.cpp +++ b/fdbrpc/FailureMonitor.actor.cpp @@ -109,7 +109,7 @@ void SimpleFailureMonitor::setStatus(NetworkAddress const& address, FailureStatu void SimpleFailureMonitor::endpointNotFound(Endpoint const& endpoint) { // SOMEDAY: Expiration (this "leaks" memory) - printf("endpointNotFound %s\n", endpoint.token.toString().c_str()); + printf("endpointNotFound %s %s\n", endpoint.getPrimaryAddress().toString().c_str(), endpoint.token.toString().c_str()); if (endpoint.token.first() == -1) { TraceEvent("WellKnownEndpointNotFound") .suppressFor(1.0) @@ -142,6 +142,7 @@ Future SimpleFailureMonitor::onDisconnectOrFailure(Endpoint const& endpoin // Return when the endpoint is triggered, which means that either the endpoint has become known failed, or the // address has changed state (and since it was previously not failed, it must now be failed), or // notifyDisconnect() has been called. + printf("OnDisconnect %s %s\n", endpoint.getPrimaryAddress().toString().c_str(), endpoint.token.toString().c_str()); return endpointKnownFailed.onChange(endpoint); } From 4fd9ef9aa315cda6cdbe7e8771b1cacbbed8d0da Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Tue, 15 Dec 2020 16:17:08 -0800 Subject: [PATCH 080/740] special handling of endpoint failures for private network addresses --- fdbrpc/FailureMonitor.actor.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/fdbrpc/FailureMonitor.actor.cpp b/fdbrpc/FailureMonitor.actor.cpp index a227e073d23..ef9e404201e 100644 --- a/fdbrpc/FailureMonitor.actor.cpp +++ b/fdbrpc/FailureMonitor.actor.cpp @@ -122,7 +122,9 @@ void SimpleFailureMonitor::endpointNotFound(Endpoint const& endpoint) { .suppressFor(1.0) .detail("Address", endpoint.getPrimaryAddress()) .detail("Token", endpoint.token); - failedEndpoints.insert(endpoint); + if(endpoint.getPrimaryAddress().isValid()) { + failedEndpoints.insert(endpoint); + } endpointKnownFailed.trigger(endpoint); } @@ -152,7 +154,13 @@ Future SimpleFailureMonitor::onDisconnect(Endpoint const& endpoint) { TraceEvent("AlreadyDisconnected").detail("Addr", endpoint.getPrimaryAddress()).detail("Tok", endpoint.token); return Void(); } - return endpointKnownFailed.onChange(endpoint); + if(endpoint.getPrimaryAddress().isPublic()) { + return endpointKnownFailed.onChange(endpoint); + } else { + Endpoint stripped; + stripped.token = endpoint.token; + return endpointKnownFailed.onChange(endpoint) || endpointKnownFailed.onChange(stripped); + } } Future SimpleFailureMonitor::onStateChanged(Endpoint const& endpoint) { From d652cac397e880f65ad26a4849cf6ef184d2770b Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Tue, 15 Dec 2020 16:18:25 -0800 Subject: [PATCH 081/740] changed to onDisconnect --- fdbrpc/fdbrpc.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index 919eaaf923d..ba55db3b7c4 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -278,7 +278,7 @@ struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAl NetNotifiedQueueWithErrors(int futures, int promises, const Endpoint& remoteEndpoint) : NotifiedQueue(futures, promises), FlowReceiver(remoteEndpoint, true) { //FIXME: creating the FlowReceiver as a stream will mean that every cancelled read will lead to a permanent endpoint in the failed endpoints map - acknowledgements.failures = tagError(makeDependent(IFailureMonitor::failureMonitor()).onDisconnectOrFailure(remoteEndpoint), request_maybe_delivered()); + acknowledgements.failures = tagError(makeDependent(IFailureMonitor::failureMonitor()).onDisconnect(remoteEndpoint), request_maybe_delivered()); printf("NetNotified create with remote endpoint: %s\n", remoteEndpoint.token.toString().c_str()); } @@ -409,7 +409,7 @@ class ReplyPromiseStream { uint32_t size() const { return queue->size(); } Future onReady() { - printf("OnReady Start\n"); + printf("OnReady Start %s\n", getEndpoint().token.toString().c_str()); if(queue->acknowledgements.failures.isError()) { printf("OnReady Error1\n"); return queue->acknowledgements.failures.getError(); From aec856d00fd9196d280a1f7093313b2007e559b5 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Tue, 15 Dec 2020 16:40:33 -0800 Subject: [PATCH 082/740] fix: if an unreliable message is sent in response to a disconnect it could prevent the connection from closing --- fdbrpc/FlowTransport.actor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/fdbrpc/FlowTransport.actor.cpp b/fdbrpc/FlowTransport.actor.cpp index f8ef9bc335f..ed1677c3ac3 100644 --- a/fdbrpc/FlowTransport.actor.cpp +++ b/fdbrpc/FlowTransport.actor.cpp @@ -645,6 +645,7 @@ ACTOR Future connectionKeeper( Reference self, throw e; } } catch (Error& e) { + self->outgoingConnectionIdle = true; delayedHealthUpdateF.cancel(); if(now() - self->lastConnectTime > FLOW_KNOBS->RECONNECTION_RESET_TIME) { self->reconnectionDelay = FLOW_KNOBS->INITIAL_RECONNECTION_TIME; From 54baa9c2f1d3552c25c9ae4fd270e6292ce72525 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Tue, 15 Dec 2020 16:43:33 -0800 Subject: [PATCH 083/740] do not add peer references to private network addresses --- fdbrpc/FlowTransport.actor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fdbrpc/FlowTransport.actor.cpp b/fdbrpc/FlowTransport.actor.cpp index ed1677c3ac3..da861ef62f9 100644 --- a/fdbrpc/FlowTransport.actor.cpp +++ b/fdbrpc/FlowTransport.actor.cpp @@ -1315,7 +1315,7 @@ Endpoint FlowTransport::loadedEndpoint( const UID& token ) { } void FlowTransport::addPeerReference(const Endpoint& endpoint, bool isStream) { - if (!isStream || !endpoint.getPrimaryAddress().isValid()) + if (!isStream || !endpoint.getPrimaryAddress().isValid() || !endpoint.getPrimaryAddress().isPublic()) return; Reference peer = self->getOrOpenPeer(endpoint.getPrimaryAddress()); @@ -1327,7 +1327,7 @@ void FlowTransport::addPeerReference(const Endpoint& endpoint, bool isStream) { } void FlowTransport::removePeerReference(const Endpoint& endpoint, bool isStream) { - if (!isStream || !endpoint.getPrimaryAddress().isValid()) return; + if (!isStream || !endpoint.getPrimaryAddress().isValid() || !endpoint.getPrimaryAddress().isPublic()) return; Reference peer = self->getPeer(endpoint.getPrimaryAddress()); if(peer) { peer->peerReferences--; From e1b44d674c5093a9f24d94d790b01309baeca892 Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Tue, 15 Dec 2020 23:49:55 +0000 Subject: [PATCH 084/740] Attempt to fix client bugs Intercept end_of_stream from storage server Break out of the second loop --- documentation/tutorial/tutorial.actor.cpp | 48 +++++++++++++++++------ fdbclient/NativeAPI.actor.cpp | 26 +++++++----- fdbserver/storageserver.actor.cpp | 29 ++------------ 3 files changed, 56 insertions(+), 47 deletions(-) diff --git a/documentation/tutorial/tutorial.actor.cpp b/documentation/tutorial/tutorial.actor.cpp index d7502040d28..ed172fe6e2f 100644 --- a/documentation/tutorial/tutorial.actor.cpp +++ b/documentation/tutorial/tutorial.actor.cpp @@ -394,7 +394,7 @@ ACTOR Future multipleClients() { std::string clusterFile = "fdb.cluster"; -ACTOR Future fdbClient() { +ACTOR Future fdbClientStream() { state Database db = Database::createDatabase(clusterFile, 300); state Transaction tx(db); state PromiseStream> results; @@ -406,7 +406,7 @@ ACTOR Future fdbClient() { KeySelector(firstGreaterOrEqual(normalKeys.end)), GetRangeLimits()); loop { Standalone range = waitNext(results.getFuture()); - std::cout << "Got " << range.expectedSize() << std::endl; + std::cout << "Got " << range.expectedSize() << " next: " << printable(next) << std::endl; next = keyAfter(range.back().key); } } catch (Error& e) { @@ -419,6 +419,27 @@ ACTOR Future fdbClient() { return Void(); } +ACTOR Future fdbClientGetRange() { + state Database db = Database::createDatabase(clusterFile, 300); + state Transaction tx(db); + state Key next; + loop { + try { + Standalone range = wait(tx.getRange( + KeySelector(firstGreaterOrEqual(next), next.arena()), KeySelector(firstGreaterOrEqual(normalKeys.end)), + GetRangeLimits(GetRangeLimits::ROW_LIMIT_UNLIMITED, CLIENT_KNOBS->REPLY_BYTE_LIMIT))); + std::cout << "Got " << range.expectedSize() << " next: " << printable(next) << std::endl; + if (!range.more) { + break; + } + next = keyAfter(range.back().key); + } catch (Error& e) { + wait(tx.onError(e)); + } + } + return Void(); +} + ACTOR Future fdbStatusStresser() { state Database db = Database::createDatabase(clusterFile, 300); state ReadYourWritesTransaction tx(db); @@ -433,16 +454,19 @@ ACTOR Future fdbStatusStresser() { } } -std::unordered_map()>> actors = { { "timer", &simpleTimer }, // ./tutorial timer - { "promiseDemo", &promiseDemo }, // ./tutorial promiseDemo - { "triggerDemo", &triggerDemo }, // ./tutorial triggerDemo - { "echoServer", &echoServer }, // ./tutorial -p 6666 echoServer - { "echoClient", &echoClient }, // ./tutorial -s 127.0.0.1:6666 echoClient - { "kvStoreServer", &kvStoreServer }, // ./tutorial -p 6666 kvStoreServer - { "kvSimpleClient", &kvSimpleClient }, // ./tutorial -s 127.0.0.1:6666 kvSimpleClient - { "multipleClients", &multipleClients }, // ./tutorial -s 127.0.0.1:6666 multipleClients - { "fdbClient", &fdbClient }, // ./tutorial -C $CLUSTER_FILE_PATH fdbClient - { "fdbStatusStresser", &fdbStatusStresser } }; // ./tutorial -C $CLUSTER_FILE_PATH fdbStatusStresser +std::unordered_map()>> actors = { + { "timer", &simpleTimer }, // ./tutorial timer + { "promiseDemo", &promiseDemo }, // ./tutorial promiseDemo + { "triggerDemo", &triggerDemo }, // ./tutorial triggerDemo + { "echoServer", &echoServer }, // ./tutorial -p 6666 echoServer + { "echoClient", &echoClient }, // ./tutorial -s 127.0.0.1:6666 echoClient + { "kvStoreServer", &kvStoreServer }, // ./tutorial -p 6666 kvStoreServer + { "kvSimpleClient", &kvSimpleClient }, // ./tutorial -s 127.0.0.1:6666 kvSimpleClient + { "multipleClients", &multipleClients }, // ./tutorial -s 127.0.0.1:6666 multipleClients + { "fdbClientStream", &fdbClientStream }, // ./tutorial -C $CLUSTER_FILE_PATH fdbClientStream + { "fdbClientGetRange", &fdbClientGetRange }, // ./tutorial -C $CLUSTER_FILE_PATH fdbClientGetRange + { "fdbStatusStresser", &fdbStatusStresser } +}; // ./tutorial -C $CLUSTER_FILE_PATH fdbStatusStresser int main(int argc, char* argv[]) { bool isServer = false; diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index e7c24c12fff..93035a857f8 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -2665,6 +2665,7 @@ ACTOR Future getRangeStream( PromiseStream> res { //FIXME: better handling to disable row limits ASSERT(!limits.hasRowLimit()); + ASSERT(!limits.hasByteLimit()); state Span span("NAPI:getRangeStream"_loc, info.spanID); state Version version = wait( fVersion ); @@ -2693,7 +2694,7 @@ ACTOR Future getRangeStream( PromiseStream> res //or allKeys.begin exists in the database and will be part of the conflict range anyways loop { - state vector< pair> > locations = wait( getKeyRangeLocations( cx, keys, CLIENT_KNOBS->GET_RANGE_SHARD_LIMIT, reverse, &StorageServerInterface::getKeyValues, info ) ); + state vector< pair> > locations = wait( getKeyRangeLocations( cx, keys, CLIENT_KNOBS->GET_RANGE_SHARD_LIMIT, reverse, &StorageServerInterface::getKeyValuesStream, info ) ); ASSERT( locations.size() ); state int shard = 0; loop { @@ -2705,11 +2706,7 @@ ACTOR Future getRangeStream( PromiseStream> res req.end = firstGreaterOrEqual( range.end ); req.spanContext = span.context; req.limit = reverse ? -CLIENT_KNOBS->REPLY_BYTE_LIMIT : CLIENT_KNOBS->REPLY_BYTE_LIMIT; - if (limits.hasByteLimit()) { - req.limitBytes = limits.bytes; - } else { - req.limitBytes = std::numeric_limits::max(); - } + req.limitBytes = std::numeric_limits::max(); ASSERT(req.limitBytes > 0 && req.limit != 0 && req.limit < 0 == reverse); @@ -2732,6 +2729,7 @@ ACTOR Future getRangeStream( PromiseStream> res //FIXME: add load balancing state ReplyPromiseStream replyStream = locations[shard].second->getInterface(0).getKeyValuesStream.getReplyStream(req); + state bool breakAgain = false; loop { try { choose { @@ -2742,13 +2740,16 @@ ACTOR Future getRangeStream( PromiseStream> res when(GetKeyValuesStreamReply _rep = waitNext(replyStream.getFuture())) { rep = _rep; - limits.decrement(rep.data); } } ++cx->transactionPhysicalReadsCompleted; - } catch(Error&) { + } catch (Error& e) { ++cx->transactionPhysicalReadsCompleted; - throw; + if (e.code() == error_code_end_of_stream) { + rep = GetKeyValuesStreamReply(); + } else { + throw; + } } if( info.debugID.present() ) g_traceBatch.addEvent("TransactionDebug", info.debugID.get().first(), "NativeAPI.getExactRange.After"); @@ -2776,7 +2777,7 @@ ACTOR Future getRangeStream( PromiseStream> res locations[shard].first = KeyRangeRef( keyAfter( output[output.size()-1].key ), locations[shard].first.end ); } - if (!more || locations[shard].first.empty() || limits.isReached()) { + if (!more || locations[shard].first.empty()) { TEST(true); // getRangeStream (!more || locations[shard].first.empty()) if(shard == locations.size()-1) { const KeyRangeRef& range = locations[shard].first; @@ -2810,10 +2811,12 @@ ACTOR Future getRangeStream( PromiseStream> res } keys = KeyRangeRef(begin, end); + breakAgain = true; break; } ++shard; + break; } if(output.size() > 0) { @@ -2839,6 +2842,9 @@ ACTOR Future getRangeStream( PromiseStream> res results.send(output); } } + if (breakAgain) { + break; + } } catch (Error& e) { if (e.code() == error_code_actor_cancelled) { throw; diff --git a/fdbserver/storageserver.actor.cpp b/fdbserver/storageserver.actor.cpp index eac398e6a29..346fa57049b 100644 --- a/fdbserver/storageserver.actor.cpp +++ b/fdbserver/storageserver.actor.cpp @@ -1641,9 +1641,9 @@ ACTOR Future getKeyValuesQ( StorageServer* data, GetKeyValuesRequest req ) return Void(); } -ACTOR Future getKeyValuesStreamWork( StorageServer* data, GetKeyValuesStreamRequest req ) -// Throws a wrong_shard_server if the keys in the request or result depend on data outside this server OR if a large selector offset prevents -// all data from being read in one range read +ACTOR Future getKeyValuesStreamQ(StorageServer* data, GetKeyValuesStreamRequest req) +// Throws a wrong_shard_server if the keys in the request or result depend on data outside this server OR if a large +// selector offset prevents all data from being read in one range read { state Span span("SS:getKeyValuesStream"_loc, { req.spanContext }); state int64_t resultSize = 0; @@ -1719,17 +1719,11 @@ ACTOR Future getKeyValuesStreamWork( StorageServer* data, GetKeyValuesStre req.reply.send( none ); req.reply.sendError( end_of_stream() ); } else { - state int remainingLimitBytes = req.limitBytes; loop { wait(req.reply.onReady()); - printf("Issuing getRange for stream impl. begin: %s end: %s limit: %d limitBytes: %d\n", - printable(begin).c_str(), printable(end).c_str(), req.limit, remainingLimitBytes); - state int byteLimit = std::min(remainingLimitBytes, CLIENT_KNOBS->REPLY_BYTE_LIMIT); - state int byteLimitBefore = byteLimit; + state int byteLimit = CLIENT_KNOBS->REPLY_BYTE_LIMIT; GetKeyValuesReply _r = wait( readRange(data, version, KeyRangeRef(begin, end), req.limit, &byteLimit, span.context) ); - remainingLimitBytes -= byteLimitBefore - byteLimit; GetKeyValuesStreamReply r(_r); - printf("Result. size: %d more: %d \n", int(r.data.expectedSize()), int(r.more)); if( req.debugID.present() ) g_traceBatch.addEvent("TransactionDebug", req.debugID.get().first(), "storageserver.getKeyValues.AfterReadRange"); @@ -1761,8 +1755,6 @@ ACTOR Future getKeyValuesStreamWork( StorageServer* data, GetKeyValuesStre req.reply.send( r ); - resultSize = req.limitBytes - remainingLimitBytes; - data->counters.bytesQueried += resultSize; data->counters.rowsQueried += r.data.size(); if(r.data.size() == 0) { ++data->counters.emptyQueries; @@ -1823,19 +1815,6 @@ ACTOR Future getKeyValuesStreamWork( StorageServer* data, GetKeyValuesStre return Void(); } -ACTOR Future getKeyValuesStreamQ( StorageServer* data, GetKeyValuesStreamRequest req ) -{ - Future disc = IFailureMonitor::failureMonitor().onDisconnectOrFailure(req.reply.getEndpoint()); - Future work = getKeyValuesStreamWork( data, req ); - choose { - when(wait(disc)) { - req.reply.sendError(end_of_stream()); - } - when(wait(work)) {} - } - return Void(); -} - ACTOR Future getKeyQ( StorageServer* data, GetKeyRequest req ) { state Span span("SS:getKey"_loc, { req.spanContext }); state int64_t resultSize = 0; From 62da2b42bcd6e05eb579a97b30ef4ebd24f3f2f3 Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Wed, 16 Dec 2020 00:45:37 +0000 Subject: [PATCH 085/740] Log throughput --- documentation/tutorial/tutorial.actor.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/documentation/tutorial/tutorial.actor.cpp b/documentation/tutorial/tutorial.actor.cpp index ed172fe6e2f..100f09af207 100644 --- a/documentation/tutorial/tutorial.actor.cpp +++ b/documentation/tutorial/tutorial.actor.cpp @@ -394,11 +394,21 @@ ACTOR Future multipleClients() { std::string clusterFile = "fdb.cluster"; +ACTOR Future logThroughput(int64_t* v) { + loop { + state int64_t last = *v; + wait(delay(1)); + printf("throughput: %ld bytes/s\n", *v - last); + } +} + ACTOR Future fdbClientStream() { state Database db = Database::createDatabase(clusterFile, 300); state Transaction tx(db); state PromiseStream> results; state Key next; + state int64_t bytes = 0; + state Future logFuture = logThroughput(&bytes); loop { try { state Future stream = @@ -406,7 +416,7 @@ ACTOR Future fdbClientStream() { KeySelector(firstGreaterOrEqual(normalKeys.end)), GetRangeLimits()); loop { Standalone range = waitNext(results.getFuture()); - std::cout << "Got " << range.expectedSize() << " next: " << printable(next) << std::endl; + bytes += range.expectedSize(); next = keyAfter(range.back().key); } } catch (Error& e) { @@ -423,12 +433,14 @@ ACTOR Future fdbClientGetRange() { state Database db = Database::createDatabase(clusterFile, 300); state Transaction tx(db); state Key next; + state int64_t bytes = 0; + state Future logFuture = logThroughput(&bytes); loop { try { Standalone range = wait(tx.getRange( KeySelector(firstGreaterOrEqual(next), next.arena()), KeySelector(firstGreaterOrEqual(normalKeys.end)), GetRangeLimits(GetRangeLimits::ROW_LIMIT_UNLIMITED, CLIENT_KNOBS->REPLY_BYTE_LIMIT))); - std::cout << "Got " << range.expectedSize() << " next: " << printable(next) << std::endl; + bytes += range.expectedSize(); if (!range.more) { break; } From ac6bf6909fb923952fe26d20098ad098a05fa41d Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Tue, 15 Dec 2020 16:49:07 -0800 Subject: [PATCH 086/740] it was not required to set this after all --- fdbrpc/FlowTransport.actor.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/fdbrpc/FlowTransport.actor.cpp b/fdbrpc/FlowTransport.actor.cpp index da861ef62f9..1afa717ce01 100644 --- a/fdbrpc/FlowTransport.actor.cpp +++ b/fdbrpc/FlowTransport.actor.cpp @@ -645,7 +645,6 @@ ACTOR Future connectionKeeper( Reference self, throw e; } } catch (Error& e) { - self->outgoingConnectionIdle = true; delayedHealthUpdateF.cancel(); if(now() - self->lastConnectTime > FLOW_KNOBS->RECONNECTION_RESET_TIME) { self->reconnectionDelay = FLOW_KNOBS->INITIAL_RECONNECTION_TIME; From 6b8465355d598fe8fcbe45cef862986e798d2ff2 Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Wed, 16 Dec 2020 01:31:32 +0000 Subject: [PATCH 087/740] Remove debug printf's --- fdbrpc/FailureMonitor.actor.cpp | 2 -- fdbrpc/FlowTransport.actor.cpp | 1 - fdbrpc/fdbrpc.h | 16 ---------------- 3 files changed, 19 deletions(-) diff --git a/fdbrpc/FailureMonitor.actor.cpp b/fdbrpc/FailureMonitor.actor.cpp index ef9e404201e..2bb958a8e4d 100644 --- a/fdbrpc/FailureMonitor.actor.cpp +++ b/fdbrpc/FailureMonitor.actor.cpp @@ -109,7 +109,6 @@ void SimpleFailureMonitor::setStatus(NetworkAddress const& address, FailureStatu void SimpleFailureMonitor::endpointNotFound(Endpoint const& endpoint) { // SOMEDAY: Expiration (this "leaks" memory) - printf("endpointNotFound %s %s\n", endpoint.getPrimaryAddress().toString().c_str(), endpoint.token.toString().c_str()); if (endpoint.token.first() == -1) { TraceEvent("WellKnownEndpointNotFound") .suppressFor(1.0) @@ -144,7 +143,6 @@ Future SimpleFailureMonitor::onDisconnectOrFailure(Endpoint const& endpoin // Return when the endpoint is triggered, which means that either the endpoint has become known failed, or the // address has changed state (and since it was previously not failed, it must now be failed), or // notifyDisconnect() has been called. - printf("OnDisconnect %s %s\n", endpoint.getPrimaryAddress().toString().c_str(), endpoint.token.toString().c_str()); return endpointKnownFailed.onChange(endpoint); } diff --git a/fdbrpc/FlowTransport.actor.cpp b/fdbrpc/FlowTransport.actor.cpp index 1afa717ce01..6161d62363e 100644 --- a/fdbrpc/FlowTransport.actor.cpp +++ b/fdbrpc/FlowTransport.actor.cpp @@ -843,7 +843,6 @@ ACTOR static void deliver(TransportData* self, Endpoint destination, ArenaReader } auto receiver = self->endpoints.get(destination.token); - printf("Deliver %d %s\n", (bool)receiver, destination.token.toString().c_str()); if (receiver) { try { g_currentDeliveryPeerAddress = destination.addresses; diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index ba55db3b7c4..901aad33a6b 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -249,7 +249,6 @@ struct AcknowledgementReceiver final : FlowReceiver, FastAllocated message; reader.deserialize(message); if(message.isError()) { @@ -279,12 +278,10 @@ struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAl : NotifiedQueue(futures, promises), FlowReceiver(remoteEndpoint, true) { //FIXME: creating the FlowReceiver as a stream will mean that every cancelled read will lead to a permanent endpoint in the failed endpoints map acknowledgements.failures = tagError(makeDependent(IFailureMonitor::failureMonitor()).onDisconnect(remoteEndpoint), request_maybe_delivered()); - printf("NetNotified create with remote endpoint: %s\n", remoteEndpoint.token.toString().c_str()); } void destroy() override { delete this; } void receive(ArenaObjectReader& reader) override { - printf("NetNotifiedReceived\n"); this->addPromiseRef(); ErrorOr> message; reader.deserialize(message); @@ -297,12 +294,10 @@ struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAl } else { if(message.get().asUnderlyingType().acknowledgeToken.present()) { acknowledgements = AcknowledgementReceiver(FlowTransport::transport().loadedEndpoint(message.get().asUnderlyingType().acknowledgeToken.get())); - printf("Acknowledgements create with remote endpoint: %s %s\n", acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).getPrimaryAddress().toString().c_str(), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).token.toString().c_str()); } if(this->shouldFireImmediately()) { if(acknowledgements.getRawEndpoint().isValid()) { acknowledgements.bytesAcknowledged += message.get().asUnderlyingType().expectedSize(); - printf("Sending acknowledgement1 to endpoint: %ld %s %s\n", acknowledgements.bytesAcknowledged, acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).getPrimaryAddress().toString().c_str(), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).token.toString().c_str()); FlowTransport::transport().sendUnreliable(SerializeSource>(AcknowledgementReply(acknowledgements.bytesAcknowledged)), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint), false); } } @@ -316,17 +311,14 @@ struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAl T res = this->popImpl(); if(acknowledgements.getRawEndpoint().isValid()) { acknowledgements.bytesAcknowledged += res.expectedSize(); - printf("Sending acknowledgement2 to endpoint: %d %s %s\n", acknowledgements.bytesAcknowledged, acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).getPrimaryAddress().toString().c_str(), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint).token.toString().c_str()); FlowTransport::transport().sendUnreliable(SerializeSource>(AcknowledgementReply(acknowledgements.bytesAcknowledged)), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint), false); } return res; } ~NetNotifiedQueueWithErrors() { - printf("NetNotifiedQueue destructor %s\n", getRawEndpoint().token.toString().c_str()); if(acknowledgements.getRawEndpoint().isValid() && acknowledgements.isRemoteEndpoint() && !this->hasError()) { FlowTransport::transport().sendUnreliable(SerializeSource>(request_maybe_delivered()), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint), false); - printf("NetNotifiedQueue destructor with error %s\n", getRawEndpoint().token.toString().c_str()); } } @@ -345,7 +337,6 @@ class ReplyPromiseStream { if (queue->isRemoteEndpoint()) { if(!queue->acknowledgements.getRawEndpoint().isValid()) { value.acknowledgeToken = queue->acknowledgements.getEndpoint(TaskPriority::DefaultEndpoint).token; - printf("Registered Ack Endpoint: %s\n", queue->acknowledgements.getEndpoint(TaskPriority::DefaultEndpoint).token.toString().c_str()); } queue->acknowledgements.bytesSent += value.expectedSize(); if((!queue->acknowledgements.ready.isValid() || (queue->acknowledgements.ready.isSet() && !queue->acknowledgements.ready.getFuture().isError())) && queue->acknowledgements.bytesSent - queue->acknowledgements.bytesAcknowledged >= 2e6) { @@ -398,9 +389,6 @@ class ReplyPromiseStream { } const Endpoint& getEndpoint(TaskPriority taskID = TaskPriority::DefaultEndpoint) const { - if(!queue->getRawEndpoint().isValid()) { - printf("Registered Endpoint: %s\n", queue->getEndpoint(taskID).token.toString().c_str()); - } return queue->getEndpoint(taskID); } @@ -409,17 +397,13 @@ class ReplyPromiseStream { uint32_t size() const { return queue->size(); } Future onReady() { - printf("OnReady Start %s\n", getEndpoint().token.toString().c_str()); if(queue->acknowledgements.failures.isError()) { - printf("OnReady Error1\n"); return queue->acknowledgements.failures.getError(); } if(queue->acknowledgements.ready.isValid() && queue->acknowledgements.ready.isSet() && queue->acknowledgements.ready.getFuture().isError()) { - printf("OnReady Error2\n"); return queue->acknowledgements.ready.getFuture().getError(); } if(queue->acknowledgements.bytesSent - queue->acknowledgements.bytesAcknowledged < 2e6) { - printf("OnReady Skip\n"); return Void(); } return queue->acknowledgements.ready.getFuture() || queue->acknowledgements.failures; From 30089a5d864594a5bccf04e1662df5a858817a5b Mon Sep 17 00:00:00 2001 From: sfc-gh-tclinkenbeard Date: Tue, 15 Dec 2020 20:50:47 -0800 Subject: [PATCH 088/740] Added ResultStream class --- fdbclient/FDBTypes.h | 2 + fdbclient/Knobs.cpp | 2 + fdbclient/Knobs.h | 2 + fdbclient/NativeAPI.actor.cpp | 167 ++++++++++++++++++++++++++-------- 4 files changed, 137 insertions(+), 36 deletions(-) diff --git a/fdbclient/FDBTypes.h b/fdbclient/FDBTypes.h index a707675695d..6f1140a9fb8 100644 --- a/fdbclient/FDBTypes.h +++ b/fdbclient/FDBTypes.h @@ -694,6 +694,8 @@ struct RangeResultRef : VectorRef { } }; +using RangeResult = Standalone; + template<> struct Traceable : std::true_type { static std::string toString(const RangeResultRef& value) { diff --git a/fdbclient/Knobs.cpp b/fdbclient/Knobs.cpp index e194f8827e9..06efd14c50d 100644 --- a/fdbclient/Knobs.cpp +++ b/fdbclient/Knobs.cpp @@ -94,6 +94,8 @@ void ClientKnobs::initialize(bool randomize) { init( DETAILED_HEALTH_METRICS_MAX_STALENESS, 5.0 ); init( MID_SHARD_SIZE_MAX_STALENESS, 10.0 ); init( TAG_ENCODE_KEY_SERVERS, false ); if( randomize && BUGGIFY ) TAG_ENCODE_KEY_SERVERS = true; + init( RANGESTREAM_FRAGMENT_SIZE, 1e6 ); + init( RANGESTREAM_CONCURRENT_FRAGMENTS, 10 ); //KeyRangeMap init( KRM_GET_RANGE_LIMIT, 1e5 ); if( randomize && BUGGIFY ) KRM_GET_RANGE_LIMIT = 10; diff --git a/fdbclient/Knobs.h b/fdbclient/Knobs.h index 11a06d52ccc..f85aeb3a831 100644 --- a/fdbclient/Knobs.h +++ b/fdbclient/Knobs.h @@ -88,6 +88,8 @@ class ClientKnobs : public Knobs { double DETAILED_HEALTH_METRICS_MAX_STALENESS; double MID_SHARD_SIZE_MAX_STALENESS; bool TAG_ENCODE_KEY_SERVERS; + int64_t RANGESTREAM_FRAGMENT_SIZE; + int RANGESTREAM_CONCURRENT_FRAGMENTS; //KeyRangeMap int KRM_GET_RANGE_LIMIT; diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index ffd13613419..789e5d669f8 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -2659,38 +2659,67 @@ ACTOR Future> getRange( Database cx, Reference getRangeStream( PromiseStream> results, Database cx, Reference trLogInfo, Future fVersion, - KeySelector begin, KeySelector end, GetRangeLimits limits, Promise> conflictRange, bool snapshot, bool reverse, - TransactionInfo info, TagSet tags ) -{ - //FIXME: better handling to disable row limits - ASSERT(!limits.hasRowLimit()); - state Span span("NAPI:getRangeStream"_loc, info.spanID); - - state Version version = wait( fVersion ); - cx->validateVersion(version); +class ResultStream { +public: + class FragmentStream { + ResultStream* resultStream; + std::deque buffer; + bool completed{ false }; + friend class ResultStream; + FragmentStream(ResultStream* resultStream) : resultStream(resultStream) {} + + public: + void send(const RangeResult& rangeResult) { buffer.push_back(rangeResult); } + void sendError(Error e) { resultStream->sendError(e); } + void finish() { + ASSERT(!completed); + completed = true; + resultStream->flushToClient(); + } + }; - Future fb = resolveKey(cx, begin, version, info, tags); - state Future fe = resolveKey(cx, end, version, info, tags); +private: + std::vector fragments; + decltype(fragments)::iterator nextFragment = fragments.begin(); + PromiseStream results; + + // TODO: Fix potential slow tasks + void flushToClient() { + while (nextFragment != fragments.end()) { + auto& fragment = *nextFragment; + while (!fragment.buffer.empty()) { + results.send(std::move(fragment.buffer.front())); + fragment.buffer.pop_front(); + } + if (fragment.completed) { + ++nextFragment; + } else { + break; + } + } + } - state Key b = wait(fb); - state Key e = wait(fe); +public: + ResultStream(PromiseStream results) : results(results) {} - if( !snapshot ) { - //FIXME: this conflict range is too large, and should be updated continously as results are returned - conflictRange.send(std::make_pair(std::min(b, Key(begin.getKey(),begin.arena())), std::max(e, Key(end.getKey(),end.arena())))); + FragmentStream& createFragmentStream() { + fragments.push_back(FragmentStream(this)); + return fragments.back(); } - if (b >= e) { - results.sendError(end_of_stream()); - return Void(); - } + void sendError(Error e) { results.sendError(e); } +}; - state KeyRangeRef keys(b, e); +ACTOR Future getRangeStreamFragment(ResultStream::FragmentStream* results, Database cx, + Reference trLogInfo, Version version, KeyRangeRef keys, + GetRangeLimits limits, bool snapshot, bool reverse, TransactionInfo info, + TagSet tags, SpanID spanContext, FlowLock* semaphore) { + // if keys.end is allKeys.end, we have read through the end of the database + // if keys.begin is allKeys.begin, we have either read through the beginning of the database, + // or allKeys.begin exists in the database and will be part of the conflict range anyways - //if e is allKeys.end, we have read through the end of the database - //if b is allKeys.begin, we have either read through the beginning of the database, - //or allKeys.begin exists in the database and will be part of the conflict range anyways + wait(semaphore->take()); + state FlowLock::Releaser releaser(*semaphore); loop { state vector< pair> > locations = wait( getKeyRangeLocations( cx, keys, CLIENT_KNOBS->GET_RANGE_SHARD_LIMIT, reverse, &StorageServerInterface::getKeyValues, info ) ); @@ -2703,7 +2732,7 @@ ACTOR Future getRangeStream( PromiseStream> res req.version = version; req.begin = firstGreaterOrEqual( range.begin ); req.end = firstGreaterOrEqual( range.end ); - req.spanContext = span.context; + req.spanContext = spanContext; req.limit = reverse ? -CLIENT_KNOBS->REPLY_BYTE_LIMIT : CLIENT_KNOBS->REPLY_BYTE_LIMIT; req.limitBytes = CLIENT_KNOBS->REPLY_BYTE_LIMIT; @@ -2722,7 +2751,7 @@ ACTOR Future getRangeStream( PromiseStream> res if( locations[shard].second->size() == 0 ) { wait(cx->connectionFileChanged()); - results.sendError( transaction_too_old() ); + results->sendError(transaction_too_old()); return Void(); } @@ -2732,7 +2761,7 @@ ACTOR Future getRangeStream( PromiseStream> res try { choose { when(wait(cx->connectionFileChanged())) { - results.sendError( transaction_too_old() ); + results->sendError(transaction_too_old()); return Void(); } @@ -2780,10 +2809,10 @@ ACTOR Future getRangeStream( PromiseStream> res if(begin >= end) { output.more = false; - if(b == allKeys.begin) { + if (range.begin == allKeys.begin) { output.readToBegin = true; } - if(e == allKeys.end) { + if (range.end == allKeys.end) { output.readThroughEnd = true; } int64_t bytes = 0; @@ -2799,8 +2828,8 @@ ACTOR Future getRangeStream( PromiseStream> res // trLogInfo->addLog(FdbClientLogEvents::EventGetRange(startTime, cx->clientLocality.dcId(), now()-startTime, bytes, begin.getKey(), end.getKey())); //} - results.send(output); - results.sendError(end_of_stream()); + results->send(std::move(output)); + results->finish(); return Void(); } @@ -2813,10 +2842,10 @@ ACTOR Future getRangeStream( PromiseStream> res if(output.size() > 0) { output.more = true; - if(b == allKeys.begin && !reverse) { + if (keys.begin == allKeys.begin && !reverse) { output.readToBegin = true; } - if(e == allKeys.end && reverse) { + if (keys.end == allKeys.end && reverse) { output.readThroughEnd = true; } int64_t bytes = 0; @@ -2831,7 +2860,7 @@ ACTOR Future getRangeStream( PromiseStream> res //if( trLogInfo ) { // trLogInfo->addLog(FdbClientLogEvents::EventGetRange(startTime, cx->clientLocality.dcId(), now()-startTime, bytes, begin.getKey(), end.getKey())); //} - results.send(output); + results->send(std::move(output)); } } } catch (Error& e) { @@ -2850,7 +2879,7 @@ ACTOR Future getRangeStream( PromiseStream> res wait( delay(CLIENT_KNOBS->WRONG_SHARD_SERVER_DELAY, info.taskID )); break; } else { - results.sendError(e); + results->sendError(e); return Void(); } } @@ -2858,6 +2887,72 @@ ACTOR Future getRangeStream( PromiseStream> res } } +ACTOR Future>> getRangeSplitPoints(Database cx, KeyRange keys, int64_t chunkSize); + +ACTOR Future getRangeStream(PromiseStream _results, Database cx, + Reference trLogInfo, Future fVersion, KeySelector begin, + KeySelector end, GetRangeLimits limits, Promise> conflictRange, + bool snapshot, bool reverse, TransactionInfo info, TagSet tags) { + + state FlowLock semaphore(CLIENT_KNOBS->RANGESTREAM_CONCURRENT_FRAGMENTS); + state ResultStream results(_results); + + // FIXME: better handling to disable row limits + ASSERT(!limits.hasRowLimit()); + state Span span("NAPI:getRangeStream"_loc, info.spanID); + + state Version version = wait(fVersion); + cx->validateVersion(version); + + Future fb = resolveKey(cx, begin, version, info, tags); + state Future fe = resolveKey(cx, end, version, info, tags); + + state Key b = wait(fb); + state Key e = wait(fe); + + if (!snapshot) { + // FIXME: this conflict range is too large, and should be updated continously as results are returned + conflictRange.send(std::make_pair(std::min(b, Key(begin.getKey(), begin.arena())), + std::max(e, Key(end.getKey(), end.arena())))); + } + + if (b >= e) { + results.sendError(end_of_stream()); + return Void(); + } + + state KeyRangeRef keys(b, e); + + state Standalone> splitPoints = + wait(getRangeSplitPoints(cx, keys, CLIENT_KNOBS->RANGESTREAM_FRAGMENT_SIZE)); + state std::vector toSend; + // state std::vector::iterator>> outstandingRequests; + state std::vector> outstandingRequests; + + if (!splitPoints.empty()) { + toSend.emplace_back(splitPoints.front(), b); + for (int i = 0; i < splitPoints.size() - 1; ++i) { + toSend.emplace_back(splitPoints[i], splitPoints[i + 1]); + } + toSend.emplace_back(splitPoints.back(), e); + } else { + toSend.emplace_back(b, e); + } + + for (const auto& range : toSend) { + auto& fragmentStream = results.createFragmentStream(); + outstandingRequests.push_back(getRangeStreamFragment(&fragmentStream, cx, trLogInfo, version, range, limits, + snapshot, reverse, info, tags, span.context, &semaphore)); + } + + try { + wait(waitForAll(outstandingRequests)); + } catch (Error& e) { + results.sendError(e); + } + results.sendError(end_of_stream()); + return Void(); +} /* ACTOR Future getRangeStreamSingleShard( PromiseStream> results, Database cx, Reference trLogInfo, Future fVersion, From 99aa8abcf56c1708d25194dbb806e388ef4636c5 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Tue, 15 Dec 2020 21:27:33 -0800 Subject: [PATCH 089/740] changed endpoint_not_found to use loadedEndpoint because it still works with private network addresses --- fdbrpc/FailureMonitor.actor.cpp | 15 +++++++-------- fdbrpc/FlowTransport.actor.cpp | 9 +++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/fdbrpc/FailureMonitor.actor.cpp b/fdbrpc/FailureMonitor.actor.cpp index 2bb958a8e4d..9d1047182d7 100644 --- a/fdbrpc/FailureMonitor.actor.cpp +++ b/fdbrpc/FailureMonitor.actor.cpp @@ -121,7 +121,12 @@ void SimpleFailureMonitor::endpointNotFound(Endpoint const& endpoint) { .suppressFor(1.0) .detail("Address", endpoint.getPrimaryAddress()) .detail("Token", endpoint.token); - if(endpoint.getPrimaryAddress().isValid()) { + if(endpoint.getPrimaryAddress().isPublic()) { + if(failedEndpoints.size() > 100000) { + TraceEvent(SevWarnAlways, "TooManyFailedEndpoints") + .suppressFor(1.0); + failedEndpoints.clear(); + } failedEndpoints.insert(endpoint); } endpointKnownFailed.trigger(endpoint); @@ -152,13 +157,7 @@ Future SimpleFailureMonitor::onDisconnect(Endpoint const& endpoint) { TraceEvent("AlreadyDisconnected").detail("Addr", endpoint.getPrimaryAddress()).detail("Tok", endpoint.token); return Void(); } - if(endpoint.getPrimaryAddress().isPublic()) { - return endpointKnownFailed.onChange(endpoint); - } else { - Endpoint stripped; - stripped.token = endpoint.token; - return endpointKnownFailed.onChange(endpoint) || endpointKnownFailed.onChange(stripped); - } + return endpointKnownFailed.onChange(endpoint); } Future SimpleFailureMonitor::onStateChanged(Endpoint const& endpoint) { diff --git a/fdbrpc/FlowTransport.actor.cpp b/fdbrpc/FlowTransport.actor.cpp index 6161d62363e..4dcd8c9827e 100644 --- a/fdbrpc/FlowTransport.actor.cpp +++ b/fdbrpc/FlowTransport.actor.cpp @@ -165,8 +165,9 @@ struct EndpointNotFoundReceiver final : NetworkMessageReceiver { } void receive(ArenaObjectReader& reader) override { // Remote machine tells us it doesn't have endpoint e - Endpoint e; - reader.deserialize(e); + UID token; + reader.deserialize(token); + Endpoint e = FlowTransport::transport().loadedEndpoint(token); IFailureMonitor::failureMonitor().endpointNotFound(e); } }; @@ -863,10 +864,10 @@ ACTOR static void deliver(TransportData* self, Endpoint destination, ArenaReader // We don't have the (stream) endpoint 'token', notify the remote machine if (destination.token.first() != -1) { if (self->isLocalAddress(destination.getPrimaryAddress())) { - sendLocal(self, SerializeSource(Endpoint(self->localAddresses, destination.token)), Endpoint(destination.addresses, WLTOKEN_ENDPOINT_NOT_FOUND)); + sendLocal(self, SerializeSource(destination.token), Endpoint(destination.addresses, WLTOKEN_ENDPOINT_NOT_FOUND)); } else { Reference peer = self->getOrOpenPeer(destination.getPrimaryAddress()); - sendPacket(self, peer, SerializeSource(Endpoint(self->localAddresses, destination.token)), Endpoint(destination.addresses, WLTOKEN_ENDPOINT_NOT_FOUND), false); + sendPacket(self, peer, SerializeSource(destination.token), Endpoint(destination.addresses, WLTOKEN_ENDPOINT_NOT_FOUND), false); } } } From 6d5a681c29ce81929e3aeebe4aa47a52f85e7081 Mon Sep 17 00:00:00 2001 From: sfc-gh-tclinkenbeard Date: Tue, 15 Dec 2020 21:54:58 -0800 Subject: [PATCH 090/740] Encapsulate semaphore in ResultStream --- fdbclient/NativeAPI.actor.cpp | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index 789e5d669f8..ec3cf2618cf 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -2660,13 +2660,16 @@ ACTOR Future> getRange( Database cx, Reference buffer; bool completed{ false }; friend class ResultStream; - FragmentStream(ResultStream* resultStream) : resultStream(resultStream) {} + FlowLock::Releaser releaser; + FragmentStream(ResultStream* resultStream) : resultStream(resultStream), releaser(resultStream->semaphore) {} public: void send(const RangeResult& rangeResult) { buffer.push_back(rangeResult); } @@ -2675,6 +2678,7 @@ class ResultStream { ASSERT(!completed); completed = true; resultStream->flushToClient(); + releaser.release(); } }; @@ -2692,6 +2696,7 @@ class ResultStream { fragment.buffer.pop_front(); } if (fragment.completed) { + fragment.releaser.release(); ++nextFragment; } else { break; @@ -2700,27 +2705,26 @@ class ResultStream { } public: - ResultStream(PromiseStream results) : results(results) {} + ResultStream(PromiseStream results, size_t concurrency) : results(results), semaphore(concurrency) {} - FragmentStream& createFragmentStream() { - fragments.push_back(FragmentStream(this)); - return fragments.back(); + ACTOR static Future createFragmentStreamImpl(ResultStream* self) { + wait(self->semaphore.take()); + return &self->fragments.emplace_back(FragmentStream(self)); } + Future createFragmentStream() { return createFragmentStreamImpl(this); } + void sendError(Error e) { results.sendError(e); } }; ACTOR Future getRangeStreamFragment(ResultStream::FragmentStream* results, Database cx, Reference trLogInfo, Version version, KeyRangeRef keys, GetRangeLimits limits, bool snapshot, bool reverse, TransactionInfo info, - TagSet tags, SpanID spanContext, FlowLock* semaphore) { + TagSet tags, SpanID spanContext) { // if keys.end is allKeys.end, we have read through the end of the database // if keys.begin is allKeys.begin, we have either read through the beginning of the database, // or allKeys.begin exists in the database and will be part of the conflict range anyways - wait(semaphore->take()); - state FlowLock::Releaser releaser(*semaphore); - loop { state vector< pair> > locations = wait( getKeyRangeLocations( cx, keys, CLIENT_KNOBS->GET_RANGE_SHARD_LIMIT, reverse, &StorageServerInterface::getKeyValues, info ) ); ASSERT( locations.size() ); @@ -2894,8 +2898,7 @@ ACTOR Future getRangeStream(PromiseStream _results, Database KeySelector end, GetRangeLimits limits, Promise> conflictRange, bool snapshot, bool reverse, TransactionInfo info, TagSet tags) { - state FlowLock semaphore(CLIENT_KNOBS->RANGESTREAM_CONCURRENT_FRAGMENTS); - state ResultStream results(_results); + state ResultStream results(_results, CLIENT_KNOBS->RANGESTREAM_CONCURRENT_FRAGMENTS); // FIXME: better handling to disable row limits ASSERT(!limits.hasRowLimit()); @@ -2939,10 +2942,11 @@ ACTOR Future getRangeStream(PromiseStream _results, Database toSend.emplace_back(b, e); } - for (const auto& range : toSend) { - auto& fragmentStream = results.createFragmentStream(); - outstandingRequests.push_back(getRangeStreamFragment(&fragmentStream, cx, trLogInfo, version, range, limits, - snapshot, reverse, info, tags, span.context, &semaphore)); + state std::vector::iterator toSendIt = toSend.begin(); + for (; toSendIt != toSend.end(); ++toSendIt) { + ResultStream::FragmentStream* fragmentStream = wait(results.createFragmentStream()); + outstandingRequests.push_back(getRangeStreamFragment(fragmentStream, cx, trLogInfo, version, *toSendIt, limits, + snapshot, reverse, info, tags, span.context)); } try { From cdf61fe610d180f5e7f4c319bc1c4be5c6cd53f6 Mon Sep 17 00:00:00 2001 From: sfc-gh-tclinkenbeard Date: Tue, 15 Dec 2020 22:00:26 -0800 Subject: [PATCH 091/740] Flush to client in ResultStream::FragmentStream::send --- fdbclient/NativeAPI.actor.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index ec3cf2618cf..1edc30c7e98 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -2672,7 +2672,10 @@ class ResultStream { FragmentStream(ResultStream* resultStream) : resultStream(resultStream), releaser(resultStream->semaphore) {} public: - void send(const RangeResult& rangeResult) { buffer.push_back(rangeResult); } + void send(const RangeResult& rangeResult) { + buffer.push_back(rangeResult); + resultStream->flushToClient(); + } void sendError(Error e) { resultStream->sendError(e); } void finish() { ASSERT(!completed); From d30a9cfc27f5adb46911d4b69f62e3a125f2e896 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Tue, 15 Dec 2020 22:31:53 -0800 Subject: [PATCH 092/740] changed error codes, and added catches in the correct places --- documentation/tutorial/tutorial.actor.cpp | 39 +++++++++++++---------- fdbclient/NativeAPI.actor.cpp | 2 +- fdbrpc/fdbrpc.h | 16 ++-------- fdbrpc/genericactors.actor.h | 2 +- fdbserver/networktest.actor.cpp | 4 +-- fdbserver/storageserver.actor.cpp | 8 +++-- 6 files changed, 35 insertions(+), 36 deletions(-) diff --git a/documentation/tutorial/tutorial.actor.cpp b/documentation/tutorial/tutorial.actor.cpp index 100f09af207..6ec160824b9 100644 --- a/documentation/tutorial/tutorial.actor.cpp +++ b/documentation/tutorial/tutorial.actor.cpp @@ -173,22 +173,29 @@ ACTOR Future echoServer() { state EchoServerInterface echoServer; echoServer.getInterface.makeWellKnownEndpoint(UID(-1, ++tokenCounter), TaskPriority::DefaultEndpoint); loop { - choose { - when(GetInterfaceRequest req = waitNext(echoServer.getInterface.getFuture())) { - req.reply.send(echoServer); - } - when(EchoRequest req = waitNext(echoServer.echo.getFuture())) { req.reply.send(req.message); } - when(ReverseRequest req = waitNext(echoServer.reverse.getFuture())) { - req.reply.send(std::string(req.message.rbegin(), req.message.rend())); - } - when(state StreamRequest req = waitNext(echoServer.stream.getFuture())) { - state int i = 0; - for (; i < 100; ++i) { - wait(req.reply.onReady()); - std::cout << "Send " << i << std::endl; - req.reply.send(StreamReply{ i }); + try { + choose { + when(GetInterfaceRequest req = waitNext(echoServer.getInterface.getFuture())) { + req.reply.send(echoServer); } - req.reply.sendError(end_of_stream()); + when(EchoRequest req = waitNext(echoServer.echo.getFuture())) { req.reply.send(req.message); } + when(ReverseRequest req = waitNext(echoServer.reverse.getFuture())) { + req.reply.send(std::string(req.message.rbegin(), req.message.rend())); + } + when(state StreamRequest req = waitNext(echoServer.stream.getFuture())) { + state int i = 0; + for (; i < 100; ++i) { + wait(req.reply.onReady()); + std::cout << "Send " << i << std::endl; + req.reply.send(StreamReply{ i }); + } + req.reply.sendError(end_of_stream()); + } + } + } catch (Error &e) { + if(e.code() != error_code_operation_obsolete) { + fprintf(stderr, "Error: %s\n", e.what()); + throw e; } } } @@ -217,7 +224,7 @@ ACTOR Future echoClient() { ASSERT(rep.index == j++); } } catch (Error& e) { - ASSERT(e.code() == error_code_end_of_stream || e.code() == error_code_request_maybe_delivered); + ASSERT(e.code() == error_code_end_of_stream || e.code() == error_code_connection_failed); } return Void(); } diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index 93035a857f8..8a7a7a566e8 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -2849,7 +2849,7 @@ ACTOR Future getRangeStream( PromiseStream> res if (e.code() == error_code_actor_cancelled) { throw; } - if (e.code() == error_code_wrong_shard_server || e.code() == error_code_all_alternatives_failed) { + if (e.code() == error_code_wrong_shard_server || e.code() == error_code_all_alternatives_failed || e.code() == error_code_connection_failed) { const KeyRangeRef& range = locations[shard].first; if( reverse ) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index 901aad33a6b..35ee9d94a22 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -223,7 +223,7 @@ struct ReplyPromiseStreamReply { }; struct AcknowledgementReply { - constexpr static FileIdentifier file_identifier = 1378929; + constexpr static FileIdentifier file_identifier = 1389929; int64_t bytes; AcknowledgementReply() : bytes(0) {} @@ -276,8 +276,7 @@ struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAl NetNotifiedQueueWithErrors(int futures, int promises) : NotifiedQueue(futures, promises) {} NetNotifiedQueueWithErrors(int futures, int promises, const Endpoint& remoteEndpoint) : NotifiedQueue(futures, promises), FlowReceiver(remoteEndpoint, true) { - //FIXME: creating the FlowReceiver as a stream will mean that every cancelled read will lead to a permanent endpoint in the failed endpoints map - acknowledgements.failures = tagError(makeDependent(IFailureMonitor::failureMonitor()).onDisconnect(remoteEndpoint), request_maybe_delivered()); + acknowledgements.failures = tagError(makeDependent(IFailureMonitor::failureMonitor()).onDisconnect(remoteEndpoint), operation_obsolete()); } void destroy() override { delete this; } @@ -318,11 +317,10 @@ struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAl ~NetNotifiedQueueWithErrors() { if(acknowledgements.getRawEndpoint().isValid() && acknowledgements.isRemoteEndpoint() && !this->hasError()) { - FlowTransport::transport().sendUnreliable(SerializeSource>(request_maybe_delivered()), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint), false); + FlowTransport::transport().sendUnreliable(SerializeSource>(operation_obsolete()), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint), false); } } - //FIXME: creating the FlowReceiver as a stream will mean that every cancelled read will lead to a permanent endpoint in the failed endpoints map bool isStream() const override { return true; } }; @@ -583,10 +581,6 @@ class RequestStream { if (queue->isRemoteEndpoint()) { Future disc = makeDependent(IFailureMonitor::failureMonitor()).onDisconnect(getEndpoint(taskID)); auto& p = getReplyPromiseStream(value); - if (disc.isReady()) { - p.sendError(request_maybe_delivered()); - return p; - } Reference peer = FlowTransport::transport().sendUnreliable(SerializeSource(value), getEndpoint(taskID), true); //FIXME: defer sending the message until we know the connection is established endStreamOnDisconnect(disc, p, peer); @@ -602,10 +596,6 @@ class RequestStream { if (queue->isRemoteEndpoint()) { Future disc = makeDependent(IFailureMonitor::failureMonitor()).onDisconnect(getEndpoint()); auto& p = getReplyPromiseStream(value); - if (disc.isReady()) { - p.sendError(request_maybe_delivered()); - return p; - } Reference peer = FlowTransport::transport().sendUnreliable(SerializeSource(value), getEndpoint(), true); //FIXME: defer sending the message until we know the connection is established endStreamOnDisconnect(disc, p, peer); diff --git a/fdbrpc/genericactors.actor.h b/fdbrpc/genericactors.actor.h index 3b75d243b10..654c412570c 100644 --- a/fdbrpc/genericactors.actor.h +++ b/fdbrpc/genericactors.actor.h @@ -202,7 +202,7 @@ void endStreamOnDisconnect( Future signal, ReplyPromiseStream stream, R state PeerHolder holder = PeerHolder(peer); choose { when(wait(signal)) { - stream.sendError(request_maybe_delivered()); + stream.sendError(connection_failed()); } when(wait(stream.getErrorFutureAndDelPromiseRef())) {} } diff --git a/fdbserver/networktest.actor.cpp b/fdbserver/networktest.actor.cpp index 0e79f87f9a2..2bc04a8a8ed 100644 --- a/fdbserver/networktest.actor.cpp +++ b/fdbserver/networktest.actor.cpp @@ -103,7 +103,7 @@ ACTOR Future networkTestServer() { } } } catch (Error &e) { - if(e.code() != error_code_request_maybe_delivered) { + if(e.code() != error_code_operation_obsolete) { fprintf(stderr, "Error: %s\n", e.what()); throw e; } @@ -149,7 +149,7 @@ ACTOR Future testClient(std::vector interfs, int* se } } catch (Error& e) { printf("Error: %s\n", e.what()); - ASSERT(e.code() == error_code_end_of_stream || e.code() == error_code_request_maybe_delivered); + ASSERT(e.code() == error_code_end_of_stream || e.code() == error_code_connection_failed); } latency->tock(sample); (*completed)++; diff --git a/fdbserver/storageserver.actor.cpp b/fdbserver/storageserver.actor.cpp index 346fa57049b..5df2c559ce4 100644 --- a/fdbserver/storageserver.actor.cpp +++ b/fdbserver/storageserver.actor.cpp @@ -1792,9 +1792,11 @@ ACTOR Future getKeyValuesStreamQ(StorageServer* data, GetKeyValuesStreamRe } } } catch (Error& e) { - if(!canReplyWith(e)) - throw; - req.reply.sendError(e); + if(e.code() != error_code_operation_obsolete) { + if(!canReplyWith(e)) + throw; + req.reply.sendError(e); + } } data->transactionTagCounter.addRequest(req.tags, resultSize); From 7bfb6a6a957fe028fc91a52c74ecedfa2ddff2ed Mon Sep 17 00:00:00 2001 From: sfc-gh-tclinkenbeard Date: Tue, 15 Dec 2020 23:01:52 -0800 Subject: [PATCH 093/740] Put ResultStream into its own files --- fdbclient/CMakeLists.txt | 2 + fdbclient/NativeAPI.actor.cpp | 70 ++------------------- fdbclient/ResultStream.actor.cpp | 26 ++++++++ fdbclient/ResultStream.actor.h | 101 +++++++++++++++++++++++++++++++ 4 files changed, 134 insertions(+), 65 deletions(-) create mode 100644 fdbclient/ResultStream.actor.cpp create mode 100644 fdbclient/ResultStream.actor.h diff --git a/fdbclient/CMakeLists.txt b/fdbclient/CMakeLists.txt index 129f9e7d3ee..b26e1bf869a 100644 --- a/fdbclient/CMakeLists.txt +++ b/fdbclient/CMakeLists.txt @@ -55,6 +55,8 @@ set(FDBCLIENT_SRCS ReadYourWrites.actor.cpp ReadYourWrites.h RestoreWorkerInterface.actor.h + ResultStream.actor.cpp + ResultStream.actor.h RunTransaction.actor.h RYWIterator.cpp RYWIterator.h diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index 1edc30c7e98..5ffcc85cc75 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -44,6 +44,7 @@ #include "fdbclient/MonitorLeader.h" #include "fdbclient/MutationList.h" #include "fdbclient/ReadYourWrites.h" +#include "fdbclient/ResultStream.actor.h" #include "fdbclient/SpecialKeySpace.actor.h" #include "fdbclient/StorageServerInterface.h" #include "fdbclient/SystemData.h" @@ -2659,68 +2660,7 @@ ACTOR Future> getRange( Database cx, Reference buffer; - bool completed{ false }; - friend class ResultStream; - FlowLock::Releaser releaser; - FragmentStream(ResultStream* resultStream) : resultStream(resultStream), releaser(resultStream->semaphore) {} - - public: - void send(const RangeResult& rangeResult) { - buffer.push_back(rangeResult); - resultStream->flushToClient(); - } - void sendError(Error e) { resultStream->sendError(e); } - void finish() { - ASSERT(!completed); - completed = true; - resultStream->flushToClient(); - releaser.release(); - } - }; - -private: - std::vector fragments; - decltype(fragments)::iterator nextFragment = fragments.begin(); - PromiseStream results; - - // TODO: Fix potential slow tasks - void flushToClient() { - while (nextFragment != fragments.end()) { - auto& fragment = *nextFragment; - while (!fragment.buffer.empty()) { - results.send(std::move(fragment.buffer.front())); - fragment.buffer.pop_front(); - } - if (fragment.completed) { - fragment.releaser.release(); - ++nextFragment; - } else { - break; - } - } - } - -public: - ResultStream(PromiseStream results, size_t concurrency) : results(results), semaphore(concurrency) {} - - ACTOR static Future createFragmentStreamImpl(ResultStream* self) { - wait(self->semaphore.take()); - return &self->fragments.emplace_back(FragmentStream(self)); - } - - Future createFragmentStream() { return createFragmentStreamImpl(this); } - - void sendError(Error e) { results.sendError(e); } -}; - -ACTOR Future getRangeStreamFragment(ResultStream::FragmentStream* results, Database cx, +ACTOR Future getRangeStreamFragment(ResultStream::FragmentStream* results, Database cx, Reference trLogInfo, Version version, KeyRangeRef keys, GetRangeLimits limits, bool snapshot, bool reverse, TransactionInfo info, TagSet tags, SpanID spanContext) { @@ -2783,7 +2723,7 @@ ACTOR Future getRangeStreamFragment(ResultStream::FragmentStream* results, } if( info.debugID.present() ) g_traceBatch.addEvent("TransactionDebug", info.debugID.get().first(), "NativeAPI.getExactRange.After"); - Standalone output( RangeResultRef(rep.data, rep.more), rep.arena ); + RangeResult output(RangeResultRef(rep.data, rep.more), rep.arena); bool more = rep.more; // If the reply says there is more but we know that we finished the shard, then fix rep.more @@ -2901,7 +2841,7 @@ ACTOR Future getRangeStream(PromiseStream _results, Database KeySelector end, GetRangeLimits limits, Promise> conflictRange, bool snapshot, bool reverse, TransactionInfo info, TagSet tags) { - state ResultStream results(_results, CLIENT_KNOBS->RANGESTREAM_CONCURRENT_FRAGMENTS); + state ResultStream results(_results, CLIENT_KNOBS->RANGESTREAM_CONCURRENT_FRAGMENTS); // FIXME: better handling to disable row limits ASSERT(!limits.hasRowLimit()); @@ -2947,7 +2887,7 @@ ACTOR Future getRangeStream(PromiseStream _results, Database state std::vector::iterator toSendIt = toSend.begin(); for (; toSendIt != toSend.end(); ++toSendIt) { - ResultStream::FragmentStream* fragmentStream = wait(results.createFragmentStream()); + ResultStream::FragmentStream* fragmentStream = wait(results.createFragmentStream()); outstandingRequests.push_back(getRangeStreamFragment(fragmentStream, cx, trLogInfo, version, *toSendIt, limits, snapshot, reverse, info, tags, span.context)); } diff --git a/fdbclient/ResultStream.actor.cpp b/fdbclient/ResultStream.actor.cpp new file mode 100644 index 00000000000..52345c24ec8 --- /dev/null +++ b/fdbclient/ResultStream.actor.cpp @@ -0,0 +1,26 @@ +/* + * ResultStream.actor.cpp + * + * This source file is part of the FoundationDB open source project + * + * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "fdbclient/ResultStream.actor.h" +#include "flow/UnitTest.h" + +TEST_CASE("/fdbclient/result_stream") { + return Void(); +} diff --git a/fdbclient/ResultStream.actor.h b/fdbclient/ResultStream.actor.h new file mode 100644 index 00000000000..bdba304c5eb --- /dev/null +++ b/fdbclient/ResultStream.actor.h @@ -0,0 +1,101 @@ +/* + * ResultStream.actor.h + * + * This source file is part of the FoundationDB open source project + * + * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +// When actually compiled (NO_INTELLISENSE), include the generated version of this file. In intellisense use the source +// version. +#if defined(NO_INTELLISENSE) && !defined(FDBCLIENT_RESULTSTREAM_ACTOR_G_H) +#define FDBCLIENT_RESULTSTREAM_ACTOR_G_H +#include "fdbclient/ResultStream.actor.g.h" +#elif !defined(FDBCLIENT_RESULTSTREAM_ACTOR_H) +#define FDBCLIENT_RESULTSTREAM_ACTOR_H + +#include +#include + +#include "flow/genericactors.actor.h" +#include "flow/actorcompiler.h" // must be last include + +template +class ResultStream { + FlowLock semaphore; + +public: + class FragmentStream { + ResultStream* resultStream; + std::deque buffer; + bool completed{ false }; + friend class ResultStream; + FlowLock::Releaser releaser; + FragmentStream(ResultStream* resultStream) : resultStream(resultStream), releaser(resultStream->semaphore) {} + + public: + void send(const T& value) { + buffer.push_back(value); + resultStream->flushToClient(); + } + void sendError(Error e) { resultStream->sendError(e); } + void finish() { + ASSERT(!completed); + completed = true; + resultStream->flushToClient(); + releaser.release(); + } + }; + +private: + std::vector fragments; + typename std::vector::iterator nextFragment = fragments.begin(); + PromiseStream results; + + // TODO: Fix potential slow task + void flushToClient() { + while (nextFragment != fragments.end()) { + auto& fragment = *nextFragment; + while (!fragment.buffer.empty()) { + results.send(std::move(fragment.buffer.front())); + fragment.buffer.pop_front(); + } + if (fragment.completed) { + fragment.releaser.release(); + ++nextFragment; + } else { + break; + } + } + } + +public: + ResultStream(PromiseStream results, size_t concurrency) : results(results), semaphore(concurrency) {} + + ACTOR static Future createFragmentStreamImpl(ResultStream* self) { + wait(self->semaphore.take()); + return &self->fragments.emplace_back(FragmentStream(self)); + } + + Future createFragmentStream() { return createFragmentStreamImpl(this); } + + void sendError(Error e) { results.sendError(e); } +}; + +#include "flow/unactorcompiler.h" + +#endif From 3e8e4fd7d95dfc9445019a4b6bbe55b8d2a163f4 Mon Sep 17 00:00:00 2001 From: sfc-gh-tclinkenbeard Date: Tue, 15 Dec 2020 23:13:32 -0800 Subject: [PATCH 094/740] Rename ResultStream to ParallelStream --- fdbclient/CMakeLists.txt | 10 ++--- fdbclient/NativeAPI.actor.cpp | 10 ++--- ...eam.actor.cpp => ParallelStream.actor.cpp} | 6 +-- ...tStream.actor.h => ParallelStream.actor.h} | 41 ++++++++++--------- 4 files changed, 34 insertions(+), 33 deletions(-) rename fdbclient/{ResultStream.actor.cpp => ParallelStream.actor.cpp} (86%) rename fdbclient/{ResultStream.actor.h => ParallelStream.actor.h} (63%) diff --git a/fdbclient/CMakeLists.txt b/fdbclient/CMakeLists.txt index b26e1bf869a..4029567e757 100644 --- a/fdbclient/CMakeLists.txt +++ b/fdbclient/CMakeLists.txt @@ -18,6 +18,7 @@ set(FDBCLIENT_SRCS ClientLogEvents.h ClientWorkerInterface.h ClusterInterface.h + CommitProxyInterface.h CommitTransaction.h CoordinationInterface.h DatabaseBackupAgent.actor.cpp @@ -40,7 +41,6 @@ set(FDBCLIENT_SRCS Knobs.h ManagementAPI.actor.cpp ManagementAPI.actor.h - CommitProxyInterface.h MonitorLeader.actor.cpp MonitorLeader.h MultiVersionAssignmentVars.h @@ -50,13 +50,11 @@ set(FDBCLIENT_SRCS NativeAPI.actor.cpp NativeAPI.actor.h Notified.h - SpecialKeySpace.actor.cpp - SpecialKeySpace.actor.h + ParallelStream.actor.cpp + ParallelStream.actor.h ReadYourWrites.actor.cpp ReadYourWrites.h RestoreWorkerInterface.actor.h - ResultStream.actor.cpp - ResultStream.actor.h RunTransaction.actor.h RYWIterator.cpp RYWIterator.h @@ -64,6 +62,8 @@ set(FDBCLIENT_SRCS Schemas.cpp Schemas.h SnapshotCache.h + SpecialKeySpace.actor.cpp + SpecialKeySpace.actor.h Status.h StatusClient.actor.cpp StatusClient.h diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index 5ffcc85cc75..4235010d06a 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -44,7 +44,7 @@ #include "fdbclient/MonitorLeader.h" #include "fdbclient/MutationList.h" #include "fdbclient/ReadYourWrites.h" -#include "fdbclient/ResultStream.actor.h" +#include "fdbclient/ParallelStream.actor.h" #include "fdbclient/SpecialKeySpace.actor.h" #include "fdbclient/StorageServerInterface.h" #include "fdbclient/SystemData.h" @@ -2660,7 +2660,7 @@ ACTOR Future> getRange( Database cx, Reference getRangeStreamFragment(ResultStream::FragmentStream* results, Database cx, +ACTOR Future getRangeStreamFragment(ParallelStream::Fragment* results, Database cx, Reference trLogInfo, Version version, KeyRangeRef keys, GetRangeLimits limits, bool snapshot, bool reverse, TransactionInfo info, TagSet tags, SpanID spanContext) { @@ -2841,7 +2841,7 @@ ACTOR Future getRangeStream(PromiseStream _results, Database KeySelector end, GetRangeLimits limits, Promise> conflictRange, bool snapshot, bool reverse, TransactionInfo info, TagSet tags) { - state ResultStream results(_results, CLIENT_KNOBS->RANGESTREAM_CONCURRENT_FRAGMENTS); + state ParallelStream results(_results, CLIENT_KNOBS->RANGESTREAM_CONCURRENT_FRAGMENTS); // FIXME: better handling to disable row limits ASSERT(!limits.hasRowLimit()); @@ -2887,8 +2887,8 @@ ACTOR Future getRangeStream(PromiseStream _results, Database state std::vector::iterator toSendIt = toSend.begin(); for (; toSendIt != toSend.end(); ++toSendIt) { - ResultStream::FragmentStream* fragmentStream = wait(results.createFragmentStream()); - outstandingRequests.push_back(getRangeStreamFragment(fragmentStream, cx, trLogInfo, version, *toSendIt, limits, + ParallelStream::Fragment* fragment = wait(results.createFragment()); + outstandingRequests.push_back(getRangeStreamFragment(fragment, cx, trLogInfo, version, *toSendIt, limits, snapshot, reverse, info, tags, span.context)); } diff --git a/fdbclient/ResultStream.actor.cpp b/fdbclient/ParallelStream.actor.cpp similarity index 86% rename from fdbclient/ResultStream.actor.cpp rename to fdbclient/ParallelStream.actor.cpp index 52345c24ec8..38b76718356 100644 --- a/fdbclient/ResultStream.actor.cpp +++ b/fdbclient/ParallelStream.actor.cpp @@ -1,5 +1,5 @@ /* - * ResultStream.actor.cpp + * ParallelStream.actor.cpp * * This source file is part of the FoundationDB open source project * @@ -18,9 +18,9 @@ * limitations under the License. */ -#include "fdbclient/ResultStream.actor.h" +#include "fdbclient/ParallelStream.actor.h" #include "flow/UnitTest.h" -TEST_CASE("/fdbclient/result_stream") { +TEST_CASE("/fdbclient/parallel_stream") { return Void(); } diff --git a/fdbclient/ResultStream.actor.h b/fdbclient/ParallelStream.actor.h similarity index 63% rename from fdbclient/ResultStream.actor.h rename to fdbclient/ParallelStream.actor.h index bdba304c5eb..f03e6c5339c 100644 --- a/fdbclient/ResultStream.actor.h +++ b/fdbclient/ParallelStream.actor.h @@ -1,5 +1,5 @@ /* - * ResultStream.actor.h + * ParallelStream.actor.h * * This source file is part of the FoundationDB open source project * @@ -22,11 +22,11 @@ // When actually compiled (NO_INTELLISENSE), include the generated version of this file. In intellisense use the source // version. -#if defined(NO_INTELLISENSE) && !defined(FDBCLIENT_RESULTSTREAM_ACTOR_G_H) -#define FDBCLIENT_RESULTSTREAM_ACTOR_G_H -#include "fdbclient/ResultStream.actor.g.h" -#elif !defined(FDBCLIENT_RESULTSTREAM_ACTOR_H) -#define FDBCLIENT_RESULTSTREAM_ACTOR_H +#if defined(NO_INTELLISENSE) && !defined(FDBCLIENT_PARALLEL_STREAM_ACTOR_G_H) +#define FDBCLIENT_PARALLEL_STREAM_ACTOR_G_H +#include "fdbclient/ParallelStream.actor.g.h" +#elif !defined(FDBCLIENT_PARALLEL_STREAM_ACTOR_H) +#define FDBCLIENT_PARALLEL_STREAM_ACTOR_H #include #include @@ -35,35 +35,36 @@ #include "flow/actorcompiler.h" // must be last include template -class ResultStream { +class ParallelStream { FlowLock semaphore; public: - class FragmentStream { - ResultStream* resultStream; + class Fragment { + ParallelStream* parallelStream; std::deque buffer; bool completed{ false }; - friend class ResultStream; + friend class ParallelStream; FlowLock::Releaser releaser; - FragmentStream(ResultStream* resultStream) : resultStream(resultStream), releaser(resultStream->semaphore) {} + Fragment(ParallelStream* parallelStream) + : parallelStream(parallelStream), releaser(parallelStream->semaphore) {} public: void send(const T& value) { buffer.push_back(value); - resultStream->flushToClient(); + parallelStream->flushToClient(); } - void sendError(Error e) { resultStream->sendError(e); } + void sendError(Error e) { parallelStream->sendError(e); } void finish() { ASSERT(!completed); completed = true; - resultStream->flushToClient(); + parallelStream->flushToClient(); releaser.release(); } }; private: - std::vector fragments; - typename std::vector::iterator nextFragment = fragments.begin(); + std::vector fragments; + typename std::vector::iterator nextFragment = fragments.begin(); PromiseStream results; // TODO: Fix potential slow task @@ -84,14 +85,14 @@ class ResultStream { } public: - ResultStream(PromiseStream results, size_t concurrency) : results(results), semaphore(concurrency) {} + ParallelStream(PromiseStream results, size_t concurrency) : results(results), semaphore(concurrency) {} - ACTOR static Future createFragmentStreamImpl(ResultStream* self) { + ACTOR static Future createFragmentImpl(ParallelStream* self) { wait(self->semaphore.take()); - return &self->fragments.emplace_back(FragmentStream(self)); + return &self->fragments.emplace_back(Fragment(self)); } - Future createFragmentStream() { return createFragmentStreamImpl(this); } + Future createFragment() { return createFragmentImpl(this); } void sendError(Error e) { results.sendError(e); } }; From 688e297dfc875afab0b049a88816d0babbcd8d75 Mon Sep 17 00:00:00 2001 From: sfc-gh-tclinkenbeard Date: Tue, 15 Dec 2020 23:44:03 -0800 Subject: [PATCH 095/740] Added parallel_stream unit test --- fdbclient/ParallelStream.actor.cpp | 36 ++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/fdbclient/ParallelStream.actor.cpp b/fdbclient/ParallelStream.actor.cpp index 38b76718356..c26d63781cc 100644 --- a/fdbclient/ParallelStream.actor.cpp +++ b/fdbclient/ParallelStream.actor.cpp @@ -18,9 +18,45 @@ * limitations under the License. */ +#include + #include "fdbclient/ParallelStream.actor.h" #include "flow/UnitTest.h" +#include "flow/actorcompiler.h" // This must be the last #include. + +ACTOR static Future produce(ParallelStream::Fragment* fragment, int i) { + wait(delay(deterministicRandom()->random01())); + fragment->send(i); + wait(delay(deterministicRandom()->random01())); + fragment->finish(); + return Void(); +} + +ACTOR static Future consume(FutureStream stream, int expected) { + state int next; + try { + loop { + int i = waitNext(stream); + ASSERT(i == next++); + } + } catch (Error& e) { + ASSERT(e.code() == error_code_end_of_stream); + ASSERT(next == expected); + return Void(); + } +} TEST_CASE("/fdbclient/parallel_stream") { + state PromiseStream results; + state ParallelStream parallelStream(results, 10); + state Future consumer = consume(results.getFuture(), 100); + state std::vector> producers; + state int i = 0; + for (; i < 100; ++i) { + ParallelStream::Fragment* fragment = wait(parallelStream.createFragment()); + producers.push_back(produce(fragment, i)); + } + wait(waitForAll(producers)); + results.sendError(end_of_stream()); return Void(); } From 693d101d00e3ef7f504f2919d09a5b22363b7322 Mon Sep 17 00:00:00 2001 From: sfc-gh-tclinkenbeard Date: Wed, 16 Dec 2020 00:08:52 -0800 Subject: [PATCH 096/740] Added ParallelStreamTest namespace --- fdbclient/ParallelStream.actor.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/fdbclient/ParallelStream.actor.cpp b/fdbclient/ParallelStream.actor.cpp index c26d63781cc..1c67812d6b6 100644 --- a/fdbclient/ParallelStream.actor.cpp +++ b/fdbclient/ParallelStream.actor.cpp @@ -24,6 +24,8 @@ #include "flow/UnitTest.h" #include "flow/actorcompiler.h" // This must be the last #include. +namespace ParallelStreamTest { + ACTOR static Future produce(ParallelStream::Fragment* fragment, int i) { wait(delay(deterministicRandom()->random01())); fragment->send(i); @@ -46,17 +48,20 @@ ACTOR static Future consume(FutureStream stream, int expected) { } } -TEST_CASE("/fdbclient/parallel_stream") { +} // namespace ParallelStreamTest + +TEST_CASE("/parallel_stream") { state PromiseStream results; state ParallelStream parallelStream(results, 10); - state Future consumer = consume(results.getFuture(), 100); + state Future consumer = ParallelStreamTest::consume(results.getFuture(), 100); state std::vector> producers; state int i = 0; for (; i < 100; ++i) { ParallelStream::Fragment* fragment = wait(parallelStream.createFragment()); - producers.push_back(produce(fragment, i)); + producers.push_back(ParallelStreamTest::produce(fragment, i)); } wait(waitForAll(producers)); results.sendError(end_of_stream()); + wait(consumer); return Void(); } From 19d0800356ec83113b727b3c6546584d0f1f9e4d Mon Sep 17 00:00:00 2001 From: sfc-gh-tclinkenbeard Date: Wed, 16 Dec 2020 09:05:45 -0800 Subject: [PATCH 097/740] Move ParallelStreamCorrectness into fdbserver Apparently this is required to register the unit test --- fdbclient/CMakeLists.txt | 1 - fdbserver/CMakeLists.txt | 1 + .../workloads/ParallelStreamCorrectness.actor.cpp | 4 ++-- 3 files changed, 3 insertions(+), 3 deletions(-) rename fdbclient/ParallelStream.actor.cpp => fdbserver/workloads/ParallelStreamCorrectness.actor.cpp (96%) diff --git a/fdbclient/CMakeLists.txt b/fdbclient/CMakeLists.txt index 4029567e757..3df3422ccf3 100644 --- a/fdbclient/CMakeLists.txt +++ b/fdbclient/CMakeLists.txt @@ -50,7 +50,6 @@ set(FDBCLIENT_SRCS NativeAPI.actor.cpp NativeAPI.actor.h Notified.h - ParallelStream.actor.cpp ParallelStream.actor.h ReadYourWrites.actor.cpp ReadYourWrites.h diff --git a/fdbserver/CMakeLists.txt b/fdbserver/CMakeLists.txt index bf266069cbd..1469bf8af0a 100644 --- a/fdbserver/CMakeLists.txt +++ b/fdbserver/CMakeLists.txt @@ -175,6 +175,7 @@ set(FDBSERVER_SRCS workloads/MemoryKeyValueStore.h workloads/MemoryLifetime.actor.cpp workloads/MetricLogging.actor.cpp + workloads/ParallelStreamCorrectness.actor.cpp workloads/Performance.actor.cpp workloads/Ping.actor.cpp workloads/PopulateTPCC.actor.cpp diff --git a/fdbclient/ParallelStream.actor.cpp b/fdbserver/workloads/ParallelStreamCorrectness.actor.cpp similarity index 96% rename from fdbclient/ParallelStream.actor.cpp rename to fdbserver/workloads/ParallelStreamCorrectness.actor.cpp index 1c67812d6b6..5975f3eff85 100644 --- a/fdbclient/ParallelStream.actor.cpp +++ b/fdbserver/workloads/ParallelStreamCorrectness.actor.cpp @@ -1,5 +1,5 @@ /* - * ParallelStream.actor.cpp + * ParallelStreamCorrectness.actor.cpp * * This source file is part of the FoundationDB open source project * @@ -50,7 +50,7 @@ ACTOR static Future consume(FutureStream stream, int expected) { } // namespace ParallelStreamTest -TEST_CASE("/parallel_stream") { +TEST_CASE("/fdbclient/ParallelStream") { state PromiseStream results; state ParallelStream parallelStream(results, 10); state Future consumer = ParallelStreamTest::consume(results.getFuture(), 100); From d89c591ef7b50584614876fd9dfebba58d824389 Mon Sep 17 00:00:00 2001 From: sfc-gh-tclinkenbeard Date: Wed, 16 Dec 2020 10:20:08 -0800 Subject: [PATCH 098/740] Use unique_ptrs to store parallel stream fragments --- fdbclient/ParallelStream.actor.h | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/fdbclient/ParallelStream.actor.h b/fdbclient/ParallelStream.actor.h index f03e6c5339c..7d1a3beda1e 100644 --- a/fdbclient/ParallelStream.actor.h +++ b/fdbclient/ParallelStream.actor.h @@ -45,10 +45,9 @@ class ParallelStream { bool completed{ false }; friend class ParallelStream; FlowLock::Releaser releaser; + public: Fragment(ParallelStream* parallelStream) : parallelStream(parallelStream), releaser(parallelStream->semaphore) {} - - public: void send(const T& value) { buffer.push_back(value); parallelStream->flushToClient(); @@ -63,20 +62,24 @@ class ParallelStream { }; private: - std::vector fragments; - typename std::vector::iterator nextFragment = fragments.begin(); + std::vector> fragments; + typename std::vector>::iterator nextFragment; PromiseStream results; // TODO: Fix potential slow task void flushToClient() { while (nextFragment != fragments.end()) { - auto& fragment = *nextFragment; - while (!fragment.buffer.empty()) { - results.send(std::move(fragment.buffer.front())); - fragment.buffer.pop_front(); + if (!*nextFragment) { + ++nextFragment; + continue; + } + auto fragment = nextFragment->get(); + while (!fragment->buffer.empty()) { + results.send(fragment->buffer.front()); + fragment->buffer.pop_front(); } - if (fragment.completed) { - fragment.releaser.release(); + if (fragment->completed) { + nextFragment->reset(); ++nextFragment; } else { break; @@ -89,7 +92,12 @@ class ParallelStream { ACTOR static Future createFragmentImpl(ParallelStream* self) { wait(self->semaphore.take()); - return &self->fragments.emplace_back(Fragment(self)); + self->fragments.push_back(std::make_unique(self)); + if (self->fragments.size() == 1) { + self->nextFragment = self->fragments.begin(); + } + ASSERT(*self->nextFragment); + return self->fragments.back().get(); } Future createFragment() { return createFragmentImpl(this); } From 27ce55af0c5f9719dc8e4bfc5dd4fb160f98e115 Mon Sep 17 00:00:00 2001 From: sfc-gh-tclinkenbeard Date: Wed, 16 Dec 2020 10:21:00 -0800 Subject: [PATCH 099/740] Fix range order in getRangeStream --- fdbclient/NativeAPI.actor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index 4235010d06a..4a9148033b0 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -2876,7 +2876,7 @@ ACTOR Future getRangeStream(PromiseStream _results, Database state std::vector> outstandingRequests; if (!splitPoints.empty()) { - toSend.emplace_back(splitPoints.front(), b); + toSend.emplace_back(b, splitPoints.front()); for (int i = 0; i < splitPoints.size() - 1; ++i) { toSend.emplace_back(splitPoints[i], splitPoints[i + 1]); } From 4b71ebd875173c2c0d3814fe8b0e52bad97f7212 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Wed, 16 Dec 2020 10:21:08 -0800 Subject: [PATCH 100/740] Update flow/flow.h Co-authored-by: Trevor Clinkenbeard <65554662+sfc-gh-tclinkenbeard@users.noreply.github.com> --- flow/flow.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flow/flow.h b/flow/flow.h index a993fa4061a..509e8caf207 100644 --- a/flow/flow.h +++ b/flow/flow.h @@ -898,7 +898,7 @@ decltype(std::declval().reply) const& getReplyPromise(Request const& r) } template -decltype(std::declval().reply) const& getReplyPromiseStream(Request const& r) { +auto const& getReplyPromiseStream(Request const& r) { return r.reply; } From ef16dec03688c653c52c6c34493b861c626cff9d Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Wed, 16 Dec 2020 10:26:26 -0800 Subject: [PATCH 101/740] added a knob for acknowledge limit bytes --- fdbrpc/FailureMonitor.actor.cpp | 2 +- fdbrpc/fdbrpc.h | 6 +++--- flow/Knobs.cpp | 1 + flow/Knobs.h | 1 + 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/fdbrpc/FailureMonitor.actor.cpp b/fdbrpc/FailureMonitor.actor.cpp index 9d1047182d7..70304cb3c77 100644 --- a/fdbrpc/FailureMonitor.actor.cpp +++ b/fdbrpc/FailureMonitor.actor.cpp @@ -133,7 +133,7 @@ void SimpleFailureMonitor::endpointNotFound(Endpoint const& endpoint) { } void SimpleFailureMonitor::notifyDisconnect(NetworkAddress const& address) { - TraceEvent("NotifyDisconnect").detail("Address", address); + //TraceEvent("NotifyDisconnect").detail("Address", address); endpointKnownFailed.triggerRange(Endpoint({ address }, UID()), Endpoint({ address }, UID(-1, -1))); } diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index 35ee9d94a22..5b1c1b776ff 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -259,7 +259,7 @@ struct AcknowledgementReceiver final : FlowReceiver, FastAllocated bytesAcknowledged); bytesAcknowledged = message.get().bytes; - if (bytesSent - bytesAcknowledged < 2e6 && ready.isValid() && ready.canBeSet()) { + if (bytesSent - bytesAcknowledged < FLOW_KNOBS->ACKNOWLEDGE_LIMIT_BYTES && ready.isValid() && ready.canBeSet()) { ready.send(Void()); } } @@ -337,7 +337,7 @@ class ReplyPromiseStream { value.acknowledgeToken = queue->acknowledgements.getEndpoint(TaskPriority::DefaultEndpoint).token; } queue->acknowledgements.bytesSent += value.expectedSize(); - if((!queue->acknowledgements.ready.isValid() || (queue->acknowledgements.ready.isSet() && !queue->acknowledgements.ready.getFuture().isError())) && queue->acknowledgements.bytesSent - queue->acknowledgements.bytesAcknowledged >= 2e6) { + if((!queue->acknowledgements.ready.isValid() || (queue->acknowledgements.ready.isSet() && !queue->acknowledgements.ready.getFuture().isError())) && queue->acknowledgements.bytesSent - queue->acknowledgements.bytesAcknowledged >= FLOW_KNOBS->ACKNOWLEDGE_LIMIT_BYTES) { queue->acknowledgements.ready = Promise(); } FlowTransport::transport().sendUnreliable(SerializeSource>>(value), getEndpoint(), false); @@ -401,7 +401,7 @@ class ReplyPromiseStream { if(queue->acknowledgements.ready.isValid() && queue->acknowledgements.ready.isSet() && queue->acknowledgements.ready.getFuture().isError()) { return queue->acknowledgements.ready.getFuture().getError(); } - if(queue->acknowledgements.bytesSent - queue->acknowledgements.bytesAcknowledged < 2e6) { + if(queue->acknowledgements.bytesSent - queue->acknowledgements.bytesAcknowledged < FLOW_KNOBS->ACKNOWLEDGE_LIMIT_BYTES) { return Void(); } return queue->acknowledgements.ready.getFuture() || queue->acknowledgements.failures; diff --git a/flow/Knobs.cpp b/flow/Knobs.cpp index 606ccb24e6f..4f19a56955c 100644 --- a/flow/Knobs.cpp +++ b/flow/Knobs.cpp @@ -62,6 +62,7 @@ void FlowKnobs::initialize(bool randomize, bool isSimulated) { init( HUGE_ARENA_LOGGING_INTERVAL, 5.0 ); init( WRITE_TRACING_ENABLED, true ); if( randomize && BUGGIFY ) WRITE_TRACING_ENABLED = false; + init( ACKNOWLEDGE_LIMIT_BYTES, 2e6 ); if( randomize && BUGGIFY ) ACKNOWLEDGE_LIMIT_BYTES = 1; //connectionMonitor init( CONNECTION_MONITOR_LOOP_TIME, isSimulated ? 0.75 : 1.0 ); if( randomize && BUGGIFY ) CONNECTION_MONITOR_LOOP_TIME = 6.0; diff --git a/flow/Knobs.h b/flow/Knobs.h index 656cb8eff5a..fe89d85c28d 100644 --- a/flow/Knobs.h +++ b/flow/Knobs.h @@ -70,6 +70,7 @@ class FlowKnobs : public Knobs { double HUGE_ARENA_LOGGING_INTERVAL; bool WRITE_TRACING_ENABLED; + int64_t ACKNOWLEDGE_LIMIT_BYTES; //run loop profiling double RUN_LOOP_PROFILING_INTERVAL; From 7514bd0e878b5fffc4f7de2e9b75edada982a88f Mon Sep 17 00:00:00 2001 From: sfc-gh-tclinkenbeard Date: Wed, 16 Dec 2020 11:05:30 -0800 Subject: [PATCH 102/740] Use index instead of iterator for tracking next fragment --- fdbclient/ParallelStream.actor.h | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/fdbclient/ParallelStream.actor.h b/fdbclient/ParallelStream.actor.h index 7d1a3beda1e..a204010c1a5 100644 --- a/fdbclient/ParallelStream.actor.h +++ b/fdbclient/ParallelStream.actor.h @@ -63,24 +63,24 @@ class ParallelStream { private: std::vector> fragments; - typename std::vector>::iterator nextFragment; + size_t fragmentsProcessed { 0 }; PromiseStream results; // TODO: Fix potential slow task void flushToClient() { - while (nextFragment != fragments.end()) { - if (!*nextFragment) { - ++nextFragment; + while (fragmentsProcessed < fragments.size()) { + auto &fragment = fragments[fragmentsProcessed]; + if (!fragment) { + ++fragmentsProcessed; continue; } - auto fragment = nextFragment->get(); while (!fragment->buffer.empty()) { results.send(fragment->buffer.front()); fragment->buffer.pop_front(); } if (fragment->completed) { - nextFragment->reset(); - ++nextFragment; + fragment.reset(); + ++fragmentsProcessed; } else { break; } @@ -93,10 +93,7 @@ class ParallelStream { ACTOR static Future createFragmentImpl(ParallelStream* self) { wait(self->semaphore.take()); self->fragments.push_back(std::make_unique(self)); - if (self->fragments.size() == 1) { - self->nextFragment = self->fragments.begin(); - } - ASSERT(*self->nextFragment); + ASSERT(self->fragments[self->fragmentsProcessed]); return self->fragments.back().get(); } From 91eb0c6f9eadb6c52347176224afe3860af0ab9b Mon Sep 17 00:00:00 2001 From: sfc-gh-tclinkenbeard Date: Wed, 16 Dec 2020 11:28:56 -0800 Subject: [PATCH 103/740] Use perfect forwarding in ParallelStream::Fragment::send --- fdbclient/ParallelStream.actor.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fdbclient/ParallelStream.actor.h b/fdbclient/ParallelStream.actor.h index a204010c1a5..4d2d2d16938 100644 --- a/fdbclient/ParallelStream.actor.h +++ b/fdbclient/ParallelStream.actor.h @@ -48,8 +48,9 @@ class ParallelStream { public: Fragment(ParallelStream* parallelStream) : parallelStream(parallelStream), releaser(parallelStream->semaphore) {} - void send(const T& value) { - buffer.push_back(value); + template + void send(U &&value) { + buffer.push_back(std::forward(value)); parallelStream->flushToClient(); } void sendError(Error e) { parallelStream->sendError(e); } From cb588135c7229cc9d374a71224fc4f3de6642381 Mon Sep 17 00:00:00 2001 From: sfc-gh-tclinkenbeard Date: Wed, 16 Dec 2020 11:34:27 -0800 Subject: [PATCH 104/740] Avoid calling ParallelStream::releaser::release() after destruction --- fdbclient/ParallelStream.actor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdbclient/ParallelStream.actor.h b/fdbclient/ParallelStream.actor.h index 4d2d2d16938..7449c63dfa8 100644 --- a/fdbclient/ParallelStream.actor.h +++ b/fdbclient/ParallelStream.actor.h @@ -57,8 +57,8 @@ class ParallelStream { void finish() { ASSERT(!completed); completed = true; + releaser.release(); // Release before destruction to free up pending fragments parallelStream->flushToClient(); - releaser.release(); } }; From 241b38b54f1d7e546ec7a23a3cdcaf0237f638a4 Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Wed, 16 Dec 2020 20:01:07 +0000 Subject: [PATCH 105/740] Fix fdbClientStream bug --- documentation/tutorial/tutorial.actor.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/documentation/tutorial/tutorial.actor.cpp b/documentation/tutorial/tutorial.actor.cpp index 6ec160824b9..5393c0c3e40 100644 --- a/documentation/tutorial/tutorial.actor.cpp +++ b/documentation/tutorial/tutorial.actor.cpp @@ -401,22 +401,22 @@ ACTOR Future multipleClients() { std::string clusterFile = "fdb.cluster"; -ACTOR Future logThroughput(int64_t* v) { +ACTOR Future logThroughput(int64_t* v, Key* next) { loop { state int64_t last = *v; wait(delay(1)); - printf("throughput: %ld bytes/s\n", *v - last); + printf("throughput: %ld bytes/s, next: %s\n", *v - last, printable(*next).c_str()); } } ACTOR Future fdbClientStream() { state Database db = Database::createDatabase(clusterFile, 300); state Transaction tx(db); - state PromiseStream> results; state Key next; state int64_t bytes = 0; - state Future logFuture = logThroughput(&bytes); + state Future logFuture = logThroughput(&bytes, &next); loop { + state PromiseStream> results; try { state Future stream = tx.getRangeStream(results, KeySelector(firstGreaterOrEqual(next), next.arena()), @@ -441,7 +441,7 @@ ACTOR Future fdbClientGetRange() { state Transaction tx(db); state Key next; state int64_t bytes = 0; - state Future logFuture = logThroughput(&bytes); + state Future logFuture = logThroughput(&bytes, &next); loop { try { Standalone range = wait(tx.getRange( From fc859996832e83f04657a33d9021885e7054c249 Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Wed, 16 Dec 2020 20:01:30 +0000 Subject: [PATCH 106/740] Naive load balancing --- fdbclient/NativeAPI.actor.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index d6e12563b21..046bc2e99e3 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -2699,7 +2699,10 @@ ACTOR Future getRangeStreamFragment(ParallelStream::Fragment* } //FIXME: add load balancing - state ReplyPromiseStream replyStream = locations[shard].second->getInterface(0).getKeyValuesStream.getReplyStream(req); + state ReplyPromiseStream replyStream = + locations[shard] + .second->getInterface(deterministicRandom()->randomInt(0, locations[shard].second->size())) + .getKeyValuesStream.getReplyStream(req); state bool breakAgain = false; loop { try { From 18205a9e20fa4616c700359bf49217c2b903e495 Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Wed, 16 Dec 2020 20:02:12 +0000 Subject: [PATCH 107/740] Remove broken assert --- fdbrpc/genericactors.actor.h | 1 - 1 file changed, 1 deletion(-) diff --git a/fdbrpc/genericactors.actor.h b/fdbrpc/genericactors.actor.h index 654c412570c..4f21b2441e8 100644 --- a/fdbrpc/genericactors.actor.h +++ b/fdbrpc/genericactors.actor.h @@ -229,7 +229,6 @@ Future> waitValueOrSignal( Future value, Future signal, Endp if( e.code() == error_code_actor_cancelled ) throw e; - ASSERT(e.code() != error_code_broken_promise); return ErrorOr(e); } } From 3bf9dcac4bb52dca6dc5cf893d6021fb3c07a611 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Wed, 16 Dec 2020 13:00:17 -0800 Subject: [PATCH 108/740] updated fetchKeys to properly use getRangeStream --- fdbserver/Knobs.cpp | 1 + fdbserver/Knobs.h | 1 + fdbserver/storageserver.actor.cpp | 208 ++++++++++-------------------- 3 files changed, 67 insertions(+), 143 deletions(-) diff --git a/fdbserver/Knobs.cpp b/fdbserver/Knobs.cpp index c7165d326a5..158bbd60ed5 100644 --- a/fdbserver/Knobs.cpp +++ b/fdbserver/Knobs.cpp @@ -553,6 +553,7 @@ void ServerKnobs::initialize(bool randomize, ClientKnobs* clientKnobs, bool isSi init( BUGGIFY_LIMIT_BYTES, 1000 ); init( FETCH_BLOCK_BYTES, 2e6 ); init( FETCH_KEYS_PARALLELISM_BYTES, 4e6 ); if( randomize && BUGGIFY ) FETCH_KEYS_PARALLELISM_BYTES = 3e6; + init( FETCH_KEYS_PARALLELISM, 1 ); init( FETCH_KEYS_LOWER_PRIORITY, 0 ); init( BUGGIFY_BLOCK_BYTES, 10000 ); init( STORAGE_COMMIT_BYTES, 10000000 ); if( randomize && BUGGIFY ) STORAGE_COMMIT_BYTES = 2000000; diff --git a/fdbserver/Knobs.h b/fdbserver/Knobs.h index 16160381297..2095bf4e485 100644 --- a/fdbserver/Knobs.h +++ b/fdbserver/Knobs.h @@ -480,6 +480,7 @@ class ServerKnobs : public Knobs { int BUGGIFY_LIMIT_BYTES; int FETCH_BLOCK_BYTES; int FETCH_KEYS_PARALLELISM_BYTES; + int FETCH_KESY_PARALLELISM; int FETCH_KEYS_LOWER_PRIORITY; int BUGGIFY_BLOCK_BYTES; int64_t STORAGE_HARD_LIMIT_BYTES; diff --git a/fdbserver/storageserver.actor.cpp b/fdbserver/storageserver.actor.cpp index 5df2c559ce4..d07d61d1d68 100644 --- a/fdbserver/storageserver.actor.cpp +++ b/fdbserver/storageserver.actor.cpp @@ -614,7 +614,7 @@ struct StorageServer { versionLag(0), primaryLocality(tagLocalityInvalid), updateEagerReads(0), shardChangeCounter(0), - fetchKeysParallelismLock(SERVER_KNOBS->FETCH_KEYS_PARALLELISM_BYTES), + fetchKeysParallelismLock(SERVER_KNOBS->FETCH_KEYS_PARALLELISM), shuttingDown(false), debug_inApplyUpdate(false), debug_lastValidateTime(0), watchBytes(0), numWatches(0), logProtocol(0), counters(this), tag(invalidTag), maxQueryQueue(0), thisServerID(ssi.id()), readQueueSizeMetric(LiteralStringRef("StorageServer.ReadQueueSize")), @@ -2218,70 +2218,6 @@ void coalesceShards(StorageServer *data, KeyRangeRef keys) { } } -ACTOR Future> tryGetRange( Database cx, Version version, KeyRangeRef keys, GetRangeLimits limits, bool* isTooOld ) { - state Transaction tr( cx ); - state Standalone output; - state KeySelectorRef begin = firstGreaterOrEqual( keys.begin ); - state KeySelectorRef end = firstGreaterOrEqual( keys.end ); - - if( *isTooOld ) - throw transaction_too_old(); - - ASSERT(!cx->switchable); - tr.setVersion( version ); - tr.info.taskID = TaskPriority::FetchKeys; - limits.minRows = 0; - - try { - loop { - state PromiseStream> results; - state Future hold = tr.getRangeStream(results, begin, end, limits, true); - loop { - Standalone rep = waitNext( results.getFuture() ); - limits.decrement( rep ); - //FIXME: this is only returning the first result from the stream and then cancelling the stream - if( limits.isReached() || !rep.more ) { - if( output.size() ) { - output.arena().dependsOn( rep.arena() ); - output.append( output.arena(), rep.begin(), rep.size() ); - if( limits.isReached() && rep.readThrough.present() ) - output.readThrough = rep.readThrough.get(); - } else { - output = rep; - } - - output.more = limits.isReached(); - - return output; - } else if( rep.readThrough.present() ) { - output.arena().dependsOn( rep.arena() ); - if( rep.size() ) { - output.append( output.arena(), rep.begin(), rep.size() ); - ASSERT( rep.readThrough.get() > rep.end()[-1].key ); - } else { - ASSERT( rep.readThrough.get() > keys.begin ); - } - begin = firstGreaterOrEqual( rep.readThrough.get() ); - } else { - output.arena().dependsOn( rep.arena() ); - output.append( output.arena(), rep.begin(), rep.size() ); - begin = firstGreaterThan( output.end()[-1].key ); - } - } - } - } catch( Error &e ) { - if( begin.getKey() != keys.begin && ( e.code() == error_code_transaction_too_old || e.code() == error_code_future_version || e.code() == error_code_process_behind ) ) { - if( e.code() == error_code_transaction_too_old ) - *isTooOld = true; - output.more = true; - if( begin.isFirstGreaterOrEqual() ) - output.readThrough = begin.getKey(); - return output; - } - throw; - } -} - template void addMutation( T& target, Version version, MutationRef const& mutation ) { target.addMutation( version, mutation ); @@ -2332,8 +2268,7 @@ ACTOR Future fetchKeys( StorageServer *data, AddingShard* shard ) { state KeyRange keys = shard->keys; state Future warningLogger = logFetchKeysWarning(shard); state double startt = now(); - state int fetchBlockBytes = BUGGIFY ? SERVER_KNOBS->BUGGIFY_BLOCK_BYTES : SERVER_KNOBS->FETCH_BLOCK_BYTES; - + // delay(0) to force a return to the run loop before the work of fetchKeys is started. // This allows adding->start() to be called inline with CSK. wait( data->coreStarted.getFuture() && delay( 0 ) ); @@ -2365,8 +2300,8 @@ ACTOR Future fetchKeys( StorageServer *data, AddingShard* shard ) { TraceEvent(SevDebug, "FetchKeysVersionSatisfied", data->thisServerID).detail("FKID", interval.pairID); - wait( data->fetchKeysParallelismLock.take( TaskPriority::DefaultYield, fetchBlockBytes ) ); - state FlowLock::Releaser holdingFKPL( data->fetchKeysParallelismLock, fetchBlockBytes ); + wait( data->fetchKeysParallelismLock.take( TaskPriority::DefaultYield ) ); + state FlowLock::Releaser holdingFKPL( data->fetchKeysParallelismLock ); state double executeStart = now(); ++data->counters.fetchWaitingCount; @@ -2378,8 +2313,7 @@ ACTOR Future fetchKeys( StorageServer *data, AddingShard* shard ) { wait( data->durableVersionLock.take() ); shard->phase = AddingShard::Fetching; - state Version fetchVersion = data->version.get(); - + data->durableVersionLock.release(); wait(delay(0)); @@ -2395,49 +2329,69 @@ ACTOR Future fetchKeys( StorageServer *data, AddingShard* shard ) { data->cx->invalidateCache(keys); loop { - try { - TEST(true); // Fetching keys for transferred shard - - //FIXME: this is inefficient because we are restarting the getRangeStreaming for every block - state Standalone this_block = - wait(tryGetRange(data->cx, fetchVersion, keys, - GetRangeLimits(GetRangeLimits::ROW_LIMIT_UNLIMITED, fetchBlockBytes), &isTooOld)); - - int expectedSize = (int)this_block.expectedSize() + (8-(int)sizeof(KeyValueRef))*this_block.size(); - - TraceEvent(SevDebug, "FetchKeysBlock", data->thisServerID).detail("FKID", interval.pairID) - .detail("BlockRows", this_block.size()).detail("BlockBytes", expectedSize) - .detail("KeyBegin", keys.begin).detail("KeyEnd", keys.end) - .detail("Last", this_block.size() ? this_block.end()[-1].key : std::string()) - .detail("Version", fetchVersion).detail("More", this_block.more); - DEBUG_KEY_RANGE("fetchRange", fetchVersion, keys); - for(auto k = this_block.begin(); k != this_block.end(); ++k) DEBUG_MUTATION("fetch", fetchVersion, MutationRef(MutationRef::SetValue, k->key, k->value)); - - data->counters.bytesFetched += expectedSize; - if( fetchBlockBytes > expectedSize ) { - holdingFKPL.release( fetchBlockBytes - expectedSize ); - } + state Transaction tr( data->cx ); + state Version fetchVersion = data->version.get(); + while (!shard->updates.empty() && shard->updates[0].version <= fetchVersion) shard->updates.pop_front(); + tr.setVersion( fetchVersion ); + tr.info.taskID = TaskPriority::FetchKeys; + state PromiseStream> results; + state Future hold = tr.getRangeStream(results, keys, GetRangeLimits(), true); + state Key nfk = keys.begin; - // Wait for permission to proceed - //wait( data->fetchKeysStorageWriteLock.take() ); - //state FlowLock::Releaser holdingFKSWL( data->fetchKeysStorageWriteLock ); + loop { + try { + TEST(true); // Fetching keys for transferred shard + state Standalone this_block = waitNext( results.getFuture() ); + + int expectedSize = (int)this_block.expectedSize() + (8-(int)sizeof(KeyValueRef))*this_block.size(); + + TraceEvent(SevDebug, "FetchKeysBlock", data->thisServerID).detail("FKID", interval.pairID) + .detail("BlockRows", this_block.size()).detail("BlockBytes", expectedSize) + .detail("KeyBegin", keys.begin).detail("KeyEnd", keys.end) + .detail("Last", this_block.size() ? this_block.end()[-1].key : std::string()) + .detail("Version", fetchVersion).detail("More", this_block.more); + DEBUG_KEY_RANGE("fetchRange", fetchVersion, keys); + for(auto k = this_block.begin(); k != this_block.end(); ++k) DEBUG_MUTATION("fetch", fetchVersion, MutationRef(MutationRef::SetValue, k->key, k->value)); + + data->counters.bytesFetched += expectedSize; + + // Write this_block to storage + state KeyValueRef *kvItr = this_block.begin(); + for(; kvItr != this_block.end(); ++kvItr) { + data->storage.writeKeyValue( *kvItr ); + wait(yield()); + } - // Write this_block to storage - state KeyValueRef *kvItr = this_block.begin(); - for(; kvItr != this_block.end(); ++kvItr) { - data->storage.writeKeyValue( *kvItr ); - wait(yield()); - } + kvItr = this_block.begin(); + for(; kvItr != this_block.end(); ++kvItr) { + data->byteSampleApplySet( *kvItr, invalidVersion ); + wait(yield()); + } - kvItr = this_block.begin(); - for(; kvItr != this_block.end(); ++kvItr) { - data->byteSampleApplySet( *kvItr, invalidVersion ); - wait(yield()); - } + nfk = this_block.readThrough.present() ? this_block.readThrough.get() : keyAfter( this_block.end()[-1].key ); + this_block = Standalone(); + } catch( Error &e ) { + if(e.code() != error_code_end_of_stream || e.code() != error_code_connection_failed || e.code() != error_code_transaction_too_old || + e.code() != error_code_future_version || e.code() != error_code_process_behind) { + throw; + } + if(nfk == keys.begin) { + TraceEvent("FKBlockFail", data->thisServerID).error(e,true).suppressFor(1.0).detail("FKID", interval.pairID); + + //FIXME: remove when we no longer support upgrades from 5.X + if(debug_getRangeRetries >= 100) { + data->cx->enableLocalityLoadBalance = false; + } - if (this_block.more) { - Key nfk = this_block.readThrough.present() ? this_block.readThrough.get() : keyAfter( this_block.end()[-1].key ); - if (nfk != keys.end) { + debug_getRangeRetries++; + if (debug_nextRetryToLog==debug_getRangeRetries){ + debug_nextRetryToLog += std::min(debug_nextRetryToLog, 1024); + TraceEvent(SevWarn, "FetchPast", data->thisServerID).detail("TotalAttempts", debug_getRangeRetries).detail("FKID", interval.pairID).detail("V", lastFV).detail("N", fetchVersion).detail("E", data->version.get()); + } + wait( delayJittered( FLOW_KNOBS->PREVENT_FAST_SPIN_DELAY ) ); + continue; + } + if(nfk < keys.end) { std::deque< Standalone > updatesToSplit = std::move( shard->updates ); // This actor finishes committing the keys [keys.begin,nfk) that we already fetched. @@ -2461,40 +2415,8 @@ ACTOR Future fetchKeys( StorageServer *data, AddingShard* shard ) { TEST( shard->updates.size() ); // Shard has updates ASSERT( otherShard->updates.empty() ); } + break; } - - this_block = Standalone(); - - if (BUGGIFY) wait( delay( 1 ) ); - - break; - } catch (Error& e) { - TraceEvent("FKBlockFail", data->thisServerID).error(e,true).suppressFor(1.0).detail("FKID", interval.pairID); - if (e.code() == error_code_transaction_too_old){ - TEST(true); // A storage server has forgotten the history data we are fetching - Version lastFV = fetchVersion; - fetchVersion = data->version.get(); - isTooOld = false; - - // Throw away deferred updates from before fetchVersion, since we don't need them to use blocks fetched at that version - while (!shard->updates.empty() && shard->updates[0].version <= fetchVersion) shard->updates.pop_front(); - - //FIXME: remove when we no longer support upgrades from 5.X - if(debug_getRangeRetries >= 100) { - data->cx->enableLocalityLoadBalance = false; - } - - debug_getRangeRetries++; - if (debug_nextRetryToLog==debug_getRangeRetries){ - debug_nextRetryToLog += std::min(debug_nextRetryToLog, 1024); - TraceEvent(SevWarn, "FetchPast", data->thisServerID).detail("TotalAttempts", debug_getRangeRetries).detail("FKID", interval.pairID).detail("V", lastFV).detail("N", fetchVersion).detail("E", data->version.get()); - } - } else if (e.code() == error_code_future_version || e.code() == error_code_process_behind) { - TEST(true); // fetchKeys got future_version or process_behind, so there must be a huge storage lag somewhere. Keep trying. - } else { - throw; - } - wait( delayJittered( FLOW_KNOBS->PREVENT_FAST_SPIN_DELAY ) ); } } From bebddcbc450f6433ebdb0fcd1157978639f5dece Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Wed, 16 Dec 2020 13:03:11 -0800 Subject: [PATCH 109/740] reordered the loop and try --- fdbserver/storageserver.actor.cpp | 88 +++++++++++++++---------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/fdbserver/storageserver.actor.cpp b/fdbserver/storageserver.actor.cpp index d07d61d1d68..0d4cee5b373 100644 --- a/fdbserver/storageserver.actor.cpp +++ b/fdbserver/storageserver.actor.cpp @@ -2338,8 +2338,8 @@ ACTOR Future fetchKeys( StorageServer *data, AddingShard* shard ) { state Future hold = tr.getRangeStream(results, keys, GetRangeLimits(), true); state Key nfk = keys.begin; - loop { - try { + try { + loop { TEST(true); // Fetching keys for transferred shard state Standalone this_block = waitNext( results.getFuture() ); @@ -2370,53 +2370,53 @@ ACTOR Future fetchKeys( StorageServer *data, AddingShard* shard ) { nfk = this_block.readThrough.present() ? this_block.readThrough.get() : keyAfter( this_block.end()[-1].key ); this_block = Standalone(); - } catch( Error &e ) { - if(e.code() != error_code_end_of_stream || e.code() != error_code_connection_failed || e.code() != error_code_transaction_too_old || - e.code() != error_code_future_version || e.code() != error_code_process_behind) { - throw; - } - if(nfk == keys.begin) { - TraceEvent("FKBlockFail", data->thisServerID).error(e,true).suppressFor(1.0).detail("FKID", interval.pairID); - - //FIXME: remove when we no longer support upgrades from 5.X - if(debug_getRangeRetries >= 100) { - data->cx->enableLocalityLoadBalance = false; - } + } + } catch( Error &e ) { + if(e.code() != error_code_end_of_stream || e.code() != error_code_connection_failed || e.code() != error_code_transaction_too_old || + e.code() != error_code_future_version || e.code() != error_code_process_behind) { + throw; + } + if(nfk == keys.begin) { + TraceEvent("FKBlockFail", data->thisServerID).error(e,true).suppressFor(1.0).detail("FKID", interval.pairID); - debug_getRangeRetries++; - if (debug_nextRetryToLog==debug_getRangeRetries){ - debug_nextRetryToLog += std::min(debug_nextRetryToLog, 1024); - TraceEvent(SevWarn, "FetchPast", data->thisServerID).detail("TotalAttempts", debug_getRangeRetries).detail("FKID", interval.pairID).detail("V", lastFV).detail("N", fetchVersion).detail("E", data->version.get()); - } - wait( delayJittered( FLOW_KNOBS->PREVENT_FAST_SPIN_DELAY ) ); - continue; + //FIXME: remove when we no longer support upgrades from 5.X + if(debug_getRangeRetries >= 100) { + data->cx->enableLocalityLoadBalance = false; } - if(nfk < keys.end) { - std::deque< Standalone > updatesToSplit = std::move( shard->updates ); - - // This actor finishes committing the keys [keys.begin,nfk) that we already fetched. - // The remaining unfetched keys [nfk,keys.end) will become a separate AddingShard with its own fetchKeys. - shard->server->addShard( ShardInfo::addingSplitLeft( KeyRangeRef(keys.begin, nfk), shard ) ); - shard->server->addShard( ShardInfo::newAdding( data, KeyRangeRef(nfk, keys.end) ) ); - shard = data->shards.rangeContaining( keys.begin ).value()->adding; - warningLogger = logFetchKeysWarning(shard); - AddingShard* otherShard = data->shards.rangeContaining( nfk ).value()->adding; - keys = shard->keys; - - // Split our prior updates. The ones that apply to our new, restricted key range will go back into shard->updates, - // and the ones delivered to the new shard will be discarded because it is in WaitPrevious phase (hasn't chosen a fetchVersion yet). - // What we are doing here is expensive and could get more expensive if we started having many more blocks per shard. May need optimization in the future. - std::deque< Standalone >::iterator u = updatesToSplit.begin(); - for(; u != updatesToSplit.end(); ++u) { - splitMutations(data, data->shards, *u); - } - TEST( true ); // fetchkeys has more - TEST( shard->updates.size() ); // Shard has updates - ASSERT( otherShard->updates.empty() ); + debug_getRangeRetries++; + if (debug_nextRetryToLog==debug_getRangeRetries){ + debug_nextRetryToLog += std::min(debug_nextRetryToLog, 1024); + TraceEvent(SevWarn, "FetchPast", data->thisServerID).detail("TotalAttempts", debug_getRangeRetries).detail("FKID", interval.pairID).detail("V", lastFV).detail("N", fetchVersion).detail("E", data->version.get()); } - break; + wait( delayJittered( FLOW_KNOBS->PREVENT_FAST_SPIN_DELAY ) ); + continue; } + if(nfk < keys.end) { + std::deque< Standalone > updatesToSplit = std::move( shard->updates ); + + // This actor finishes committing the keys [keys.begin,nfk) that we already fetched. + // The remaining unfetched keys [nfk,keys.end) will become a separate AddingShard with its own fetchKeys. + shard->server->addShard( ShardInfo::addingSplitLeft( KeyRangeRef(keys.begin, nfk), shard ) ); + shard->server->addShard( ShardInfo::newAdding( data, KeyRangeRef(nfk, keys.end) ) ); + shard = data->shards.rangeContaining( keys.begin ).value()->adding; + warningLogger = logFetchKeysWarning(shard); + AddingShard* otherShard = data->shards.rangeContaining( nfk ).value()->adding; + keys = shard->keys; + + // Split our prior updates. The ones that apply to our new, restricted key range will go back into shard->updates, + // and the ones delivered to the new shard will be discarded because it is in WaitPrevious phase (hasn't chosen a fetchVersion yet). + // What we are doing here is expensive and could get more expensive if we started having many more blocks per shard. May need optimization in the future. + std::deque< Standalone >::iterator u = updatesToSplit.begin(); + for(; u != updatesToSplit.end(); ++u) { + splitMutations(data, data->shards, *u); + } + + TEST( true ); // fetchkeys has more + TEST( shard->updates.size() ); // Shard has updates + ASSERT( otherShard->updates.empty() ); + } + break; } } From c063a7d98e37d1ad48a22491005ab798f06502be Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Wed, 16 Dec 2020 13:04:33 -0800 Subject: [PATCH 110/740] fixed typo --- fdbserver/Knobs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdbserver/Knobs.h b/fdbserver/Knobs.h index 2095bf4e485..edb426533af 100644 --- a/fdbserver/Knobs.h +++ b/fdbserver/Knobs.h @@ -480,7 +480,7 @@ class ServerKnobs : public Knobs { int BUGGIFY_LIMIT_BYTES; int FETCH_BLOCK_BYTES; int FETCH_KEYS_PARALLELISM_BYTES; - int FETCH_KESY_PARALLELISM; + int FETCH_KEYS_PARALLELISM; int FETCH_KEYS_LOWER_PRIORITY; int BUGGIFY_BLOCK_BYTES; int64_t STORAGE_HARD_LIMIT_BYTES; From 0cebd5e29fc18bbc7cd4208c8bad0e8afc1a7f8a Mon Sep 17 00:00:00 2001 From: sfc-gh-tclinkenbeard Date: Wed, 16 Dec 2020 12:11:08 -0800 Subject: [PATCH 111/740] Take advantage of move sematings in ParallelStream::flushToClient --- fdbclient/ParallelStream.actor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdbclient/ParallelStream.actor.h b/fdbclient/ParallelStream.actor.h index 7449c63dfa8..f26dd1a62ea 100644 --- a/fdbclient/ParallelStream.actor.h +++ b/fdbclient/ParallelStream.actor.h @@ -76,7 +76,7 @@ class ParallelStream { continue; } while (!fragment->buffer.empty()) { - results.send(fragment->buffer.front()); + results.send(std::move(fragment->buffer.front())); fragment->buffer.pop_front(); } if (fragment->completed) { From 15579299fcdabe0c43957eca22fe98662db5693f Mon Sep 17 00:00:00 2001 From: sfc-gh-tclinkenbeard Date: Wed, 16 Dec 2020 12:42:25 -0800 Subject: [PATCH 112/740] Encapsulate ParallelStream::Fragment construction --- fdbclient/ParallelStream.actor.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/fdbclient/ParallelStream.actor.h b/fdbclient/ParallelStream.actor.h index f26dd1a62ea..73aa3a65d2a 100644 --- a/fdbclient/ParallelStream.actor.h +++ b/fdbclient/ParallelStream.actor.h @@ -37,16 +37,20 @@ template class ParallelStream { FlowLock semaphore; + struct FragmentConstructorTag { + explicit FragmentConstructorTag() = default; + }; public: class Fragment { ParallelStream* parallelStream; std::deque buffer; bool completed{ false }; - friend class ParallelStream; FlowLock::Releaser releaser; + friend class ParallelStream; + public: - Fragment(ParallelStream* parallelStream) + Fragment(ParallelStream* parallelStream, FragmentConstructorTag) : parallelStream(parallelStream), releaser(parallelStream->semaphore) {} template void send(U &&value) { @@ -93,7 +97,7 @@ class ParallelStream { ACTOR static Future createFragmentImpl(ParallelStream* self) { wait(self->semaphore.take()); - self->fragments.push_back(std::make_unique(self)); + self->fragments.push_back(std::make_unique(self, FragmentConstructorTag())); ASSERT(self->fragments[self->fragmentsProcessed]); return self->fragments.back().get(); } From 2bfb178bb11dc61fcb1697f673606ae191c93955 Mon Sep 17 00:00:00 2001 From: sfc-gh-tclinkenbeard Date: Wed, 16 Dec 2020 13:41:54 -0800 Subject: [PATCH 113/740] Move ParallelStream.actor.cpp to fdbclient --- fdbclient/CMakeLists.txt | 1 + .../ParallelStream.actor.cpp | 2 ++ fdbserver/CMakeLists.txt | 1 - fdbserver/workloads/UnitTests.actor.cpp | 2 ++ 4 files changed, 5 insertions(+), 1 deletion(-) rename fdbserver/workloads/ParallelStreamCorrectness.actor.cpp => fdbclient/ParallelStream.actor.cpp (98%) diff --git a/fdbclient/CMakeLists.txt b/fdbclient/CMakeLists.txt index 3df3422ccf3..4029567e757 100644 --- a/fdbclient/CMakeLists.txt +++ b/fdbclient/CMakeLists.txt @@ -50,6 +50,7 @@ set(FDBCLIENT_SRCS NativeAPI.actor.cpp NativeAPI.actor.h Notified.h + ParallelStream.actor.cpp ParallelStream.actor.h ReadYourWrites.actor.cpp ReadYourWrites.h diff --git a/fdbserver/workloads/ParallelStreamCorrectness.actor.cpp b/fdbclient/ParallelStream.actor.cpp similarity index 98% rename from fdbserver/workloads/ParallelStreamCorrectness.actor.cpp rename to fdbclient/ParallelStream.actor.cpp index 5975f3eff85..a9a6c5ca849 100644 --- a/fdbserver/workloads/ParallelStreamCorrectness.actor.cpp +++ b/fdbclient/ParallelStream.actor.cpp @@ -65,3 +65,5 @@ TEST_CASE("/fdbclient/ParallelStream") { wait(consumer); return Void(); } + +void forceLinkParallelStreamTests() {} diff --git a/fdbserver/CMakeLists.txt b/fdbserver/CMakeLists.txt index 1469bf8af0a..bf266069cbd 100644 --- a/fdbserver/CMakeLists.txt +++ b/fdbserver/CMakeLists.txt @@ -175,7 +175,6 @@ set(FDBSERVER_SRCS workloads/MemoryKeyValueStore.h workloads/MemoryLifetime.actor.cpp workloads/MetricLogging.actor.cpp - workloads/ParallelStreamCorrectness.actor.cpp workloads/Performance.actor.cpp workloads/Ping.actor.cpp workloads/PopulateTPCC.actor.cpp diff --git a/fdbserver/workloads/UnitTests.actor.cpp b/fdbserver/workloads/UnitTests.actor.cpp index 10fa0283546..bf0a885d299 100644 --- a/fdbserver/workloads/UnitTests.actor.cpp +++ b/fdbserver/workloads/UnitTests.actor.cpp @@ -28,6 +28,7 @@ void forceLinkFlowTests(); void forceLinkVersionedMapTests(); void forceLinkMemcpyTests(); void forceLinkMemcpyPerfTests(); +void forceLinkParallelStreamTests(); struct UnitTestWorkload : TestWorkload { bool enabled; @@ -49,6 +50,7 @@ struct UnitTestWorkload : TestWorkload { forceLinkVersionedMapTests(); forceLinkMemcpyTests(); forceLinkMemcpyPerfTests(); + forceLinkParallelStreamTests(); } std::string description() const override { return "UnitTests"; } From dcd9a392401415fb1d57f9583b59ac33082f73aa Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Wed, 16 Dec 2020 22:00:22 +0000 Subject: [PATCH 114/740] Add some missing result->send's, work around getRangeSplitPoints bug --- fdbclient/NativeAPI.actor.cpp | 57 ++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index 046bc2e99e3..4c9c7baed76 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -2779,42 +2779,48 @@ ACTOR Future getRangeStreamFragment(ParallelStream::Fragment* // trLogInfo->addLog(FdbClientLogEvents::EventGetRange(startTime, cx->clientLocality.dcId(), now()-startTime, bytes, begin.getKey(), end.getKey())); //} - results->send(std::move(output)); + if (output.size()) { + results->send(std::move(output)); + } results->finish(); return Void(); } + ASSERT(output.size()); + results->send(std::move(output)); keys = KeyRangeRef(begin, end); breakAgain = true; break; } + ASSERT(output.size()); + results->send(std::move(output)); ++shard; break; } - if(output.size() > 0) { - output.more = true; - if (keys.begin == allKeys.begin && !reverse) { - output.readToBegin = true; - } - if (keys.end == allKeys.end && reverse) { - output.readThroughEnd = true; - } - int64_t bytes = 0; - for(const KeyValueRef &kv : output) { - bytes += kv.key.size() + kv.value.size(); - } + ASSERT(output.size()); + output.more = true; + if (keys.begin == allKeys.begin && !reverse) { + output.readToBegin = true; + } + if (keys.end == allKeys.end && reverse) { + output.readThroughEnd = true; + } + int64_t bytes = 0; + for (const KeyValueRef& kv : output) { + bytes += kv.key.size() + kv.value.size(); + } - cx->transactionBytesRead += bytes; - cx->transactionKeysRead += output.size(); + cx->transactionBytesRead += bytes; + cx->transactionKeysRead += output.size(); - //FIXME: figure out appropriate metrics for the client event log - //if( trLogInfo ) { - // trLogInfo->addLog(FdbClientLogEvents::EventGetRange(startTime, cx->clientLocality.dcId(), now()-startTime, bytes, begin.getKey(), end.getKey())); - //} - results->send(std::move(output)); - } + // FIXME: figure out appropriate metrics for the client event log + // if( trLogInfo ) { + // trLogInfo->addLog(FdbClientLogEvents::EventGetRange(startTime, cx->clientLocality.dcId(), + //now()-startTime, bytes, begin.getKey(), end.getKey())); + //} + results->send(std::move(output)); } if (breakAgain) { break; @@ -2900,6 +2906,9 @@ ACTOR Future getRangeStream(PromiseStream _results, Database state std::vector::iterator toSendIt = toSend.begin(); for (; toSendIt != toSend.end(); ++toSendIt) { + if (toSendIt->empty()) { + continue; + } ParallelStream::Fragment* fragment = wait(results.createFragment()); outstandingRequests.push_back(getRangeStreamFragment(fragment, cx, trLogInfo, version, *toSendIt, limits, snapshot, reverse, info, tags, span.context)); @@ -4996,9 +5005,9 @@ Future>> Transaction::getReadHotRa ACTOR Future>> getRangeSplitPoints(Database cx, KeyRange keys, int64_t chunkSize) { state Span span("NAPI:GetRangeSplitPoints"_loc); loop { - state vector>> locations = - wait(getKeyRangeLocations(cx, keys, 100, false, &StorageServerInterface::getRangeSplitPoints, - TransactionInfo(TaskPriority::DataDistribution, span.context))); + state vector>> locations = wait( + getKeyRangeLocations(cx, keys, CLIENT_KNOBS->TOO_MANY, false, &StorageServerInterface::getRangeSplitPoints, + TransactionInfo(TaskPriority::DataDistribution, span.context))); try { state int nLocs = locations.size(); state vector> fReplies(nLocs); From 2c030658e901d8baee8d2e2f2b2979131914d26f Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Wed, 16 Dec 2020 22:41:30 +0000 Subject: [PATCH 115/740] Handle empty range from client --- documentation/tutorial/tutorial.actor.cpp | 6 ++++-- fdbclient/NativeAPI.actor.cpp | 4 +--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/documentation/tutorial/tutorial.actor.cpp b/documentation/tutorial/tutorial.actor.cpp index 5393c0c3e40..8f69716177f 100644 --- a/documentation/tutorial/tutorial.actor.cpp +++ b/documentation/tutorial/tutorial.actor.cpp @@ -423,8 +423,10 @@ ACTOR Future fdbClientStream() { KeySelector(firstGreaterOrEqual(normalKeys.end)), GetRangeLimits()); loop { Standalone range = waitNext(results.getFuture()); - bytes += range.expectedSize(); - next = keyAfter(range.back().key); + if (range.size()) { + bytes += range.expectedSize(); + next = keyAfter(range.back().key); + } } } catch (Error& e) { if (e.code() == error_code_end_of_stream) { diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index 4c9c7baed76..533dfa77403 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -2779,9 +2779,7 @@ ACTOR Future getRangeStreamFragment(ParallelStream::Fragment* // trLogInfo->addLog(FdbClientLogEvents::EventGetRange(startTime, cx->clientLocality.dcId(), now()-startTime, bytes, begin.getKey(), end.getKey())); //} - if (output.size()) { - results->send(std::move(output)); - } + results->send(std::move(output)); results->finish(); return Void(); } From 702a882a5c9f74e88b22c368b947f177458d2bdc Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Wed, 16 Dec 2020 14:47:48 -0800 Subject: [PATCH 116/740] get split points one shard at a time --- fdbclient/NativeAPI.actor.cpp | 62 +++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index 533dfa77403..c8724b8964d 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -2789,6 +2789,11 @@ ACTOR Future getRangeStreamFragment(ParallelStream::Fragment* keys = KeyRangeRef(begin, end); breakAgain = true; break; + } else { + output.more = true; + output.arena().dependsOn( locations[shard].first.arena() ); + output.readThrough = reverse ? locations[shard].first.begin : locations[shard].first.end; + results->send(std::move(output)); } ASSERT(output.size()); @@ -2880,38 +2885,47 @@ ACTOR Future getRangeStream(PromiseStream _results, Database return Void(); } - state KeyRangeRef keys(b, e); - //if e is allKeys.end, we have read through the end of the database //if b is allKeys.begin, we have either read through the beginning of the database, //or allKeys.begin exists in the database and will be part of the conflict range anyways - state Standalone> splitPoints = - wait(getRangeSplitPoints(cx, keys, CLIENT_KNOBS->RANGESTREAM_FRAGMENT_SIZE)); - state std::vector toSend; - // state std::vector::iterator>> outstandingRequests; - state std::vector> outstandingRequests; - - if (!splitPoints.empty()) { - toSend.emplace_back(b, splitPoints.front()); - for (int i = 0; i < splitPoints.size() - 1; ++i) { - toSend.emplace_back(splitPoints[i], splitPoints[i + 1]); + loop { + state pair> ssi = + wait(getKeyLocation(cx, reverse ? e : b, &StorageServerInterface::getKeyValuesStream, info, reverse)); + state Standalone> splitPoints = + wait(getRangeSplitPoints(cx, ssi.first, CLIENT_KNOBS->RANGESTREAM_FRAGMENT_SIZE)); + state std::vector toSend; + // state std::vector::iterator>> outstandingRequests; + state std::vector> outstandingRequests; + + if (!splitPoints.empty()) { + toSend.emplace_back(b, splitPoints.front()); + for (int i = 0; i < splitPoints.size() - 1; ++i) { + toSend.emplace_back(splitPoints[i], splitPoints[i + 1]); + } + toSend.emplace_back(splitPoints.back(), e); + } else { + toSend.emplace_back(b, e); } - toSend.emplace_back(splitPoints.back(), e); - } else { - toSend.emplace_back(b, e); - } - state std::vector::iterator toSendIt = toSend.begin(); - for (; toSendIt != toSend.end(); ++toSendIt) { - if (toSendIt->empty()) { - continue; + state std::vector::iterator toSendIt = toSend.begin(); + for (; toSendIt != toSend.end(); ++toSendIt) { + if (toSendIt->empty()) { + continue; + } + ParallelStream::Fragment* fragment = wait(results.createFragment()); + outstandingRequests.push_back(getRangeStreamFragment(fragment, cx, trLogInfo, version, *toSendIt, limits, + snapshot, reverse, info, tags, span.context)); + } + if(reverse) { + e = ssi.first.begin; + } else { + b = ssi.first.end; + } + if(b >= e) { + break; } - ParallelStream::Fragment* fragment = wait(results.createFragment()); - outstandingRequests.push_back(getRangeStreamFragment(fragment, cx, trLogInfo, version, *toSendIt, limits, - snapshot, reverse, info, tags, span.context)); } - try { wait(waitForAll(outstandingRequests)); } catch (Error& e) { From c7ac1622cc1d590065a84958f4566248982455d1 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Wed, 16 Dec 2020 14:51:41 -0800 Subject: [PATCH 117/740] removed missing variable --- fdbserver/storageserver.actor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdbserver/storageserver.actor.cpp b/fdbserver/storageserver.actor.cpp index 0d4cee5b373..d04ab9a1c00 100644 --- a/fdbserver/storageserver.actor.cpp +++ b/fdbserver/storageserver.actor.cpp @@ -2387,7 +2387,7 @@ ACTOR Future fetchKeys( StorageServer *data, AddingShard* shard ) { debug_getRangeRetries++; if (debug_nextRetryToLog==debug_getRangeRetries){ debug_nextRetryToLog += std::min(debug_nextRetryToLog, 1024); - TraceEvent(SevWarn, "FetchPast", data->thisServerID).detail("TotalAttempts", debug_getRangeRetries).detail("FKID", interval.pairID).detail("V", lastFV).detail("N", fetchVersion).detail("E", data->version.get()); + TraceEvent(SevWarn, "FetchPast", data->thisServerID).detail("TotalAttempts", debug_getRangeRetries).detail("FKID", interval.pairID).detail("N", fetchVersion).detail("E", data->version.get()); } wait( delayJittered( FLOW_KNOBS->PREVENT_FAST_SPIN_DELAY ) ); continue; From 4237bd93eccca08b92dd1bd205102885b7bdf06d Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Wed, 16 Dec 2020 15:09:20 -0800 Subject: [PATCH 118/740] fixed a bug with reverse range reads --- fdbclient/NativeAPI.actor.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index c8724b8964d..4554f39e90e 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -2908,13 +2908,15 @@ ACTOR Future getRangeStream(PromiseStream _results, Database toSend.emplace_back(b, e); } - state std::vector::iterator toSendIt = toSend.begin(); - for (; toSendIt != toSend.end(); ++toSendIt) { - if (toSendIt->empty()) { + state int idx = 0; + state int useIdx = 0; + for (; idx < toSend.size(); ++idx) { + useIdx = reverse ? toSend.size() - idx - 1 : idx; + if (toSend[useIdx].empty()) { continue; } ParallelStream::Fragment* fragment = wait(results.createFragment()); - outstandingRequests.push_back(getRangeStreamFragment(fragment, cx, trLogInfo, version, *toSendIt, limits, + outstandingRequests.push_back(getRangeStreamFragment(fragment, cx, trLogInfo, version, toSend[useIdx], limits, snapshot, reverse, info, tags, span.context)); } if(reverse) { From f4e9a9ac40c69587ea9c712fd17db1458cd82345 Mon Sep 17 00:00:00 2001 From: sfc-gh-tclinkenbeard Date: Wed, 16 Dec 2020 15:36:18 -0800 Subject: [PATCH 119/740] Use PromiseStreams for ParallelStream implementation --- fdbclient/ParallelStream.actor.h | 58 +++++++++++++++----------------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/fdbclient/ParallelStream.actor.h b/fdbclient/ParallelStream.actor.h index 73aa3a65d2a..78690ad69b5 100644 --- a/fdbclient/ParallelStream.actor.h +++ b/fdbclient/ParallelStream.actor.h @@ -28,9 +28,6 @@ #elif !defined(FDBCLIENT_PARALLEL_STREAM_ACTOR_H) #define FDBCLIENT_PARALLEL_STREAM_ACTOR_H -#include -#include - #include "flow/genericactors.actor.h" #include "flow/actorcompiler.h" // must be last include @@ -42,9 +39,9 @@ class ParallelStream { }; public: - class Fragment { + class Fragment : public ReferenceCounted { ParallelStream* parallelStream; - std::deque buffer; + PromiseStream stream; bool completed{ false }; FlowLock::Releaser releaser; friend class ParallelStream; @@ -54,52 +51,53 @@ class ParallelStream { : parallelStream(parallelStream), releaser(parallelStream->semaphore) {} template void send(U &&value) { - buffer.push_back(std::forward(value)); - parallelStream->flushToClient(); + stream.send(std::forward(value)); } void sendError(Error e) { parallelStream->sendError(e); } void finish() { ASSERT(!completed); completed = true; releaser.release(); // Release before destruction to free up pending fragments - parallelStream->flushToClient(); } }; private: - std::vector> fragments; + PromiseStream> fragments; size_t fragmentsProcessed { 0 }; PromiseStream results; + Future flusher; + +public: // TODO: Fix potential slow task - void flushToClient() { - while (fragmentsProcessed < fragments.size()) { - auto &fragment = fragments[fragmentsProcessed]; - if (!fragment) { - ++fragmentsProcessed; - continue; - } - while (!fragment->buffer.empty()) { - results.send(std::move(fragment->buffer.front())); - fragment->buffer.pop_front(); - } - if (fragment->completed) { - fragment.reset(); - ++fragmentsProcessed; - } else { - break; + ACTOR static Future flushToClient(ParallelStream *self) { + loop { + state Reference fragment = waitNext(self->fragments.getFuture()); + loop { + try { + T value = waitNext(fragment->stream.getFuture()); + self->results.send(value); + } catch (Error &e) { + if (e.code() == error_code_end_of_stream) { + fragment.clear(); + break; + } else { + throw e; + } + } } } } -public: - ParallelStream(PromiseStream results, size_t concurrency) : results(results), semaphore(concurrency) {} + ParallelStream(PromiseStream results, size_t concurrency) : results(results), semaphore(concurrency) { + flusher = flushToClient(this); + } ACTOR static Future createFragmentImpl(ParallelStream* self) { wait(self->semaphore.take()); - self->fragments.push_back(std::make_unique(self, FragmentConstructorTag())); - ASSERT(self->fragments[self->fragmentsProcessed]); - return self->fragments.back().get(); + auto fragment = makeReference(self, FragmentConstructorTag()); + self->fragments.send(fragment); + return fragment.getPtr(); } Future createFragment() { return createFragmentImpl(this); } From f056fddb4d2fc6031a17986cfd133ab6a02469b1 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Wed, 16 Dec 2020 16:18:09 -0800 Subject: [PATCH 120/740] fix: readThrough was not being set in all cases --- fdbclient/NativeAPI.actor.cpp | 17 +++++++++++------ fdbserver/storageserver.actor.cpp | 1 + 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index 4554f39e90e..b60bfc72866 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -2661,7 +2661,7 @@ ACTOR Future> getRange( Database cx, Reference getRangeStreamFragment(ParallelStream::Fragment* results, Database cx, - Reference trLogInfo, Version version, KeyRangeRef keys, + Reference trLogInfo, Version version, KeyRange keys, GetRangeLimits limits, bool snapshot, bool reverse, TransactionInfo info, TagSet tags, SpanID spanContext) { loop { @@ -2766,6 +2766,11 @@ ACTOR Future getRangeStreamFragment(ParallelStream::Fragment* if (range.end == allKeys.end) { output.readThroughEnd = true; } + if(!output.size()) { + output.arena().dependsOn( keys.arena() ); + output.readThrough = reverse ? keys.begin : keys.end; + } + int64_t bytes = 0; for(const KeyValueRef &kv : output) { bytes += kv.key.size() + kv.value.size(); @@ -2894,18 +2899,18 @@ ACTOR Future getRangeStream(PromiseStream _results, Database wait(getKeyLocation(cx, reverse ? e : b, &StorageServerInterface::getKeyValuesStream, info, reverse)); state Standalone> splitPoints = wait(getRangeSplitPoints(cx, ssi.first, CLIENT_KNOBS->RANGESTREAM_FRAGMENT_SIZE)); - state std::vector toSend; + state std::vector toSend; // state std::vector::iterator>> outstandingRequests; state std::vector> outstandingRequests; if (!splitPoints.empty()) { - toSend.emplace_back(b, splitPoints.front()); + toSend.push_back(KeyRange(KeyRangeRef(b, splitPoints.front()), splitPoints.arena())); for (int i = 0; i < splitPoints.size() - 1; ++i) { - toSend.emplace_back(splitPoints[i], splitPoints[i + 1]); + toSend.push_back(KeyRange(KeyRangeRef(splitPoints[i], splitPoints[i + 1]), splitPoints.arena())); } - toSend.emplace_back(splitPoints.back(), e); + toSend.push_back(KeyRange(KeyRangeRef(splitPoints.back(), e), splitPoints.arena())); } else { - toSend.emplace_back(b, e); + toSend.push_back(KeyRange(KeyRangeRef(b, e), splitPoints.arena())); } state int idx = 0; diff --git a/fdbserver/storageserver.actor.cpp b/fdbserver/storageserver.actor.cpp index d04ab9a1c00..76b83d1e980 100644 --- a/fdbserver/storageserver.actor.cpp +++ b/fdbserver/storageserver.actor.cpp @@ -2368,6 +2368,7 @@ ACTOR Future fetchKeys( StorageServer *data, AddingShard* shard ) { wait(yield()); } + ASSERT(this_block.readThrough.present() || this_block.size()); nfk = this_block.readThrough.present() ? this_block.readThrough.get() : keyAfter( this_block.end()[-1].key ); this_block = Standalone(); } From 9edf3c2e1acf5934a7ccee98a79158fb8c846843 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Wed, 16 Dec 2020 16:42:31 -0800 Subject: [PATCH 121/740] for streaming the more flag is always true --- fdbclient/NativeAPI.actor.cpp | 15 +++++---------- fdbserver/storageserver.actor.cpp | 4 ++-- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index b60bfc72866..4750a111d3e 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -2727,7 +2727,7 @@ ACTOR Future getRangeStreamFragment(ParallelStream::Fragment* } if( info.debugID.present() ) g_traceBatch.addEvent("TransactionDebug", info.debugID.get().first(), "NativeAPI.getExactRange.After"); - RangeResult output(RangeResultRef(rep.data, rep.more), rep.arena); + RangeResult output(RangeResultRef(rep.data, true), rep.arena); bool more = rep.more; // If the reply says there is more but we know that we finished the shard, then fix rep.more @@ -2759,17 +2759,14 @@ ACTOR Future getRangeStreamFragment(ParallelStream::Fragment* KeyRef end = reverse ? range.begin : keys.end; if(begin >= end) { - output.more = false; if (range.begin == allKeys.begin) { output.readToBegin = true; } if (range.end == allKeys.end) { output.readThroughEnd = true; } - if(!output.size()) { - output.arena().dependsOn( keys.arena() ); - output.readThrough = reverse ? keys.begin : keys.end; - } + output.arena().dependsOn( keys.arena() ); + output.readThrough = reverse ? keys.begin : keys.end; int64_t bytes = 0; for(const KeyValueRef &kv : output) { @@ -2795,9 +2792,8 @@ ACTOR Future getRangeStreamFragment(ParallelStream::Fragment* breakAgain = true; break; } else { - output.more = true; - output.arena().dependsOn( locations[shard].first.arena() ); - output.readThrough = reverse ? locations[shard].first.begin : locations[shard].first.end; + output.arena().dependsOn( range.arena() ); + output.readThrough = reverse ? range.begin : range.end; results->send(std::move(output)); } @@ -2808,7 +2804,6 @@ ACTOR Future getRangeStreamFragment(ParallelStream::Fragment* } ASSERT(output.size()); - output.more = true; if (keys.begin == allKeys.begin && !reverse) { output.readToBegin = true; } diff --git a/fdbserver/storageserver.actor.cpp b/fdbserver/storageserver.actor.cpp index 76b83d1e980..3a58272045c 100644 --- a/fdbserver/storageserver.actor.cpp +++ b/fdbserver/storageserver.actor.cpp @@ -2373,8 +2373,8 @@ ACTOR Future fetchKeys( StorageServer *data, AddingShard* shard ) { this_block = Standalone(); } } catch( Error &e ) { - if(e.code() != error_code_end_of_stream || e.code() != error_code_connection_failed || e.code() != error_code_transaction_too_old || - e.code() != error_code_future_version || e.code() != error_code_process_behind) { + if(e.code() != error_code_end_of_stream && e.code() != error_code_connection_failed && e.code() != error_code_transaction_too_old && + e.code() != error_code_future_version && e.code() != error_code_process_behind) { throw; } if(nfk == keys.begin) { From a4c5867657f2a79c03e2d59a54b1b94b6aed34c5 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Wed, 16 Dec 2020 16:45:00 -0800 Subject: [PATCH 122/740] compile error --- fdbclient/NativeAPI.actor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index 4750a111d3e..0c6b299421a 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -2753,8 +2753,8 @@ ACTOR Future getRangeStreamFragment(ParallelStream::Fragment* if (!more || locations[shard].first.empty()) { TEST(true); // getRangeStream (!more || locations[shard].first.empty()) + const KeyRangeRef& range = locations[shard].first; if(shard == locations.size()-1) { - const KeyRangeRef& range = locations[shard].first; KeyRef begin = reverse ? keys.begin : range.end; KeyRef end = reverse ? range.begin : keys.end; From 6216d2f84ef53e14f1e48258795987588df5f855 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Wed, 16 Dec 2020 16:46:10 -0800 Subject: [PATCH 123/740] another fix --- fdbclient/NativeAPI.actor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index 0c6b299421a..38b1997b681 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -2753,7 +2753,7 @@ ACTOR Future getRangeStreamFragment(ParallelStream::Fragment* if (!more || locations[shard].first.empty()) { TEST(true); // getRangeStream (!more || locations[shard].first.empty()) - const KeyRangeRef& range = locations[shard].first; + const KeyRange& range = locations[shard].first; if(shard == locations.size()-1) { KeyRef begin = reverse ? keys.begin : range.end; KeyRef end = reverse ? range.begin : keys.end; From 97686fd181d1d4c95d498970778a11cf40377b38 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Wed, 16 Dec 2020 17:07:48 -0800 Subject: [PATCH 124/740] fix: the wrong range was being used --- fdbclient/NativeAPI.actor.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index 38b1997b681..f8031ff05ec 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -2899,13 +2899,13 @@ ACTOR Future getRangeStream(PromiseStream _results, Database state std::vector> outstandingRequests; if (!splitPoints.empty()) { - toSend.push_back(KeyRange(KeyRangeRef(b, splitPoints.front()), splitPoints.arena())); + toSend.push_back(KeyRange(KeyRangeRef(ssi.first.begin, splitPoints.front()), splitPoints.arena())); for (int i = 0; i < splitPoints.size() - 1; ++i) { toSend.push_back(KeyRange(KeyRangeRef(splitPoints[i], splitPoints[i + 1]), splitPoints.arena())); } - toSend.push_back(KeyRange(KeyRangeRef(splitPoints.back(), e), splitPoints.arena())); + toSend.push_back(KeyRange(KeyRangeRef(splitPoints.back(), ssi.first.end), splitPoints.arena())); } else { - toSend.push_back(KeyRange(KeyRangeRef(b, e), splitPoints.arena())); + toSend.push_back(KeyRange(KeyRangeRef(ssi.first.begin, ssi.first.end), splitPoints.arena())); } state int idx = 0; From e4ec9634f5109732e156442d1dab11050236ee21 Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Thu, 17 Dec 2020 01:12:14 +0000 Subject: [PATCH 125/740] Attempt to fix broken_promise issue --- fdbrpc/genericactors.actor.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fdbrpc/genericactors.actor.h b/fdbrpc/genericactors.actor.h index 4f21b2441e8..0c3c4f70375 100644 --- a/fdbrpc/genericactors.actor.h +++ b/fdbrpc/genericactors.actor.h @@ -229,7 +229,11 @@ Future> waitValueOrSignal( Future value, Future signal, Endp if( e.code() == error_code_actor_cancelled ) throw e; - return ErrorOr(e); + // broken_promise error normally means an endpoint failure, which in tryGetReply has the same semantics as receiving the failure signal + if (e.code() != error_code_broken_promise || signal.isError()) + return ErrorOr(e); + + value = Never(); } } } From c6f079443b458d7c678c1ebbf9ad42d625a0f00e Mon Sep 17 00:00:00 2001 From: sfc-gh-tclinkenbeard Date: Wed, 16 Dec 2020 17:54:53 -0800 Subject: [PATCH 126/740] Fix some ParallelStream bugs --- fdbclient/ParallelStream.actor.cpp | 8 ++++---- fdbclient/ParallelStream.actor.h | 4 +--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/fdbclient/ParallelStream.actor.cpp b/fdbclient/ParallelStream.actor.cpp index a9a6c5ca849..3e383f24bc7 100644 --- a/fdbclient/ParallelStream.actor.cpp +++ b/fdbclient/ParallelStream.actor.cpp @@ -26,9 +26,9 @@ namespace ParallelStreamTest { -ACTOR static Future produce(ParallelStream::Fragment* fragment, int i) { +ACTOR static Future produce(ParallelStream::Fragment* fragment, int value) { wait(delay(deterministicRandom()->random01())); - fragment->send(i); + fragment->send(value); wait(delay(deterministicRandom()->random01())); fragment->finish(); return Void(); @@ -38,8 +38,8 @@ ACTOR static Future consume(FutureStream stream, int expected) { state int next; try { loop { - int i = waitNext(stream); - ASSERT(i == next++); + int value = waitNext(stream); + ASSERT(value == next++); } } catch (Error& e) { ASSERT(e.code() == error_code_end_of_stream); diff --git a/fdbclient/ParallelStream.actor.h b/fdbclient/ParallelStream.actor.h index 78690ad69b5..cf9a3150af0 100644 --- a/fdbclient/ParallelStream.actor.h +++ b/fdbclient/ParallelStream.actor.h @@ -42,7 +42,6 @@ class ParallelStream { class Fragment : public ReferenceCounted { ParallelStream* parallelStream; PromiseStream stream; - bool completed{ false }; FlowLock::Releaser releaser; friend class ParallelStream; @@ -55,9 +54,8 @@ class ParallelStream { } void sendError(Error e) { parallelStream->sendError(e); } void finish() { - ASSERT(!completed); - completed = true; releaser.release(); // Release before destruction to free up pending fragments + stream.sendError(end_of_stream()); } }; From 5ec3481366dd8c43d7306af3dd935c3593288dc1 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Wed, 16 Dec 2020 21:03:08 -0800 Subject: [PATCH 127/740] code cleanup --- fdbclient/NativeAPI.actor.cpp | 202 +------------------------------- fdbrpc/fdbrpc.h | 6 +- fdbserver/NetworkTest.h | 4 +- fdbserver/networktest.actor.cpp | 59 ++++++++-- 4 files changed, 58 insertions(+), 213 deletions(-) diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index f8031ff05ec..e39fbc9f55e 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -2669,7 +2669,7 @@ ACTOR Future getRangeStreamFragment(ParallelStream::Fragment* ASSERT( locations.size() ); state int shard = 0; loop { - const KeyRangeRef& range = locations[shard].first; + const KeyRange& range = locations[shard].first; state GetKeyValuesStreamRequest req; req.version = version; @@ -2937,206 +2937,6 @@ ACTOR Future getRangeStream(PromiseStream _results, Database return Void(); } -/* -ACTOR Future getRangeStreamSingleShard( PromiseStream> results, Database cx, Reference trLogInfo, Future fVersion, - KeySelector begin, KeySelector end, GetRangeLimits limits, Promise> conflictRange, bool snapshot, bool reverse, - TransactionInfo info, TagSet tags ) -{ - state GetRangeLimits originalLimits( limits ); - state KeySelector originalBegin = begin; - state KeySelector originalEnd = end; - state Standalone output; - state Span span("NAPI:getRangeStream"_loc, info.spanID); - - try { - state Version version = wait( fVersion ); - cx->validateVersion(version); - - state double startTime = now(); - state Version readVersion = version; // Needed for latestVersion requests; if more, make future requests at the version that the first one completed - // FIXME: Is this really right? Weaken this and see if there is a problem; if so maybe there is a much subtler problem even with this. - - if( begin.getKey() == allKeys.begin && begin.offset < 1 ) { - output.readToBegin = true; - begin = KeySelector(firstGreaterOrEqual( begin.getKey() ), begin.arena()); - } - - ASSERT( !limits.isReached() ); - ASSERT( (!limits.hasRowLimit() || limits.rows >= limits.minRows) && limits.minRows >= 0 ); - - loop { - if( end.getKey() == allKeys.begin && (end.offset < 1 || end.isFirstGreaterOrEqual()) ) { - getRangeFinished(cx, trLogInfo, startTime, originalBegin, originalEnd, snapshot, conflictRange, reverse, output); - results.send(output); - results.sendError(end_of_stream()); - return Void(); - } - - Key locationKey = reverse ? Key(end.getKey(), end.arena()) : Key(begin.getKey(), begin.arena()); - bool locationBackward = reverse ? (end-1).isBackward() : begin.isBackward(); - state pair> beginServer = wait( getKeyLocation( cx, locationKey, &StorageServerInterface::getKeyValues, info, locationBackward ) ); - state KeyRange shard = beginServer.first; - state bool modifiedSelectors = false; - state GetKeyValuesRequest req; - - req.isFetchKeys = (info.taskID == TaskPriority::FetchKeys); - req.version = readVersion; - - if( reverse && (begin-1).isDefinitelyLess(shard.begin) && - ( !begin.isFirstGreaterOrEqual() || begin.getKey() != shard.begin ) ) { //In this case we would be setting modifiedSelectors to true, but not modifying anything - - req.begin = firstGreaterOrEqual( shard.begin ); - modifiedSelectors = true; - } - else req.begin = begin; - - if( !reverse && end.isDefinitelyGreater(shard.end) ) { - req.end = firstGreaterOrEqual( shard.end ); - modifiedSelectors = true; - } - else req.end = end; - - transformRangeLimits(limits, reverse, req); - ASSERT(req.limitBytes > 0 && req.limit != 0 && req.limit < 0 == reverse); - - req.tags = cx->sampleReadTags() ? tags : Optional(); - req.debugID = info.debugID; - req.spanContext = span.context; - try { - if( info.debugID.present() ) { - g_traceBatch.addEvent("TransactionDebug", info.debugID.get().first(), "NativeAPI.getRange.Before"); - } - - ++cx->transactionPhysicalReads; - state GetKeyValuesReply rep; - if (CLIENT_BUGGIFY) { - throw deterministicRandom()->randomChoice(std::vector{ - transaction_too_old(), future_version() - }); - } - //FIXME: load balance requests - if(beginServer.second->size() == 0) { - wait(Future(Never())); - } - state ReplyPromiseStream repStream = beginServer.second->getInterface(0).getKeyValuesStream.getReplyStream(req); - loop { - GetKeyValuesStreamReply rep = waitNext(repStream.getFuture()); - - if( info.debugID.present() ) { - g_traceBatch.addEvent("TransactionDebug", info.debugID.get().first(), "NativeAPI.getRange.After");//.detail("SizeOf", rep.data.size()); - } - - ASSERT( !rep.more || rep.data.size() ); - ASSERT( !limits.hasRowLimit() || rep.data.size() <= limits.rows ); - - limits.decrement( rep.data ); - - if(reverse && begin.isLastLessOrEqual() && rep.data.size() && rep.data.end()[-1].key == begin.getKey()) { - modifiedSelectors = false; - } - - bool finished = limits.isReached() || ( !modifiedSelectors && !rep.more ) || limits.hasSatisfiedMinRows(); - bool readThrough = modifiedSelectors && !rep.more; - - // optimization: first request got all data--just return it - if( finished && !output.size() ) { - bool readToBegin = output.readToBegin; - bool readThroughEnd = output.readThroughEnd; - - output = Standalone( RangeResultRef( rep.data, modifiedSelectors || limits.isReached() || rep.more ), rep.arena ); - output.readToBegin = readToBegin; - output.readThroughEnd = readThroughEnd; - - if( BUGGIFY && limits.hasByteLimit() && output.size() > std::max(1, originalLimits.minRows) ) { - output.more = true; - output.resize(output.arena(), deterministicRandom()->randomInt(std::max(1,originalLimits.minRows),output.size())); - getRangeFinished(cx, trLogInfo, startTime, originalBegin, originalEnd, snapshot, conflictRange, reverse, output); - return output; - } - - if( readThrough ) { - output.arena().dependsOn( shard.arena() ); - output.readThrough = reverse ? shard.begin : shard.end; - } - - getRangeFinished(cx, trLogInfo, startTime, originalBegin, originalEnd, snapshot, conflictRange, reverse, output); - return output; - } - - output.arena().dependsOn( rep.arena ); - output.append(output.arena(), rep.data.begin(), rep.data.size()); - - if( finished ) { - if( readThrough ) { - output.arena().dependsOn( shard.arena() ); - output.readThrough = reverse ? shard.begin : shard.end; - } - output.more = modifiedSelectors || limits.isReached() || rep.more; - - getRangeFinished(cx, trLogInfo, startTime, originalBegin, originalEnd, snapshot, conflictRange, reverse, output); - return output; - } - - readVersion = rep.version; // see above comment - - if( !rep.more ) { - ASSERT( modifiedSelectors ); - TEST(true); // !GetKeyValuesReply.more and modifiedSelectors in getRangeStream - - if( !rep.data.size() ) { - Standalone result = wait( getRangeFallback(cx, version, originalBegin, originalEnd, originalLimits, reverse, info, tags ) ); - getRangeFinished(cx, trLogInfo, startTime, originalBegin, originalEnd, snapshot, conflictRange, reverse, result); - return result; - } - - if( reverse ) - end = firstGreaterOrEqual( shard.begin ); - else - begin = firstGreaterOrEqual( shard.end ); - } else { - TEST(true); // GetKeyValuesReply.more in getRangeStream - if( reverse ) - end = firstGreaterOrEqual( output[output.size()-1].key ); - else - begin = firstGreaterThan( output[output.size()-1].key ); - } - } - - } catch ( Error& e ) { - if( info.debugID.present() ) { - g_traceBatch.addEvent("TransactionDebug", info.debugID.get().first(), "NativeAPI.getRange.Error"); - TraceEvent("TransactionDebugError", info.debugID.get()).error(e); - } - if (e.code() == error_code_wrong_shard_server || e.code() == error_code_all_alternatives_failed || - (e.code() == error_code_transaction_too_old && readVersion == latestVersion)) - { - cx->invalidateCache( reverse ? end.getKey() : begin.getKey(), reverse ? (end-1).isBackward() : begin.isBackward() ); - - if (e.code() == error_code_wrong_shard_server) { - Standalone result = wait( getRangeFallback(cx, version, originalBegin, originalEnd, originalLimits, reverse, info, tags ) ); - getRangeFinished(cx, trLogInfo, startTime, originalBegin, originalEnd, snapshot, conflictRange, reverse, result); - return result; - } - - wait(delay(CLIENT_KNOBS->WRONG_SHARD_SERVER_DELAY, info.taskID)); - } else { - if (trLogInfo) - trLogInfo->addLog(FdbClientLogEvents::EventGetRangeError(startTime, cx->clientLocality.dcId(), static_cast(e.code()), begin.getKey(), end.getKey())); - - throw e; - } - } - } - } - catch(Error &e) { - if(conflictRange.canBeSet()) { - conflictRange.send(std::make_pair(Key(), Key())); - } - - throw; - } -}*/ - Future> getRange( Database const& cx, Future const& fVersion, KeySelector const& begin, KeySelector const& end, GetRangeLimits const& limits, bool const& reverse, TransactionInfo const& info, TagSet const& tags ) { diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index 5b1c1b776ff..04e485cacc9 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -573,7 +573,11 @@ class RequestStream { } } - //FIXME comment + // stream.getReplyStream( request ) + // Unreliable at most once delivery. + // Registers the request with the remote endpoint which sends back a stream of replies, followed by an end_of_stream error. + // If the connection is ever broken the remote endpoint will stop attempting to send replies. + // The caller sends acknowledgements to the remote endpoint so that at most 2MB of replies is ever inflight. template ReplyPromiseStream getReplyStream(const X& value, TaskPriority taskID) const { diff --git a/fdbserver/NetworkTest.h b/fdbserver/NetworkTest.h index 7e5cd30411b..7d6fa946302 100644 --- a/fdbserver/NetworkTest.h +++ b/fdbserver/NetworkTest.h @@ -27,8 +27,8 @@ #include "flow/FileIdentifier.h" struct NetworkTestInterface { - // RequestStream< struct NetworkTestRequest > test; - RequestStream test; + RequestStream< struct NetworkTestRequest > test; + RequestStream testStream; NetworkTestInterface() {} NetworkTestInterface( NetworkAddress remote ); NetworkTestInterface( INetwork* local ); diff --git a/fdbserver/networktest.actor.cpp b/fdbserver/networktest.actor.cpp index 2bc04a8a8ed..2c78ca545c0 100644 --- a/fdbserver/networktest.actor.cpp +++ b/fdbserver/networktest.actor.cpp @@ -72,6 +72,37 @@ ACTOR Future networkTestServer() { state int sent = 0; state LatencyStats latency; + loop { + choose { + when( NetworkTestRequest req = waitNext( interf.test.getFuture() ) ) { + LatencyStats::sample sample = latency.tick(); + req.reply.send( NetworkTestReply( Value( std::string( req.replySize, '.' ) ) ) ); + latency.tock(sample); + sent++; + } + when( wait( logging ) ) { + auto spd = sent / (now() - lastTime); + if (FLOW_KNOBS->NETWORK_TEST_SCRIPT_MODE) { + fprintf(stderr, "%f\t%.3f\t%.3f\n", spd, latency.mean() * 1e6, latency.stddev() * 1e6); + } else { + fprintf(stderr, "responses per second: %f (%f us)\n", spd, latency.mean() * 1e6); + } + latency.reset(); + lastTime = now(); + sent = 0; + logging = delay( 1.0 ); + } + } + } +} + +ACTOR Future networkTestStreamingServer() { + state NetworkTestInterface interf( g_network ); + state Future logging = delay( 1.0 ); + state double lastTime = now(); + state int sent = 0; + state LatencyStats latency; + loop { try { choose { @@ -79,12 +110,9 @@ ACTOR Future networkTestServer() { state LatencyStats::sample sample = latency.tick(); state int i = 0; for (; i < 100; ++i) { - fprintf(stderr, "Wait onReady %d\n", i); wait(req.reply.onReady()); - fprintf(stderr, "Send reply %d\n", i); req.reply.send(NetworkTestStreamingReply{ i }); } - fprintf(stderr, "Send end_of_stream\n"); req.reply.sendError(end_of_stream()); latency.tock(sample); sent++; @@ -104,7 +132,6 @@ ACTOR Future networkTestServer() { } } catch (Error &e) { if(e.code() != error_code_operation_obsolete) { - fprintf(stderr, "Error: %s\n", e.what()); throw e; } } @@ -133,22 +160,36 @@ ACTOR Future testClient(std::vector interfs, int* se state std::string request_payload(FLOW_KNOBS->NETWORK_TEST_REQUEST_SIZE, '.'); state LatencyStats::sample sample; + while (moreRequestsPending(*sent)) { + (*sent)++; + sample = latency->tick(); + NetworkTestReply rep = wait( + retryBrokenPromise(interfs[deterministicRandom()->randomInt(0, interfs.size())].test, + NetworkTestRequest(StringRef(request_payload), FLOW_KNOBS->NETWORK_TEST_REPLY_SIZE))); + latency->tock(sample); + (*completed)++; + } + return Void(); +} + +ACTOR Future testClientStream(std::vector interfs, int* sent, int* completed, + LatencyStats* latency) { + state std::string request_payload(FLOW_KNOBS->NETWORK_TEST_REQUEST_SIZE, '.'); + state LatencyStats::sample sample; + while (moreRequestsPending(*sent)) { (*sent)++; sample = latency->tick(); state ReplyPromiseStream stream = - interfs[deterministicRandom()->randomInt(0, interfs.size())].test.getReplyStream( + interfs[deterministicRandom()->randomInt(0, interfs.size())].testStream.getReplyStream( NetworkTestStreamingRequest{}); state int j = 0; try { loop { - printf("Wait for result\n"); NetworkTestStreamingReply rep = waitNext(stream.getFuture()); ASSERT(rep.index == j++); - printf("Result: %d\n", rep.index); } } catch (Error& e) { - printf("Error: %s\n", e.what()); ASSERT(e.code() == error_code_end_of_stream || e.code() == error_code_connection_failed); } latency->tock(sample); @@ -255,7 +296,7 @@ ACTOR Future networkTestClient( std:: string testServers ) { } state std::vector> clients; - for (int i = 0; i < 1; i++) { + for (int i = 0; i < FLOW_KNOBS->NETWORK_TEST_CLIENT_COUNT; i++) { clients.push_back(testClient(interfs, &sent, &completed, &latency)); } clients.push_back(logger(&sent, &completed, &latency)); From 4fd01c8511a6e326984986442e3f0338fb4d6c18 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Wed, 16 Dec 2020 21:04:57 -0800 Subject: [PATCH 128/740] compile error --- fdbserver/networktest.actor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdbserver/networktest.actor.cpp b/fdbserver/networktest.actor.cpp index 2c78ca545c0..825dafab652 100644 --- a/fdbserver/networktest.actor.cpp +++ b/fdbserver/networktest.actor.cpp @@ -106,7 +106,7 @@ ACTOR Future networkTestStreamingServer() { loop { try { choose { - when(state NetworkTestStreamingRequest req = waitNext(interf.test.getFuture())) { + when(state NetworkTestStreamingRequest req = waitNext(interf.testStream.getFuture())) { state LatencyStats::sample sample = latency.tick(); state int i = 0; for (; i < 100; ++i) { From 7e88adf0c11716c6f42c727f59acd09360346395 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Wed, 16 Dec 2020 21:12:46 -0800 Subject: [PATCH 129/740] added a yield to avoid slow tasks --- fdbclient/ParallelStream.actor.h | 1 + 1 file changed, 1 insertion(+) diff --git a/fdbclient/ParallelStream.actor.h b/fdbclient/ParallelStream.actor.h index cf9a3150af0..fb019e258b6 100644 --- a/fdbclient/ParallelStream.actor.h +++ b/fdbclient/ParallelStream.actor.h @@ -75,6 +75,7 @@ class ParallelStream { try { T value = waitNext(fragment->stream.getFuture()); self->results.send(value); + wait(yield()); } catch (Error &e) { if (e.code() == error_code_end_of_stream) { fragment.clear(); From c6e01aa6e4c004113c108c08f7bbe3f80f40933b Mon Sep 17 00:00:00 2001 From: sfc-gh-tclinkenbeard Date: Wed, 16 Dec 2020 20:03:20 -0800 Subject: [PATCH 130/740] Yield to prevent slow tasks in ParallelStream::flushToClient --- fdbclient/ParallelStream.actor.cpp | 27 +++++++++++++++++---------- fdbclient/ParallelStream.actor.h | 16 +++++++++++++++- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/fdbclient/ParallelStream.actor.cpp b/fdbclient/ParallelStream.actor.cpp index 3e383f24bc7..6aaee058e76 100644 --- a/fdbclient/ParallelStream.actor.cpp +++ b/fdbclient/ParallelStream.actor.cpp @@ -26,20 +26,25 @@ namespace ParallelStreamTest { -ACTOR static Future produce(ParallelStream::Fragment* fragment, int value) { +struct Data { + static constexpr size_t expectedSize() { return sizeof(Data); } + int v; +}; + +ACTOR static Future produce(ParallelStream::Fragment* fragment, int value) { wait(delay(deterministicRandom()->random01())); - fragment->send(value); + fragment->send(Data{value}); wait(delay(deterministicRandom()->random01())); fragment->finish(); return Void(); } -ACTOR static Future consume(FutureStream stream, int expected) { +ACTOR static Future consume(FutureStream stream, int expected) { state int next; try { loop { - int value = waitNext(stream); - ASSERT(value == next++); + Data data = waitNext(stream); + ASSERT(data.v == next++); } } catch (Error& e) { ASSERT(e.code() == error_code_end_of_stream); @@ -51,13 +56,15 @@ ACTOR static Future consume(FutureStream stream, int expected) { } // namespace ParallelStreamTest TEST_CASE("/fdbclient/ParallelStream") { - state PromiseStream results; - state ParallelStream parallelStream(results, 10); - state Future consumer = ParallelStreamTest::consume(results.getFuture(), 100); + state PromiseStream results; + state size_t concurrency = deterministicRandom()->randomInt(1,11); + state size_t numProducers = deterministicRandom()->randomInt(1,1001); + state ParallelStream parallelStream(results, concurrency); + state Future consumer = ParallelStreamTest::consume(results.getFuture(), numProducers); state std::vector> producers; state int i = 0; - for (; i < 100; ++i) { - ParallelStream::Fragment* fragment = wait(parallelStream.createFragment()); + for (; i < numProducers; ++i) { + ParallelStream::Fragment* fragment = wait(parallelStream.createFragment()); producers.push_back(ParallelStreamTest::produce(fragment, i)); } wait(waitForAll(producers)); diff --git a/fdbclient/ParallelStream.actor.h b/fdbclient/ParallelStream.actor.h index fb019e258b6..8283edb204f 100644 --- a/fdbclient/ParallelStream.actor.h +++ b/fdbclient/ParallelStream.actor.h @@ -67,13 +67,27 @@ class ParallelStream { public: - // TODO: Fix potential slow task ACTOR static Future flushToClient(ParallelStream *self) { + state const int bytesPerTaskLimit = 1e6; // TODO: buggify + state int bytesFlushedInTask = 0; loop { + if (!self->fragments.getFuture().isReady()) { + bytesFlushedInTask = 0; + } + if (bytesFlushedInTask > bytesPerTaskLimit) { + wait(yield()); + } state Reference fragment = waitNext(self->fragments.getFuture()); loop { try { + if (!fragment->stream.getFuture().isReady()) { + bytesFlushedInTask = 0; + } + if (bytesFlushedInTask > bytesPerTaskLimit) { + wait(yield()); + } T value = waitNext(fragment->stream.getFuture()); + bytesFlushedInTask += value.expectedSize(); self->results.send(value); wait(yield()); } catch (Error &e) { From 7e529fb2e20b76d7ba7184a1cb73602a1528d7e3 Mon Sep 17 00:00:00 2001 From: sfc-gh-tclinkenbeard Date: Wed, 16 Dec 2020 20:36:19 -0800 Subject: [PATCH 131/740] Buggify bytesPerTaskLimit in ResultStream::flushToClient --- fdbclient/ParallelStream.actor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdbclient/ParallelStream.actor.h b/fdbclient/ParallelStream.actor.h index 8283edb204f..dc8170a77ac 100644 --- a/fdbclient/ParallelStream.actor.h +++ b/fdbclient/ParallelStream.actor.h @@ -68,7 +68,7 @@ class ParallelStream { public: ACTOR static Future flushToClient(ParallelStream *self) { - state const int bytesPerTaskLimit = 1e6; // TODO: buggify + state const int bytesPerTaskLimit = BUGGIFY ? 1 : 1e6; state int bytesFlushedInTask = 0; loop { if (!self->fragments.getFuture().isReady()) { From df5c381f928f3de6472d55ed04ccdbd58eb4b2e2 Mon Sep 17 00:00:00 2001 From: sfc-gh-tclinkenbeard Date: Wed, 16 Dec 2020 22:27:17 -0800 Subject: [PATCH 132/740] Use BoundedFlowLock in ParallelStream --- fdbclient/Knobs.cpp | 1 + fdbclient/Knobs.h | 1 + fdbclient/NativeAPI.actor.cpp | 3 ++- fdbclient/ParallelStream.actor.cpp | 7 ++++++- fdbclient/ParallelStream.actor.h | 16 ++++++++-------- 5 files changed, 18 insertions(+), 10 deletions(-) diff --git a/fdbclient/Knobs.cpp b/fdbclient/Knobs.cpp index 06efd14c50d..7d50c738d51 100644 --- a/fdbclient/Knobs.cpp +++ b/fdbclient/Knobs.cpp @@ -96,6 +96,7 @@ void ClientKnobs::initialize(bool randomize) { init( TAG_ENCODE_KEY_SERVERS, false ); if( randomize && BUGGIFY ) TAG_ENCODE_KEY_SERVERS = true; init( RANGESTREAM_FRAGMENT_SIZE, 1e6 ); init( RANGESTREAM_CONCURRENT_FRAGMENTS, 10 ); + init( RANGESTREAM_BUFFERED_FRAGMENTS_LIMIT, 2*RANGESTREAM_CONCURRENT_FRAGMENTS ); //KeyRangeMap init( KRM_GET_RANGE_LIMIT, 1e5 ); if( randomize && BUGGIFY ) KRM_GET_RANGE_LIMIT = 10; diff --git a/fdbclient/Knobs.h b/fdbclient/Knobs.h index f85aeb3a831..0dd02a7f49d 100644 --- a/fdbclient/Knobs.h +++ b/fdbclient/Knobs.h @@ -90,6 +90,7 @@ class ClientKnobs : public Knobs { bool TAG_ENCODE_KEY_SERVERS; int64_t RANGESTREAM_FRAGMENT_SIZE; int RANGESTREAM_CONCURRENT_FRAGMENTS; + int RANGESTREAM_BUFFERED_FRAGMENTS_LIMIT; //KeyRangeMap int KRM_GET_RANGE_LIMIT; diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index e39fbc9f55e..12e519d2475 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -2859,7 +2859,8 @@ ACTOR Future getRangeStream(PromiseStream _results, Database KeySelector end, GetRangeLimits limits, Promise> conflictRange, bool snapshot, bool reverse, TransactionInfo info, TagSet tags) { - state ParallelStream results(_results, CLIENT_KNOBS->RANGESTREAM_CONCURRENT_FRAGMENTS); + state ParallelStream results(_results, CLIENT_KNOBS->RANGESTREAM_CONCURRENT_FRAGMENTS, + CLIENT_KNOBS->RANGESTREAM_BUFFERED_FRAGMENTS_LIMIT); // FIXME: better handling to disable row limits ASSERT(!limits.hasRowLimit()); diff --git a/fdbclient/ParallelStream.actor.cpp b/fdbclient/ParallelStream.actor.cpp index 6aaee058e76..536e366e4ed 100644 --- a/fdbclient/ParallelStream.actor.cpp +++ b/fdbclient/ParallelStream.actor.cpp @@ -58,10 +58,15 @@ ACTOR static Future consume(FutureStream stream, int expected) { TEST_CASE("/fdbclient/ParallelStream") { state PromiseStream results; state size_t concurrency = deterministicRandom()->randomInt(1,11); + state size_t bufferLimit = concurrency + deterministicRandom()->randomInt(0, 11); state size_t numProducers = deterministicRandom()->randomInt(1,1001); - state ParallelStream parallelStream(results, concurrency); + state ParallelStream parallelStream(results, concurrency, bufferLimit); state Future consumer = ParallelStreamTest::consume(results.getFuture(), numProducers); state std::vector> producers; + TraceEvent("StartingParallelStreamTest") + .detail("Concurrency", concurrency) + .detail("BufferLimit", bufferLimit) + .detail("NumProducers", numProducers); state int i = 0; for (; i < numProducers; ++i) { ParallelStream::Fragment* fragment = wait(parallelStream.createFragment()); diff --git a/fdbclient/ParallelStream.actor.h b/fdbclient/ParallelStream.actor.h index dc8170a77ac..176b5fb98f2 100644 --- a/fdbclient/ParallelStream.actor.h +++ b/fdbclient/ParallelStream.actor.h @@ -33,7 +33,7 @@ template class ParallelStream { - FlowLock semaphore; + BoundedFlowLock semaphore; struct FragmentConstructorTag { explicit FragmentConstructorTag() = default; }; @@ -42,12 +42,11 @@ class ParallelStream { class Fragment : public ReferenceCounted { ParallelStream* parallelStream; PromiseStream stream; - FlowLock::Releaser releaser; + BoundedFlowLock::Releaser releaser; friend class ParallelStream; - public: - Fragment(ParallelStream* parallelStream, FragmentConstructorTag) - : parallelStream(parallelStream), releaser(parallelStream->semaphore) {} + Fragment(ParallelStream* parallelStream, int64_t permitNumber, FragmentConstructorTag) + : parallelStream(parallelStream), releaser(¶llelStream->semaphore, permitNumber) {} template void send(U &&value) { stream.send(std::forward(value)); @@ -102,13 +101,14 @@ class ParallelStream { } } - ParallelStream(PromiseStream results, size_t concurrency) : results(results), semaphore(concurrency) { + ParallelStream(PromiseStream results, size_t concurrency, size_t bufferLimit) + : results(results), semaphore(concurrency, bufferLimit) { flusher = flushToClient(this); } ACTOR static Future createFragmentImpl(ParallelStream* self) { - wait(self->semaphore.take()); - auto fragment = makeReference(self, FragmentConstructorTag()); + int64_t permitNumber = wait(self->semaphore.take()); + auto fragment = makeReference(self, permitNumber, FragmentConstructorTag()); self->fragments.send(fragment); return fragment.getPtr(); } From 2813cc0aa4200d5a2d42ee16f38f1706bdff5d22 Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Thu, 17 Dec 2020 19:21:00 +0000 Subject: [PATCH 133/740] Add GetRangeStream.actor.cpp --- fdbserver/CMakeLists.txt | 1 + fdbserver/workloads/GetRangeStream.actor.cpp | 110 +++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 fdbserver/workloads/GetRangeStream.actor.cpp diff --git a/fdbserver/CMakeLists.txt b/fdbserver/CMakeLists.txt index bf266069cbd..abe3efeaf8d 100644 --- a/fdbserver/CMakeLists.txt +++ b/fdbserver/CMakeLists.txt @@ -157,6 +157,7 @@ set(FDBSERVER_SRCS workloads/FileSystem.actor.cpp workloads/Fuzz.cpp workloads/FuzzApiCorrectness.actor.cpp + workloads/GetRangeStream.actor.cpp workloads/HealthMetricsApi.actor.cpp workloads/IncrementalBackup.actor.cpp workloads/Increment.actor.cpp diff --git a/fdbserver/workloads/GetRangeStream.actor.cpp b/fdbserver/workloads/GetRangeStream.actor.cpp new file mode 100644 index 00000000000..eb35b3389a9 --- /dev/null +++ b/fdbserver/workloads/GetRangeStream.actor.cpp @@ -0,0 +1,110 @@ +/* + * GetRangeStream.actor.cpp + * + * This source file is part of the FoundationDB open source project + * + * Copyright 2013-2020 Apple Inc. and the FoundationDB project authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "fdbclient/NativeAPI.actor.h" +#include "fdbserver/TesterInterface.actor.h" +#include "fdbserver/workloads/workloads.actor.h" +#include "fdbserver/workloads/BulkSetup.actor.h" +#include "flow/actorcompiler.h" // This must be the last #include. + +struct GetRangeStream : TestWorkload { + PerfIntCounter bytesRead; + bool useGetRange; + + GetRangeStream(WorkloadContext const& wcx) : TestWorkload(wcx), bytesRead("BytesRead") { + useGetRange = getOption(options, LiteralStringRef("useGetRange"), false); + } + + std::string description() const override { return "GetRangeStreamWorkload"; } + + Future setup(Database const& cx) override { return Void(); } + + Future start(Database const& cx) override { + return clientId != 0 ? Void() : useGetRange ? fdbClientGetRange(cx, this) : fdbClientStream(cx, this); + } + + Future check(Database const& cx) override { return true; } + + void getMetrics(vector& m) override { m.push_back(bytesRead.getMetric()); } + + ACTOR static Future logThroughput(GetRangeStream* self, Key* next) { + loop { + state int64_t last = self->bytesRead.getValue(); + state double before = g_network->now(); + wait(delay(1)); + state double after = g_network->now(); + if (after > before) { + printf("throughput: %g bytes/s, next: %s\n", (self->bytesRead.getValue() - last) / (after - before), + printable(*next).c_str()); + } + } + } + + ACTOR static Future fdbClientGetRange(Database db, GetRangeStream* self) { + state Transaction tx(db); + state Key next; + state Future logFuture = logThroughput(self, &next); + loop { + try { + Standalone range = wait( + tx.getRange(KeySelector(firstGreaterOrEqual(next), next.arena()), + KeySelector(firstGreaterOrEqual(normalKeys.end)), + GetRangeLimits(GetRangeLimits::ROW_LIMIT_UNLIMITED, CLIENT_KNOBS->REPLY_BYTE_LIMIT))); + self->bytesRead += range.expectedSize(); + if (!range.more) { + break; + } + next = keyAfter(range.back().key); + } catch (Error& e) { + wait(tx.onError(e)); + } + } + return Void(); + } + + ACTOR static Future fdbClientStream(Database db, GetRangeStream* self) { + state Transaction tx(db); + state Key next; + state Future logFuture = logThroughput(self, &next); + loop { + state PromiseStream> results; + try { + state Future stream = + tx.getRangeStream(results, KeySelector(firstGreaterOrEqual(next), next.arena()), + KeySelector(firstGreaterOrEqual(normalKeys.end)), GetRangeLimits()); + loop { + Standalone range = waitNext(results.getFuture()); + if (range.size()) { + self->bytesRead += range.expectedSize(); + next = keyAfter(range.back().key); + } + } + } catch (Error& e) { + if (e.code() == error_code_end_of_stream) { + break; + } + wait(tx.onError(e)); + } + } + return Void(); + } +}; + +WorkloadFactory GetRangeStreamWorkloadFactory("GetRangeStream"); From d1d822d4809e6809004b618bfce4074393f6691f Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Thu, 17 Dec 2020 19:53:42 +0000 Subject: [PATCH 134/740] Fix bug where stream would hang --- fdbclient/NativeAPI.actor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index 12e519d2475..0fc8736b343 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -2890,6 +2890,7 @@ ACTOR Future getRangeStream(PromiseStream _results, Database //if b is allKeys.begin, we have either read through the beginning of the database, //or allKeys.begin exists in the database and will be part of the conflict range anyways + state std::vector> outstandingRequests; loop { state pair> ssi = wait(getKeyLocation(cx, reverse ? e : b, &StorageServerInterface::getKeyValuesStream, info, reverse)); @@ -2897,7 +2898,6 @@ ACTOR Future getRangeStream(PromiseStream _results, Database wait(getRangeSplitPoints(cx, ssi.first, CLIENT_KNOBS->RANGESTREAM_FRAGMENT_SIZE)); state std::vector toSend; // state std::vector::iterator>> outstandingRequests; - state std::vector> outstandingRequests; if (!splitPoints.empty()) { toSend.push_back(KeyRange(KeyRangeRef(ssi.first.begin, splitPoints.front()), splitPoints.arena())); From 9ba408ae8f4f0c630cea503e49ffa014785e1f16 Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Thu, 17 Dec 2020 19:53:51 +0000 Subject: [PATCH 135/740] Add begin, end, printKVPairs --- fdbserver/workloads/GetRangeStream.actor.cpp | 29 +++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/fdbserver/workloads/GetRangeStream.actor.cpp b/fdbserver/workloads/GetRangeStream.actor.cpp index eb35b3389a9..77be4135ca6 100644 --- a/fdbserver/workloads/GetRangeStream.actor.cpp +++ b/fdbserver/workloads/GetRangeStream.actor.cpp @@ -27,9 +27,15 @@ struct GetRangeStream : TestWorkload { PerfIntCounter bytesRead; bool useGetRange; + Key begin; + Key end; + bool printKVPairs; GetRangeStream(WorkloadContext const& wcx) : TestWorkload(wcx), bytesRead("BytesRead") { useGetRange = getOption(options, LiteralStringRef("useGetRange"), false); + begin = getOption(options, LiteralStringRef("begin"), normalKeys.begin); + end = getOption(options, LiteralStringRef("end"), normalKeys.end); + printKVPairs = getOption(options, LiteralStringRef("printKVPairs"), false); } std::string description() const override { return "GetRangeStreamWorkload"; } @@ -59,15 +65,19 @@ struct GetRangeStream : TestWorkload { ACTOR static Future fdbClientGetRange(Database db, GetRangeStream* self) { state Transaction tx(db); - state Key next; + state Key next = self->begin; state Future logFuture = logThroughput(self, &next); loop { try { - Standalone range = wait( - tx.getRange(KeySelector(firstGreaterOrEqual(next), next.arena()), - KeySelector(firstGreaterOrEqual(normalKeys.end)), - GetRangeLimits(GetRangeLimits::ROW_LIMIT_UNLIMITED, CLIENT_KNOBS->REPLY_BYTE_LIMIT))); + Standalone range = wait(tx.getRange( + KeySelector(firstGreaterOrEqual(next), next.arena()), KeySelector(firstGreaterOrEqual(self->end)), + GetRangeLimits(GetRangeLimits::ROW_LIMIT_UNLIMITED, CLIENT_KNOBS->REPLY_BYTE_LIMIT))); self->bytesRead += range.expectedSize(); + if (self->printKVPairs) { + for (const auto & [ k, v ] : range) { + printf("%s -> %s\n", printable(k).c_str(), printable(v).c_str()); + } + } if (!range.more) { break; } @@ -81,16 +91,21 @@ struct GetRangeStream : TestWorkload { ACTOR static Future fdbClientStream(Database db, GetRangeStream* self) { state Transaction tx(db); - state Key next; + state Key next = self->begin; state Future logFuture = logThroughput(self, &next); loop { state PromiseStream> results; try { state Future stream = tx.getRangeStream(results, KeySelector(firstGreaterOrEqual(next), next.arena()), - KeySelector(firstGreaterOrEqual(normalKeys.end)), GetRangeLimits()); + KeySelector(firstGreaterOrEqual(self->end)), GetRangeLimits()); loop { Standalone range = waitNext(results.getFuture()); + if (self->printKVPairs) { + for (const auto & [ k, v ] : range) { + printf("%s -> %s\n", printable(k).c_str(), printable(v).c_str()); + } + } if (range.size()) { self->bytesRead += range.expectedSize(); next = keyAfter(range.back().key); From 46d39584f57cc3a8440479cbfc6b3a26422fce0f Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Thu, 17 Dec 2020 21:25:44 +0000 Subject: [PATCH 136/740] Clamp shard to requested keyrange --- fdbclient/NativeAPI.actor.cpp | 17 +++++++++++------ fdbserver/workloads/GetRangeStream.actor.cpp | 12 ++++++------ 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index 0fc8736b343..8fca5220ef0 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -2854,6 +2854,10 @@ ACTOR Future getRangeStreamFragment(ParallelStream::Fragment* ACTOR Future>> getRangeSplitPoints(Database cx, KeyRange keys, int64_t chunkSize); +static KeyRange intersect(KeyRangeRef lhs, KeyRangeRef rhs) { + return KeyRange(KeyRangeRef(std::max(lhs.begin, rhs.begin), std::min(lhs.end, rhs.end))); +} + ACTOR Future getRangeStream(PromiseStream _results, Database cx, Reference trLogInfo, Future fVersion, KeySelector begin, KeySelector end, GetRangeLimits limits, Promise> conflictRange, @@ -2894,19 +2898,20 @@ ACTOR Future getRangeStream(PromiseStream _results, Database loop { state pair> ssi = wait(getKeyLocation(cx, reverse ? e : b, &StorageServerInterface::getKeyValuesStream, info, reverse)); + state KeyRange shardIntersection = intersect(ssi.first, KeyRangeRef(b, e)); state Standalone> splitPoints = - wait(getRangeSplitPoints(cx, ssi.first, CLIENT_KNOBS->RANGESTREAM_FRAGMENT_SIZE)); + wait(getRangeSplitPoints(cx, shardIntersection, CLIENT_KNOBS->RANGESTREAM_FRAGMENT_SIZE)); state std::vector toSend; // state std::vector::iterator>> outstandingRequests; if (!splitPoints.empty()) { - toSend.push_back(KeyRange(KeyRangeRef(ssi.first.begin, splitPoints.front()), splitPoints.arena())); + toSend.push_back(KeyRange(KeyRangeRef(shardIntersection.begin, splitPoints.front()), splitPoints.arena())); for (int i = 0; i < splitPoints.size() - 1; ++i) { toSend.push_back(KeyRange(KeyRangeRef(splitPoints[i], splitPoints[i + 1]), splitPoints.arena())); } - toSend.push_back(KeyRange(KeyRangeRef(splitPoints.back(), ssi.first.end), splitPoints.arena())); + toSend.push_back(KeyRange(KeyRangeRef(splitPoints.back(), shardIntersection.end), splitPoints.arena())); } else { - toSend.push_back(KeyRange(KeyRangeRef(ssi.first.begin, ssi.first.end), splitPoints.arena())); + toSend.push_back(KeyRange(KeyRangeRef(shardIntersection.begin, shardIntersection.end))); } state int idx = 0; @@ -2921,9 +2926,9 @@ ACTOR Future getRangeStream(PromiseStream _results, Database snapshot, reverse, info, tags, span.context)); } if(reverse) { - e = ssi.first.begin; + e = shardIntersection.begin; } else { - b = ssi.first.end; + b = shardIntersection.end; } if(b >= e) { break; diff --git a/fdbserver/workloads/GetRangeStream.actor.cpp b/fdbserver/workloads/GetRangeStream.actor.cpp index 77be4135ca6..0159204f120 100644 --- a/fdbserver/workloads/GetRangeStream.actor.cpp +++ b/fdbserver/workloads/GetRangeStream.actor.cpp @@ -72,11 +72,11 @@ struct GetRangeStream : TestWorkload { Standalone range = wait(tx.getRange( KeySelector(firstGreaterOrEqual(next), next.arena()), KeySelector(firstGreaterOrEqual(self->end)), GetRangeLimits(GetRangeLimits::ROW_LIMIT_UNLIMITED, CLIENT_KNOBS->REPLY_BYTE_LIMIT))); - self->bytesRead += range.expectedSize(); - if (self->printKVPairs) { - for (const auto & [ k, v ] : range) { + for (const auto & [ k, v ] : range) { + if (self->printKVPairs) { printf("%s -> %s\n", printable(k).c_str(), printable(v).c_str()); } + self->bytesRead += k.size() + v.size(); } if (!range.more) { break; @@ -101,13 +101,13 @@ struct GetRangeStream : TestWorkload { KeySelector(firstGreaterOrEqual(self->end)), GetRangeLimits()); loop { Standalone range = waitNext(results.getFuture()); - if (self->printKVPairs) { - for (const auto & [ k, v ] : range) { + for (const auto & [ k, v ] : range) { + if (self->printKVPairs) { printf("%s -> %s\n", printable(k).c_str(), printable(v).c_str()); } + self->bytesRead += k.size() + v.size(); } if (range.size()) { - self->bytesRead += range.expectedSize(); next = keyAfter(range.back().key); } } From 2c2b6ed8a0fc6c804dda986d81133a5345316a31 Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Thu, 17 Dec 2020 22:30:10 +0000 Subject: [PATCH 137/740] Avoid double sending results --- fdbclient/NativeAPI.actor.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index 8fca5220ef0..e4a1d37b427 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -2792,15 +2792,13 @@ ACTOR Future getRangeStreamFragment(ParallelStream::Fragment* breakAgain = true; break; } else { + ASSERT(output.size()); output.arena().dependsOn( range.arena() ); output.readThrough = reverse ? range.begin : range.end; - results->send(std::move(output)); + results.send(std::move(output)); + ++shard; + break; } - - ASSERT(output.size()); - results->send(std::move(output)); - ++shard; - break; } ASSERT(output.size()); From 92425ade0af4e19b7d29a0bf596217960cd03af3 Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Thu, 17 Dec 2020 22:42:14 +0000 Subject: [PATCH 138/740] Remove potentially bogus asserts --- fdbclient/NativeAPI.actor.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index e4a1d37b427..6a365e07912 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -2786,13 +2786,11 @@ ACTOR Future getRangeStreamFragment(ParallelStream::Fragment* return Void(); } - ASSERT(output.size()); results->send(std::move(output)); keys = KeyRangeRef(begin, end); breakAgain = true; break; } else { - ASSERT(output.size()); output.arena().dependsOn( range.arena() ); output.readThrough = reverse ? range.begin : range.end; results.send(std::move(output)); From 4d32bc24c3343ebeacaf3d2dd65caa12e06b1da7 Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Thu, 17 Dec 2020 22:56:55 +0000 Subject: [PATCH 139/740] Change ParallelStream::sendError to finish --- fdbclient/NativeAPI.actor.cpp | 11 ++---- fdbclient/ParallelStream.actor.h | 68 ++++++++++++++++++-------------- 2 files changed, 42 insertions(+), 37 deletions(-) diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index 6a365e07912..efb237dbc49 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -2793,7 +2793,7 @@ ACTOR Future getRangeStreamFragment(ParallelStream::Fragment* } else { output.arena().dependsOn( range.arena() ); output.readThrough = reverse ? range.begin : range.end; - results.send(std::move(output)); + results->send(std::move(output)); ++shard; break; } @@ -2882,7 +2882,7 @@ ACTOR Future getRangeStream(PromiseStream _results, Database } if (b >= e) { - results.sendError(end_of_stream()); + wait(results.finish()); return Void(); } @@ -2930,12 +2930,7 @@ ACTOR Future getRangeStream(PromiseStream _results, Database break; } } - try { - wait(waitForAll(outstandingRequests)); - } catch (Error& e) { - results.sendError(e); - } - results.sendError(end_of_stream()); + wait(waitForAll(outstandingRequests) && results.finish()); return Void(); } diff --git a/fdbclient/ParallelStream.actor.h b/fdbclient/ParallelStream.actor.h index 176b5fb98f2..139c9acc370 100644 --- a/fdbclient/ParallelStream.actor.h +++ b/fdbclient/ParallelStream.actor.h @@ -51,7 +51,7 @@ class ParallelStream { void send(U &&value) { stream.send(std::forward(value)); } - void sendError(Error e) { parallelStream->sendError(e); } + void sendError(Error e) { stream.sendError(e); } void finish() { releaser.release(); // Release before destruction to free up pending fragments stream.sendError(end_of_stream()); @@ -65,39 +65,46 @@ class ParallelStream { Future flusher; public: - - ACTOR static Future flushToClient(ParallelStream *self) { + ACTOR static Future flushToClient(ParallelStream* self) { state const int bytesPerTaskLimit = BUGGIFY ? 1 : 1e6; - state int bytesFlushedInTask = 0; - loop { - if (!self->fragments.getFuture().isReady()) { - bytesFlushedInTask = 0; - } - if (bytesFlushedInTask > bytesPerTaskLimit) { - wait(yield()); - } - state Reference fragment = waitNext(self->fragments.getFuture()); + try { + state int bytesFlushedInTask = 0; loop { - try { - if (!fragment->stream.getFuture().isReady()) { - bytesFlushedInTask = 0; - } - if (bytesFlushedInTask > bytesPerTaskLimit) { - wait(yield()); - } - T value = waitNext(fragment->stream.getFuture()); - bytesFlushedInTask += value.expectedSize(); - self->results.send(value); + if (!self->fragments.getFuture().isReady()) { + bytesFlushedInTask = 0; + } + if (bytesFlushedInTask > bytesPerTaskLimit) { wait(yield()); - } catch (Error &e) { - if (e.code() == error_code_end_of_stream) { - fragment.clear(); - break; - } else { - throw e; + } + state Reference fragment = waitNext(self->fragments.getFuture()); + loop { + try { + if (!fragment->stream.getFuture().isReady()) { + bytesFlushedInTask = 0; + } + if (bytesFlushedInTask > bytesPerTaskLimit) { + wait(yield()); + } + T value = waitNext(fragment->stream.getFuture()); + bytesFlushedInTask += value.expectedSize(); + self->results.send(value); + wait(yield()); + } catch (Error& e) { + if (e.code() == error_code_end_of_stream) { + fragment.clear(); + break; + } else { + throw e; + } } } } + } catch (Error& e) { + if (e.code() == error_code_actor_cancelled) { + throw; + } + self->results.sendError(e); + return Void(); } } @@ -115,7 +122,10 @@ class ParallelStream { Future createFragment() { return createFragmentImpl(this); } - void sendError(Error e) { results.sendError(e); } + Future finish() { + fragments.sendError(end_of_stream()); + return flusher; + } }; #include "flow/unactorcompiler.h" From 650e79302628c24d3c2b3a9bd6d726d9ac50c766 Mon Sep 17 00:00:00 2001 From: sfc-gh-tclinkenbeard Date: Thu, 17 Dec 2020 15:46:54 -0800 Subject: [PATCH 140/740] Simplify yielding logic in ParallelStream::flushToClient --- fdbclient/ParallelStream.actor.cpp | 24 +++++++++--------------- fdbclient/ParallelStream.actor.h | 22 ++++++---------------- 2 files changed, 15 insertions(+), 31 deletions(-) diff --git a/fdbclient/ParallelStream.actor.cpp b/fdbclient/ParallelStream.actor.cpp index 536e366e4ed..beb7f42dc75 100644 --- a/fdbclient/ParallelStream.actor.cpp +++ b/fdbclient/ParallelStream.actor.cpp @@ -26,25 +26,20 @@ namespace ParallelStreamTest { -struct Data { - static constexpr size_t expectedSize() { return sizeof(Data); } - int v; -}; - -ACTOR static Future produce(ParallelStream::Fragment* fragment, int value) { +ACTOR static Future produce(ParallelStream::Fragment* fragment, int value) { wait(delay(deterministicRandom()->random01())); - fragment->send(Data{value}); + fragment->send(value); wait(delay(deterministicRandom()->random01())); fragment->finish(); return Void(); } -ACTOR static Future consume(FutureStream stream, int expected) { +ACTOR static Future consume(FutureStream stream, int expected) { state int next; try { loop { - Data data = waitNext(stream); - ASSERT(data.v == next++); + int value = waitNext(stream); + ASSERT(value == next++); } } catch (Error& e) { ASSERT(e.code() == error_code_end_of_stream); @@ -56,11 +51,11 @@ ACTOR static Future consume(FutureStream stream, int expected) { } // namespace ParallelStreamTest TEST_CASE("/fdbclient/ParallelStream") { - state PromiseStream results; + state PromiseStream results; state size_t concurrency = deterministicRandom()->randomInt(1,11); state size_t bufferLimit = concurrency + deterministicRandom()->randomInt(0, 11); state size_t numProducers = deterministicRandom()->randomInt(1,1001); - state ParallelStream parallelStream(results, concurrency, bufferLimit); + state ParallelStream parallelStream(results, concurrency, bufferLimit); state Future consumer = ParallelStreamTest::consume(results.getFuture(), numProducers); state std::vector> producers; TraceEvent("StartingParallelStreamTest") @@ -69,11 +64,10 @@ TEST_CASE("/fdbclient/ParallelStream") { .detail("NumProducers", numProducers); state int i = 0; for (; i < numProducers; ++i) { - ParallelStream::Fragment* fragment = wait(parallelStream.createFragment()); + ParallelStream::Fragment* fragment = wait(parallelStream.createFragment()); producers.push_back(ParallelStreamTest::produce(fragment, i)); } - wait(waitForAll(producers)); - results.sendError(end_of_stream()); + wait(parallelStream.finish()); wait(consumer); return Void(); } diff --git a/fdbclient/ParallelStream.actor.h b/fdbclient/ParallelStream.actor.h index 139c9acc370..0357f17d70b 100644 --- a/fdbclient/ParallelStream.actor.h +++ b/fdbclient/ParallelStream.actor.h @@ -66,29 +66,19 @@ class ParallelStream { public: ACTOR static Future flushToClient(ParallelStream* self) { - state const int bytesPerTaskLimit = BUGGIFY ? 1 : 1e6; + state const int messagesBetweenYields = 1000; + state int messagesSinceYield = 0; try { - state int bytesFlushedInTask = 0; loop { - if (!self->fragments.getFuture().isReady()) { - bytesFlushedInTask = 0; - } - if (bytesFlushedInTask > bytesPerTaskLimit) { - wait(yield()); - } state Reference fragment = waitNext(self->fragments.getFuture()); loop { try { - if (!fragment->stream.getFuture().isReady()) { - bytesFlushedInTask = 0; - } - if (bytesFlushedInTask > bytesPerTaskLimit) { - wait(yield()); - } T value = waitNext(fragment->stream.getFuture()); - bytesFlushedInTask += value.expectedSize(); self->results.send(value); - wait(yield()); + if (++messagesSinceYield == messagesBetweenYields) { + wait(yield()); + messagesSinceYield = 0; + } } catch (Error& e) { if (e.code() == error_code_end_of_stream) { fragment.clear(); From e0d6376de927febfb8bbeed7fdae16f174ea870a Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Sat, 1 May 2021 14:34:52 -0700 Subject: [PATCH 141/740] clang format code --- documentation/tutorial/tutorial.actor.cpp | 56 ++-- fdbclient/FDBTypes.h | 2 +- fdbclient/NativeAPI.actor.cpp | 221 +++++++++------ fdbclient/NativeAPI.actor.h | 47 +++- fdbclient/ParallelStream.actor.cpp | 4 +- fdbclient/ParallelStream.actor.h | 7 +- fdbclient/StorageServerInterface.h | 12 +- fdbrpc/FailureMonitor.actor.cpp | 7 +- fdbrpc/FlowTransport.actor.cpp | 15 +- fdbrpc/FlowTransport.h | 2 +- fdbrpc/fdbrpc.h | 161 ++++++----- fdbrpc/genericactors.actor.h | 19 +- fdbserver/NetworkTest.h | 4 +- fdbserver/storageserver.actor.cpp | 280 +++++++++++-------- fdbserver/workloads/GetRangeStream.actor.cpp | 21 +- flow/flow.h | 24 +- flow/genericactors.actor.h | 3 +- 17 files changed, 514 insertions(+), 371 deletions(-) diff --git a/documentation/tutorial/tutorial.actor.cpp b/documentation/tutorial/tutorial.actor.cpp index 841f7481662..f5eed7ab394 100644 --- a/documentation/tutorial/tutorial.actor.cpp +++ b/documentation/tutorial/tutorial.actor.cpp @@ -1,23 +1,23 @@ /* - * tutorial.actor.cpp - - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +* tutorial.actor.cpp + +* +* This source file is part of the FoundationDB open source project +* +* Copyright 2013-2018 Apple Inc. and the FoundationDB project authors +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ #include "flow/flow.h" #include "flow/Platform.h" @@ -192,8 +192,8 @@ ACTOR Future echoServer() { req.reply.sendError(end_of_stream()); } } - } catch (Error &e) { - if(e.code() != error_code_operation_obsolete) { + } catch (Error& e) { + if (e.code() != error_code_operation_obsolete) { fprintf(stderr, "Error: %s\n", e.what()); throw e; } @@ -418,9 +418,10 @@ ACTOR Future fdbClientStream() { loop { state PromiseStream> results; try { - state Future stream = - tx.getRangeStream(results, KeySelector(firstGreaterOrEqual(next), next.arena()), - KeySelector(firstGreaterOrEqual(normalKeys.end)), GetRangeLimits()); + state Future stream = tx.getRangeStream(results, + KeySelector(firstGreaterOrEqual(next), next.arena()), + KeySelector(firstGreaterOrEqual(normalKeys.end)), + GetRangeLimits()); loop { Standalone range = waitNext(results.getFuture()); if (range.size()) { @@ -446,9 +447,10 @@ ACTOR Future fdbClientGetRange() { state Future logFuture = logThroughput(&bytes, &next); loop { try { - Standalone range = wait(tx.getRange( - KeySelector(firstGreaterOrEqual(next), next.arena()), KeySelector(firstGreaterOrEqual(normalKeys.end)), - GetRangeLimits(GetRangeLimits::ROW_LIMIT_UNLIMITED, CLIENT_KNOBS->REPLY_BYTE_LIMIT))); + Standalone range = + wait(tx.getRange(KeySelector(firstGreaterOrEqual(next), next.arena()), + KeySelector(firstGreaterOrEqual(normalKeys.end)), + GetRangeLimits(GetRangeLimits::ROW_LIMIT_UNLIMITED, CLIENT_KNOBS->REPLY_BYTE_LIMIT))); bytes += range.expectedSize(); if (!range.more) { break; diff --git a/fdbclient/FDBTypes.h b/fdbclient/FDBTypes.h index 6af364fbd68..76ad36416c4 100644 --- a/fdbclient/FDBTypes.h +++ b/fdbclient/FDBTypes.h @@ -709,7 +709,7 @@ struct RangeResultRef : VectorRef { using RangeResult = Standalone; -template<> +template <> struct Traceable : std::true_type { static std::string toString(const RangeResultRef& value) { return Traceable>::toString(value); diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index 65bebc29eef..d783e073bb6 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -927,7 +927,7 @@ DatabaseContext::DatabaseContext(Reference( KeyRangeRef(LiteralStringRef("profiling/"), LiteralStringRef("profiling0")) - .withPrefix(SpecialKeySpace::getModuleRange(SpecialKeySpace::MODULE::MANAGEMENT).begin))); + .withPrefix(SpecialKeySpace::getModuleRange(SpecialKeySpace::MODULE::MANAGEMENT).begin))); registerSpecialKeySpaceModule( - SpecialKeySpace::MODULE::MANAGEMENT, SpecialKeySpace::IMPLTYPE::READWRITE, + SpecialKeySpace::MODULE::MANAGEMENT, + SpecialKeySpace::IMPLTYPE::READWRITE, std::make_unique( KeyRangeRef(LiteralStringRef("maintenance/"), LiteralStringRef("maintenance0")) .withPrefix(SpecialKeySpace::getModuleRange(SpecialKeySpace::MODULE::MANAGEMENT).begin))); registerSpecialKeySpaceModule( - SpecialKeySpace::MODULE::MANAGEMENT, SpecialKeySpace::IMPLTYPE::READWRITE, + SpecialKeySpace::MODULE::MANAGEMENT, + SpecialKeySpace::IMPLTYPE::READWRITE, std::make_unique( KeyRangeRef(LiteralStringRef("data_distribution/"), LiteralStringRef("data_distribution0")) .withPrefix(SpecialKeySpace::getModuleRange(SpecialKeySpace::MODULE::MANAGEMENT).begin))); @@ -1161,7 +1163,7 @@ DatabaseContext::DatabaseContext(const Error& err) transactionPhysicalReadsCompleted("PhysicalReadRequestsCompleted", cc), transactionGetKeyRequests("GetKeyRequests", cc), transactionGetValueRequests("GetValueRequests", cc), transactionGetRangeRequests("GetRangeRequests", cc), - transactionGetRangeStreamRequests("GetRangeStreamRequests", cc), transactionWatchRequests("WatchRequests", cc), + transactionGetRangeStreamRequests("GetRangeStreamRequests", cc), transactionWatchRequests("WatchRequests", cc), transactionGetAddressesForKeyRequests("GetAddressesForKeyRequests", cc), transactionBytesRead("BytesRead", cc), transactionKeysRead("KeysRead", cc), transactionMetadataVersionReads("MetadataVersionReads", cc), transactionCommittedMutations("CommittedMutations", cc), @@ -3260,45 +3262,54 @@ ACTOR Future> getRange(Database cx, } } -ACTOR Future getRangeStreamFragment(ParallelStream::Fragment* results, Database cx, - Reference trLogInfo, Version version, KeyRange keys, - GetRangeLimits limits, bool snapshot, bool reverse, TransactionInfo info, - TagSet tags, SpanID spanContext) { +ACTOR Future getRangeStreamFragment(ParallelStream::Fragment* results, + Database cx, + Reference trLogInfo, + Version version, + KeyRange keys, + GetRangeLimits limits, + bool snapshot, + bool reverse, + TransactionInfo info, + TagSet tags, + SpanID spanContext) { loop { - state vector< pair> > locations = wait( getKeyRangeLocations( cx, keys, CLIENT_KNOBS->GET_RANGE_SHARD_LIMIT, reverse, &StorageServerInterface::getKeyValuesStream, info ) ); - ASSERT( locations.size() ); + state vector>> locations = wait(getKeyRangeLocations( + cx, keys, CLIENT_KNOBS->GET_RANGE_SHARD_LIMIT, reverse, &StorageServerInterface::getKeyValuesStream, info)); + ASSERT(locations.size()); state int shard = 0; loop { const KeyRange& range = locations[shard].first; state GetKeyValuesStreamRequest req; req.version = version; - req.begin = firstGreaterOrEqual( range.begin ); - req.end = firstGreaterOrEqual( range.end ); + req.begin = firstGreaterOrEqual(range.begin); + req.end = firstGreaterOrEqual(range.end); req.spanContext = spanContext; req.limit = reverse ? -CLIENT_KNOBS->REPLY_BYTE_LIMIT : CLIENT_KNOBS->REPLY_BYTE_LIMIT; req.limitBytes = std::numeric_limits::max(); ASSERT(req.limitBytes > 0 && req.limit != 0 && req.limit < 0 == reverse); - //FIXME: buggify byte limits on internal functions that use them, instead of globally + // FIXME: buggify byte limits on internal functions that use them, instead of globally req.tags = cx->sampleReadTags() ? tags : Optional(); req.debugID = info.debugID; try { - if( info.debugID.present() ) { - g_traceBatch.addEvent("TransactionDebug", info.debugID.get().first(), "NativeAPI.RangeStream.Before"); + if (info.debugID.present()) { + g_traceBatch.addEvent( + "TransactionDebug", info.debugID.get().first(), "NativeAPI.RangeStream.Before"); } ++cx->transactionPhysicalReads; state GetKeyValuesStreamReply rep; - if( locations[shard].second->size() == 0 ) { + if (locations[shard].second->size() == 0) { wait(cx->connectionFileChanged()); results->sendError(transaction_too_old()); return Void(); } - //FIXME: add load balancing + // FIXME: add load balancing state ReplyPromiseStream replyStream = locations[shard] .second->getInterface(deterministicRandom()->randomInt(0, locations[shard].second->size())) @@ -3312,9 +3323,7 @@ ACTOR Future getRangeStreamFragment(ParallelStream::Fragment* return Void(); } - when(GetKeyValuesStreamReply _rep = waitNext(replyStream.getFuture())) { - rep = _rep; - } + when(GetKeyValuesStreamReply _rep = waitNext(replyStream.getFuture())) { rep = _rep; } } ++cx->transactionPhysicalReadsCompleted; } catch (Error& e) { @@ -3325,60 +3334,69 @@ ACTOR Future getRangeStreamFragment(ParallelStream::Fragment* throw; } } - if( info.debugID.present() ) - g_traceBatch.addEvent("TransactionDebug", info.debugID.get().first(), "NativeAPI.getExactRange.After"); + if (info.debugID.present()) + g_traceBatch.addEvent( + "TransactionDebug", info.debugID.get().first(), "NativeAPI.getExactRange.After"); RangeResult output(RangeResultRef(rep.data, true), rep.arena); bool more = rep.more; // If the reply says there is more but we know that we finished the shard, then fix rep.more - if( reverse && more && rep.data.size() > 0 && output[output.size()-1].key == locations[shard].first.begin ) { + if (reverse && more && rep.data.size() > 0 && + output[output.size() - 1].key == locations[shard].first.begin) { more = false; } if (more) { - if( !rep.data.size() ) { - TraceEvent(SevError, "GetRangeStreamError").detail("Reason", "More data indicated but no rows present") - .detail("LimitBytes", limits.bytes).detail("LimitRows", limits.rows) - .detail("OutputSize", output.size()).detail("OutputBytes", output.expectedSize()) - .detail("BlockSize", rep.data.size()).detail("BlockBytes", rep.data.expectedSize()); - ASSERT( false ); + if (!rep.data.size()) { + TraceEvent(SevError, "GetRangeStreamError") + .detail("Reason", "More data indicated but no rows present") + .detail("LimitBytes", limits.bytes) + .detail("LimitRows", limits.rows) + .detail("OutputSize", output.size()) + .detail("OutputBytes", output.expectedSize()) + .detail("BlockSize", rep.data.size()) + .detail("BlockBytes", rep.data.expectedSize()); + ASSERT(false); } - TEST(true); // GetKeyValuesStreamReply.more in getRangeStream + TEST(true); // GetKeyValuesStreamReply.more in getRangeStream // Make next request to the same shard with a beginning key just after the last key returned - if( reverse ) - locations[shard].first = KeyRangeRef( locations[shard].first.begin, output[output.size()-1].key ); + if (reverse) + locations[shard].first = + KeyRangeRef(locations[shard].first.begin, output[output.size() - 1].key); else - locations[shard].first = KeyRangeRef( keyAfter( output[output.size()-1].key ), locations[shard].first.end ); + locations[shard].first = + KeyRangeRef(keyAfter(output[output.size() - 1].key), locations[shard].first.end); } if (!more || locations[shard].first.empty()) { TEST(true); // getRangeStream (!more || locations[shard].first.empty()) const KeyRange& range = locations[shard].first; - if(shard == locations.size()-1) { + if (shard == locations.size() - 1) { KeyRef begin = reverse ? keys.begin : range.end; KeyRef end = reverse ? range.begin : keys.end; - if(begin >= end) { + if (begin >= end) { if (range.begin == allKeys.begin) { output.readToBegin = true; } if (range.end == allKeys.end) { output.readThroughEnd = true; } - output.arena().dependsOn( keys.arena() ); + output.arena().dependsOn(keys.arena()); output.readThrough = reverse ? keys.begin : keys.end; int64_t bytes = 0; - for(const KeyValueRef &kv : output) { + for (const KeyValueRef& kv : output) { bytes += kv.key.size() + kv.value.size(); } cx->transactionBytesRead += bytes; cx->transactionKeysRead += output.size(); - //FIXME: figure out appropriate metrics for the client event log - //if( trLogInfo ) { - // trLogInfo->addLog(FdbClientLogEvents::EventGetRange(startTime, cx->clientLocality.dcId(), now()-startTime, bytes, begin.getKey(), end.getKey())); + // FIXME: figure out appropriate metrics for the client event log + // if( trLogInfo ) { + // trLogInfo->addLog(FdbClientLogEvents::EventGetRange(startTime, + //cx->clientLocality.dcId(), now()-startTime, bytes, begin.getKey(), end.getKey())); //} results->send(std::move(output)); @@ -3391,7 +3409,7 @@ ACTOR Future getRangeStreamFragment(ParallelStream::Fragment* breakAgain = true; break; } else { - output.arena().dependsOn( range.arena() ); + output.arena().dependsOn(range.arena()); output.readThrough = reverse ? range.begin : range.end; results->send(std::move(output)); ++shard; @@ -3417,7 +3435,7 @@ ACTOR Future getRangeStreamFragment(ParallelStream::Fragment* // FIXME: figure out appropriate metrics for the client event log // if( trLogInfo ) { // trLogInfo->addLog(FdbClientLogEvents::EventGetRange(startTime, cx->clientLocality.dcId(), - //now()-startTime, bytes, begin.getKey(), end.getKey())); + // now()-startTime, bytes, begin.getKey(), end.getKey())); //} results->send(std::move(output)); } @@ -3428,16 +3446,17 @@ ACTOR Future getRangeStreamFragment(ParallelStream::Fragment* if (e.code() == error_code_actor_cancelled) { throw; } - if (e.code() == error_code_wrong_shard_server || e.code() == error_code_all_alternatives_failed || e.code() == error_code_connection_failed) { + if (e.code() == error_code_wrong_shard_server || e.code() == error_code_all_alternatives_failed || + e.code() == error_code_connection_failed) { const KeyRangeRef& range = locations[shard].first; - if( reverse ) - keys = KeyRangeRef( keys.begin, range.end ); + if (reverse) + keys = KeyRangeRef(keys.begin, range.end); else - keys = KeyRangeRef( range.begin, keys.end ); + keys = KeyRangeRef(range.begin, keys.end); - cx->invalidateCache( keys ); - wait( delay(CLIENT_KNOBS->WRONG_SHARD_SERVER_DELAY, info.taskID )); + cx->invalidateCache(keys); + wait(delay(CLIENT_KNOBS->WRONG_SHARD_SERVER_DELAY, info.taskID)); break; } else { results->sendError(e); @@ -3454,13 +3473,21 @@ static KeyRange intersect(KeyRangeRef lhs, KeyRangeRef rhs) { return KeyRange(KeyRangeRef(std::max(lhs.begin, rhs.begin), std::min(lhs.end, rhs.end))); } -ACTOR Future getRangeStream(PromiseStream _results, Database cx, - Reference trLogInfo, Future fVersion, KeySelector begin, - KeySelector end, GetRangeLimits limits, Promise> conflictRange, - bool snapshot, bool reverse, TransactionInfo info, TagSet tags) { +ACTOR Future getRangeStream(PromiseStream _results, + Database cx, + Reference trLogInfo, + Future fVersion, + KeySelector begin, + KeySelector end, + GetRangeLimits limits, + Promise> conflictRange, + bool snapshot, + bool reverse, + TransactionInfo info, + TagSet tags) { - state ParallelStream results(_results, CLIENT_KNOBS->RANGESTREAM_CONCURRENT_FRAGMENTS, - CLIENT_KNOBS->RANGESTREAM_BUFFERED_FRAGMENTS_LIMIT); + state ParallelStream results( + _results, CLIENT_KNOBS->RANGESTREAM_CONCURRENT_FRAGMENTS, CLIENT_KNOBS->RANGESTREAM_BUFFERED_FRAGMENTS_LIMIT); // FIXME: better handling to disable row limits ASSERT(!limits.hasRowLimit()); @@ -3486,14 +3513,14 @@ ACTOR Future getRangeStream(PromiseStream _results, Database return Void(); } - //if e is allKeys.end, we have read through the end of the database - //if b is allKeys.begin, we have either read through the beginning of the database, - //or allKeys.begin exists in the database and will be part of the conflict range anyways + // if e is allKeys.end, we have read through the end of the database + // if b is allKeys.begin, we have either read through the beginning of the database, + // or allKeys.begin exists in the database and will be part of the conflict range anyways state std::vector> outstandingRequests; loop { - state pair> ssi = - wait(getKeyLocation(cx, reverse ? e : b, &StorageServerInterface::getKeyValuesStream, info, reverse)); + state pair> ssi = + wait(getKeyLocation(cx, reverse ? e : b, &StorageServerInterface::getKeyValuesStream, info, reverse)); state KeyRange shardIntersection = intersect(ssi.first, KeyRangeRef(b, e)); state Standalone> splitPoints = wait(getRangeSplitPoints(cx, shardIntersection, CLIENT_KNOBS->RANGESTREAM_FRAGMENT_SIZE)); @@ -3518,15 +3545,15 @@ ACTOR Future getRangeStream(PromiseStream _results, Database continue; } ParallelStream::Fragment* fragment = wait(results.createFragment()); - outstandingRequests.push_back(getRangeStreamFragment(fragment, cx, trLogInfo, version, toSend[useIdx], limits, - snapshot, reverse, info, tags, span.context)); + outstandingRequests.push_back(getRangeStreamFragment( + fragment, cx, trLogInfo, version, toSend[useIdx], limits, snapshot, reverse, info, tags, span.context)); } - if(reverse) { + if (reverse) { e = shardIntersection.begin; } else { b = shardIntersection.end; } - if(b >= e) { + if (b >= e) { break; } } @@ -3889,23 +3916,21 @@ Future> Transaction::getRange(const KeySelector& begi return getRange(begin, end, GetRangeLimits(limit), snapshot, reverse); } -Future Transaction::getRangeStream( - const PromiseStream>& results, - const KeySelector& begin, - const KeySelector& end, - GetRangeLimits limits, - bool snapshot, - bool reverse ) -{ +Future Transaction::getRangeStream(const PromiseStream>& results, + const KeySelector& begin, + const KeySelector& end, + GetRangeLimits limits, + bool snapshot, + bool reverse) { ++cx->transactionLogicalReads; ++cx->transactionGetRangeStreamRequests; - if( limits.isReached() ) { + if (limits.isReached()) { results.sendError(end_of_stream()); return Void(); } - if( !limits.isValid() ) { + if (!limits.isValid()) { results.sendError(range_limits_invalid()); return Void(); } @@ -3913,44 +3938,54 @@ Future Transaction::getRangeStream( ASSERT(limits.rows != 0); KeySelector b = begin; - if( b.orEqual ) { + if (b.orEqual) { TEST(true); // Native stream begin orEqual==true b.removeOrEqual(b.arena()); } KeySelector e = end; - if( e.orEqual ) { + if (e.orEqual) { TEST(true); // Native stream end orEqual==true e.removeOrEqual(e.arena()); } - if( b.offset >= e.offset && b.getKey() >= e.getKey() ) { + if (b.offset >= e.offset && b.getKey() >= e.getKey()) { TEST(true); // Native stream range inverted results.sendError(end_of_stream()); return Void(); } Promise> conflictRange; - if(!snapshot) { - extraConflictRanges.push_back( conflictRange.getFuture() ); + if (!snapshot) { + extraConflictRanges.push_back(conflictRange.getFuture()); } - return forwardErrors(::getRangeStream(results, cx, trLogInfo, getReadVersion(), b, e, limits, conflictRange, snapshot, reverse, info, options.readTags), results); -} - -Future Transaction::getRangeStream( - const PromiseStream>& results, - const KeySelector& begin, - const KeySelector& end, - int limit, - bool snapshot, - bool reverse ) -{ - return getRangeStream( results, begin, end, GetRangeLimits( limit ), snapshot, reverse ); + return forwardErrors(::getRangeStream(results, + cx, + trLogInfo, + getReadVersion(), + b, + e, + limits, + conflictRange, + snapshot, + reverse, + info, + options.readTags), + results); +} + +Future Transaction::getRangeStream(const PromiseStream>& results, + const KeySelector& begin, + const KeySelector& end, + int limit, + bool snapshot, + bool reverse) { + return getRangeStream(results, begin, end, GetRangeLimits(limit), snapshot, reverse); } -void Transaction::addReadConflictRange( KeyRangeRef const& keys ) { - ASSERT( !keys.empty() ); +void Transaction::addReadConflictRange(KeyRangeRef const& keys) { + ASSERT(!keys.empty()); // There aren't any keys in the database with size larger than KEY_SIZE_LIMIT, so if range contains large keys // we can translate it to an equivalent one with smaller keys diff --git a/fdbclient/NativeAPI.actor.h b/fdbclient/NativeAPI.actor.h index 99e18a6b421..c6b537a3650 100644 --- a/fdbclient/NativeAPI.actor.h +++ b/fdbclient/NativeAPI.actor.h @@ -283,20 +283,41 @@ class Transaction : NonCopyable { reverse); } - [[nodiscard]] Future getRangeStream(const PromiseStream>& results, const KeySelector& begin, const KeySelector& end, - int limit, bool snapshot = false, bool reverse = false); - [[nodiscard]] Future getRangeStream(const PromiseStream>& results, const KeySelector& begin, const KeySelector& end, - GetRangeLimits limits, bool snapshot = false, - bool reverse = false); - [[nodiscard]] Future getRangeStream(const PromiseStream>& results, const KeyRange& keys, int limit, bool snapshot = false, - bool reverse = false) { - return getRangeStream(results, KeySelector(firstGreaterOrEqual(keys.begin), keys.arena()), - KeySelector(firstGreaterOrEqual(keys.end), keys.arena()), limit, snapshot, reverse); + [[nodiscard]] Future getRangeStream(const PromiseStream>& results, + const KeySelector& begin, + const KeySelector& end, + int limit, + bool snapshot = false, + bool reverse = false); + [[nodiscard]] Future getRangeStream(const PromiseStream>& results, + const KeySelector& begin, + const KeySelector& end, + GetRangeLimits limits, + bool snapshot = false, + bool reverse = false); + [[nodiscard]] Future getRangeStream(const PromiseStream>& results, + const KeyRange& keys, + int limit, + bool snapshot = false, + bool reverse = false) { + return getRangeStream(results, + KeySelector(firstGreaterOrEqual(keys.begin), keys.arena()), + KeySelector(firstGreaterOrEqual(keys.end), keys.arena()), + limit, + snapshot, + reverse); } - [[nodiscard]] Future getRangeStream(const PromiseStream>& results, const KeyRange& keys, GetRangeLimits limits, - bool snapshot = false, bool reverse = false) { - return getRangeStream(results, KeySelector(firstGreaterOrEqual(keys.begin), keys.arena()), - KeySelector(firstGreaterOrEqual(keys.end), keys.arena()), limits, snapshot, reverse); + [[nodiscard]] Future getRangeStream(const PromiseStream>& results, + const KeyRange& keys, + GetRangeLimits limits, + bool snapshot = false, + bool reverse = false) { + return getRangeStream(results, + KeySelector(firstGreaterOrEqual(keys.begin), keys.arena()), + KeySelector(firstGreaterOrEqual(keys.end), keys.arena()), + limits, + snapshot, + reverse); } [[nodiscard]] Future>> getAddressesForKey(const Key& key); diff --git a/fdbclient/ParallelStream.actor.cpp b/fdbclient/ParallelStream.actor.cpp index beb7f42dc75..e8372b39fa2 100644 --- a/fdbclient/ParallelStream.actor.cpp +++ b/fdbclient/ParallelStream.actor.cpp @@ -52,9 +52,9 @@ ACTOR static Future consume(FutureStream stream, int expected) { TEST_CASE("/fdbclient/ParallelStream") { state PromiseStream results; - state size_t concurrency = deterministicRandom()->randomInt(1,11); + state size_t concurrency = deterministicRandom()->randomInt(1, 11); state size_t bufferLimit = concurrency + deterministicRandom()->randomInt(0, 11); - state size_t numProducers = deterministicRandom()->randomInt(1,1001); + state size_t numProducers = deterministicRandom()->randomInt(1, 1001); state ParallelStream parallelStream(results, concurrency, bufferLimit); state Future consumer = ParallelStreamTest::consume(results.getFuture(), numProducers); state std::vector> producers; diff --git a/fdbclient/ParallelStream.actor.h b/fdbclient/ParallelStream.actor.h index 0357f17d70b..d4562749da9 100644 --- a/fdbclient/ParallelStream.actor.h +++ b/fdbclient/ParallelStream.actor.h @@ -44,11 +44,12 @@ class ParallelStream { PromiseStream stream; BoundedFlowLock::Releaser releaser; friend class ParallelStream; + public: Fragment(ParallelStream* parallelStream, int64_t permitNumber, FragmentConstructorTag) : parallelStream(parallelStream), releaser(¶llelStream->semaphore, permitNumber) {} - template - void send(U &&value) { + template + void send(U&& value) { stream.send(std::forward(value)); } void sendError(Error e) { stream.sendError(e); } @@ -60,7 +61,7 @@ class ParallelStream { private: PromiseStream> fragments; - size_t fragmentsProcessed { 0 }; + size_t fragmentsProcessed{ 0 }; PromiseStream results; Future flusher; diff --git a/fdbclient/StorageServerInterface.h b/fdbclient/StorageServerInterface.h index f6040cbe5df..5548107e433 100644 --- a/fdbclient/StorageServerInterface.h +++ b/fdbclient/StorageServerInterface.h @@ -109,7 +109,8 @@ struct StorageServerInterface { RequestStream(getValue.getEndpoint().getAdjustedEndpoint(11)); getRangeSplitPoints = RequestStream(getValue.getEndpoint().getAdjustedEndpoint(12)); - getKeyValuesStream = RequestStream(getValue.getEndpoint().getAdjustedEndpoint(13)); + getKeyValuesStream = + RequestStream(getValue.getEndpoint().getAdjustedEndpoint(13)); } } else { ASSERT(Ar::isDeserializing); @@ -296,12 +297,13 @@ struct GetKeyValuesStreamReply : public ReplyPromiseStreamReply { bool cached = false; GetKeyValuesStreamReply() : version(invalidVersion), more(false), cached(false) {} - GetKeyValuesStreamReply(GetKeyValuesReply r) : arena(r.arena), data(r.data), version(r.version), more(r.more), cached(r.cached) {} + GetKeyValuesStreamReply(GetKeyValuesReply r) + : arena(r.arena), data(r.data), version(r.version), more(r.more), cached(r.cached) {} int expectedSize() const { return sizeof(GetKeyValuesStreamReply) + data.expectedSize(); } template - void serialize( Ar& ar ) { + void serialize(Ar& ar) { serializer(ar, ReplyPromiseStreamReply::acknowledgeToken, data, version, more, cached, arena); } }; @@ -311,7 +313,7 @@ struct GetKeyValuesStreamRequest { SpanID spanContext; Arena arena; KeySelectorRef begin, end; - Version version; // or latestVersion + Version version; // or latestVersion int limit, limitBytes; bool isFetchKeys; Optional tags; @@ -320,7 +322,7 @@ struct GetKeyValuesStreamRequest { GetKeyValuesStreamRequest() : isFetchKeys(false) {} template - void serialize( Ar& ar ) { + void serialize(Ar& ar) { serializer(ar, begin, end, version, limit, limitBytes, isFetchKeys, tags, debugID, reply, spanContext, arena); } }; diff --git a/fdbrpc/FailureMonitor.actor.cpp b/fdbrpc/FailureMonitor.actor.cpp index 438a891a27a..58980d1f085 100644 --- a/fdbrpc/FailureMonitor.actor.cpp +++ b/fdbrpc/FailureMonitor.actor.cpp @@ -126,10 +126,9 @@ void SimpleFailureMonitor::endpointNotFound(Endpoint const& endpoint) { .suppressFor(1.0) .detail("Address", endpoint.getPrimaryAddress()) .detail("Token", endpoint.token); - if(endpoint.getPrimaryAddress().isPublic()) { - if(failedEndpoints.size() > 100000) { - TraceEvent(SevWarnAlways, "TooManyFailedEndpoints") - .suppressFor(1.0); + if (endpoint.getPrimaryAddress().isPublic()) { + if (failedEndpoints.size() > 100000) { + TraceEvent(SevWarnAlways, "TooManyFailedEndpoints").suppressFor(1.0); failedEndpoints.clear(); } failedEndpoints.insert(endpoint); diff --git a/fdbrpc/FlowTransport.actor.cpp b/fdbrpc/FlowTransport.actor.cpp index 3a753008f8c..83a9f00c6c7 100644 --- a/fdbrpc/FlowTransport.actor.cpp +++ b/fdbrpc/FlowTransport.actor.cpp @@ -950,10 +950,16 @@ ACTOR static void deliver(TransportData* self, // We don't have the (stream) endpoint 'token', notify the remote machine if (destination.token.first() != -1) { if (self->isLocalAddress(destination.getPrimaryAddress())) { - sendLocal(self, SerializeSource(destination.token), Endpoint(destination.addresses, WLTOKEN_ENDPOINT_NOT_FOUND)); + sendLocal(self, + SerializeSource(destination.token), + Endpoint(destination.addresses, WLTOKEN_ENDPOINT_NOT_FOUND)); } else { Reference peer = self->getOrOpenPeer(destination.getPrimaryAddress()); - sendPacket(self, peer, SerializeSource(destination.token), Endpoint(destination.addresses, WLTOKEN_ENDPOINT_NOT_FOUND), false); + sendPacket(self, + peer, + SerializeSource(destination.token), + Endpoint(destination.addresses, WLTOKEN_ENDPOINT_NOT_FOUND), + false); } } } @@ -1209,7 +1215,7 @@ ACTOR static Future connectionReader(TransportData* transport, } compatible = false; if (!protocolVersion.hasInexpensiveMultiVersionClient()) { - if(peer) { + if (peer) { peer->protocolVersion->set(protocolVersion); } @@ -1472,7 +1478,8 @@ void FlowTransport::addPeerReference(const Endpoint& endpoint, bool isStream) { } void FlowTransport::removePeerReference(const Endpoint& endpoint, bool isStream) { - if (!isStream || !endpoint.getPrimaryAddress().isValid() || !endpoint.getPrimaryAddress().isPublic()) return; + if (!isStream || !endpoint.getPrimaryAddress().isValid() || !endpoint.getPrimaryAddress().isPublic()) + return; Reference peer = self->getPeer(endpoint.getPrimaryAddress()); if (peer) { peer->peerReferences--; diff --git a/fdbrpc/FlowTransport.h b/fdbrpc/FlowTransport.h index 7387281e324..e7078288034 100644 --- a/fdbrpc/FlowTransport.h +++ b/fdbrpc/FlowTransport.h @@ -64,7 +64,7 @@ class Endpoint { NetworkAddress getStableAddress() const { return addresses.getTLSAddress(); } - Endpoint getAdjustedEndpoint( uint32_t index ) const { + Endpoint getAdjustedEndpoint(uint32_t index) const { uint32_t newIndex = token.second(); newIndex += index; return Endpoint( diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index 4e40b6206ee..cdef40ce129 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -79,9 +79,7 @@ struct FlowReceiver : public NetworkMessageReceiver { FlowTransport::transport().addWellKnownEndpoint(endpoint, this, taskID); } - const Endpoint& getRawEndpoint() { - return endpoint; - } + const Endpoint& getRawEndpoint() { return endpoint; } private: Optional peerCompatibilityPolicy_; @@ -107,8 +105,8 @@ struct NetSAV final : SAV, FlowReceiver, FastAllocated> { ErrorOr> message; reader.deserialize(message); if (message.isError()) { - if(message.getError().code() == error_code_broken_promise) { - IFailureMonitor::failureMonitor().endpointNotFound( getRawEndpoint() ); + if (message.getError().code() == error_code_broken_promise) { + IFailureMonitor::failureMonitor().endpointNotFound(getRawEndpoint()); } SAV::sendErrorAndDelPromiseRef(message.getError()); } else { @@ -271,7 +269,7 @@ struct AcknowledgementReply { explicit AcknowledgementReply(int64_t bytes) : bytes(bytes) {} template - void serialize( Ar& ar ) { + void serialize(Ar& ar) { serializer(ar, bytes); } }; @@ -286,21 +284,22 @@ struct AcknowledgementReceiver final : FlowReceiver, FastAllocated failures; AcknowledgementReceiver() : bytesSent(0), bytesAcknowledged(0), ready(nullptr) {} - AcknowledgementReceiver(const Endpoint& remoteEndpoint) : FlowReceiver(remoteEndpoint, false), - bytesSent(0), bytesAcknowledged(0), ready(nullptr) {} + AcknowledgementReceiver(const Endpoint& remoteEndpoint) + : FlowReceiver(remoteEndpoint, false), bytesSent(0), bytesAcknowledged(0), ready(nullptr) {} void receive(ArenaObjectReader& reader) override { ErrorOr message; reader.deserialize(message); - if(message.isError()) { - if(!ready.isValid() || ready.isSet()) { + if (message.isError()) { + if (!ready.isValid() || ready.isSet()) { ready = Promise(); } ready.sendError(message.getError()); } else { ASSERT(message.get().bytes > bytesAcknowledged); bytesAcknowledged = message.get().bytes; - if (bytesSent - bytesAcknowledged < FLOW_KNOBS->ACKNOWLEDGE_LIMIT_BYTES && ready.isValid() && ready.canBeSet()) { + if (bytesSent - bytesAcknowledged < FLOW_KNOBS->ACKNOWLEDGE_LIMIT_BYTES && ready.isValid() && + ready.canBeSet()) { ready.send(Void()); } } @@ -316,9 +315,10 @@ struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAl NetNotifiedQueueWithErrors(int futures, int promises) : NotifiedQueue(futures, promises) {} NetNotifiedQueueWithErrors(int futures, int promises, const Endpoint& remoteEndpoint) - : NotifiedQueue(futures, promises), FlowReceiver(remoteEndpoint, true) { - acknowledgements.failures = tagError(makeDependent(IFailureMonitor::failureMonitor()).onDisconnect(remoteEndpoint), operation_obsolete()); - } + : NotifiedQueue(futures, promises), FlowReceiver(remoteEndpoint, true) { + acknowledgements.failures = tagError( + makeDependent(IFailureMonitor::failureMonitor()).onDisconnect(remoteEndpoint), operation_obsolete()); + } void destroy() override { delete this; } void receive(ArenaObjectReader& reader) override { @@ -327,18 +327,23 @@ struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAl reader.deserialize(message); if (message.isError()) { - if(message.getError().code() == error_code_broken_promise) { - IFailureMonitor::failureMonitor().endpointNotFound( getRawEndpoint() ); + if (message.getError().code() == error_code_broken_promise) { + IFailureMonitor::failureMonitor().endpointNotFound(getRawEndpoint()); } this->sendError(message.getError()); } else { - if(message.get().asUnderlyingType().acknowledgeToken.present()) { - acknowledgements = AcknowledgementReceiver(FlowTransport::transport().loadedEndpoint(message.get().asUnderlyingType().acknowledgeToken.get())); + if (message.get().asUnderlyingType().acknowledgeToken.present()) { + acknowledgements = AcknowledgementReceiver( + FlowTransport::transport().loadedEndpoint(message.get().asUnderlyingType().acknowledgeToken.get())); } - if(this->shouldFireImmediately()) { - if(acknowledgements.getRawEndpoint().isValid()) { + if (this->shouldFireImmediately()) { + if (acknowledgements.getRawEndpoint().isValid()) { acknowledgements.bytesAcknowledged += message.get().asUnderlyingType().expectedSize(); - FlowTransport::transport().sendUnreliable(SerializeSource>(AcknowledgementReply(acknowledgements.bytesAcknowledged)), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint), false); + FlowTransport::transport().sendUnreliable( + SerializeSource>( + AcknowledgementReply(acknowledgements.bytesAcknowledged)), + acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint), + false); } } @@ -349,16 +354,23 @@ struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAl T pop() override { T res = this->popImpl(); - if(acknowledgements.getRawEndpoint().isValid()) { + if (acknowledgements.getRawEndpoint().isValid()) { acknowledgements.bytesAcknowledged += res.expectedSize(); - FlowTransport::transport().sendUnreliable(SerializeSource>(AcknowledgementReply(acknowledgements.bytesAcknowledged)), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint), false); + FlowTransport::transport().sendUnreliable( + SerializeSource>( + AcknowledgementReply(acknowledgements.bytesAcknowledged)), + acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint), + false); } return res; } ~NetNotifiedQueueWithErrors() { - if(acknowledgements.getRawEndpoint().isValid() && acknowledgements.isRemoteEndpoint() && !this->hasError()) { - FlowTransport::transport().sendUnreliable(SerializeSource>(operation_obsolete()), acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint), false); + if (acknowledgements.getRawEndpoint().isValid() && acknowledgements.isRemoteEndpoint() && !this->hasError()) { + FlowTransport::transport().sendUnreliable( + SerializeSource>(operation_obsolete()), + acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint), + false); } } @@ -371,45 +383,56 @@ class ReplyPromiseStream { // stream.send( request ) // Unreliable at most once delivery: Delivers request unless there is a connection failure (zero or one times) - template - void send(U && value) const { + template + void send(U&& value) const { if (queue->isRemoteEndpoint()) { - if(!queue->acknowledgements.getRawEndpoint().isValid()) { + if (!queue->acknowledgements.getRawEndpoint().isValid()) { value.acknowledgeToken = queue->acknowledgements.getEndpoint(TaskPriority::DefaultEndpoint).token; } queue->acknowledgements.bytesSent += value.expectedSize(); - if((!queue->acknowledgements.ready.isValid() || (queue->acknowledgements.ready.isSet() && !queue->acknowledgements.ready.getFuture().isError())) && queue->acknowledgements.bytesSent - queue->acknowledgements.bytesAcknowledged >= FLOW_KNOBS->ACKNOWLEDGE_LIMIT_BYTES) { + if ((!queue->acknowledgements.ready.isValid() || + (queue->acknowledgements.ready.isSet() && !queue->acknowledgements.ready.getFuture().isError())) && + queue->acknowledgements.bytesSent - queue->acknowledgements.bytesAcknowledged >= + FLOW_KNOBS->ACKNOWLEDGE_LIMIT_BYTES) { queue->acknowledgements.ready = Promise(); } - FlowTransport::transport().sendUnreliable(SerializeSource>>(value), getEndpoint(), false); - } - else { + FlowTransport::transport().sendUnreliable( + SerializeSource>>(value), getEndpoint(), false); + } else { queue->send(std::forward(value)); } } template - void sendError(const E& exc) const { + void sendError(const E& exc) const { if (queue->isRemoteEndpoint()) { - FlowTransport::transport().sendUnreliable(SerializeSource>>(exc), getEndpoint(), false); + FlowTransport::transport().sendUnreliable( + SerializeSource>>(exc), getEndpoint(), false); } else { queue->sendError(exc); - if(errors && errors->canBeSet()) { + if (errors && errors->canBeSet()) { errors->sendError(exc); } } } - FutureStream getFuture() const { queue->addFutureRef(); return FutureStream(queue); } + FutureStream getFuture() const { + queue->addFutureRef(); + return FutureStream(queue); + } ReplyPromiseStream() : queue(new NetNotifiedQueueWithErrors(0, 1)), errors(new SAV(0, 1)) {} - ReplyPromiseStream(const ReplyPromiseStream& rhs) : queue(rhs.queue), errors(rhs.errors) { + ReplyPromiseStream(const ReplyPromiseStream& rhs) : queue(rhs.queue), errors(rhs.errors) { queue->addPromiseRef(); - if(errors) { + if (errors) { errors->addPromiseRef(); } } - ReplyPromiseStream(ReplyPromiseStream&& rhs) noexcept : queue(rhs.queue), errors(rhs.errors) { rhs.queue = nullptr; rhs.errors = nullptr; } - explicit ReplyPromiseStream(const Endpoint& endpoint) : queue(new NetNotifiedQueueWithErrors(0, 1, endpoint)), errors(nullptr) {} + ReplyPromiseStream(ReplyPromiseStream&& rhs) noexcept : queue(rhs.queue), errors(rhs.errors) { + rhs.queue = nullptr; + rhs.errors = nullptr; + } + explicit ReplyPromiseStream(const Endpoint& endpoint) + : queue(new NetNotifiedQueueWithErrors(0, 1, endpoint)), errors(nullptr) {} Future getErrorFutureAndDelPromiseRef() { ASSERT(errors && errors->getPromiseReferenceCount() > 1); @@ -419,7 +442,7 @@ class ReplyPromiseStream { errors = nullptr; return res; } - + ~ReplyPromiseStream() { if (queue) queue->delPromiseRef(); @@ -428,21 +451,23 @@ class ReplyPromiseStream { } const Endpoint& getEndpoint(TaskPriority taskID = TaskPriority::DefaultEndpoint) const { - return queue->getEndpoint(taskID); + return queue->getEndpoint(taskID); } - - bool operator == (const ReplyPromiseStream& rhs) const { return queue == rhs.queue; } + + bool operator==(const ReplyPromiseStream& rhs) const { return queue == rhs.queue; } bool isEmpty() const { return !queue->isReady(); } uint32_t size() const { return queue->size(); } Future onReady() { - if(queue->acknowledgements.failures.isError()) { + if (queue->acknowledgements.failures.isError()) { return queue->acknowledgements.failures.getError(); } - if(queue->acknowledgements.ready.isValid() && queue->acknowledgements.ready.isSet() && queue->acknowledgements.ready.getFuture().isError()) { + if (queue->acknowledgements.ready.isValid() && queue->acknowledgements.ready.isSet() && + queue->acknowledgements.ready.getFuture().isError()) { return queue->acknowledgements.ready.getFuture().getError(); } - if(queue->acknowledgements.bytesSent - queue->acknowledgements.bytesAcknowledged < FLOW_KNOBS->ACKNOWLEDGE_LIMIT_BYTES) { + if (queue->acknowledgements.bytesSent - queue->acknowledgements.bytesAcknowledged < + FLOW_KNOBS->ACKNOWLEDGE_LIMIT_BYTES) { return Void(); } return queue->acknowledgements.ready.getFuture() || queue->acknowledgements.failures; @@ -450,20 +475,25 @@ class ReplyPromiseStream { void operator=(const ReplyPromiseStream& rhs) { rhs.queue->addPromiseRef(); - if (queue) queue->delPromiseRef(); + if (queue) + queue->delPromiseRef(); queue = rhs.queue; - if(rhs.errors) rhs.errors->addPromiseRef(); - if (errors) errors->delPromiseRef(); + if (rhs.errors) + rhs.errors->addPromiseRef(); + if (errors) + errors->delPromiseRef(); errors = rhs.errors; } void operator=(ReplyPromiseStream&& rhs) noexcept { if (queue != rhs.queue) { - if (queue) queue->delPromiseRef(); + if (queue) + queue->delPromiseRef(); queue = rhs.queue; rhs.queue = 0; } if (errors != rhs.errors) { - if (errors) errors->delPromiseRef(); + if (errors) + errors->delPromiseRef(); errors = rhs.errors; rhs.errors = 0; } @@ -490,7 +520,7 @@ void load(Ar& ar, ReplyPromiseStream& value) { template struct serializable_traits> : std::true_type { - template + template static void serialize(Archiver& ar, ReplyPromiseStream& p) { if constexpr (Archiver::isDeserializing) { UID token; @@ -620,10 +650,10 @@ class RequestStream { } // stream.getReplyStream( request ) - // Unreliable at most once delivery. - // Registers the request with the remote endpoint which sends back a stream of replies, followed by an end_of_stream error. - // If the connection is ever broken the remote endpoint will stop attempting to send replies. - // The caller sends acknowledgements to the remote endpoint so that at most 2MB of replies is ever inflight. + // Unreliable at most once delivery. + // Registers the request with the remote endpoint which sends back a stream of replies, followed by an + // end_of_stream error. If the connection is ever broken the remote endpoint will stop attempting to send replies. + // The caller sends acknowledgements to the remote endpoint so that at most 2MB of replies is ever inflight. template ReplyPromiseStream getReplyStream(const X& value, TaskPriority taskID) const { @@ -631,8 +661,9 @@ class RequestStream { if (queue->isRemoteEndpoint()) { Future disc = makeDependent(IFailureMonitor::failureMonitor()).onDisconnect(getEndpoint(taskID)); auto& p = getReplyPromiseStream(value); - Reference peer = FlowTransport::transport().sendUnreliable(SerializeSource(value), getEndpoint(taskID), true); - //FIXME: defer sending the message until we know the connection is established + Reference peer = + FlowTransport::transport().sendUnreliable(SerializeSource(value), getEndpoint(taskID), true); + // FIXME: defer sending the message until we know the connection is established endStreamOnDisconnect(disc, p, peer); return p; } @@ -646,12 +677,12 @@ class RequestStream { if (queue->isRemoteEndpoint()) { Future disc = makeDependent(IFailureMonitor::failureMonitor()).onDisconnect(getEndpoint()); auto& p = getReplyPromiseStream(value); - Reference peer = FlowTransport::transport().sendUnreliable(SerializeSource(value), getEndpoint(), true); - //FIXME: defer sending the message until we know the connection is established + Reference peer = + FlowTransport::transport().sendUnreliable(SerializeSource(value), getEndpoint(), true); + // FIXME: defer sending the message until we know the connection is established endStreamOnDisconnect(disc, p, peer); return p; - } - else { + } else { send(value); auto& p = getReplyPromiseStream(value); return p; @@ -727,7 +758,9 @@ class RequestStream { // queue = (NetNotifiedQueue*)0xdeadbeef; } - const Endpoint& getEndpoint(TaskPriority taskID = TaskPriority::DefaultEndpoint) const { return queue->getEndpoint(taskID); } + const Endpoint& getEndpoint(TaskPriority taskID = TaskPriority::DefaultEndpoint) const { + return queue->getEndpoint(taskID); + } void makeWellKnownEndpoint(Endpoint::Token token, TaskPriority taskID) { queue->makeWellKnownEndpoint(token, taskID); } diff --git a/fdbrpc/genericactors.actor.h b/fdbrpc/genericactors.actor.h index b5cfdeaea0e..ef0283ad235 100644 --- a/fdbrpc/genericactors.actor.h +++ b/fdbrpc/genericactors.actor.h @@ -198,23 +198,22 @@ struct PeerHolder { }; // Implements getRepyStream, this a void actor with the same lifetime as the input ReplyPromiseStream. -// Because this actor holds a reference to the stream, normally it would be impossible to know when there are no other references. -// To get around this, there is a SAV inside the stream that has one less promise reference than -// it should (caused by getErrorFutureAndDelPromiseRef()). When that SAV gets a broken promise because no one besides this void actor -// is referencing it, this void actor will get a broken_promise dropping the final reference to the full ReplyPromiseStream +// Because this actor holds a reference to the stream, normally it would be impossible to know when there are no other +// references. To get around this, there is a SAV inside the stream that has one less promise reference than it should +// (caused by getErrorFutureAndDelPromiseRef()). When that SAV gets a broken promise because no one besides this void +// actor is referencing it, this void actor will get a broken_promise dropping the final reference to the full +// ReplyPromiseStream ACTOR template -void endStreamOnDisconnect( Future signal, ReplyPromiseStream stream, Reference peer = Reference() ) { +void endStreamOnDisconnect(Future signal, + ReplyPromiseStream stream, + Reference peer = Reference()) { state PeerHolder holder = PeerHolder(peer); choose { - when(wait(signal)) { - stream.sendError(connection_failed()); - } + when(wait(signal)) { stream.sendError(connection_failed()); } when(wait(stream.getErrorFutureAndDelPromiseRef())) {} } } - - // Implements tryGetReply, getReplyUnlessFailedFor ACTOR template Future> waitValueOrSignal(Future value, diff --git a/fdbserver/NetworkTest.h b/fdbserver/NetworkTest.h index 307c0f02825..a6aa60708b9 100644 --- a/fdbserver/NetworkTest.h +++ b/fdbserver/NetworkTest.h @@ -27,7 +27,7 @@ #include "flow/FileIdentifier.h" struct NetworkTestInterface { - RequestStream< struct NetworkTestRequest > test; + RequestStream test; RequestStream testStream; NetworkTestInterface() {} NetworkTestInterface(NetworkAddress remote); @@ -64,7 +64,7 @@ struct NetworkTestStreamingReply : ReplyPromiseStreamReply { int index = 0; NetworkTestStreamingReply() = default; explicit NetworkTestStreamingReply(int index) : index(index) {} - size_t expectedSize() const { return 4e6;/*sizeof(*this);*/ } + size_t expectedSize() const { return 4e6; /*sizeof(*this);*/ } template void serialize(Ar& ar) { diff --git a/fdbserver/storageserver.actor.cpp b/fdbserver/storageserver.actor.cpp index 648938dc218..a01fe668196 100644 --- a/fdbserver/storageserver.actor.cpp +++ b/fdbserver/storageserver.actor.cpp @@ -667,7 +667,8 @@ struct StorageServer { struct Counters { CounterCollection cc; - Counter allQueries, getKeyQueries, getValueQueries, getRangeQueries, getRangeStreamQueries, finishedQueries, lowPriorityQueries, rowsQueried, bytesQueried, watchQueries, emptyQueries; + Counter allQueries, getKeyQueries, getValueQueries, getRangeQueries, getRangeStreamQueries, finishedQueries, + lowPriorityQueries, rowsQueried, bytesQueried, watchQueries, emptyQueries; Counter bytesInput, bytesDurable, bytesFetched, mutationBytes; // Like bytesInput but without MVCC accounting Counter sampledBytesCleared; @@ -682,21 +683,22 @@ struct StorageServer { Counters(StorageServer* self) : cc("StorageServer", self->thisServerID.toString()), getKeyQueries("GetKeyQueries", cc), - getValueQueries("GetValueQueries", cc), getRangeQueries("GetRangeQueries", cc), getRangeStreamQueries("GetRangeStreamQueries", cc), - allQueries("QueryQueue", cc), finishedQueries("FinishedQueries", cc), - lowPriorityQueries("LowPriorityQueries", cc), rowsQueried("RowsQueried", cc), - bytesQueried("BytesQueried", cc), watchQueries("WatchQueries", cc), emptyQueries("EmptyQueries", cc), - bytesInput("BytesInput", cc), bytesDurable("BytesDurable", cc), bytesFetched("BytesFetched", cc), - mutationBytes("MutationBytes", cc), sampledBytesCleared("SampledBytesCleared", cc), - mutations("Mutations", cc), setMutations("SetMutations", cc), - clearRangeMutations("ClearRangeMutations", cc), atomicMutations("AtomicMutations", cc), - updateBatches("UpdateBatches", cc), updateVersions("UpdateVersions", cc), loops("Loops", cc), - fetchWaitingMS("FetchWaitingMS", cc), fetchWaitingCount("FetchWaitingCount", cc), - fetchExecutingMS("FetchExecutingMS", cc), fetchExecutingCount("FetchExecutingCount", cc), - readsRejected("ReadsRejected", cc), readLatencySample("ReadLatencyMetrics", - self->thisServerID, - SERVER_KNOBS->LATENCY_METRICS_LOGGING_INTERVAL, - SERVER_KNOBS->LATENCY_SAMPLE_SIZE), + getValueQueries("GetValueQueries", cc), getRangeQueries("GetRangeQueries", cc), + getRangeStreamQueries("GetRangeStreamQueries", cc), allQueries("QueryQueue", cc), + finishedQueries("FinishedQueries", cc), lowPriorityQueries("LowPriorityQueries", cc), + rowsQueried("RowsQueried", cc), bytesQueried("BytesQueried", cc), watchQueries("WatchQueries", cc), + emptyQueries("EmptyQueries", cc), bytesInput("BytesInput", cc), bytesDurable("BytesDurable", cc), + bytesFetched("BytesFetched", cc), mutationBytes("MutationBytes", cc), + sampledBytesCleared("SampledBytesCleared", cc), mutations("Mutations", cc), + setMutations("SetMutations", cc), clearRangeMutations("ClearRangeMutations", cc), + atomicMutations("AtomicMutations", cc), updateBatches("UpdateBatches", cc), + updateVersions("UpdateVersions", cc), loops("Loops", cc), fetchWaitingMS("FetchWaitingMS", cc), + fetchWaitingCount("FetchWaitingCount", cc), fetchExecutingMS("FetchExecutingMS", cc), + fetchExecutingCount("FetchExecutingCount", cc), readsRejected("ReadsRejected", cc), + readLatencySample("ReadLatencyMetrics", + self->thisServerID, + SERVER_KNOBS->LATENCY_METRICS_LOGGING_INTERVAL, + SERVER_KNOBS->LATENCY_SAMPLE_SIZE), readLatencyBands("ReadLatencyBands", self->thisServerID, SERVER_KNOBS->STORAGE_LOGGING_DELAY) { specialCounter(cc, "LastTLogVersion", [self]() { return self->lastTLogVersion; }); specialCounter(cc, "Version", [self]() { return self->version.get(); }); @@ -1965,32 +1967,38 @@ ACTOR Future getKeyValuesStreamQ(StorageServer* data, GetKeyValuesStreamRe ++data->counters.getRangeStreamQueries; ++data->counters.allQueries; ++data->readQueueSizeMetric; - data->maxQueryQueue = std::max( data->maxQueryQueue, data->counters.allQueries.getValue() - data->counters.finishedQueries.getValue()); + data->maxQueryQueue = std::max( + data->maxQueryQueue, data->counters.allQueries.getValue() - data->counters.finishedQueries.getValue()); // Active load balancing runs at a very high priority (to obtain accurate queue lengths) // so we need to downgrade here if (SERVER_KNOBS->FETCH_KEYS_LOWER_PRIORITY && req.isFetchKeys) { - wait( delay(0, TaskPriority::FetchKeys) ); + wait(delay(0, TaskPriority::FetchKeys)); } else { - wait( delay(0, TaskPriority::DefaultEndpoint) ); + wait(delay(0, TaskPriority::DefaultEndpoint)); } - + try { - if( req.debugID.present() ) + if (req.debugID.present()) g_traceBatch.addEvent("TransactionDebug", req.debugID.get().first(), "storageserver.getKeyValues.Before"); - state Version version = wait( waitForVersion( data, req.version, span.context ) ); + state Version version = wait(waitForVersion(data, req.version, span.context)); state uint64_t changeCounter = data->shardChangeCounter; -// try { - state KeyRange shard = getShardKeyRange( data, req.begin ); + // try { + state KeyRange shard = getShardKeyRange(data, req.begin); - if( req.debugID.present() ) - g_traceBatch.addEvent("TransactionDebug", req.debugID.get().first(), "storageserver.getKeyValues.AfterVersion"); + if (req.debugID.present()) + g_traceBatch.addEvent( + "TransactionDebug", req.debugID.get().first(), "storageserver.getKeyValues.AfterVersion"); //.detail("ShardBegin", shard.begin).detail("ShardEnd", shard.end); - //} catch (Error& e) { TraceEvent("WrongShardServer", data->thisServerID).detail("Begin", req.begin.toString()).detail("End", req.end.toString()).detail("Version", version).detail("Shard", "None").detail("In", "getKeyValues>getShardKeyRange"); throw e; } + //} catch (Error& e) { TraceEvent("WrongShardServer", data->thisServerID).detail("Begin", + //req.begin.toString()).detail("End", req.end.toString()).detail("Version", version).detail("Shard", + //"None").detail("In", "getKeyValues>getShardKeyRange"); throw e; } - if ( !selectorInRange(req.end, shard) && !(req.end.isFirstGreaterOrEqual() && req.end.getKey() == shard.end) ) { -// TraceEvent("WrongShardServer1", data->thisServerID).detail("Begin", req.begin.toString()).detail("End", req.end.toString()).detail("Version", version).detail("ShardBegin", shard.begin).detail("ShardEnd", shard.end).detail("In", "getKeyValues>checkShardExtents"); + if (!selectorInRange(req.end, shard) && !(req.end.isFirstGreaterOrEqual() && req.end.getKey() == shard.end)) { + // TraceEvent("WrongShardServer1", data->thisServerID).detail("Begin", + //req.begin.toString()).detail("End", req.end.toString()).detail("Version", version).detail("ShardBegin", + //shard.begin).detail("ShardEnd", shard.end).detail("In", "getKeyValues>checkShardExtents"); throw wrong_shard_server(); } @@ -2004,24 +2012,27 @@ ACTOR Future getKeyValuesStreamQ(StorageServer* data, GetKeyValuesStreamRe : findKey(data, req.end, version, shard, &offset2, span.context); state Key begin = wait(fBegin); state Key end = wait(fEnd); - if( req.debugID.present() ) - g_traceBatch.addEvent("TransactionDebug", req.debugID.get().first(), "storageserver.getKeyValues.AfterKeys"); + if (req.debugID.present()) + g_traceBatch.addEvent( + "TransactionDebug", req.debugID.get().first(), "storageserver.getKeyValues.AfterKeys"); //.detail("Off1",offset1).detail("Off2",offset2).detail("ReqBegin",req.begin.getKey()).detail("ReqEnd",req.end.getKey()); // Offsets of zero indicate begin/end keys in this shard, which obviously means we can answer the query - // An end offset of 1 is also OK because the end key is exclusive, so if the first key of the next shard is the end the last actual key returned must be from this shard. - // A begin offset of 1 is also OK because then either begin is past end or equal to end (so the result is definitely empty) - if ((offset1 && offset1!=1) || (offset2 && offset2!=1)) { - TEST(true); // wrong_shard_server due to offset in rangeStream - // We could detect when offset1 takes us off the beginning of the database or offset2 takes us off the end, and return a clipped range rather - // than an error (since that is what the NativeAPI.getRange will do anyway via its "slow path"), but we would have to add some flags to the response - // to encode whether we went off the beginning and the end, since it needs that information. + // An end offset of 1 is also OK because the end key is exclusive, so if the first key of the next shard is the + // end the last actual key returned must be from this shard. A begin offset of 1 is also OK because then either + // begin is past end or equal to end (so the result is definitely empty) + if ((offset1 && offset1 != 1) || (offset2 && offset2 != 1)) { + TEST(true); // wrong_shard_server due to offset in rangeStream + // We could detect when offset1 takes us off the beginning of the database or offset2 takes us off the end, + // and return a clipped range rather than an error (since that is what the NativeAPI.getRange will do anyway + // via its "slow path"), but we would have to add some flags to the response to encode whether we went off + // the beginning and the end, since it needs that information. //TraceEvent("WrongShardServer2", data->thisServerID).detail("Begin", req.begin.toString()).detail("End", req.end.toString()).detail("Version", version).detail("ShardBegin", shard.begin).detail("ShardEnd", shard.end).detail("In", "getKeyValues>checkOffsets").detail("BeginKey", begin).detail("EndKey", end).detail("BeginOffset", offset1).detail("EndOffset", offset2); throw wrong_shard_server(); } if (begin >= end) { - if( req.debugID.present() ) + if (req.debugID.present()) g_traceBatch.addEvent("TransactionDebug", req.debugID.get().first(), "storageserver.getKeyValues.Send"); //.detail("Begin",begin).detail("End",end); @@ -2029,20 +2040,27 @@ ACTOR Future getKeyValuesStreamQ(StorageServer* data, GetKeyValuesStreamRe none.version = version; none.more = false; - data->checkChangeCounter( changeCounter, KeyRangeRef( std::min(req.begin.getKey(), req.end.getKey()), std::max(req.begin.getKey(), req.end.getKey()) ) ); - req.reply.send( none ); - req.reply.sendError( end_of_stream() ); + data->checkChangeCounter(changeCounter, + KeyRangeRef(std::min(req.begin.getKey(), req.end.getKey()), + std::max(req.begin.getKey(), req.end.getKey()))); + req.reply.send(none); + req.reply.sendError(end_of_stream()); } else { loop { wait(req.reply.onReady()); state int byteLimit = CLIENT_KNOBS->REPLY_BYTE_LIMIT; - GetKeyValuesReply _r = wait( readRange(data, version, KeyRangeRef(begin, end), req.limit, &byteLimit, span.context) ); + GetKeyValuesReply _r = + wait(readRange(data, version, KeyRangeRef(begin, end), req.limit, &byteLimit, span.context)); GetKeyValuesStreamReply r(_r); - if( req.debugID.present() ) - g_traceBatch.addEvent("TransactionDebug", req.debugID.get().first(), "storageserver.getKeyValues.AfterReadRange"); + if (req.debugID.present()) + g_traceBatch.addEvent( + "TransactionDebug", req.debugID.get().first(), "storageserver.getKeyValues.AfterReadRange"); //.detail("Begin",begin).detail("End",end).detail("SizeOf",r.data.size()); - data->checkChangeCounter( changeCounter, KeyRangeRef( std::min(begin, std::min(req.begin.getKey(), req.end.getKey())), std::max(end, std::max(req.begin.getKey(), req.end.getKey())) ) ); + data->checkChangeCounter( + changeCounter, + KeyRangeRef(std::min(begin, std::min(req.begin.getKey(), req.end.getKey())), + std::max(end, std::max(req.begin.getKey(), req.end.getKey())))); if (EXPENSIVE_VALIDATION) { for (int i = 0; i < r.data.size(); i++) ASSERT(r.data[i].key >= begin && r.data[i].key < end); @@ -2056,7 +2074,8 @@ ACTOR Future getKeyValuesStreamQ(StorageServer* data, GetKeyValuesStreamRe data->metrics.notify(r.data[i].key, m); }*/ - // For performance concerns, the cost of a range read is billed to the start key and end key of the range. + // For performance concerns, the cost of a range read is billed to the start key and end key of the + // range. int64_t totalByteSize = 0; for (int i = 0; i < r.data.size(); i++) { totalByteSize += r.data[i].expectedSize(); @@ -2067,38 +2086,40 @@ ACTOR Future getKeyValuesStreamQ(StorageServer* data, GetKeyValuesStreamRe data->metrics.notifyBytesReadPerKSecond(r.data[r.data.size() - 1].key, bytesReadPerKSecond); } - req.reply.send( r ); + req.reply.send(r); data->counters.rowsQueried += r.data.size(); - if(r.data.size() == 0) { + if (r.data.size() == 0) { ++data->counters.emptyQueries; } - if(!r.more) { + if (!r.more) { req.reply.sendError(end_of_stream()); break; } ASSERT(r.data.size()); - if(req.limit >= 0) { + if (req.limit >= 0) { begin = keyAfter(r.data.back().key); } else { end = r.data.back().key; } if (SERVER_KNOBS->FETCH_KEYS_LOWER_PRIORITY && req.isFetchKeys) { - wait( delay(0, TaskPriority::FetchKeys) ); + wait(delay(0, TaskPriority::FetchKeys)); } else { - wait( delay(0, TaskPriority::DefaultEndpoint) ); + wait(delay(0, TaskPriority::DefaultEndpoint)); } - + data->transactionTagCounter.addRequest(req.tags, resultSize); - //FIXME: figure out what to do with latency measurements - //double duration = g_network->timer() - req.requestTime(); - //data->counters.readLatencySample.addMeasurement(duration); - //if(data->latencyBandConfig.present()) { - // int maxReadBytes = data->latencyBandConfig.get().readConfig.maxReadBytes.orDefault(std::numeric_limits::max()); - // int maxSelectorOffset = data->latencyBandConfig.get().readConfig.maxKeySelectorOffset.orDefault(std::numeric_limits::max()); + // FIXME: figure out what to do with latency measurements + // double duration = g_network->timer() - req.requestTime(); + // data->counters.readLatencySample.addMeasurement(duration); + // if(data->latencyBandConfig.present()) { + // int maxReadBytes = + //data->latencyBandConfig.get().readConfig.maxReadBytes.orDefault(std::numeric_limits::max()); int + //maxSelectorOffset = + //data->latencyBandConfig.get().readConfig.maxKeySelectorOffset.orDefault(std::numeric_limits::max()); // data->counters.readLatencyBands.addMeasurement( // duration, resultSize > maxReadBytes || abs(req.begin.offset) > maxSelectorOffset || // abs(req.end.offset) > maxSelectorOffset); @@ -2106,8 +2127,8 @@ ACTOR Future getKeyValuesStreamQ(StorageServer* data, GetKeyValuesStreamRe } } } catch (Error& e) { - if(e.code() != error_code_operation_obsolete) { - if(!canReplyWith(e)) + if (e.code() != error_code_operation_obsolete) { + if (!canReplyWith(e)) throw; req.reply.sendError(e); } @@ -2117,12 +2138,14 @@ ACTOR Future getKeyValuesStreamQ(StorageServer* data, GetKeyValuesStreamRe ++data->counters.finishedQueries; --data->readQueueSizeMetric; - //FIXME: figure out what to do with latency measurements - //double duration = g_network->timer() - req.requestTime(); - //data->counters.readLatencySample.addMeasurement(duration); - //if(data->latencyBandConfig.present()) { - // int maxReadBytes = data->latencyBandConfig.get().readConfig.maxReadBytes.orDefault(std::numeric_limits::max()); - // int maxSelectorOffset = data->latencyBandConfig.get().readConfig.maxKeySelectorOffset.orDefault(std::numeric_limits::max()); + // FIXME: figure out what to do with latency measurements + // double duration = g_network->timer() - req.requestTime(); + // data->counters.readLatencySample.addMeasurement(duration); + // if(data->latencyBandConfig.present()) { + // int maxReadBytes = + //data->latencyBandConfig.get().readConfig.maxReadBytes.orDefault(std::numeric_limits::max()); int + //maxSelectorOffset = + //data->latencyBandConfig.get().readConfig.maxKeySelectorOffset.orDefault(std::numeric_limits::max()); // data->counters.readLatencyBands.addMeasurement( // duration, resultSize > maxReadBytes || abs(req.begin.offset) > maxSelectorOffset || // abs(req.end.offset) > maxSelectorOffset); @@ -2131,7 +2154,7 @@ ACTOR Future getKeyValuesStreamQ(StorageServer* data, GetKeyValuesStreamRe return Void(); } -ACTOR Future getKeyQ( StorageServer* data, GetKeyRequest req ) { +ACTOR Future getKeyQ(StorageServer* data, GetKeyRequest req) { state Span span("SS:getKey"_loc, { req.spanContext }); state int64_t resultSize = 0; @@ -2687,8 +2710,8 @@ ACTOR Future fetchKeys(StorageServer* data, AddingShard* shard) { TraceEvent(SevDebug, "FetchKeysVersionSatisfied", data->thisServerID).detail("FKID", interval.pairID); - wait( data->fetchKeysParallelismLock.take( TaskPriority::DefaultYield ) ); - state FlowLock::Releaser holdingFKPL( data->fetchKeysParallelismLock ); + wait(data->fetchKeysParallelismLock.take(TaskPriority::DefaultYield)); + state FlowLock::Releaser holdingFKPL(data->fetchKeysParallelismLock); state double executeStart = now(); ++data->counters.fetchWaitingCount; @@ -2700,7 +2723,7 @@ ACTOR Future fetchKeys(StorageServer* data, AddingShard* shard) { wait(data->durableVersionLock.take()); shard->phase = AddingShard::Fetching; - + data->durableVersionLock.release(); wait(delay(0)); @@ -2719,10 +2742,11 @@ ACTOR Future fetchKeys(StorageServer* data, AddingShard* shard) { data->cx->invalidateCache(keys); loop { - state Transaction tr( data->cx ); + state Transaction tr(data->cx); state Version fetchVersion = data->version.get(); - while (!shard->updates.empty() && shard->updates[0].version <= fetchVersion) shard->updates.pop_front(); - tr.setVersion( fetchVersion ); + while (!shard->updates.empty() && shard->updates[0].version <= fetchVersion) + shard->updates.pop_front(); + tr.setVersion(fetchVersion); tr.info.taskID = TaskPriority::FetchKeys; state PromiseStream> results; state Future hold = tr.getRangeStream(results, keys, GetRangeLimits(), true); @@ -2730,46 +2754,57 @@ ACTOR Future fetchKeys(StorageServer* data, AddingShard* shard) { try { loop { - TEST(true); // Fetching keys for transferred shard - state Standalone this_block = waitNext( results.getFuture() ); - - int expectedSize = (int)this_block.expectedSize() + (8-(int)sizeof(KeyValueRef))*this_block.size(); - - TraceEvent(SevDebug, "FetchKeysBlock", data->thisServerID).detail("FKID", interval.pairID) - .detail("BlockRows", this_block.size()).detail("BlockBytes", expectedSize) - .detail("KeyBegin", keys.begin).detail("KeyEnd", keys.end) - .detail("Last", this_block.size() ? this_block.end()[-1].key : std::string()) - .detail("Version", fetchVersion).detail("More", this_block.more); + TEST(true); // Fetching keys for transferred shard + state Standalone this_block = waitNext(results.getFuture()); + + int expectedSize = + (int)this_block.expectedSize() + (8 - (int)sizeof(KeyValueRef)) * this_block.size(); + + TraceEvent(SevDebug, "FetchKeysBlock", data->thisServerID) + .detail("FKID", interval.pairID) + .detail("BlockRows", this_block.size()) + .detail("BlockBytes", expectedSize) + .detail("KeyBegin", keys.begin) + .detail("KeyEnd", keys.end) + .detail("Last", this_block.size() ? this_block.end()[-1].key : std::string()) + .detail("Version", fetchVersion) + .detail("More", this_block.more); DEBUG_KEY_RANGE("fetchRange", fetchVersion, keys); - for(auto k = this_block.begin(); k != this_block.end(); ++k) DEBUG_MUTATION("fetch", fetchVersion, MutationRef(MutationRef::SetValue, k->key, k->value)); + for (auto k = this_block.begin(); k != this_block.end(); ++k) + DEBUG_MUTATION("fetch", fetchVersion, MutationRef(MutationRef::SetValue, k->key, k->value)); metricReporter.addFetchedBytes(expectedSize); data->counters.bytesFetched += expectedSize; // Write this_block to storage - state KeyValueRef *kvItr = this_block.begin(); - for(; kvItr != this_block.end(); ++kvItr) { - data->storage.writeKeyValue( *kvItr ); + state KeyValueRef* kvItr = this_block.begin(); + for (; kvItr != this_block.end(); ++kvItr) { + data->storage.writeKeyValue(*kvItr); wait(yield()); } kvItr = this_block.begin(); - for(; kvItr != this_block.end(); ++kvItr) { - data->byteSampleApplySet( *kvItr, invalidVersion ); + for (; kvItr != this_block.end(); ++kvItr) { + data->byteSampleApplySet(*kvItr, invalidVersion); wait(yield()); } ASSERT(this_block.readThrough.present() || this_block.size()); - nfk = this_block.readThrough.present() ? this_block.readThrough.get() : keyAfter( this_block.end()[-1].key ); + nfk = this_block.readThrough.present() ? this_block.readThrough.get() + : keyAfter(this_block.end()[-1].key); this_block = Standalone(); } - } catch( Error &e ) { - if(e.code() != error_code_end_of_stream && e.code() != error_code_connection_failed && e.code() != error_code_transaction_too_old && - e.code() != error_code_future_version && e.code() != error_code_process_behind) { + } catch (Error& e) { + if (e.code() != error_code_end_of_stream && e.code() != error_code_connection_failed && + e.code() != error_code_transaction_too_old && e.code() != error_code_future_version && + e.code() != error_code_process_behind) { throw; } - if(nfk == keys.begin) { - TraceEvent("FKBlockFail", data->thisServerID).error(e,true).suppressFor(1.0).detail("FKID", interval.pairID); + if (nfk == keys.begin) { + TraceEvent("FKBlockFail", data->thisServerID) + .error(e, true) + .suppressFor(1.0) + .detail("FKID", interval.pairID); // FIXME: remove when we no longer support upgrades from 5.X if (debug_getRangeRetries >= 100) { @@ -2780,34 +2815,41 @@ ACTOR Future fetchKeys(StorageServer* data, AddingShard* shard) { debug_getRangeRetries++; if (debug_nextRetryToLog == debug_getRangeRetries) { debug_nextRetryToLog += std::min(debug_nextRetryToLog, 1024); - TraceEvent(SevWarn, "FetchPast", data->thisServerID).detail("TotalAttempts", debug_getRangeRetries).detail("FKID", interval.pairID).detail("N", fetchVersion).detail("E", data->version.get()); + TraceEvent(SevWarn, "FetchPast", data->thisServerID) + .detail("TotalAttempts", debug_getRangeRetries) + .detail("FKID", interval.pairID) + .detail("N", fetchVersion) + .detail("E", data->version.get()); } - wait( delayJittered( FLOW_KNOBS->PREVENT_FAST_SPIN_DELAY ) ); + wait(delayJittered(FLOW_KNOBS->PREVENT_FAST_SPIN_DELAY)); continue; } - if(nfk < keys.end) { - std::deque< Standalone > updatesToSplit = std::move( shard->updates ); + if (nfk < keys.end) { + std::deque> updatesToSplit = std::move(shard->updates); // This actor finishes committing the keys [keys.begin,nfk) that we already fetched. - // The remaining unfetched keys [nfk,keys.end) will become a separate AddingShard with its own fetchKeys. - shard->server->addShard( ShardInfo::addingSplitLeft( KeyRangeRef(keys.begin, nfk), shard ) ); - shard->server->addShard( ShardInfo::newAdding( data, KeyRangeRef(nfk, keys.end) ) ); - shard = data->shards.rangeContaining( keys.begin ).value()->adding; + // The remaining unfetched keys [nfk,keys.end) will become a separate AddingShard with its own + // fetchKeys. + shard->server->addShard(ShardInfo::addingSplitLeft(KeyRangeRef(keys.begin, nfk), shard)); + shard->server->addShard(ShardInfo::newAdding(data, KeyRangeRef(nfk, keys.end))); + shard = data->shards.rangeContaining(keys.begin).value()->adding; warningLogger = logFetchKeysWarning(shard); - AddingShard* otherShard = data->shards.rangeContaining( nfk ).value()->adding; + AddingShard* otherShard = data->shards.rangeContaining(nfk).value()->adding; keys = shard->keys; - // Split our prior updates. The ones that apply to our new, restricted key range will go back into shard->updates, - // and the ones delivered to the new shard will be discarded because it is in WaitPrevious phase (hasn't chosen a fetchVersion yet). - // What we are doing here is expensive and could get more expensive if we started having many more blocks per shard. May need optimization in the future. - std::deque< Standalone >::iterator u = updatesToSplit.begin(); - for(; u != updatesToSplit.end(); ++u) { + // Split our prior updates. The ones that apply to our new, restricted key range will go back into + // shard->updates, and the ones delivered to the new shard will be discarded because it is in + // WaitPrevious phase (hasn't chosen a fetchVersion yet). What we are doing here is expensive and + // could get more expensive if we started having many more blocks per shard. May need optimization + // in the future. + std::deque>::iterator u = updatesToSplit.begin(); + for (; u != updatesToSplit.end(); ++u) { splitMutations(data, data->shards, *u); } - TEST( true ); // fetchkeys has more - TEST( shard->updates.size() ); // Shard has updates - ASSERT( otherShard->updates.empty() ); + TEST(true); // fetchkeys has more + TEST(shard->updates.size()); // Shard has updates + ASSERT(otherShard->updates.empty()); } break; } @@ -4422,16 +4464,18 @@ ACTOR Future serveGetKeyValuesRequests(StorageServer* self, FutureStream serveGetKeyValuesStreamRequests( StorageServer* self, FutureStream getKeyValuesStream ) { +ACTOR Future serveGetKeyValuesStreamRequests(StorageServer* self, + FutureStream getKeyValuesStream) { loop { GetKeyValuesStreamRequest req = waitNext(getKeyValuesStream); - // Warning: This code is executed at extremely high priority (TaskPriority::LoadBalancedEndpoint), so downgrade before doing real work - //FIXME: add readGuard again + // Warning: This code is executed at extremely high priority (TaskPriority::LoadBalancedEndpoint), so downgrade + // before doing real work + // FIXME: add readGuard again self->actors.add(getKeyValuesStreamQ(self, req)); } } -ACTOR Future serveGetKeyRequests( StorageServer* self, FutureStream getKey ) { +ACTOR Future serveGetKeyRequests(StorageServer* self, FutureStream getKey) { loop { GetKeyRequest req = waitNext(getKey); // Warning: This code is executed at extremely high priority (TaskPriority::LoadBalancedEndpoint), so downgrade diff --git a/fdbserver/workloads/GetRangeStream.actor.cpp b/fdbserver/workloads/GetRangeStream.actor.cpp index 0159204f120..b63e2129799 100644 --- a/fdbserver/workloads/GetRangeStream.actor.cpp +++ b/fdbserver/workloads/GetRangeStream.actor.cpp @@ -57,7 +57,8 @@ struct GetRangeStream : TestWorkload { wait(delay(1)); state double after = g_network->now(); if (after > before) { - printf("throughput: %g bytes/s, next: %s\n", (self->bytesRead.getValue() - last) / (after - before), + printf("throughput: %g bytes/s, next: %s\n", + (self->bytesRead.getValue() - last) / (after - before), printable(*next).c_str()); } } @@ -69,10 +70,11 @@ struct GetRangeStream : TestWorkload { state Future logFuture = logThroughput(self, &next); loop { try { - Standalone range = wait(tx.getRange( - KeySelector(firstGreaterOrEqual(next), next.arena()), KeySelector(firstGreaterOrEqual(self->end)), - GetRangeLimits(GetRangeLimits::ROW_LIMIT_UNLIMITED, CLIENT_KNOBS->REPLY_BYTE_LIMIT))); - for (const auto & [ k, v ] : range) { + Standalone range = wait( + tx.getRange(KeySelector(firstGreaterOrEqual(next), next.arena()), + KeySelector(firstGreaterOrEqual(self->end)), + GetRangeLimits(GetRangeLimits::ROW_LIMIT_UNLIMITED, CLIENT_KNOBS->REPLY_BYTE_LIMIT))); + for (const auto& [k, v] : range) { if (self->printKVPairs) { printf("%s -> %s\n", printable(k).c_str(), printable(v).c_str()); } @@ -96,12 +98,13 @@ struct GetRangeStream : TestWorkload { loop { state PromiseStream> results; try { - state Future stream = - tx.getRangeStream(results, KeySelector(firstGreaterOrEqual(next), next.arena()), - KeySelector(firstGreaterOrEqual(self->end)), GetRangeLimits()); + state Future stream = tx.getRangeStream(results, + KeySelector(firstGreaterOrEqual(next), next.arena()), + KeySelector(firstGreaterOrEqual(self->end)), + GetRangeLimits()); loop { Standalone range = waitNext(results.getFuture()); - for (const auto & [ k, v ] : range) { + for (const auto& [k, v] : range) { if (self->printKVPairs) { printf("%s -> %s\n", printable(k).c_str(), printable(v).c_str()); } diff --git a/flow/flow.h b/flow/flow.h index 27319a081e6..c6a8f8b224a 100644 --- a/flow/flow.h +++ b/flow/flow.h @@ -23,7 +23,7 @@ #pragma once #pragma warning(disable : 4244 4267) // SOMEDAY: Carefully check for integer overflow issues (e.g. size_t to int - // conversions like this suppresses) +// conversions like this suppresses) #pragma warning(disable : 4345) #pragma warning(error : 4239) @@ -595,9 +595,7 @@ struct NotifiedQueue : private SingleCallback, FastAllocated bool isError() const { return queue.empty() && error.isValid(); } // the *next* thing queued is an error uint32_t size() const { return queue.size(); } - virtual T pop() { - return popImpl(); - } + virtual T pop() { return popImpl(); } template void send(U&& value) { @@ -654,10 +652,11 @@ struct NotifiedQueue : private SingleCallback, FastAllocated virtual void fire(T const&) override { ASSERT(false); } virtual void fire(T&&) override { ASSERT(false); } - protected: +protected: T popImpl() { if (queue.empty()) { - if (error.isValid()) throw error; + if (error.isValid()) + throw error; throw internal_error(); } auto copy = std::move(queue.front()); @@ -665,13 +664,9 @@ struct NotifiedQueue : private SingleCallback, FastAllocated return copy; } - bool shouldFireImmediately() { - return SingleCallback::next != this; - } + bool shouldFireImmediately() { return SingleCallback::next != this; } - bool hasError() { - return error.isValid(); - } + bool hasError() { return error.isValid(); } }; template @@ -1010,7 +1005,8 @@ struct ReplyStreamType { // breaks IntelliSense in VS2010; this is a workaround. typedef decltype(std::declval().reply.getFuture().pop()) Type; }; -template class ReplyPromiseStream; +template +class ReplyPromiseStream; template struct ReplyStreamType> { typedef T Type; @@ -1018,7 +1014,7 @@ struct ReplyStreamType> { #define REPLYSTREAM_TYPE(RequestType) typename ReplyStreamType::Type #endif -//extern int actorCount; +// extern int actorCount; template static inline void destruct(T& t) { diff --git a/flow/genericactors.actor.h b/flow/genericactors.actor.h index 608611059ac..b977d4c4ae6 100644 --- a/flow/genericactors.actor.h +++ b/flow/genericactors.actor.h @@ -1261,7 +1261,8 @@ Future waitOrError(Future f, Future errorSignal) { } } -ACTOR template Future forwardErrors(Future f, PromiseStream output) { +ACTOR template +Future forwardErrors(Future f, PromiseStream output) { try { T val = wait(f); return val; From ccb39a6c1c484d4281f939b8b0f0ed296ba33791 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Sun, 2 May 2021 12:00:13 -0700 Subject: [PATCH 142/740] fixed merge errors --- documentation/tutorial/tutorial.actor.cpp | 1 - fdbserver/storageserver.actor.cpp | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/documentation/tutorial/tutorial.actor.cpp b/documentation/tutorial/tutorial.actor.cpp index f5eed7ab394..bcee4e7cc59 100644 --- a/documentation/tutorial/tutorial.actor.cpp +++ b/documentation/tutorial/tutorial.actor.cpp @@ -488,7 +488,6 @@ std::unordered_map()>> actors = { { "multipleClients", &multipleClients }, // ./tutorial -s 127.0.0.1:6666 multipleClients { "fdbClientStream", &fdbClientStream }, // ./tutorial -C $CLUSTER_FILE_PATH fdbClientStream { "fdbClientGetRange", &fdbClientGetRange }, // ./tutorial -C $CLUSTER_FILE_PATH fdbClientGetRange - { "fdbClient", &fdbClient }, // ./tutorial -C $CLUSTER_FILE_PATH fdbClient { "fdbStatusStresser", &fdbStatusStresser } }; // ./tutorial -C $CLUSTER_FILE_PATH fdbStatusStresser diff --git a/fdbserver/storageserver.actor.cpp b/fdbserver/storageserver.actor.cpp index a01fe668196..5ea3b1fa6dd 100644 --- a/fdbserver/storageserver.actor.cpp +++ b/fdbserver/storageserver.actor.cpp @@ -2832,9 +2832,9 @@ ACTOR Future fetchKeys(StorageServer* data, AddingShard* shard) { // fetchKeys. shard->server->addShard(ShardInfo::addingSplitLeft(KeyRangeRef(keys.begin, nfk), shard)); shard->server->addShard(ShardInfo::newAdding(data, KeyRangeRef(nfk, keys.end))); - shard = data->shards.rangeContaining(keys.begin).value()->adding; + shard = data->shards.rangeContaining(keys.begin).value()->adding.get(); warningLogger = logFetchKeysWarning(shard); - AddingShard* otherShard = data->shards.rangeContaining(nfk).value()->adding; + AddingShard* otherShard = data->shards.rangeContaining(nfk).value()->adding.get(); keys = shard->keys; // Split our prior updates. The ones that apply to our new, restricted key range will go back into From b44fa2f05c1be20ca11dd04818fa4e611bc686dc Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Tue, 4 May 2021 20:53:02 -0700 Subject: [PATCH 143/740] fix: replyPromiseStream must be at ReadSocket priority so it gets in-order delivery to they reply stream --- fdbrpc/fdbrpc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index cdef40ce129..93dc290b1bd 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -506,7 +506,7 @@ class ReplyPromiseStream { template void save(Ar& ar, const ReplyPromiseStream& value) { - auto const& ep = value.getEndpoint().token; + auto const& ep = value.getEndpoint(TaskPriority::ReadSocket).token; ar << ep; } From 542a266e83538ad2873ccd6b3826122f5d978a52 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Tue, 4 May 2021 22:44:20 -0700 Subject: [PATCH 144/740] changed all task priorities for both the ReplyPromiseStream and the acknowledgements to be at ReadSocket --- fdbrpc/fdbrpc.h | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index 93dc290b1bd..508ca0352ab 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -342,7 +342,7 @@ struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAl FlowTransport::transport().sendUnreliable( SerializeSource>( AcknowledgementReply(acknowledgements.bytesAcknowledged)), - acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint), + acknowledgements.getEndpoint(TaskPriority::ReadSocket), false); } } @@ -356,11 +356,10 @@ struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAl T res = this->popImpl(); if (acknowledgements.getRawEndpoint().isValid()) { acknowledgements.bytesAcknowledged += res.expectedSize(); - FlowTransport::transport().sendUnreliable( - SerializeSource>( - AcknowledgementReply(acknowledgements.bytesAcknowledged)), - acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint), - false); + FlowTransport::transport().sendUnreliable(SerializeSource>( + AcknowledgementReply(acknowledgements.bytesAcknowledged)), + acknowledgements.getEndpoint(TaskPriority::ReadSocket), + false); } return res; } @@ -369,7 +368,7 @@ struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAl if (acknowledgements.getRawEndpoint().isValid() && acknowledgements.isRemoteEndpoint() && !this->hasError()) { FlowTransport::transport().sendUnreliable( SerializeSource>(operation_obsolete()), - acknowledgements.getEndpoint(TaskPriority::DefaultPromiseEndpoint), + acknowledgements.getEndpoint(TaskPriority::ReadSocket), false); } } @@ -387,7 +386,7 @@ class ReplyPromiseStream { void send(U&& value) const { if (queue->isRemoteEndpoint()) { if (!queue->acknowledgements.getRawEndpoint().isValid()) { - value.acknowledgeToken = queue->acknowledgements.getEndpoint(TaskPriority::DefaultEndpoint).token; + value.acknowledgeToken = queue->acknowledgements.getEndpoint(TaskPriority::ReadSocket).token; } queue->acknowledgements.bytesSent += value.expectedSize(); if ((!queue->acknowledgements.ready.isValid() || @@ -450,9 +449,7 @@ class ReplyPromiseStream { errors->delPromiseRef(); } - const Endpoint& getEndpoint(TaskPriority taskID = TaskPriority::DefaultEndpoint) const { - return queue->getEndpoint(taskID); - } + const Endpoint& getEndpoint() const { return queue->getEndpoint(TaskPriority::ReadSocket); } bool operator==(const ReplyPromiseStream& rhs) const { return queue == rhs.queue; } bool isEmpty() const { return !queue->isReady(); } @@ -506,7 +503,7 @@ class ReplyPromiseStream { template void save(Ar& ar, const ReplyPromiseStream& value) { - auto const& ep = value.getEndpoint(TaskPriority::ReadSocket).token; + auto const& ep = value.getEndpoint().token; ar << ep; } From f60fbeb1ab7d71ace4428e5d0d478378a226e05c Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Tue, 4 May 2021 23:11:15 -0700 Subject: [PATCH 145/740] formatting --- fdbclient/NativeAPI.actor.cpp | 14 +++++++------- fdbserver/storageserver.actor.cpp | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index d160a7aa28e..6e9aeacdc16 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -3577,13 +3577,13 @@ ACTOR Future getRangeStream(PromiseStream _results, } Future getRange(Database const& cx, - Future const& fVersion, - KeySelector const& begin, - KeySelector const& end, - GetRangeLimits const& limits, - bool const& reverse, - TransactionInfo const& info, - TagSet const& tags) { + Future const& fVersion, + KeySelector const& begin, + KeySelector const& end, + GetRangeLimits const& limits, + bool const& reverse, + TransactionInfo const& info, + TagSet const& tags) { return getRange(cx, Reference(), fVersion, diff --git a/fdbserver/storageserver.actor.cpp b/fdbserver/storageserver.actor.cpp index ddabfe2d5b0..aa90f7f315c 100644 --- a/fdbserver/storageserver.actor.cpp +++ b/fdbserver/storageserver.actor.cpp @@ -4355,7 +4355,7 @@ ACTOR Future metricsCore(StorageServer* self, StorageServerInterface ssi) SERVER_KNOBS->STORAGE_LOGGING_DELAY, &self->counters.cc, self->thisServerID.toString() + "/StorageMetrics", - [tag, self=self](TraceEvent& te) { + [tag, self = self](TraceEvent& te) { te.detail("Tag", tag.toString()); StorageBytes sb = self->storage.getStorageBytes(); te.detail("KvstoreBytesUsed", sb.used); From cc72789661d8b6a50fc40187f901a35d4961e547 Mon Sep 17 00:00:00 2001 From: Jon Fu Date: Tue, 4 May 2021 19:54:33 -0400 Subject: [PATCH 146/740] Merge pull request #4763 from sfc-gh-jfu/jfu-fix-docs Fix documentation build --- documentation/sphinx/source/administration.rst | 2 +- documentation/sphinx/source/release-notes/release-notes-620.rst | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/documentation/sphinx/source/administration.rst b/documentation/sphinx/source/administration.rst index c71d26ee41e..7053a78ca08 100644 --- a/documentation/sphinx/source/administration.rst +++ b/documentation/sphinx/source/administration.rst @@ -801,7 +801,7 @@ Upgrading from Older Versions Upgrades from versions older than 5.0.0 are no longer supported. Version-specific notes on downgrading -=================================== +===================================== In general, downgrades between non-patch releases (i.e. 6.2.x - 6.1.x) are not supported. diff --git a/documentation/sphinx/source/release-notes/release-notes-620.rst b/documentation/sphinx/source/release-notes/release-notes-620.rst index b61b33e4451..3e388a81299 100644 --- a/documentation/sphinx/source/release-notes/release-notes-620.rst +++ b/documentation/sphinx/source/release-notes/release-notes-620.rst @@ -9,6 +9,7 @@ Release Notes * Backup agent no longer uses 4k block caching layer on local output files so that write operations are larger. `(PR #4428) `_ * Fix accounting error that could cause commits to incorrectly fail with ``proxy_memory_limit_exceeded``. `(PR #4529) `_ * Added support for downgrades from FDB version 6.3. For more details, see the :ref:`administration notes `. `(PR #4673) `_ `(PR #4469) `_ + 6.2.32 ====== * Fix an issue where symbolic links in cmake-built RPMs are broken if you unpack the RPM to a custom directory. `(PR #4380) `_ From 5bff9cd1964da862416210b9b1848b7c215da3d6 Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Tue, 4 May 2021 18:07:48 -0700 Subject: [PATCH 147/740] Merge pull request #4756 from apple/revert-4562-bugfixes/simulator-close-files Revert "Actually close files in simulation" --- fdbrpc/AsyncFileNonDurable.actor.h | 14 -------------- fdbrpc/sim2.actor.cpp | 16 ++++++++-------- flow/flow.h | 2 -- 3 files changed, 8 insertions(+), 24 deletions(-) diff --git a/fdbrpc/AsyncFileNonDurable.actor.h b/fdbrpc/AsyncFileNonDurable.actor.h index 28b3506d6e0..00c0f7441d7 100644 --- a/fdbrpc/AsyncFileNonDurable.actor.h +++ b/fdbrpc/AsyncFileNonDurable.actor.h @@ -276,20 +276,6 @@ class AsyncFileNonDurable final : public IAsyncFile, public ReferenceCounted deleteFuture = deleteFile(this); if (!deleteFuture.isReady()) filesBeingDeleted[filename] = deleteFuture; - } else if (isSoleOwner()) { - // isSoleOwner is a bit confusing here. What we mean is that the openFiles map is the sole owner. If we - // remove the file from the map to make sure it gets closed. - auto& openFiles = g_simulator.getCurrentProcess()->machine->openFiles; - auto iter = openFiles.find(filename); - // the file could've been renamed (DiskQueue does that for example). In that case the file won't be in the - // map anymore. - if (iter != openFiles.end()) { - // even if the filename exists, it doesn't mean that it references the same file. It could be that the - // file was renamed and later a file with the same name was opened. - if (iter->second.canGet() && iter->second.get().getPtr() == this) { - openFiles.erase(filename); - } - } } } diff --git a/fdbrpc/sim2.actor.cpp b/fdbrpc/sim2.actor.cpp index d72dcc62b8d..5cf65da0a5e 100644 --- a/fdbrpc/sim2.actor.cpp +++ b/fdbrpc/sim2.actor.cpp @@ -537,10 +537,7 @@ class SimpleFile : public IAsyncFile, public ReferenceCounted { std::string getFilename() const override { return actualFilename; } - ~SimpleFile() override { - _close(h); - --openCount; - } + ~SimpleFile() override { _close(h); } private: int h; @@ -1941,7 +1938,10 @@ class Sim2 final : public ISimulator, public INetworkConnections { TraceEvent("ClogInterface") .detail("IP", ip.toString()) .detail("Delay", seconds) - .detail("Queue", mode == ClogSend ? "Send" : mode == ClogReceive ? "Receive" : "All"); + .detail("Queue", + mode == ClogSend ? "Send" + : mode == ClogReceive ? "Receive" + : "All"); if (mode == ClogSend || mode == ClogAll) g_clogging.clogSendFor(ip, seconds); @@ -2415,9 +2415,9 @@ int sf_open(const char* filename, int flags, int convFlags, int mode) { GENERIC_READ | ((flags & IAsyncFile::OPEN_READWRITE) ? GENERIC_WRITE : 0), FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, - (flags & IAsyncFile::OPEN_EXCLUSIVE) - ? CREATE_NEW - : (flags & IAsyncFile::OPEN_CREATE) ? OPEN_ALWAYS : OPEN_EXISTING, + (flags & IAsyncFile::OPEN_EXCLUSIVE) ? CREATE_NEW + : (flags & IAsyncFile::OPEN_CREATE) ? OPEN_ALWAYS + : OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); int h = -1; diff --git a/flow/flow.h b/flow/flow.h index 86d5ce05298..8388113253b 100644 --- a/flow/flow.h +++ b/flow/flow.h @@ -805,8 +805,6 @@ class Future { bool isValid() const { return sav != 0; } bool isReady() const { return sav->isSet(); } bool isError() const { return sav->isError(); } - // returns true if get can be called on this future (counterpart of canBeSet on Promises) - bool canGet() const { return isValid() && isReady() && !isError(); } Error& getError() const { ASSERT(isError()); return sav->error_state; From eaefd03bb0a3748e606a74b0ec46ea92c7861336 Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Wed, 5 May 2021 10:03:29 -0700 Subject: [PATCH 148/740] Merge pull request #4747 from sfc-gh-anoyes/anoyes/fix-clang-unseed-mismatch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use a deterministic iteration order for committing in the special key… --- fdbclient/SpecialKeySpace.actor.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/fdbclient/SpecialKeySpace.actor.cpp b/fdbclient/SpecialKeySpace.actor.cpp index 9eb8e3aacb9..5d24fa4c985 100644 --- a/fdbclient/SpecialKeySpace.actor.cpp +++ b/fdbclient/SpecialKeySpace.actor.cpp @@ -572,16 +572,20 @@ ACTOR Future commitActor(SpecialKeySpace* sks, ReadYourWritesTransaction* state RangeMap>, KeyRangeRef>::Ranges ranges = ryw->getSpecialKeySpaceWriteMap().containedRanges(specialKeys); state RangeMap>, KeyRangeRef>::iterator iter = ranges.begin(); - state std::set writeModulePtrs; + state std::vector writeModulePtrs; + std::unordered_set deduplicate; while (iter != ranges.end()) { std::pair> entry = iter->value(); if (entry.first) { auto modulePtr = sks->getRWImpls().rangeContaining(iter->begin())->value(); - writeModulePtrs.insert(modulePtr); + auto [_, inserted] = deduplicate.insert(modulePtr); + if (inserted) { + writeModulePtrs.push_back(modulePtr); + } } ++iter; } - state std::set::const_iterator it; + state std::vector::const_iterator it; for (it = writeModulePtrs.begin(); it != writeModulePtrs.end(); ++it) { Optional msg = wait((*it)->commit(ryw)); if (msg.present()) { From e25d2ed489a693bc336a61110650da4da91d105a Mon Sep 17 00:00:00 2001 From: sfc-gh-tclinkenbeard Date: Wed, 5 May 2021 14:18:06 -0700 Subject: [PATCH 149/740] Use default initializer for TraceEvent::errorKind --- flow/Trace.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flow/Trace.h b/flow/Trace.h index ef86671cc17..4c2eadb215b 100644 --- a/flow/Trace.h +++ b/flow/Trace.h @@ -483,7 +483,7 @@ struct TraceEvent { std::string trackingKey; TraceEventFields fields; Severity severity; - ErrorKind errorKind; + ErrorKind errorKind{ ErrorKind::Unset }; const char* type; UID id; Error err; From 40169600adbfa92ae41d47496c69dd26afa2f0fe Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Wed, 5 May 2021 16:05:34 -0700 Subject: [PATCH 150/740] Merge pull request #4746 from sfc-gh-ljoswiak/fixes/boost Fix boost download links --- README.md | 2 +- build/cmake/Dockerfile | 2 +- build/docker/centos6/build/Dockerfile | 4 ++-- build/docker/centos7/build/Dockerfile | 4 ++-- cmake/CompileBoost.cmake | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 44b451c1355..cd28c798f0f 100755 --- a/README.md +++ b/README.md @@ -171,7 +171,7 @@ that Visual Studio is used to compile. 1. Install Visual Studio 2017 (Community Edition is tested) 1. Install cmake Version 3.12 or higher [CMake](https://cmake.org/) -1. Download version 1.72 of [Boost](https://dl.bintray.com/boostorg/release/1.72.0/source/boost_1_72_0.tar.bz2) +1. Download version 1.72 of [Boost](https://boostorg.jfrog.io/artifactory/main/release/1.72.0/source/boost_1_72_0.tar.bz2) 1. Unpack boost (you don't need to compile it) 1. Install [Mono](http://www.mono-project.com/download/stable/) 1. (Optional) Install a [JDK](http://www.oracle.com/technetwork/java/javase/downloads/index.html). FoundationDB currently builds with Java 8 diff --git a/build/cmake/Dockerfile b/build/cmake/Dockerfile index 3f9d51a29a4..0452606a1fe 100644 --- a/build/cmake/Dockerfile +++ b/build/cmake/Dockerfile @@ -13,7 +13,7 @@ RUN curl -L https://github.com/Kitware/CMake/releases/download/v3.13.4/cmake-3.1 cd /tmp && tar xf cmake.tar.gz && cp -r cmake-3.13.4-Linux-x86_64/* /usr/local/ # install boost -RUN curl -L https://dl.bintray.com/boostorg/release/1.67.0/source/boost_1_72_0.tar.bz2 > /tmp/boost.tar.bz2 &&\ +RUN curl -L https://boostorg.jfrog.io/artifactory/main/release/1.67.0/source/boost_1_67_0.tar.bz2 > /tmp/boost.tar.bz2 &&\ cd /tmp && echo "2684c972994ee57fc5632e03bf044746f6eb45d4920c343937a465fd67a5adba boost.tar.bz2" > boost-sha.txt &&\ sha256sum -c boost-sha.txt && tar xf boost.tar.bz2 && cp -r boost_1_72_0/boost /usr/local/include/ &&\ rm -rf boost.tar.bz2 boost_1_72_0 diff --git a/build/docker/centos6/build/Dockerfile b/build/docker/centos6/build/Dockerfile index c0076266438..08ad28256ba 100644 --- a/build/docker/centos6/build/Dockerfile +++ b/build/docker/centos6/build/Dockerfile @@ -156,7 +156,7 @@ RUN curl -Ls https://github.com/facebook/rocksdb/archive/v6.10.1.tar.gz -o rocks rm -rf /tmp/* # install boost 1.67 to /opt -RUN curl -Ls https://dl.bintray.com/boostorg/release/1.67.0/source/boost_1_67_0.tar.bz2 -o boost_1_67_0.tar.bz2 && \ +RUN curl -Ls https://boostorg.jfrog.io/artifactory/main/release/1.67.0/source/boost_1_67_0.tar.bz2 -o boost_1_67_0.tar.bz2 && \ echo "2684c972994ee57fc5632e03bf044746f6eb45d4920c343937a465fd67a5adba boost_1_67_0.tar.bz2" > boost-sha-67.txt && \ sha256sum -c boost-sha-67.txt && \ tar --no-same-owner --directory /opt -xjf boost_1_67_0.tar.bz2 && \ @@ -165,7 +165,7 @@ RUN curl -Ls https://dl.bintray.com/boostorg/release/1.67.0/source/boost_1_67_0. # install boost 1.72 to /opt RUN source /opt/rh/devtoolset-8/enable && \ - curl -Ls https://dl.bintray.com/boostorg/release/1.72.0/source/boost_1_72_0.tar.bz2 -o boost_1_72_0.tar.bz2 && \ + curl -Ls https://boostorg.jfrog.io/artifactory/main/release/1.72.0/source/boost_1_72_0.tar.bz2 -o boost_1_72_0.tar.bz2 && \ echo "59c9b274bc451cf91a9ba1dd2c7fdcaf5d60b1b3aa83f2c9fa143417cc660722 boost_1_72_0.tar.bz2" > boost-sha-72.txt && \ sha256sum -c boost-sha-72.txt && \ tar --no-same-owner --directory /opt -xjf boost_1_72_0.tar.bz2 && \ diff --git a/build/docker/centos7/build/Dockerfile b/build/docker/centos7/build/Dockerfile index 18773c041a8..3492fc15f49 100644 --- a/build/docker/centos7/build/Dockerfile +++ b/build/docker/centos7/build/Dockerfile @@ -139,7 +139,7 @@ RUN curl -Ls https://github.com/facebook/rocksdb/archive/v6.10.1.tar.gz -o rocks rm -rf /tmp/* # install boost 1.67 to /opt -RUN curl -Ls https://dl.bintray.com/boostorg/release/1.67.0/source/boost_1_67_0.tar.bz2 -o boost_1_67_0.tar.bz2 && \ +RUN curl -Ls https://boostorg.jfrog.io/artifactory/main/release/1.67.0/source/boost_1_67_0.tar.bz2 -o boost_1_67_0.tar.bz2 && \ echo "2684c972994ee57fc5632e03bf044746f6eb45d4920c343937a465fd67a5adba boost_1_67_0.tar.bz2" > boost-sha-67.txt && \ sha256sum -c boost-sha-67.txt && \ tar --no-same-owner --directory /opt -xjf boost_1_67_0.tar.bz2 && \ @@ -148,7 +148,7 @@ RUN curl -Ls https://dl.bintray.com/boostorg/release/1.67.0/source/boost_1_67_0. # install boost 1.72 to /opt RUN source /opt/rh/devtoolset-8/enable && \ - curl -Ls https://dl.bintray.com/boostorg/release/1.72.0/source/boost_1_72_0.tar.bz2 -o boost_1_72_0.tar.bz2 && \ + curl -Ls https://boostorg.jfrog.io/artifactory/main/release/1.72.0/source/boost_1_72_0.tar.bz2 -o boost_1_72_0.tar.bz2 && \ echo "59c9b274bc451cf91a9ba1dd2c7fdcaf5d60b1b3aa83f2c9fa143417cc660722 boost_1_72_0.tar.bz2" > boost-sha-72.txt && \ sha256sum -c boost-sha-72.txt && \ tar --no-same-owner --directory /opt -xjf boost_1_72_0.tar.bz2 && \ diff --git a/cmake/CompileBoost.cmake b/cmake/CompileBoost.cmake index 0b1cc68502d..687c266f0b7 100644 --- a/cmake/CompileBoost.cmake +++ b/cmake/CompileBoost.cmake @@ -38,7 +38,7 @@ function(compile_boost) include(ExternalProject) set(BOOST_INSTALL_DIR "${CMAKE_BINARY_DIR}/boost_install") ExternalProject_add("${MY_TARGET}Project" - URL "https://dl.bintray.com/boostorg/release/1.72.0/source/boost_1_72_0.tar.bz2" + URL "https://boostorg.jfrog.io/artifactory/main/release/1.72.0/source/boost_1_72_0.tar.bz2" URL_HASH SHA256=59c9b274bc451cf91a9ba1dd2c7fdcaf5d60b1b3aa83f2c9fa143417cc660722 CONFIGURE_COMMAND ./bootstrap.sh ${BOOTSTRAP_ARGS} BUILD_COMMAND ${B2_COMMAND} link=static ${MY_BUILD_ARGS} --prefix=${BOOST_INSTALL_DIR} ${USER_CONFIG_FLAG} install From b68051fd2d7a45fbe5f58cece170254841f91250 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Thu, 6 May 2021 15:46:49 -0700 Subject: [PATCH 151/740] fix: endpointNotFound needs to be called on the endpoint of the RequestStream, not the endpoint of the reply --- fdbrpc/fdbrpc.h | 10 ++-------- fdbrpc/genericactors.actor.h | 15 +++++++++++---- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index 508ca0352ab..d987456db2f 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -105,9 +105,6 @@ struct NetSAV final : SAV, FlowReceiver, FastAllocated> { ErrorOr> message; reader.deserialize(message); if (message.isError()) { - if (message.getError().code() == error_code_broken_promise) { - IFailureMonitor::failureMonitor().endpointNotFound(getRawEndpoint()); - } SAV::sendErrorAndDelPromiseRef(message.getError()); } else { SAV::sendAndDelPromiseRef(message.get().asUnderlyingType()); @@ -327,9 +324,6 @@ struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAl reader.deserialize(message); if (message.isError()) { - if (message.getError().code() == error_code_broken_promise) { - IFailureMonitor::failureMonitor().endpointNotFound(getRawEndpoint()); - } this->sendError(message.getError()); } else { if (message.get().asUnderlyingType().acknowledgeToken.present()) { @@ -661,7 +655,7 @@ class RequestStream { Reference peer = FlowTransport::transport().sendUnreliable(SerializeSource(value), getEndpoint(taskID), true); // FIXME: defer sending the message until we know the connection is established - endStreamOnDisconnect(disc, p, peer); + endStreamOnDisconnect(disc, p, getEndpoint(taskID), peer); return p; } send(value); @@ -677,7 +671,7 @@ class RequestStream { Reference peer = FlowTransport::transport().sendUnreliable(SerializeSource(value), getEndpoint(), true); // FIXME: defer sending the message until we know the connection is established - endStreamOnDisconnect(disc, p, peer); + endStreamOnDisconnect(disc, p, getEndpoint(), peer); return p; } else { send(value); diff --git a/fdbrpc/genericactors.actor.h b/fdbrpc/genericactors.actor.h index ef0283ad235..f00182b5778 100644 --- a/fdbrpc/genericactors.actor.h +++ b/fdbrpc/genericactors.actor.h @@ -206,11 +206,18 @@ struct PeerHolder { ACTOR template void endStreamOnDisconnect(Future signal, ReplyPromiseStream stream, + Endpoint endpoint, Reference peer = Reference()) { state PeerHolder holder = PeerHolder(peer); - choose { - when(wait(signal)) { stream.sendError(connection_failed()); } - when(wait(stream.getErrorFutureAndDelPromiseRef())) {} + try { + choose { + when(wait(signal)) { stream.sendError(connection_failed()); } + when(wait(stream.getErrorFutureAndDelPromiseRef())) {} + } + } catch (Error& e) { + if (e.code() == error_code_broken_promise) { + IFailureMonitor::failureMonitor().endpointNotFound(endpoint); + } } } @@ -241,7 +248,7 @@ Future> waitValueOrSignal(Future value, // receiving the failure signal if (e.code() != error_code_broken_promise || signal.isError()) return ErrorOr(e); - + IFailureMonitor::failureMonitor().endpointNotFound(endpoint); value = Never(); } } From d918f080360fb52d41a3312f1618b79bfe86b5b3 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Thu, 6 May 2021 23:15:14 -0700 Subject: [PATCH 152/740] fix: handle a streaming read lasting long enough that the version is gone --- fdbserver/storageserver.actor.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fdbserver/storageserver.actor.cpp b/fdbserver/storageserver.actor.cpp index aa90f7f315c..74000e4223f 100644 --- a/fdbserver/storageserver.actor.cpp +++ b/fdbserver/storageserver.actor.cpp @@ -2047,6 +2047,11 @@ ACTOR Future getKeyValuesStreamQ(StorageServer* data, GetKeyValuesStreamRe } else { loop { wait(req.reply.onReady()); + + if (version < data->oldestVersion.get()) { + throw transaction_too_old(); + } + state int byteLimit = CLIENT_KNOBS->REPLY_BYTE_LIMIT; GetKeyValuesReply _r = wait(readRange(data, version, KeyRangeRef(begin, end), req.limit, &byteLimit, span.context)); From def877382f3f06978119f2d96674e945b1cdf565 Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Thu, 6 May 2021 23:16:02 -0700 Subject: [PATCH 153/740] hold a reference to the promise because the second could cause it to be replaced by a new promise which will crash --- fdbrpc/fdbrpc.h | 1 + 1 file changed, 1 insertion(+) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index d987456db2f..819425f52ff 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -297,6 +297,7 @@ struct AcknowledgementReceiver final : FlowReceiver, FastAllocatedACKNOWLEDGE_LIMIT_BYTES && ready.isValid() && ready.canBeSet()) { + Promise hold = ready; ready.send(Void()); } } From 3e74686c2a420ff8a6122ba3608eb3021869563e Mon Sep 17 00:00:00 2001 From: Evan Tschannen Date: Sun, 9 May 2021 22:34:43 -0700 Subject: [PATCH 154/740] fix: endStreamOnDisconnect gets broken promises when dropping references to the ReplyPromise, so it cannot be used for endpointNotFound --- fdbrpc/fdbrpc.h | 7 +++++++ fdbrpc/genericactors.actor.h | 13 ++++--------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/fdbrpc/fdbrpc.h b/fdbrpc/fdbrpc.h index 819425f52ff..5d5ee2f83b1 100644 --- a/fdbrpc/fdbrpc.h +++ b/fdbrpc/fdbrpc.h @@ -310,6 +310,7 @@ struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAl using FastAllocated>::operator delete; AcknowledgementReceiver acknowledgements; + Endpoint requestStreamEndpoint; NetNotifiedQueueWithErrors(int futures, int promises) : NotifiedQueue(futures, promises) {} NetNotifiedQueueWithErrors(int futures, int promises, const Endpoint& remoteEndpoint) @@ -325,6 +326,10 @@ struct NetNotifiedQueueWithErrors final : NotifiedQueue, FlowReceiver, FastAl reader.deserialize(message); if (message.isError()) { + if (message.getError().code() == error_code_broken_promise) { + ASSERT(requestStreamEndpoint.isValid()); + IFailureMonitor::failureMonitor().endpointNotFound(requestStreamEndpoint); + } this->sendError(message.getError()); } else { if (message.get().asUnderlyingType().acknowledgeToken.present()) { @@ -437,6 +442,8 @@ class ReplyPromiseStream { return res; } + void setRequestStreamEndpoint(const Endpoint& endpoint) { queue->requestStreamEndpoint = endpoint; } + ~ReplyPromiseStream() { if (queue) queue->delPromiseRef(); diff --git a/fdbrpc/genericactors.actor.h b/fdbrpc/genericactors.actor.h index f00182b5778..23bd3e97c25 100644 --- a/fdbrpc/genericactors.actor.h +++ b/fdbrpc/genericactors.actor.h @@ -209,15 +209,10 @@ void endStreamOnDisconnect(Future signal, Endpoint endpoint, Reference peer = Reference()) { state PeerHolder holder = PeerHolder(peer); - try { - choose { - when(wait(signal)) { stream.sendError(connection_failed()); } - when(wait(stream.getErrorFutureAndDelPromiseRef())) {} - } - } catch (Error& e) { - if (e.code() == error_code_broken_promise) { - IFailureMonitor::failureMonitor().endpointNotFound(endpoint); - } + stream.setRequestStreamEndpoint(endpoint); + choose { + when(wait(signal)) { stream.sendError(connection_failed()); } + when(wait(stream.getErrorFutureAndDelPromiseRef())) {} } } From f84e9c6b72d6725116f373d0708adc34d053706e Mon Sep 17 00:00:00 2001 From: Lukas Joswiak Date: Mon, 10 May 2021 20:36:35 -0700 Subject: [PATCH 155/740] Revert "Merge pull request #4136 from sfc-gh-mpilman/features/actor-lineage" This reverts commit da41534618a2a1edbf6b0b760635175372a66294, reversing changes made to e6300905d6f294c52ebd166f4714541b084f37b4. --- CMakeLists.txt | 1 - cmake/GetMsgpack.cmake | 20 -- fdbclient/ActorLineageProfiler.cpp | 381 ------------------------ fdbclient/ActorLineageProfiler.h | 192 ------------ fdbclient/AnnotateActor.cpp | 23 -- fdbclient/AnnotateActor.h | 85 ------ fdbclient/CMakeLists.txt | 9 +- fdbclient/FluentDSampleIngestor.cpp | 257 ---------------- fdbclient/GlobalConfig.actor.cpp | 46 +-- fdbclient/GlobalConfig.actor.h | 29 +- fdbclient/NativeAPI.actor.cpp | 20 +- fdbclient/ProcessInterface.h | 81 ----- fdbclient/SpecialKeySpace.actor.cpp | 293 +----------------- fdbclient/SpecialKeySpace.actor.h | 29 -- fdbclient/TransactionLineage.cpp | 25 -- fdbclient/TransactionLineage.h | 128 -------- fdbclient/Tuple.cpp | 29 -- fdbclient/Tuple.h | 4 +- fdbrpc/AsyncFileKAIO.actor.h | 7 +- fdbrpc/FlowTests.actor.cpp | 4 - fdbrpc/FlowTransport.actor.cpp | 2 +- fdbrpc/IAsyncFile.h | 4 - fdbrpc/Locality.h | 1 - fdbrpc/Net2FileSystem.cpp | 4 - fdbrpc/Net2FileSystem.h | 3 - fdbrpc/sim2.actor.cpp | 11 - fdbrpc/simulator.h | 4 - fdbserver/CMakeLists.txt | 3 - fdbserver/ClusterController.actor.cpp | 4 +- fdbserver/CommitProxyServer.actor.cpp | 6 +- fdbserver/GrvProxyServer.actor.cpp | 5 - fdbserver/RoleLineage.actor.cpp | 25 -- fdbserver/RoleLineage.actor.h | 67 ----- fdbserver/SigStack.cpp | 23 -- fdbserver/WorkerInterface.actor.h | 35 --- fdbserver/fdbserver.actor.cpp | 38 +-- fdbserver/storageserver.actor.cpp | 11 - fdbserver/worker.actor.cpp | 70 ----- flow/CMakeLists.txt | 1 - flow/Net2.actor.cpp | 12 +- flow/Platform.actor.cpp | 4 - flow/Platform.h | 6 +- flow/Profiler.actor.cpp | 3 - flow/WriteOnlySet.actor.cpp | 273 ----------------- flow/WriteOnlySet.h | 162 ---------- flow/actorcompiler/ActorCompiler.cs | 2 - flow/actorcompiler/actorcompiler.csproj | 108 ++++++- flow/actorcompiler/actorcompiler.sln | 34 --- flow/flow.cpp | 21 -- flow/flow.h | 188 +----------- flow/genericactors.actor.h | 4 - flow/network.h | 4 - flow/singleton.h | 237 --------------- tests/TestRunner/local_cluster.py | 2 +- 54 files changed, 142 insertions(+), 2898 deletions(-) delete mode 100644 cmake/GetMsgpack.cmake delete mode 100644 fdbclient/ActorLineageProfiler.cpp delete mode 100644 fdbclient/ActorLineageProfiler.h delete mode 100644 fdbclient/AnnotateActor.cpp delete mode 100644 fdbclient/AnnotateActor.h delete mode 100644 fdbclient/FluentDSampleIngestor.cpp delete mode 100644 fdbclient/ProcessInterface.h delete mode 100644 fdbclient/TransactionLineage.cpp delete mode 100644 fdbclient/TransactionLineage.h delete mode 100644 fdbserver/RoleLineage.actor.cpp delete mode 100644 fdbserver/RoleLineage.actor.h delete mode 100644 fdbserver/SigStack.cpp delete mode 100644 flow/WriteOnlySet.actor.cpp delete mode 100644 flow/WriteOnlySet.h delete mode 100644 flow/actorcompiler/actorcompiler.sln delete mode 100644 flow/singleton.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 2e48d954476..f6e85984f16 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -152,7 +152,6 @@ if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") endif() include(CompileBoost) -include(GetMsgpack) add_subdirectory(flow) add_subdirectory(fdbrpc) add_subdirectory(fdbclient) diff --git a/cmake/GetMsgpack.cmake b/cmake/GetMsgpack.cmake deleted file mode 100644 index b3313f336e9..00000000000 --- a/cmake/GetMsgpack.cmake +++ /dev/null @@ -1,20 +0,0 @@ -find_package(msgpack 3.3.0 EXACT QUIET CONFIG) - -add_library(msgpack INTERFACE) - -if(msgpack_FOUND) - target_link_libraries(msgpack INTERFACE msgpackc-cxx) -else() - include(ExternalProject) - ExternalProject_add(msgpackProject - URL "https://github.com/msgpack/msgpack-c/releases/download/cpp-3.3.0/msgpack-3.3.0.tar.gz" - URL_HASH SHA256=6e114d12a5ddb8cb11f669f83f32246e484a8addd0ce93f274996f1941c1f07b - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" - ) - - ExternalProject_Get_property(msgpackProject SOURCE_DIR) - target_include_directories(msgpack SYSTEM INTERFACE "${SOURCE_DIR}/include") - add_dependencies(msgpack msgpackProject) -endif() diff --git a/fdbclient/ActorLineageProfiler.cpp b/fdbclient/ActorLineageProfiler.cpp deleted file mode 100644 index 9be7a60704b..00000000000 --- a/fdbclient/ActorLineageProfiler.cpp +++ /dev/null @@ -1,381 +0,0 @@ -/* - * ActorLineageProfiler.cpp - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2021 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "flow/flow.h" -#include "flow/singleton.h" -#include "fdbrpc/IAsyncFile.h" -#include "fdbclient/ActorLineageProfiler.h" -#include -#include -#include -#include - -using namespace std::literals; - -class Packer : public msgpack::packer { - struct visitor_t { - using VisitorMap = std::unordered_map>; - VisitorMap visitorMap; - - template - static void any_visitor(std::any const& val, Packer& packer) { - const T& v = std::any_cast(val); - packer.pack(v); - } - - template - struct populate_visitor_map; - template - struct populate_visitor_map { - static void populate(VisitorMap& map) { - map.emplace(std::type_index(typeid(Head)), any_visitor); - populate_visitor_map::populate(map); - } - }; - template - struct populate_visitor_map { - static void populate(VisitorMap&) {} - }; - - visitor_t() { - populate_visitor_map, - std::map, - std::map, - std::vector>>::populate(visitorMap); - } - - void visit(const std::any& val, Packer& packer) { - auto iter = visitorMap.find(val.type()); - if (iter == visitorMap.end()) { - TraceEvent(SevError, "PackerTypeNotFound").detail("Type", val.type().name()); - } else { - iter->second(val, packer); - } - } - }; - msgpack::sbuffer sbuffer; - // Initializing visitor_t involves building a type-map. As this is a relatively expensive operation, we don't want - // to do this each time we create a Packer object. So visitor_t is a stateless class and we only use it as a - // visitor. - crossbow::singleton visitor; - -public: - Packer() : msgpack::packer(sbuffer) {} - - void pack(std::any const& val) { visitor->visit(val, *this); } - - void pack(bool val) { - if (val) { - pack_true(); - } else { - pack_false(); - } - } - - void pack(uint64_t val) { - if (val <= std::numeric_limits::max()) { - pack_uint8(uint8_t(val)); - } else if (val <= std::numeric_limits::max()) { - pack_uint16(uint16_t(val)); - } else if (val <= std::numeric_limits::max()) { - pack_uint32(uint32_t(val)); - } else { - pack_uint64(val); - } - } - - void pack(int64_t val) { - if (val >= 0) { - this->pack(uint64_t(val)); - } else if (val >= std::numeric_limits::min()) { - pack_int8(int8_t(val)); - } else if (val >= std::numeric_limits::min()) { - pack_int16(int16_t(val)); - } else if (val >= std::numeric_limits::min()) { - pack_int32(int32_t(val)); - } else if (val >= std::numeric_limits::min()) { - pack_int64(int64_t(val)); - } - } - - void pack(float val) { pack_float(val); } - void pack(double val) { pack_double(val); } - void pack(std::string const& str) { - pack_str(str.size()); - pack_str_body(str.data(), str.size()); - } - - void pack(std::string_view val) { - pack_str(val.size()); - pack_str_body(val.data(), val.size()); - } - - template - void pack(std::map const& map) { - pack_map(map.size()); - for (const auto& p : map) { - pack(p.first); - pack(p.second); - } - } - - template - void pack(std::vector const& val) { - pack_array(val.size()); - for (const auto& v : val) { - pack(v); - } - } - - std::pair getbuf() { - unsigned size = sbuffer.size(); - return std::make_pair(sbuffer.release(), size); - } -}; - -IALPCollectorBase::IALPCollectorBase() { - SampleCollector::instance().addCollector(this); -} - -std::map SampleCollectorT::collect(ActorLineage* lineage) { - std::map out; - for (auto& collector : collectors) { - auto val = collector->collect(lineage); - if (val.has_value()) { - out[collector->name()] = val.value(); - } - } - return out; -} - -std::shared_ptr SampleCollectorT::collect() { - auto sample = std::make_shared(); - double time = g_network->now(); - sample->time = time; - for (auto& p : getSamples) { - Packer packer; - std::vector> samples; - auto sampleVec = p.second(); - for (auto& val : sampleVec) { - auto m = collect(val.getPtr()); - if (!m.empty()) { - samples.emplace_back(std::move(m)); - } - } - if (!samples.empty()) { - packer.pack(samples); - sample->data[p.first] = packer.getbuf(); - } - } - return sample; -} - -void SampleCollection_t::refresh() { - auto sample = _collector->collect(); - auto min = std::min(sample->time - windowSize, sample->time); - { - Lock _{ mutex }; - data.emplace_back(std::move(sample)); - } - double oldest = data.front()->time; - // we don't need to check for data.empty() in this loop (or the inner loop) as we know that we will end - // up with at least one entry which is the most recent sample - while (oldest < min) { - Lock _{ mutex }; - // we remove at most 10 elements at a time. This is so we don't block the main thread for too long. - for (int i = 0; i < 10 && oldest < min; ++i) { - data.pop_front(); - oldest = data.front()->time; - } - } - //config->ingest(sample); -} - -std::vector> SampleCollection_t::get(double from /*= 0.0*/, - double to /*= std::numeric_limits::max()*/) const { - Lock _{ mutex }; - std::vector> res; - for (const auto& sample : data) { - if (sample->time > to) { - break; - } else if (sample->time >= from) { - res.push_back(sample); - } - } - return res; -} - -struct ProfilerImpl { - boost::asio::io_context context; - boost::asio::executor_work_guard workGuard; - boost::asio::steady_timer timer; - std::thread mainThread; - unsigned frequency; - - SampleCollection collection; - - ProfilerImpl() : workGuard(context.get_executor()), timer(context) { - mainThread = std::thread([this]() { context.run(); }); - } - ~ProfilerImpl() { - setFrequency(0); - workGuard.reset(); - mainThread.join(); - } - - void profileHandler(boost::system::error_code const& ec) { - if (ec) { - return; - } - collection->refresh(); - timer = boost::asio::steady_timer(context, std::chrono::microseconds(1000000 / frequency)); - timer.async_wait([this](auto const& ec) { profileHandler(ec); }); - } - - void setFrequency(unsigned frequency) { - boost::asio::post(context, [this, frequency]() { - this->frequency = frequency; - timer.cancel(); - if (frequency > 0) { - profileHandler(boost::system::error_code{}); - } - }); - } -}; - -ActorLineageProfilerT::ActorLineageProfilerT() : impl(new ProfilerImpl()) { - collection->collector()->addGetter(WaitState::Network, - std::bind(&ActorLineageSet::copy, std::ref(g_network->getActorLineageSet()))); - collection->collector()->addGetter( - WaitState::Disk, - std::bind(&ActorLineageSet::copy, std::ref(IAsyncFileSystem::filesystem()->getActorLineageSet()))); - collection->collector()->addGetter(WaitState::Running, []() { - auto res = currentLineageThreadSafe.get(); - if (res.isValid()) { - return std::vector>({ res }); - } - return std::vector>(); - }); -} - -ActorLineageProfilerT::~ActorLineageProfilerT() { - delete impl; -} - -void ActorLineageProfilerT::setFrequency(unsigned frequency) { - impl->setFrequency(frequency); -} - -boost::asio::io_context& ActorLineageProfilerT::context() { - return impl->context; -} - -SampleIngestor::~SampleIngestor() {} - -// Callback used to update the sampling profilers run frequency whenever the -// frequency changes. -void samplingProfilerUpdateFrequency(std::optional freq) { - double frequency = 0; - if (freq.has_value()) { - frequency = std::any_cast(freq.value()); - } - TraceEvent(SevInfo, "SamplingProfilerUpdateFrequency").detail("Frequency", frequency); - ActorLineageProfiler::instance().setFrequency(frequency); -} - -void ProfilerConfigT::reset(std::map const& config) { - bool expectNoMore = false, useFluentD = false, useTCP = false; - std::string endpoint; - ConfigError err; - for (auto& kv : config) { - if (expectNoMore) { - err.description = format("Unexpected option %s", kv.first.c_str()); - throw err; - } - if (kv.first == "collector") { - std::string val = kv.second; - std::for_each(val.begin(), val.end(), [](auto c) { return std::tolower(c); }); - if (val == "none") { - setBackend(std::make_shared()); - } else if (val == "fluentd") { - useFluentD = true; - } else { - err.description = format("Unsupported collector: %s", val.c_str()); - throw err; - } - } else if (kv.first == "collector_endpoint") { - endpoint = kv.second; - } else if (kv.first == "collector_protocol") { - auto val = kv.second; - std::for_each(val.begin(), val.end(), [](auto c) { return std::tolower(c); }); - if (val == "tcp") { - useTCP = true; - } else if (val == "udp") { - useTCP = false; - } else { - err.description = format("Unsupported protocol for fluentd: %s", kv.second.c_str()); - throw err; - } - } else { - err.description = format("Unknown option %s", kv.first.c_str()); - throw err; - } - } - if (useFluentD) { - if (endpoint.empty()) { - err.description = "Endpoint is required for fluentd ingestor"; - throw err; - } - NetworkAddress address; - try { - address = NetworkAddress::parse(endpoint); - } catch (Error& e) { - err.description = format("Can't parse address %s", endpoint.c_str()); - throw err; - } - setBackend(std::make_shared( - useTCP ? FluentDIngestor::Protocol::TCP : FluentDIngestor::Protocol::TCP, address)); - } -} - -std::map ProfilerConfigT::getConfig() const { - std::map res; - if (ingestor) { - ingestor->getConfig(res); - } - return res; -} - -// Callback used to update the sample collector window size. -void samplingProfilerUpdateWindow(std::optional window) { - double duration = 0; - if (window.has_value()) { - duration = std::any_cast(window.value()); - } - TraceEvent(SevInfo, "SamplingProfilerUpdateWindow").detail("Duration", duration); - SampleCollection::instance().setWindowSize(duration); -} diff --git a/fdbclient/ActorLineageProfiler.h b/fdbclient/ActorLineageProfiler.h deleted file mode 100644 index 30a3eec3e7b..00000000000 --- a/fdbclient/ActorLineageProfiler.h +++ /dev/null @@ -1,192 +0,0 @@ -/* - * ActorLineageProfiler.h - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2021 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "fdbclient/AnnotateActor.h" - -#include -#include -#include -#include -#include -#include -#include "flow/singleton.h" -#include "flow/flow.h" - -void samplingProfilerUpdateFrequency(std::optional freq); -void samplingProfilerUpdateWindow(std::optional window); - -struct IALPCollectorBase { - virtual std::optional collect(ActorLineage*) = 0; - virtual const std::string_view& name() = 0; - IALPCollectorBase(); -}; - -template -struct IALPCollector : IALPCollectorBase { - const std::string_view& name() override { return T::name; } -}; - -struct Sample : std::enable_shared_from_this { - double time = 0.0; - Sample() {} - Sample(Sample const&) = delete; - Sample& operator=(Sample const&) = delete; - std::unordered_map> data; - ~Sample() { - std::for_each(data.begin(), data.end(), [](std::pair> entry) { - ::free(entry.second.first); - }); - } -}; - -class SampleIngestor : std::enable_shared_from_this { -public: - virtual ~SampleIngestor(); - virtual void ingest(std::shared_ptr const& sample) = 0; - virtual void getConfig(std::map&) const = 0; -}; - -class NoneIngestor : public SampleIngestor { -public: - void ingest(std::shared_ptr const& sample) override {} - void getConfig(std::map& res) const override { res["ingestor"] = "none"; } -}; - -// The FluentD ingestor uses the pimpl idiom. This is to make compilation less heavy weight as this implementation has -// dependencies to boost::asio -struct FluentDIngestorImpl; - -class FluentDIngestor : public SampleIngestor { -public: // Public Types - enum class Protocol { TCP, UDP }; - -private: // members - FluentDIngestorImpl* impl; - -public: // interface - void ingest(std::shared_ptr const& sample) override; - FluentDIngestor(Protocol protocol, NetworkAddress& endpoint); - void getConfig(std::map& res) const override; - ~FluentDIngestor(); -}; - -struct ConfigError { - std::string description; -}; - -class ProfilerConfigT { -private: // private types - using Lock = std::unique_lock; - friend class crossbow::create_static; - -private: // members - std::shared_ptr ingestor = std::make_shared(); - -private: // construction - ProfilerConfigT() {} - ProfilerConfigT(ProfilerConfigT const&) = delete; - ProfilerConfigT& operator=(ProfilerConfigT const&) = delete; - void setBackend(std::shared_ptr ingestor) { this->ingestor = ingestor; } - -public: - void reset(std::map const& config); - std::map getConfig() const; -}; - -using ProfilerConfig = crossbow::singleton; - -class SampleCollectorT { -public: // Types - friend struct crossbow::create_static; - using Getter = std::function>()>; - -private: - std::vector collectors; - std::map getSamples; - SampleCollectorT() {} - std::map collect(ActorLineage* lineage); - -public: - void addCollector(IALPCollectorBase* collector) { collectors.push_back(collector); } - std::shared_ptr collect(); - void addGetter(WaitState waitState, Getter const& getter) { getSamples[waitState] = getter; }; -}; - -using SampleCollector = crossbow::singleton; - -class SampleCollection_t { - friend struct crossbow::create_static; - using Lock = std::unique_lock; - SampleCollection_t() {} - - SampleCollector _collector; - mutable std::mutex mutex; - std::atomic windowSize = 0.0; - std::deque> data; - ProfilerConfig config; - -public: - /** - * Define how many samples the collection shoul keep. The window size is defined by time dimension. - * - * \param duration How long a sample should be kept in the collection. - */ - void setWindowSize(double duration) { windowSize.store(duration); } - /** - * By default returns reference counted pointers of all samples. A window can be defined in terms of absolute time. - * - * \param from The minimal age of all returned samples. - * \param to The max age of all returned samples. - */ - std::vector> get(double from = 0.0, double to = std::numeric_limits::max()) const; - /** - * Collects all new samples from the sample collector and stores them in the collection. - */ - void refresh(); - const SampleCollector& collector() const { return _collector; } - SampleCollector& collector() { return _collector; } -}; - -using SampleCollection = crossbow::singleton; - -struct ProfilerImpl; - -namespace boost { -namespace asio { -// forward declare io_context because including boost asio is super expensive -class io_context; -} // namespace asio -} // namespace boost - -class ActorLineageProfilerT { - friend struct crossbow::create_static; - ProfilerImpl* impl; - SampleCollection collection; - ActorLineageProfilerT(); - -public: - ~ActorLineageProfilerT(); - void setFrequency(unsigned frequency); - boost::asio::io_context& context(); -}; - -using ActorLineageProfiler = crossbow::singleton; diff --git a/fdbclient/AnnotateActor.cpp b/fdbclient/AnnotateActor.cpp deleted file mode 100644 index 80b9a8cec4a..00000000000 --- a/fdbclient/AnnotateActor.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * AnnotateActor.cpp - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2021 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "fdbclient/AnnotateActor.h" - -std::map>()>> samples; diff --git a/fdbclient/AnnotateActor.h b/fdbclient/AnnotateActor.h deleted file mode 100644 index dfc944fd024..00000000000 --- a/fdbclient/AnnotateActor.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * AnnotateActor.h - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2021 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "flow/flow.h" -#include "flow/network.h" - -#include - -// Used to manually instrument waiting actors to collect samples for the -// sampling profiler. -struct AnnotateActor { - unsigned index; - bool set; - - AnnotateActor() : set(false) {} - - AnnotateActor(Reference lineage) : set(true) { - index = g_network->getActorLineageSet().insert(lineage); - if (index == ActorLineageSet::npos) { - set = false; - } - } - - AnnotateActor(const AnnotateActor& other) = delete; - AnnotateActor(AnnotateActor&& other) = delete; - AnnotateActor& operator=(const AnnotateActor& other) = delete; - - AnnotateActor& operator=(AnnotateActor&& other) { - if (this == &other) { - return *this; - } - - this->index = other.index; - this->set = other.set; - - other.set = false; - - return *this; - } - - ~AnnotateActor() { - if (set) { - g_network->getActorLineageSet().erase(index); - } - } -}; - -enum class WaitState { Disk, Network, Running }; -// usually we shouldn't use `using namespace` in a header file, but literals should be safe as user defined literals -// need to be prefixed with `_` -using namespace std::literals; - -constexpr std::string_view to_string(WaitState st) { - switch (st) { - case WaitState::Disk: - return "Disk"sv; - case WaitState::Network: - return "Network"sv; - case WaitState::Running: - return "Running"sv; - default: - return ""sv; - } -} - -extern std::map>()>> samples; diff --git a/fdbclient/CMakeLists.txt b/fdbclient/CMakeLists.txt index e9d3d3716b5..bd14ef7b528 100644 --- a/fdbclient/CMakeLists.txt +++ b/fdbclient/CMakeLists.txt @@ -1,7 +1,4 @@ set(FDBCLIENT_SRCS - ActorLineageProfiler.h - ActorLineageProfiler.cpp - AnnotateActor.cpp AsyncFileS3BlobStore.actor.cpp AsyncFileS3BlobStore.actor.h AsyncTaskThread.actor.cpp @@ -30,7 +27,6 @@ set(FDBCLIENT_SRCS EventTypes.actor.h FDBOptions.h FDBTypes.h - FluentDSampleIngestor.cpp FileBackupAgent.actor.cpp GlobalConfig.h GlobalConfig.actor.h @@ -144,7 +140,8 @@ endif() add_flow_target(STATIC_LIBRARY NAME fdbclient SRCS ${FDBCLIENT_SRCS} ADDL_SRCS ${options_srcs}) add_dependencies(fdbclient fdboptions) -target_link_libraries(fdbclient PUBLIC fdbrpc msgpack) if(BUILD_AZURE_BACKUP) - target_link_libraries(fdbclient PRIVATE curl uuid azure-storage-lite) + target_link_libraries(fdbclient PUBLIC fdbrpc PRIVATE curl uuid azure-storage-lite) +else() + target_link_libraries(fdbclient PUBLIC fdbrpc) endif() diff --git a/fdbclient/FluentDSampleIngestor.cpp b/fdbclient/FluentDSampleIngestor.cpp deleted file mode 100644 index 08d5bfe55fb..00000000000 --- a/fdbclient/FluentDSampleIngestor.cpp +++ /dev/null @@ -1,257 +0,0 @@ -/* - * FluentDSampleIngestor.cpp - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2021 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "fdbclient/ActorLineageProfiler.h" -#include -#include -#include - -namespace { - -boost::asio::ip::address ipAddress(IPAddress const& n) { - if (n.isV6()) { - return boost::asio::ip::address_v6(n.toV6()); - } else { - return boost::asio::ip::address_v4(n.toV4()); - } -} - -template -boost::asio::ip::basic_endpoint toEndpoint(NetworkAddress const n) { - return boost::asio::ip::basic_endpoint(ipAddress(n.ip), n.port); -} - -struct FluentDSocket { - virtual ~FluentDSocket() {} - virtual void connect(NetworkAddress const& endpoint) = 0; - virtual void send(std::shared_ptr const& sample) = 0; - virtual const boost::system::error_code& failed() const = 0; -}; - -template -class SampleSender : public std::enable_shared_from_this> { - using Socket = typename Protocol::socket; - using Iter = typename decltype(Sample::data)::iterator; - Socket& socket; - Callback callback; - Iter iter, end; - - struct Buf { - const char* data; - const unsigned size; - Buf(const char* data, unsigned size) : data(data), size(size) {} - Buf(Buf const&) = delete; - Buf& operator=(Buf const&) = delete; - ~Buf() { delete[] data; } - }; - - void sendCompletionHandler(boost::system::error_code const& ec) { - if (ec) { - callback(ec); - } else { - ++iter; - sendNext(); - } - } - - void send(boost::asio::ip::tcp::socket& socket, std::shared_ptr const& buf) { - boost::asio::async_write( - socket, - boost::asio::const_buffer(buf->data, buf->size), - [buf, self = this->shared_from_this()](auto const& ec, size_t) { self->sendCompletionHandler(ec); }); - } - void send(boost::asio::ip::udp::socket& socket, std::shared_ptr const& buf) { - socket.async_send( - boost::asio::const_buffer(buf->data, buf->size), - [buf, self = this->shared_from_this()](auto const& ec, size_t) { self->sendCompletionHandler(ec); }); - } - - void sendNext() { - if (iter == end) { - callback(boost::system::error_code()); - } - // 1. calculate size of buffer - unsigned size = 1; // 1 for fixmap identifier byte - auto waitState = to_string(iter->first); - if (waitState.size() < 32) { - size = waitState.size() + 1; - } else { - size = waitState.size() + 2; - } - size += iter->second.second; - // 2. allocate the buffer - std::unique_ptr buf(new char[size]); - unsigned off = 0; - // 3. serialize fixmap - buf[off++] = 0x81; // map of size 1 - // 3.1 serialize key - if (waitState.size() < 32) { - buf[off++] = 0xa0 + waitState.size(); // fixstr - } else { - buf[off++] = 0xd9; - buf[off++] = char(waitState.size()); - } - memcpy(buf.get() + off, waitState.data(), waitState.size()); - off += waitState.size(); - // 3.2 append serialized value - memcpy(buf.get() + off, iter->second.first, iter->second.second); - // 4. send the result to fluentd - send(socket, std::make_shared(buf.release(), size)); - } - -public: - SampleSender(Socket& socket, Callback const& callback, std::shared_ptr const& sample) - : socket(socket), callback(callback), iter(sample->data.begin()), end(sample->data.end()) { - sendNext(); - } -}; - -// Sample function to make instanciation of SampleSender easier -template -std::shared_ptr> makeSampleSender(typename Protocol::socket& socket, Callback const& callback, std::shared_ptr const& sample) { - return std::make_shared>(socket, callback, sample); -} - -template -struct FluentDSocketImpl : FluentDSocket, std::enable_shared_from_this> { - static constexpr unsigned MAX_QUEUE_SIZE = 100; - boost::asio::io_context& context; - typename Protocol::socket socket; - FluentDSocketImpl(boost::asio::io_context& context) : context(context), socket(context) {} - bool ready = false; - std::deque> queue; - boost::system::error_code _failed; - - const boost::system::error_code& failed() const override { return _failed; } - - void sendCompletionHandler(boost::system::error_code const& ec) { - if (ec) { - // TODO: trace error - _failed = ec; - return; - } - if (queue.empty()) { - ready = true; - } else { - auto sample = queue.front(); - queue.pop_front(); - sendImpl(sample); - } - } - - - void sendImpl(std::shared_ptr const& sample) { - makeSampleSender(socket, [self = this->shared_from_this()](boost::system::error_code const& ec){ - self->sendCompletionHandler(ec); - }, sample); - } - - void send(std::shared_ptr const& sample) override { - if (_failed) { - return; - } - if (ready) { - ready = false; - sendImpl(sample); - } else { - if (queue.size() < MAX_QUEUE_SIZE) { - queue.push_back(sample); - } // TODO: else trace a warning - } - } - - void connect(NetworkAddress const& endpoint) override { - auto to = toEndpoint(endpoint); - socket.async_connect(to, [self = this->shared_from_this()](boost::system::error_code const& ec) { - if (ec) { - // TODO: error handling - self->_failed = ec; - return; - } - self->ready = true; - }); - } -}; - -} // namespace - -struct FluentDIngestorImpl { - using Protocol = FluentDIngestor::Protocol; - Protocol protocol; - NetworkAddress endpoint; - boost::asio::io_context& io_context; - std::unique_ptr socket; - boost::asio::steady_timer retryTimer; - FluentDIngestorImpl(Protocol protocol, NetworkAddress const& endpoint) - : protocol(protocol), endpoint(endpoint), io_context(ActorLineageProfiler::instance().context()), - retryTimer(io_context) { - connect(); - } - - ~FluentDIngestorImpl() { retryTimer.cancel(); } - - void connect() { - switch (protocol) { - case Protocol::TCP: - socket.reset(new FluentDSocketImpl(io_context)); - break; - case Protocol::UDP: - socket.reset(new FluentDSocketImpl(io_context)); - break; - } - socket->connect(endpoint); - } - - void retry() { - retryTimer = boost::asio::steady_timer(io_context, std::chrono::seconds(1)); - retryTimer.async_wait([this](auto const& ec) { - if (ec) { - return; - } - connect(); - }); - socket.reset(); - } -}; - -FluentDIngestor::~FluentDIngestor() { - delete impl; -} - -FluentDIngestor::FluentDIngestor(Protocol protocol, NetworkAddress& endpoint) - : impl(new FluentDIngestorImpl(protocol, endpoint)) {} - -void FluentDIngestor::ingest(const std::shared_ptr& sample) { - if (!impl->socket) { - // the connection failed in the past and we wait for a timeout before we retry - return; - } else if (impl->socket->failed()) { - impl->retry(); - return; - } else { - impl->socket->send(sample); - } -} - -void FluentDIngestor::getConfig(std::map& res) const { - res["ingestor"] = "fluentd"; - res["collector_endpoint"] = impl->endpoint.toString(); - res["collector_protocol"] = impl->protocol == Protocol::TCP ? "tcp" : "udp"; -} diff --git a/fdbclient/GlobalConfig.actor.cpp b/fdbclient/GlobalConfig.actor.cpp index e4f07914317..5fa901df0e8 100644 --- a/fdbclient/GlobalConfig.actor.cpp +++ b/fdbclient/GlobalConfig.actor.cpp @@ -34,18 +34,14 @@ const KeyRef fdbClientInfoTxnSizeLimit = LiteralStringRef("config/fdb_client_inf const KeyRef transactionTagSampleRate = LiteralStringRef("config/transaction_tag_sample_rate"); const KeyRef transactionTagSampleCost = LiteralStringRef("config/transaction_tag_sample_cost"); -const KeyRef samplingFrequency = LiteralStringRef("visibility/sampling/frequency"); -const KeyRef samplingWindow = LiteralStringRef("visibility/sampling/window"); - GlobalConfig::GlobalConfig() : lastUpdate(0) {} void GlobalConfig::create(DatabaseContext* cx, Reference> dbInfo) { if (g_network->global(INetwork::enGlobalConfig) == nullptr) { auto config = new GlobalConfig{}; config->cx = Database(cx); - config->dbInfo = dbInfo; g_network->setGlobal(INetwork::enGlobalConfig, config); - config->_updater = updater(config); + config->_updater = updater(config, dbInfo); } } @@ -55,10 +51,6 @@ GlobalConfig& GlobalConfig::globalConfig() { return *reinterpret_cast(res); } -void GlobalConfig::updateDBInfo(Reference> dbInfo) { - // this->dbInfo = dbInfo; -} - Key GlobalConfig::prefixedKey(KeyRef key) { return key.withPrefix(SpecialKeySpace::getModuleRange(SpecialKeySpace::MODULE::GLOBALCONFIG).begin); } @@ -85,14 +77,6 @@ Future GlobalConfig::onInitialized() { return initialized.getFuture(); } -Future GlobalConfig::onChange() { - return configChanged.onTrigger(); -} - -void GlobalConfig::trigger(KeyRef key, std::function)> fn) { - callbacks.emplace(key, std::move(fn)); -} - void GlobalConfig::insert(KeyRef key, ValueRef value) { data.erase(key); @@ -105,8 +89,6 @@ void GlobalConfig::insert(KeyRef key, ValueRef value) { any = StringRef(arena, t.getString(0).contents()); } else if (t.getType(0) == Tuple::ElementType::INT) { any = t.getInt(0); - } else if (t.getType(0) == Tuple::ElementType::BOOL) { - any = t.getBool(0); } else if (t.getType(0) == Tuple::ElementType::FLOAT) { any = t.getFloat(0); } else if (t.getType(0) == Tuple::ElementType::DOUBLE) { @@ -115,26 +97,19 @@ void GlobalConfig::insert(KeyRef key, ValueRef value) { ASSERT(false); } data[stableKey] = makeReference(std::move(arena), std::move(any)); - - if (callbacks.find(stableKey) != callbacks.end()) { - callbacks[stableKey](data[stableKey]->value); - } } catch (Error& e) { TraceEvent("GlobalConfigTupleParseError").detail("What", e.what()); } } -void GlobalConfig::erase(Key key) { - erase(KeyRangeRef(key, keyAfter(key))); +void GlobalConfig::erase(KeyRef key) { + data.erase(key); } void GlobalConfig::erase(KeyRangeRef range) { auto it = data.begin(); while (it != data.end()) { if (range.contains(it->first)) { - if (callbacks.find(it->first) != callbacks.end()) { - callbacks[it->first](std::nullopt); - } it = data.erase(it); } else { ++it; @@ -188,7 +163,7 @@ ACTOR Future GlobalConfig::migrate(GlobalConfig* self) { // Updates local copy of global configuration by reading the entire key-range // from storage. ACTOR Future GlobalConfig::refresh(GlobalConfig* self) { - self->erase(KeyRangeRef(""_sr, "\xff"_sr)); + self->data.clear(); Transaction tr(self->cx); RangeResult result = wait(tr.getRange(globalConfigDataKeys, CLIENT_KNOBS->TOO_MANY)); @@ -201,8 +176,7 @@ ACTOR Future GlobalConfig::refresh(GlobalConfig* self) { // Applies updates to the local copy of the global configuration when this // process receives an updated history. -ACTOR Future GlobalConfig::updater(GlobalConfig* self) { - // wait(self->cx->onConnected()); +ACTOR Future GlobalConfig::updater(GlobalConfig* self, Reference> dbInfo) { wait(self->migrate(self)); wait(self->refresh(self)); @@ -210,9 +184,9 @@ ACTOR Future GlobalConfig::updater(GlobalConfig* self) { loop { try { - wait(self->dbInfo->onChange()); + wait(dbInfo->onChange()); - auto& history = self->dbInfo->get().history; + auto& history = dbInfo->get().history; if (history.size() == 0) { continue; } @@ -222,8 +196,8 @@ ACTOR Future GlobalConfig::updater(GlobalConfig* self) { // history updates or the protocol version changed, so it // must re-read the entire configuration range. wait(self->refresh(self)); - if (self->dbInfo->get().history.size() > 0) { - self->lastUpdate = self->dbInfo->get().history.back().version; + if (dbInfo->get().history.size() > 0) { + self->lastUpdate = dbInfo->get().history.back().version; } } else { // Apply history in order, from lowest version to highest @@ -248,8 +222,6 @@ ACTOR Future GlobalConfig::updater(GlobalConfig* self) { self->lastUpdate = vh.version; } } - - self->configChanged.trigger(); } catch (Error& e) { throw; } diff --git a/fdbclient/GlobalConfig.actor.h b/fdbclient/GlobalConfig.actor.h index 967ec77f8d0..5c3693f450e 100644 --- a/fdbclient/GlobalConfig.actor.h +++ b/fdbclient/GlobalConfig.actor.h @@ -27,9 +27,7 @@ #define FDBCLIENT_GLOBALCONFIG_ACTOR_H #include -#include #include -#include #include #include @@ -51,9 +49,6 @@ extern const KeyRef fdbClientInfoTxnSizeLimit; extern const KeyRef transactionTagSampleRate; extern const KeyRef transactionTagSampleCost; -extern const KeyRef samplingFrequency; -extern const KeyRef samplingWindow; - // Structure used to hold the values stored by global configuration. The arena // is used as memory to store both the key and the value (the value is only // stored in the arena if it is an object; primitives are just copied). @@ -77,13 +72,6 @@ class GlobalConfig : NonCopyable { // configuration. static GlobalConfig& globalConfig(); - // Updates the ClientDBInfo object used by global configuration to read new - // data. For server processes, this value needs to be set by the cluster - // controller, but global config is initialized before the cluster - // controller is, so this function provides a mechanism to update the - // object after initialization. - void updateDBInfo(Reference> dbInfo); - // Use this function to turn a global configuration key defined above into // the full path needed to set the value in the database. // @@ -126,16 +114,6 @@ class GlobalConfig : NonCopyable { // been created and is ready. Future onInitialized(); - // Triggers the returned future when any key-value pair in the global - // configuration changes. - Future onChange(); - - // Calls \ref fn when the value associated with \ref key is changed. \ref - // fn is passed the updated value for the key, or an empty optional if the - // key has been cleared. If the value is an allocated object, its memory - // remains in the control of the global configuration. - void trigger(KeyRef key, std::function)> fn); - private: GlobalConfig(); @@ -149,23 +127,20 @@ class GlobalConfig : NonCopyable { void insert(KeyRef key, ValueRef value); // Removes the given key (and associated value) from the local copy of the // global configuration keyspace. - void erase(Key key); + void erase(KeyRef key); // Removes the given key range (and associated values) from the local copy // of the global configuration keyspace. void erase(KeyRangeRef range); ACTOR static Future migrate(GlobalConfig* self); ACTOR static Future refresh(GlobalConfig* self); - ACTOR static Future updater(GlobalConfig* self); + ACTOR static Future updater(GlobalConfig* self, Reference> dbInfo); Database cx; - Reference> dbInfo; Future _updater; Promise initialized; - AsyncTrigger configChanged; std::unordered_map> data; Version lastUpdate; - std::unordered_map)>> callbacks; }; #endif diff --git a/fdbclient/NativeAPI.actor.cpp b/fdbclient/NativeAPI.actor.cpp index a9bc969a130..75c11db5941 100644 --- a/fdbclient/NativeAPI.actor.cpp +++ b/fdbclient/NativeAPI.actor.cpp @@ -32,8 +32,6 @@ #include "fdbrpc/FailureMonitor.h" #include "fdbrpc/MultiInterface.h" -#include "fdbclient/ActorLineageProfiler.h" -#include "fdbclient/AnnotateActor.h" #include "fdbclient/Atomic.h" #include "fdbclient/ClusterInterface.h" #include "fdbclient/CoordinationInterface.h" @@ -50,7 +48,6 @@ #include "fdbclient/SpecialKeySpace.actor.h" #include "fdbclient/StorageServerInterface.h" #include "fdbclient/SystemData.h" -#include "fdbclient/TransactionLineage.h" #include "fdbclient/versions.h" #include "fdbrpc/LoadBalance.h" #include "fdbrpc/Net2FileSystem.h" @@ -88,8 +85,6 @@ using std::pair; namespace { -TransactionLineageCollector transactionLineageCollector; - template Future loadBalance( DatabaseContext* ctx, @@ -963,8 +958,6 @@ DatabaseContext::DatabaseContext(Reference( KeyRangeRef(LiteralStringRef("data_distribution/"), LiteralStringRef("data_distribution0")) .withPrefix(SpecialKeySpace::getModuleRange(SpecialKeySpace::MODULE::MANAGEMENT).begin))); - registerSpecialKeySpaceModule( - SpecialKeySpace::MODULE::ACTORLINEAGE, - SpecialKeySpace::IMPLTYPE::READONLY, - std::make_unique(SpecialKeySpace::getModuleRange(SpecialKeySpace::MODULE::ACTORLINEAGE))); - registerSpecialKeySpaceModule(SpecialKeySpace::MODULE::ACTOR_PROFILER_CONF, - SpecialKeySpace::IMPLTYPE::READWRITE, - std::make_unique(SpecialKeySpace::getModuleRange( - SpecialKeySpace::MODULE::ACTOR_PROFILER_CONF))); } if (apiVersionAtLeast(630)) { registerSpecialKeySpaceModule(SpecialKeySpace::MODULE::TRANSACTION, @@ -2523,10 +2508,8 @@ ACTOR Future watchValue(Future version, cx->invalidateCache(key); wait(delay(CLIENT_KNOBS->WRONG_SHARD_SERVER_DELAY, info.taskID)); } else if (e.code() == error_code_watch_cancelled || e.code() == error_code_process_behind) { - // clang-format off - TEST(e.code() == error_code_watch_cancelled); // Too many watches on the storage server, poll for changes instead + TEST(e.code() == error_code_watch_cancelled); // Too many watches on storage server, poll for changes TEST(e.code() == error_code_process_behind); // The storage servers are all behind - // clang-format on wait(delay(CLIENT_KNOBS->WATCH_POLLING_TIME, info.taskID)); } else if (e.code() == error_code_timed_out) { // The storage server occasionally times out watches in case // it was cancelled @@ -3099,7 +3082,6 @@ ACTOR Future getRange(Database cx, throw deterministicRandom()->randomChoice( std::vector{ transaction_too_old(), future_version() }); } - state AnnotateActor annotation(currentLineage); GetKeyValuesReply _rep = wait(loadBalance(cx.getPtr(), beginServer.second, diff --git a/fdbclient/ProcessInterface.h b/fdbclient/ProcessInterface.h deleted file mode 100644 index 11bafc29871..00000000000 --- a/fdbclient/ProcessInterface.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * ProcessInterface.h - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2021 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "fdbclient/AnnotateActor.h" -#include "fdbclient/FDBTypes.h" -#include "fdbrpc/fdbrpc.h" - -constexpr UID WLTOKEN_PROCESS(-1, 11); - -struct ProcessInterface { - constexpr static FileIdentifier file_identifier = 985636; - RequestStream getInterface; - RequestStream actorLineage; - - template - void serialize(Ar& ar) { - serializer(ar, actorLineage); - } -}; - -struct GetProcessInterfaceRequest { - constexpr static FileIdentifier file_identifier = 7632546; - ReplyPromise reply; - - template - void serialize(Ar& ar) { - serializer(ar, reply); - } -}; - -// This type is used to send serialized sample data over the network. -struct SerializedSample { - constexpr static FileIdentifier file_identifier = 15785634; - - double time; - std::unordered_map data; - - template - void serialize(Ar& ar) { - serializer(ar, time, data); - } -}; - -struct ActorLineageReply { - constexpr static FileIdentifier file_identifier = 1887656; - std::vector samples; - - template - void serialize(Ar& ar) { - serializer(ar, samples); - } -}; - -struct ActorLineageRequest { - constexpr static FileIdentifier file_identifier = 11654765; - WaitState waitStateStart, waitStateEnd; - time_t timeStart, timeEnd; - ReplyPromise reply; - - template - void serialize(Ar& ar) { - serializer(ar, waitStateStart, waitStateEnd, timeStart, timeEnd, reply); - } -}; diff --git a/fdbclient/SpecialKeySpace.actor.cpp b/fdbclient/SpecialKeySpace.actor.cpp index 5d24fa4c985..6b147eaa07a 100644 --- a/fdbclient/SpecialKeySpace.actor.cpp +++ b/fdbclient/SpecialKeySpace.actor.cpp @@ -21,14 +21,6 @@ #include "boost/lexical_cast.hpp" #include "boost/algorithm/string.hpp" -#include -#include - -#include - -#include "fdbclient/ActorLineageProfiler.h" -#include "fdbclient/Knobs.h" -#include "fdbclient/ProcessInterface.h" #include "fdbclient/GlobalConfig.actor.h" #include "fdbclient/SpecialKeySpace.actor.h" #include "flow/Arena.h" @@ -75,12 +67,7 @@ std::unordered_map SpecialKeySpace::moduleToB { SpecialKeySpace::MODULE::GLOBALCONFIG, KeyRangeRef(LiteralStringRef("\xff\xff/global_config/"), LiteralStringRef("\xff\xff/global_config0")) }, { SpecialKeySpace::MODULE::TRACING, - KeyRangeRef(LiteralStringRef("\xff\xff/tracing/"), LiteralStringRef("\xff\xff/tracing0")) }, - { SpecialKeySpace::MODULE::ACTORLINEAGE, - KeyRangeRef(LiteralStringRef("\xff\xff/actor_lineage/"), LiteralStringRef("\xff\xff/actor_lineage0")) }, - { SpecialKeySpace::MODULE::ACTOR_PROFILER_CONF, - KeyRangeRef(LiteralStringRef("\xff\xff/actor_profiler_conf/"), - LiteralStringRef("\xff\xff/actor_profiler_conf0")) } + KeyRangeRef(LiteralStringRef("\xff\xff/tracing/"), LiteralStringRef("\xff\xff/tracing0")) } }; std::unordered_map SpecialKeySpace::managementApiCommandToRange = { @@ -111,15 +98,6 @@ std::unordered_map SpecialKeySpace::managementApiCommandT .withPrefix(moduleToBoundary[MODULE::MANAGEMENT].begin) } }; -std::unordered_map SpecialKeySpace::actorLineageApiCommandToRange = { - { "state", - KeyRangeRef(LiteralStringRef("state/"), LiteralStringRef("state0")) - .withPrefix(moduleToBoundary[MODULE::ACTORLINEAGE].begin) }, - { "time", - KeyRangeRef(LiteralStringRef("time/"), LiteralStringRef("time0")) - .withPrefix(moduleToBoundary[MODULE::ACTORLINEAGE].begin) } -}; - std::set SpecialKeySpace::options = { "excluded/force", "failed/force" }; std::set SpecialKeySpace::tracingOptions = { kTracingTransactionIdKey, kTracingTokenKey }; @@ -1406,9 +1384,6 @@ Future GlobalConfigImpl::getRange(ReadYourWritesTransaction* ryw, K } else if (config->value.type() == typeid(int64_t)) { result.push_back_deep(result.arena(), KeyValueRef(prefixedKey, std::to_string(std::any_cast(config->value)))); - } else if (config->value.type() == typeid(bool)) { - result.push_back_deep(result.arena(), - KeyValueRef(prefixedKey, std::to_string(std::any_cast(config->value)))); } else if (config->value.type() == typeid(float)) { result.push_back_deep(result.arena(), KeyValueRef(prefixedKey, std::to_string(std::any_cast(config->value)))); @@ -1930,272 +1905,6 @@ void ClientProfilingImpl::clear(ReadYourWritesTransaction* ryw, const KeyRef& ke "Clear operation is forbidden for profile client. You can set it to default to disable profiling."); } -ActorLineageImpl::ActorLineageImpl(KeyRangeRef kr) : SpecialKeyRangeReadImpl(kr) {} - -void parse(StringRef& val, int& i) { - i = std::stoi(val.toString()); -} - -void parse(StringRef& val, double& d) { - d = std::stod(val.toString()); -} - -void parse(StringRef& val, WaitState& w) { - if (val == LiteralStringRef("disk")) { - w = WaitState::Disk; - } else if (val == LiteralStringRef("network")) { - w = WaitState::Network; - } else if (val == LiteralStringRef("running")) { - w = WaitState::Running; - } else { - throw std::range_error("failed to parse run state"); - } -} - -void parse(StringRef& val, time_t& t) { - struct tm tm = { 0 }; - if (strptime(val.toString().c_str(), "%FT%T%z", &tm) == nullptr) { - throw std::invalid_argument("failed to parse ISO 8601 datetime"); - } - - long timezone = tm.tm_gmtoff; - t = timegm(&tm); - if (t == -1) { - throw std::runtime_error("failed to convert ISO 8601 datetime"); - } - t -= timezone; -} - -void parse(StringRef& val, NetworkAddress& a) { - auto address = NetworkAddress::parse(val.toString()); - if (!address.isValid()) { - throw std::invalid_argument("invalid host"); - } - a = address; -} - -// Base case function for parsing function below. -template -void parse(std::vector::iterator it, std::vector::iterator end, T& t1) { - if (it == end) { - return; - } - parse(*it, t1); -} - -// Given an iterator into a vector of string tokens, an iterator to the end of -// the search space in the vector (exclusive), and a list of references to -// types, parses each token in the vector into the associated type according to -// the order of the arguments. -// -// For example, given the vector ["1", "1.5", "127.0.0.1:4000"] and the -// argument list int a, double b, NetworkAddress c, after this function returns -// each parameter passed in will hold the parsed value from the token list. -// -// The appropriate parsing function must be implemented for the type you wish -// to parse. See the existing parsing functions above, and add your own if -// necessary. -template -void parse(std::vector::iterator it, std::vector::iterator end, T& t1, Types&... remaining) { - // Return as soon as all tokens have been parsed. This allows parameters - // passed at the end to act as optional parameters -- they will only be set - // if the value exists. - if (it == end) { - return; - } - - try { - parse(*it, t1); - parse(++it, end, remaining...); - } catch (Error& e) { - throw e; - } catch (std::exception& e) { - throw e; - } -} - -ACTOR static Future actorLineageGetRangeActor(ReadYourWritesTransaction* ryw, - KeyRef prefix, - KeyRangeRef kr) { - state RangeResult result; - - // Set default values for all fields. The default will be used if the field - // is missing in the key. - state NetworkAddress host; - state WaitState waitStateStart = WaitState{ 0 }; - state WaitState waitStateEnd = WaitState{ 2 }; - state time_t timeStart = 0; - state time_t timeEnd = std::numeric_limits::max(); - state int seqStart = 0; - state int seqEnd = std::numeric_limits::max(); - - state std::vector beginValues = kr.begin.removePrefix(prefix).splitAny("/"_sr); - state std::vector endValues = kr.end.removePrefix(prefix).splitAny("/"_sr); - // Require index (either "state" or "time") and address:port. - if (beginValues.size() < 2 || endValues.size() < 2) { - ryw->setSpecialKeySpaceErrorMsg("missing required parameters (index, host)"); - throw special_keys_api_failure(); - } - - state NetworkAddress endRangeHost; - try { - if (SpecialKeySpace::getActorLineageApiCommandRange("state").contains(kr)) { - // For the range \xff\xff/actor_lineage/state/ip:port/wait-state/time/seq - parse(beginValues.begin() + 1, beginValues.end(), host, waitStateStart, timeStart, seqStart); - if (kr.begin != kr.end) { - parse(endValues.begin() + 1, endValues.end(), endRangeHost, waitStateEnd, timeEnd, seqEnd); - } - } else if (SpecialKeySpace::getActorLineageApiCommandRange("time").contains(kr)) { - // For the range \xff\xff/actor_lineage/time/ip:port/time/wait-state/seq - parse(beginValues.begin() + 1, beginValues.end(), host, timeStart, waitStateStart, seqStart); - if (kr.begin != kr.end) { - parse(endValues.begin() + 1, endValues.end(), endRangeHost, timeEnd, waitStateEnd, seqEnd); - } - } else { - ryw->setSpecialKeySpaceErrorMsg("invalid index in actor_lineage"); - throw special_keys_api_failure(); - } - } catch (Error& e) { - if (e.code() != special_keys_api_failure().code()) { - ryw->setSpecialKeySpaceErrorMsg("failed to parse key"); - throw special_keys_api_failure(); - } else { - throw e; - } - } - - if (kr.begin != kr.end && host != endRangeHost) { - // The client doesn't know about all the hosts, so a get range covering - // multiple hosts has no way of knowing which IP:port combos to use. - ryw->setSpecialKeySpaceErrorMsg("the host must remain the same on both ends of the range"); - throw special_keys_api_failure(); - } - - // Open endpoint to target process on each call. This can be optimized at - // some point... - state ProcessInterface process; - process.getInterface = RequestStream(Endpoint({ host }, WLTOKEN_PROCESS)); - ProcessInterface p = wait(retryBrokenPromise(process.getInterface, GetProcessInterfaceRequest{})); - process = p; - - ActorLineageRequest actorLineageRequest; - actorLineageRequest.waitStateStart = waitStateStart; - actorLineageRequest.waitStateEnd = waitStateEnd; - actorLineageRequest.timeStart = timeStart; - actorLineageRequest.timeEnd = timeEnd; - ActorLineageReply reply = wait(process.actorLineage.getReply(actorLineageRequest)); - - time_t dt = 0; - int seq = -1; - for (const auto& sample : reply.samples) { - for (const auto& [waitState, data] : sample.data) { - time_t datetime = (time_t)sample.time; - seq = dt == datetime ? seq + 1 : 0; - dt = datetime; - - if (seq < seqStart) { continue; } - else if (seq >= seqEnd) { break; } - - char buf[50]; - struct tm* tm; - tm = localtime(&datetime); - size_t size = strftime(buf, 50, "%FT%T%z", tm); - std::string date(buf, size); - - std::ostringstream streamKey; - if (SpecialKeySpace::getActorLineageApiCommandRange("state").contains(kr)) { - streamKey << SpecialKeySpace::getActorLineageApiCommandPrefix("state").toString() << host.toString() - << "/" << to_string(waitState) << "/" << date; - } else if (SpecialKeySpace::getActorLineageApiCommandRange("time").contains(kr)) { - streamKey << SpecialKeySpace::getActorLineageApiCommandPrefix("time").toString() << host.toString() - << "/" << date << "/" << to_string(waitState); - ; - } else { - ASSERT(false); - } - streamKey << "/" << seq; - - msgpack::object_handle oh = msgpack::unpack(data.data(), data.size()); - msgpack::object deserialized = oh.get(); - - std::ostringstream stream; - stream << deserialized; - - result.push_back_deep(result.arena(), KeyValueRef(streamKey.str(), stream.str())); - } - } - - return result; -} - -Future ActorLineageImpl::getRange(ReadYourWritesTransaction* ryw, KeyRangeRef kr) const { - return actorLineageGetRangeActor(ryw, getKeyRange().begin, kr); -} - -namespace { -std::string_view to_string_view(StringRef sr) { - return std::string_view(reinterpret_cast(sr.begin()), sr.size()); -} -} // namespace - -ActorProfilerConf::ActorProfilerConf(KeyRangeRef kr) - : SpecialKeyRangeRWImpl(kr), config(ProfilerConfig::instance().getConfig()) {} - -Future ActorProfilerConf::getRange(ReadYourWritesTransaction* ryw, KeyRangeRef kr) const { - RangeResult res; - std::string_view begin(to_string_view(kr.begin.removePrefix(range.begin))), - end(to_string_view(kr.end.removePrefix(range.begin))); - for (auto& p : config) { - if (p.first > end) { - break; - } else if (p.first > begin) { - KeyValueRef kv; - kv.key = StringRef(res.arena(), p.first); - kv.value = StringRef(res.arena(), p.second); - res.push_back(res.arena(), kv); - } - } - return res; -} - -void ActorProfilerConf::set(ReadYourWritesTransaction* ryw, const KeyRef& key, const ValueRef& value) { - config[key.removePrefix(range.begin).toString()] = value.toString(); - didWrite = true; -} - -void ActorProfilerConf::clear(ReadYourWritesTransaction* ryw, const KeyRangeRef& kr) { - std::string begin(kr.begin.removePrefix(range.begin).toString()), end(kr.end.removePrefix(range.begin).toString()); - auto first = config.lower_bound(begin); - if (first == config.end()) { - // nothing to clear - return; - } - didWrite = true; - auto last = config.upper_bound(end); - config.erase(first, last); -} - -void ActorProfilerConf::clear(ReadYourWritesTransaction* ryw, const KeyRef& key) { - std::string k = key.removePrefix(range.begin).toString(); - auto iter = config.find(k); - if (iter != config.end()) { - config.erase(iter); - } - didWrite = true; -} - -Future> ActorProfilerConf::commit(ReadYourWritesTransaction* ryw) { - Optional res{}; - try { - if (didWrite) { - ProfilerConfig::instance().reset(config); - } - return res; - } catch (ConfigError& err) { - return Optional{ err.description }; - } -} - MaintenanceImpl::MaintenanceImpl(KeyRangeRef kr) : SpecialKeyRangeRWImpl(kr) {} // Used to read the healthZoneKey diff --git a/fdbclient/SpecialKeySpace.actor.h b/fdbclient/SpecialKeySpace.actor.h index 9bf6bb7109a..084135bfb65 100644 --- a/fdbclient/SpecialKeySpace.actor.h +++ b/fdbclient/SpecialKeySpace.actor.h @@ -140,8 +140,6 @@ class SpecialKeyRangeAsyncImpl : public SpecialKeyRangeReadImpl { class SpecialKeySpace { public: enum class MODULE { - ACTORLINEAGE, // Sampling data - ACTOR_PROFILER_CONF, // profiler configuration CLUSTERFILEPATH, CONFIGURATION, // Configuration of the cluster CONNECTIONSTRING, @@ -199,12 +197,6 @@ class SpecialKeySpace { static KeyRef getManagementApiCommandPrefix(const std::string& command) { return managementApiCommandToRange.at(command).begin; } - static KeyRangeRef getActorLineageApiCommandRange(const std::string& command) { - return actorLineageApiCommandToRange.at(command); - } - static KeyRef getActorLineageApiCommandPrefix(const std::string& command) { - return actorLineageApiCommandToRange.at(command).begin; - } static Key getManagementApiCommandOptionSpecialKey(const std::string& command, const std::string& option); static const std::set& getManagementApiOptionsSet() { return options; } static const std::set& getTracingOptions() { return tracingOptions; } @@ -233,7 +225,6 @@ class SpecialKeySpace { static std::unordered_map moduleToBoundary; static std::unordered_map managementApiCommandToRange; // management command to its special keys' range - static std::unordered_map actorLineageApiCommandToRange; static std::set options; // "/