2017-05-26 04:48:44 +08:00
|
|
|
/*
|
|
|
|
* batcher.actor.h
|
|
|
|
*
|
|
|
|
* This source file is part of the FoundationDB open source project
|
|
|
|
*
|
|
|
|
* Copyright 2013-2018 Apple Inc. and the FoundationDB project authors
|
2018-02-22 02:25:11 +08:00
|
|
|
*
|
2017-05-26 04:48:44 +08:00
|
|
|
* 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
|
2018-02-22 02:25:11 +08:00
|
|
|
*
|
2017-05-26 04:48:44 +08:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2018-02-22 02:25:11 +08:00
|
|
|
*
|
2017-05-26 04:48:44 +08:00
|
|
|
* 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(FLOW_BATCHER_ACTOR_G_H)
|
|
|
|
#define FLOW_BATCHER_ACTOR_G_H
|
2018-10-20 01:30:13 +08:00
|
|
|
#include "fdbrpc/batcher.actor.g.h"
|
2017-05-26 04:48:44 +08:00
|
|
|
#elif !defined(FLOW_BATCHER_ACTOR_H)
|
|
|
|
#define FLOW_BATCHER_ACTOR_H
|
|
|
|
|
|
|
|
#include "flow/flow.h"
|
|
|
|
#include "flow/Stats.h"
|
2018-08-11 06:18:24 +08:00
|
|
|
#include "flow/actorcompiler.h" // This must be the last #include.
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
template <class X>
|
|
|
|
void logOnReceive(X x) { }
|
|
|
|
|
|
|
|
void logOnReceive(CommitTransactionRequest x) {
|
|
|
|
if(x.debugID.present())
|
|
|
|
g_traceBatch.addEvent("CommitDebug", x.debugID.get().first(), "MasterProxyServer.batcher");
|
|
|
|
}
|
|
|
|
|
2018-02-10 10:21:29 +08:00
|
|
|
template <class X>
|
|
|
|
bool firstInBatch(X x) { return false; }
|
|
|
|
|
|
|
|
bool firstInBatch(CommitTransactionRequest x) {
|
|
|
|
return x.firstInBatch();
|
|
|
|
}
|
|
|
|
|
2017-05-26 04:48:44 +08:00
|
|
|
ACTOR template <class X>
|
2019-06-25 17:47:35 +08:00
|
|
|
Future<Void> batcher(PromiseStream<std::pair<std::vector<X>, int> > out, FutureStream<X> in, double avgMinDelay, double* avgMaxDelay, double emptyBatchTimeout, int maxCount, int desiredBytes, int maxBytes, Optional<PromiseStream<Void>> batchStartedStream, int64_t *commitBatchesMemBytesCount, int64_t commitBatchesMemBytesLimit, TaskPriority taskID = TaskPriority::DefaultDelay, Counter* counter = 0)
|
2017-05-26 04:48:44 +08:00
|
|
|
{
|
2018-08-11 04:57:10 +08:00
|
|
|
wait( delayJittered(*avgMaxDelay, taskID) ); // smooth out
|
2017-05-26 04:48:44 +08:00
|
|
|
// This is set up to deliver even zero-size batches if emptyBatchTimeout elapses, because that's what master proxy wants. The source control history
|
|
|
|
// contains a version that does not.
|
|
|
|
|
|
|
|
state double lastBatch = 0;
|
|
|
|
|
|
|
|
loop {
|
|
|
|
state Future<Void> timeout;
|
|
|
|
state std::vector<X> batch;
|
|
|
|
state int batchBytes = 0;
|
|
|
|
|
|
|
|
if(emptyBatchTimeout <= 0)
|
|
|
|
timeout = Never();
|
|
|
|
else
|
|
|
|
timeout = delayJittered(emptyBatchTimeout, taskID);
|
|
|
|
|
|
|
|
while (!timeout.isReady() && !(batch.size() == maxCount || batchBytes >= desiredBytes)) {
|
|
|
|
choose {
|
|
|
|
when ( X x = waitNext(in) ) {
|
2018-06-02 06:21:40 +08:00
|
|
|
int bytes = getBytes(x);
|
|
|
|
// Drop requests if memory is under severe pressure
|
|
|
|
if (*commitBatchesMemBytesCount + bytes > commitBatchesMemBytesLimit) {
|
|
|
|
x.reply.sendError(proxy_memory_limit_exceeded());
|
2018-08-02 05:30:57 +08:00
|
|
|
TraceEvent(SevWarnAlways, "ProxyCommitBatchMemoryThresholdExceeded").suppressFor(60).detail("CommitBatchesMemBytesCount", *commitBatchesMemBytesCount).detail("CommitBatchesMemLimit", commitBatchesMemBytesLimit);
|
2018-06-02 06:21:40 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Process requests in the normal case
|
2017-05-26 04:48:44 +08:00
|
|
|
if (counter) ++*counter;
|
|
|
|
logOnReceive(x);
|
|
|
|
if (!batch.size()) {
|
|
|
|
if(batchStartedStream.present())
|
|
|
|
batchStartedStream.get().send(Void());
|
|
|
|
if (now() - lastBatch > *avgMaxDelay)
|
|
|
|
timeout = delayJittered(avgMinDelay, taskID);
|
|
|
|
else
|
|
|
|
timeout = delayJittered(*avgMaxDelay - (now() - lastBatch), taskID);
|
|
|
|
}
|
|
|
|
|
2018-02-10 10:21:29 +08:00
|
|
|
bool first = firstInBatch( x );
|
|
|
|
if((batchBytes + bytes > maxBytes || first) && batch.size()) {
|
2018-06-02 06:21:40 +08:00
|
|
|
out.send({ batch, batchBytes });
|
2017-05-26 04:48:44 +08:00
|
|
|
lastBatch = now();
|
|
|
|
if(batchStartedStream.present())
|
|
|
|
batchStartedStream.get().send(Void());
|
|
|
|
timeout = delayJittered(*avgMaxDelay, taskID);
|
|
|
|
batch = std::vector<X>();
|
|
|
|
batchBytes = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
batch.push_back(x);
|
|
|
|
batchBytes += bytes;
|
2018-06-02 06:21:40 +08:00
|
|
|
*commitBatchesMemBytesCount += bytes;
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
2018-08-11 04:57:10 +08:00
|
|
|
when ( wait( timeout ) ) {}
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
}
|
2018-06-02 06:21:40 +08:00
|
|
|
out.send({std::move(batch), batchBytes});
|
2017-05-26 04:48:44 +08:00
|
|
|
lastBatch = now();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-11 05:05:28 +08:00
|
|
|
#include "flow/unactorcompiler.h"
|
|
|
|
|
2018-06-02 06:21:40 +08:00
|
|
|
#endif
|