2017-05-26 04:48:44 +08:00
|
|
|
/*
|
|
|
|
* flow.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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef FLOW_FLOW_H
|
|
|
|
#define FLOW_FLOW_H
|
|
|
|
#pragma once
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
#pragma warning(disable : 4244 4267) // SOMEDAY: Carefully check for integer overflow issues (e.g. size_t to int
|
2021-06-20 00:47:13 +08:00
|
|
|
// conversions like this suppresses)
|
2021-03-11 02:06:03 +08:00
|
|
|
#pragma warning(disable : 4345)
|
|
|
|
#pragma warning(error : 4239)
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
#include <queue>
|
|
|
|
#include <map>
|
|
|
|
#include <unordered_map>
|
|
|
|
#include <set>
|
|
|
|
#include <functional>
|
|
|
|
#include <iostream>
|
|
|
|
#include <string>
|
|
|
|
#include <utility>
|
|
|
|
#include <algorithm>
|
|
|
|
|
2018-10-20 01:30:13 +08:00
|
|
|
#include "flow/Platform.h"
|
|
|
|
#include "flow/FastAlloc.h"
|
|
|
|
#include "flow/IRandom.h"
|
|
|
|
#include "flow/serialize.h"
|
|
|
|
#include "flow/Deque.h"
|
|
|
|
#include "flow/ThreadPrimitives.h"
|
|
|
|
#include "flow/network.h"
|
2019-01-31 05:53:23 +08:00
|
|
|
#include "flow/FileIdentifier.h"
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2019-01-26 03:40:47 +08:00
|
|
|
#include <boost/version.hpp>
|
|
|
|
|
2019-04-10 02:16:45 +08:00
|
|
|
#define TEST(condition) \
|
2019-04-17 00:48:15 +08:00
|
|
|
if (!(condition)) { \
|
|
|
|
} else { \
|
2019-04-10 02:16:45 +08:00
|
|
|
static TraceEvent* __test = &(TraceEvent("CodeCoverage") \
|
|
|
|
.detail("File", __FILE__) \
|
|
|
|
.detail("Line", __LINE__) \
|
|
|
|
.detail("Condition", #condition)); \
|
|
|
|
(void)__test; \
|
|
|
|
}
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
usage:
|
|
|
|
if (BUGGIFY) (
|
|
|
|
// code here is executed on some runs (with probability P_BUGGIFIED_SECTION_ACTIVATED),
|
|
|
|
// sometimes --
|
|
|
|
)
|
|
|
|
*/
|
|
|
|
|
2019-04-04 08:37:14 +08:00
|
|
|
extern std::vector<double> P_BUGGIFIED_SECTION_ACTIVATED, P_BUGGIFIED_SECTION_FIRES;
|
|
|
|
extern double P_EXPENSIVE_VALIDATION;
|
2021-03-11 02:06:03 +08:00
|
|
|
enum class BuggifyType : uint8_t { General = 0, Client };
|
2019-04-04 08:37:14 +08:00
|
|
|
bool isBuggifyEnabled(BuggifyType type);
|
2019-06-17 00:52:40 +08:00
|
|
|
void clearBuggifySections(BuggifyType type);
|
2021-06-10 02:37:14 +08:00
|
|
|
int getSBVar(std::string const& file, int line, BuggifyType);
|
2021-03-11 02:06:03 +08:00
|
|
|
void enableBuggify(bool enabled,
|
|
|
|
BuggifyType type); // Currently controls buggification and (randomized) expensive validation
|
2019-04-04 08:37:14 +08:00
|
|
|
bool validationIsEnabled(BuggifyType type);
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
#define BUGGIFY_WITH_PROB(x) \
|
|
|
|
(getSBVar(__FILE__, __LINE__, BuggifyType::General) && deterministicRandom()->random01() < (x))
|
2019-04-04 08:37:14 +08:00
|
|
|
#define BUGGIFY BUGGIFY_WITH_PROB(P_BUGGIFIED_SECTION_FIRES[int(BuggifyType::General)])
|
2021-03-11 02:06:03 +08:00
|
|
|
#define EXPENSIVE_VALIDATION \
|
|
|
|
(validationIsEnabled(BuggifyType::General) && deterministicRandom()->random01() < P_EXPENSIVE_VALIDATION)
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-06-10 02:37:14 +08:00
|
|
|
extern Optional<uint64_t> parse_with_suffix(std::string const& toparse, std::string const& default_unit = "");
|
|
|
|
extern Optional<uint64_t> parseDuration(std::string const& str, std::string const& defaultUnit = "");
|
2017-05-26 04:48:44 +08:00
|
|
|
extern std::string format(const char* form, ...);
|
2018-05-05 04:35:25 +08:00
|
|
|
|
|
|
|
// On success, returns the number of characters written. On failure, returns a negative number.
|
2021-03-11 02:06:03 +08:00
|
|
|
extern int vsformat(std::string& outputString, const char* form, va_list args);
|
2018-05-05 04:35:25 +08:00
|
|
|
|
2017-05-26 04:48:44 +08:00
|
|
|
extern Standalone<StringRef> strinc(StringRef const& str);
|
|
|
|
extern StringRef strinc(StringRef const& str, Arena& arena);
|
2018-01-29 03:52:54 +08:00
|
|
|
extern Standalone<StringRef> addVersionStampAtEnd(StringRef const& str);
|
|
|
|
extern StringRef addVersionStampAtEnd(StringRef const& str, Arena& arena);
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
template <typename Iter>
|
2021-03-11 02:06:03 +08:00
|
|
|
StringRef concatenate(Iter b, Iter const& e, Arena& arena) {
|
2017-05-26 04:48:44 +08:00
|
|
|
int rsize = 0;
|
|
|
|
Iter i = b;
|
2021-03-11 02:06:03 +08:00
|
|
|
while (i != e) {
|
2017-05-26 04:48:44 +08:00
|
|
|
rsize += i->size();
|
|
|
|
++i;
|
|
|
|
}
|
2021-03-11 02:06:03 +08:00
|
|
|
uint8_t* s = new (arena) uint8_t[rsize];
|
2017-05-26 04:48:44 +08:00
|
|
|
uint8_t* p = s;
|
2021-03-11 02:06:03 +08:00
|
|
|
while (b != e) {
|
|
|
|
memcpy(p, b->begin(), b->size());
|
2017-05-26 04:48:44 +08:00
|
|
|
p += b->size();
|
|
|
|
++b;
|
|
|
|
}
|
|
|
|
return StringRef(s, rsize);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename Iter>
|
2021-03-11 02:06:03 +08:00
|
|
|
Standalone<StringRef> concatenate(Iter b, Iter const& e) {
|
2017-05-26 04:48:44 +08:00
|
|
|
Standalone<StringRef> r;
|
2021-03-11 02:06:03 +08:00
|
|
|
((StringRef&)r) = concatenate(b, e, r.arena());
|
2017-05-26 04:48:44 +08:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
class Void {
|
|
|
|
public:
|
2019-01-31 05:53:23 +08:00
|
|
|
constexpr static FileIdentifier file_identifier = 2010442;
|
2017-05-26 04:48:44 +08:00
|
|
|
template <class Ar>
|
2019-07-26 04:40:54 +08:00
|
|
|
void serialize(Ar& ar) {
|
|
|
|
serializer(ar);
|
|
|
|
}
|
2017-05-26 04:48:44 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
class Never {};
|
|
|
|
|
|
|
|
template <class T>
|
2020-07-15 07:26:16 +08:00
|
|
|
class ErrorOr : public ComposedIdentifier<T, 2> {
|
2021-07-12 17:17:57 +08:00
|
|
|
std::variant<Error, T> value;
|
|
|
|
|
2017-05-26 04:48:44 +08:00
|
|
|
public:
|
2019-11-27 03:31:30 +08:00
|
|
|
ErrorOr() : ErrorOr(default_error_or()) {}
|
2021-07-12 17:17:57 +08:00
|
|
|
ErrorOr(Error const& error) : value(std::in_place_type<Error>, error) {}
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
template <class U>
|
2021-07-12 17:17:57 +08:00
|
|
|
ErrorOr(U const& t) : value(std::in_place_type<T>, t) {}
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-07-12 17:17:57 +08:00
|
|
|
ErrorOr(Arena& a, ErrorOr<T> const& o) {
|
|
|
|
if (o.present()) {
|
|
|
|
value = std::variant<Error, T>(std::in_place_type<T>, a, o.get());
|
|
|
|
} else {
|
|
|
|
value = std::variant<Error, T>(std::in_place_type<Error>, o.getError());
|
|
|
|
}
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
int expectedSize() const { return present() ? get().expectedSize() : 0; }
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
template <class R>
|
|
|
|
ErrorOr<R> castTo() const {
|
|
|
|
return map<R>([](const T& v) { return (R)v; });
|
2019-01-12 01:03:38 +08:00
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
template <class R>
|
2021-07-12 17:22:03 +08:00
|
|
|
ErrorOr<R> map(std::function<R(T)> f) const& {
|
|
|
|
return present() ? ErrorOr<R>(f(get())) : ErrorOr<R>(getError());
|
|
|
|
}
|
|
|
|
template <class R>
|
|
|
|
ErrorOr<R> map(std::function<R(T)> f) && {
|
|
|
|
return present() ? ErrorOr<R>(f(std::move(*this).get())) : ErrorOr<R>(getError());
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
|
2021-07-12 17:17:57 +08:00
|
|
|
bool present() const { return std::holds_alternative<T>(value); }
|
|
|
|
T& get() & {
|
|
|
|
UNSTOPPABLE_ASSERT(present());
|
|
|
|
return std::get<T>(value);
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
2021-07-12 17:17:57 +08:00
|
|
|
T const& get() const& {
|
2017-05-26 04:48:44 +08:00
|
|
|
UNSTOPPABLE_ASSERT(present());
|
2021-07-12 17:17:57 +08:00
|
|
|
return std::get<T>(value);
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
2021-07-12 17:17:57 +08:00
|
|
|
T&& get() && {
|
2017-05-26 04:48:44 +08:00
|
|
|
UNSTOPPABLE_ASSERT(present());
|
2021-07-12 17:17:57 +08:00
|
|
|
return std::get<T>(std::move(value));
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
2021-07-12 17:17:57 +08:00
|
|
|
template <class U>
|
|
|
|
T orDefault(U&& defaultValue) const& {
|
|
|
|
return present() ? get() : std::forward<U>(defaultValue);
|
2021-03-11 02:06:03 +08:00
|
|
|
}
|
2021-07-12 17:17:57 +08:00
|
|
|
template <class U>
|
|
|
|
T orDefault(U&& defaultValue) && {
|
|
|
|
return present() ? std::move(*this).get() : std::forward<U>(defaultValue);
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
|
2021-07-12 17:17:57 +08:00
|
|
|
bool isError() const { return std::holds_alternative<Error>(value); }
|
|
|
|
bool isError(int code) const { return isError() && getError().code() == code; }
|
|
|
|
Error const& getError() const {
|
2021-03-11 02:06:03 +08:00
|
|
|
ASSERT(isError());
|
2021-07-12 17:17:57 +08:00
|
|
|
return std::get<Error>(value);
|
2021-03-11 02:06:03 +08:00
|
|
|
}
|
2021-07-12 17:17:57 +08:00
|
|
|
};
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-07-12 17:17:57 +08:00
|
|
|
template <class Archive, class T>
|
|
|
|
void load(Archive& ar, ErrorOr<T>& value) {
|
2017-05-26 04:48:44 +08:00
|
|
|
Error error;
|
2021-07-12 17:17:57 +08:00
|
|
|
ar >> error;
|
|
|
|
if (error.code() != invalid_error_code) {
|
|
|
|
T t;
|
|
|
|
ar >> t;
|
|
|
|
value = ErrorOr<T>(t);
|
|
|
|
} else {
|
|
|
|
value = ErrorOr<T>(error);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class Archive, class T>
|
|
|
|
void save(Archive& ar, ErrorOr<T> const& value) {
|
|
|
|
if (value.present()) {
|
|
|
|
ar << Error{}; // invalid error code
|
|
|
|
ar << value.get();
|
|
|
|
} else {
|
|
|
|
ar << value.getError();
|
|
|
|
}
|
|
|
|
}
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2019-02-01 06:45:42 +08:00
|
|
|
template <class T>
|
|
|
|
struct union_like_traits<ErrorOr<T>> : std::true_type {
|
|
|
|
using Member = ErrorOr<T>;
|
|
|
|
using alternatives = pack<Error, T>;
|
2019-07-16 03:58:31 +08:00
|
|
|
template <class Context>
|
2021-03-11 02:06:03 +08:00
|
|
|
static uint8_t index(const Member& variant, Context&) {
|
|
|
|
return variant.present() ? 1 : 0;
|
|
|
|
}
|
2019-07-16 03:58:31 +08:00
|
|
|
template <class Context>
|
2021-03-11 02:06:03 +08:00
|
|
|
static bool empty(const Member& variant, Context&) {
|
|
|
|
return false;
|
|
|
|
}
|
2019-02-01 06:45:42 +08:00
|
|
|
|
2019-07-16 03:58:31 +08:00
|
|
|
template <int i, class Context>
|
|
|
|
static const index_t<i, alternatives>& get(const Member& m, Context&) {
|
2019-02-01 06:45:42 +08:00
|
|
|
if constexpr (i == 0) {
|
|
|
|
return m.getError();
|
|
|
|
} else {
|
|
|
|
static_assert(i == 1, "ErrorOr only has two members");
|
|
|
|
return m.get();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-16 03:58:31 +08:00
|
|
|
template <int i, class Alternative, class Context>
|
2019-10-27 05:29:05 +08:00
|
|
|
static void assign(Member& m, const Alternative& a, Context&) {
|
2019-02-01 06:45:42 +08:00
|
|
|
if constexpr (i == 0) {
|
|
|
|
m = a;
|
|
|
|
} else {
|
|
|
|
static_assert(i == 1);
|
|
|
|
m = a;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-09-12 02:45:07 +08:00
|
|
|
template <class T>
|
|
|
|
class CachedSerialization {
|
|
|
|
public:
|
|
|
|
constexpr static FileIdentifier file_identifier = FileIdentifierFor<T>::value;
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// FIXME: this code will not work for caching a direct serialization from ObjectWriter, because it adds an ErrorOr,
|
2019-09-13 07:30:29 +08:00
|
|
|
// we should create a separate SerializeType for direct serialization
|
2019-09-12 02:45:07 +08:00
|
|
|
enum class SerializeType { None, Binary, Object };
|
|
|
|
|
|
|
|
CachedSerialization() : cacheType(SerializeType::None) {}
|
|
|
|
explicit CachedSerialization(const T& data) : data(data), cacheType(SerializeType::None) {}
|
2020-02-05 02:26:18 +08:00
|
|
|
|
2019-09-12 02:45:07 +08:00
|
|
|
const T& read() const { return data; }
|
|
|
|
|
|
|
|
T& mutate() {
|
|
|
|
cacheType = SerializeType::None;
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// This should only be called from the ObjectSerializer load function
|
2019-09-12 02:45:07 +08:00
|
|
|
Standalone<StringRef> getCache() const {
|
2021-03-11 02:06:03 +08:00
|
|
|
if (cacheType != SerializeType::Object) {
|
2020-09-29 01:58:49 +08:00
|
|
|
cache = ObjectWriter::toValue(ErrorOr<EnsureTable<T>>(data), AssumeVersion(g_network->protocolVersion()));
|
2019-09-12 02:45:07 +08:00
|
|
|
cacheType = SerializeType::Object;
|
|
|
|
}
|
|
|
|
return cache;
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
bool operator==(CachedSerialization<T> const& rhs) const { return data == rhs.data; }
|
|
|
|
bool operator!=(CachedSerialization<T> const& rhs) const { return !(*this == rhs); }
|
|
|
|
bool operator<(CachedSerialization<T> const& rhs) const { return data < rhs.data; }
|
2019-09-12 02:45:07 +08:00
|
|
|
|
|
|
|
template <class Ar>
|
|
|
|
void serialize(Ar& ar) {
|
2019-09-12 04:31:07 +08:00
|
|
|
if constexpr (is_fb_function<Ar>) {
|
|
|
|
// Suppress vtable collection. Save and load are implemented via the specializations below
|
2019-09-12 02:45:07 +08:00
|
|
|
} else {
|
2019-09-12 04:31:07 +08:00
|
|
|
if (Ar::isDeserializing) {
|
|
|
|
cache = Standalone<StringRef>();
|
|
|
|
cacheType = SerializeType::None;
|
|
|
|
serializer(ar, data);
|
|
|
|
} else {
|
|
|
|
if (cacheType != SerializeType::Binary) {
|
2020-09-29 01:58:49 +08:00
|
|
|
cache = BinaryWriter::toValue(data, AssumeVersion(g_network->protocolVersion()));
|
2019-09-12 04:31:07 +08:00
|
|
|
cacheType = SerializeType::Binary;
|
|
|
|
}
|
|
|
|
ar.serializeBytes(const_cast<uint8_t*>(cache.begin()), cache.size());
|
2019-09-12 02:45:07 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
T data;
|
|
|
|
mutable SerializeType cacheType;
|
2019-09-12 04:31:07 +08:00
|
|
|
mutable Standalone<StringRef> cache;
|
2019-09-12 02:45:07 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
// this special case is needed - the code expects
|
|
|
|
// Standalone<T> and T to be equivalent for serialization
|
|
|
|
namespace detail {
|
|
|
|
|
|
|
|
template <class T, class Context>
|
|
|
|
struct LoadSaveHelper<CachedSerialization<T>, Context> : Context {
|
2021-03-11 02:06:03 +08:00
|
|
|
LoadSaveHelper(const Context& context) : Context(context), helper(context) {}
|
2019-09-12 02:45:07 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
void load(CachedSerialization<T>& member, const uint8_t* current) { helper.load(member.mutate(), current); }
|
2019-09-12 02:45:07 +08:00
|
|
|
|
|
|
|
template <class Writer>
|
|
|
|
RelativeOffset save(const CachedSerialization<T>& member, Writer& writer, const VTableSet* vtables) {
|
|
|
|
throw internal_error();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
LoadSaveHelper<T, Context> helper;
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace detail
|
|
|
|
|
|
|
|
template <class V>
|
|
|
|
struct serialize_raw<ErrorOr<EnsureTable<CachedSerialization<V>>>> : std::true_type {
|
|
|
|
template <class Context>
|
2019-09-12 04:31:07 +08:00
|
|
|
static uint8_t* save_raw(Context& context, const ErrorOr<EnsureTable<CachedSerialization<V>>>& obj) {
|
|
|
|
auto cache = obj.present() ? obj.get().asUnderlyingType().getCache()
|
|
|
|
: ObjectWriter::toValue(ErrorOr<EnsureTable<V>>(obj.getError()),
|
2020-09-29 01:58:49 +08:00
|
|
|
AssumeVersion(g_network->protocolVersion()));
|
2019-09-12 02:45:07 +08:00
|
|
|
uint8_t* out = context.allocate(cache.size());
|
|
|
|
memcpy(out, cache.begin(), cache.size());
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-05-26 04:48:44 +08:00
|
|
|
template <class T>
|
|
|
|
struct Callback {
|
2021-03-11 02:06:03 +08:00
|
|
|
Callback<T>*prev, *next;
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
virtual void fire(T const&) {}
|
2020-10-09 00:31:19 +08:00
|
|
|
virtual void fire(T&&) {}
|
2017-05-26 04:48:44 +08:00
|
|
|
virtual void error(Error) {}
|
|
|
|
virtual void unwait() {}
|
|
|
|
|
|
|
|
void insert(Callback<T>* into) {
|
|
|
|
// Add this (uninitialized) callback just after `into`
|
|
|
|
this->prev = into;
|
|
|
|
this->next = into->next;
|
|
|
|
into->next->prev = this;
|
|
|
|
into->next = this;
|
|
|
|
}
|
|
|
|
|
|
|
|
void insertBack(Callback<T>* into) {
|
|
|
|
// Add this (uninitialized) callback just before `into`
|
|
|
|
this->next = into;
|
|
|
|
this->prev = into->prev;
|
|
|
|
into->prev->next = this;
|
|
|
|
into->prev = this;
|
|
|
|
}
|
|
|
|
|
|
|
|
void insertChain(Callback<T>* into) {
|
|
|
|
// Combine this callback's (initialized) chain and `into`'s such that this callback is just after `into`
|
|
|
|
auto p = this->prev;
|
|
|
|
auto n = into->next;
|
|
|
|
this->prev = into;
|
|
|
|
into->next = this;
|
|
|
|
p->next = n;
|
|
|
|
n->prev = p;
|
|
|
|
}
|
|
|
|
|
|
|
|
void remove() {
|
2021-03-11 02:06:03 +08:00
|
|
|
// Remove this callback from the list it is in, and call unwait() on the head of that list if this was the last
|
|
|
|
// callback
|
2017-05-26 04:48:44 +08:00
|
|
|
next->prev = prev;
|
|
|
|
prev->next = next;
|
|
|
|
if (prev == next)
|
|
|
|
next->unwait();
|
|
|
|
}
|
|
|
|
|
|
|
|
int countCallbacks() {
|
|
|
|
int count = 0;
|
|
|
|
for (Callback* c = next; c != this; c = c->next)
|
|
|
|
count++;
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
struct SingleCallback {
|
|
|
|
// Used for waiting on FutureStreams, which don't support multiple callbacks
|
2021-03-11 02:06:03 +08:00
|
|
|
SingleCallback<T>* next;
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
virtual void fire(T const&) {}
|
2021-03-11 02:06:03 +08:00
|
|
|
virtual void fire(T&&) {}
|
2017-05-26 04:48:44 +08:00
|
|
|
virtual void error(Error) {}
|
|
|
|
virtual void unwait() {}
|
|
|
|
|
|
|
|
void insert(SingleCallback<T>* into) {
|
|
|
|
this->next = into->next;
|
|
|
|
into->next = this;
|
|
|
|
}
|
|
|
|
|
|
|
|
void remove() {
|
|
|
|
ASSERT(next->next == this);
|
|
|
|
next->next = next;
|
|
|
|
next->unwait();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-07-17 00:48:10 +08:00
|
|
|
// SAV is short for Single Assignment Variable: It can be assigned for only once!
|
2017-05-26 04:48:44 +08:00
|
|
|
template <class T>
|
|
|
|
struct SAV : private Callback<T>, FastAllocated<SAV<T>> {
|
|
|
|
int promises; // one for each promise (and one for an active actor if this is an actor)
|
2021-03-11 02:06:03 +08:00
|
|
|
int futures; // one for each future and one more if there are any callbacks
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
private:
|
2021-03-11 02:06:03 +08:00
|
|
|
typename std::aligned_storage<sizeof(T), __alignof(T)>::type value_storage;
|
|
|
|
|
2017-05-26 04:48:44 +08:00
|
|
|
public:
|
|
|
|
Error error_state;
|
|
|
|
|
|
|
|
enum { UNSET_ERROR_CODE = -3, NEVER_ERROR_CODE, SET_ERROR_CODE };
|
|
|
|
|
|
|
|
T& value() { return *(T*)&value_storage; }
|
|
|
|
|
2020-12-08 06:15:25 +08:00
|
|
|
SAV(int futures, int promises)
|
|
|
|
: futures(futures), promises(promises), error_state(Error::fromCode(UNSET_ERROR_CODE)) {
|
2017-05-26 04:48:44 +08:00
|
|
|
Callback<T>::prev = Callback<T>::next = this;
|
|
|
|
}
|
|
|
|
~SAV() {
|
|
|
|
if (int16_t(error_state.code()) == SET_ERROR_CODE)
|
|
|
|
value().~T();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isSet() const { return int16_t(error_state.code()) > NEVER_ERROR_CODE; }
|
|
|
|
bool canBeSet() const { return int16_t(error_state.code()) == UNSET_ERROR_CODE; }
|
|
|
|
bool isError() const { return int16_t(error_state.code()) > SET_ERROR_CODE; }
|
|
|
|
|
2020-10-08 06:55:11 +08:00
|
|
|
T const& get() const {
|
2017-05-26 04:48:44 +08:00
|
|
|
ASSERT(isSet());
|
2021-03-11 02:06:03 +08:00
|
|
|
if (isError())
|
|
|
|
throw error_state;
|
2020-10-08 06:55:11 +08:00
|
|
|
return *(T const*)&value_storage;
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class U>
|
2020-12-08 06:15:25 +08:00
|
|
|
void send(U&& value) {
|
2017-05-26 04:48:44 +08:00
|
|
|
ASSERT(canBeSet());
|
|
|
|
new (&value_storage) T(std::forward<U>(value));
|
|
|
|
this->error_state = Error::fromCode(SET_ERROR_CODE);
|
2021-05-11 11:26:12 +08:00
|
|
|
while (Callback<T>::next != this)
|
2017-05-26 04:48:44 +08:00
|
|
|
Callback<T>::next->fire(this->value());
|
|
|
|
}
|
|
|
|
|
|
|
|
void send(Never) {
|
|
|
|
ASSERT(canBeSet());
|
|
|
|
this->error_state = Error::fromCode(NEVER_ERROR_CODE);
|
|
|
|
}
|
|
|
|
|
|
|
|
void sendError(Error err) {
|
|
|
|
ASSERT(canBeSet() && int16_t(err.code()) > 0);
|
|
|
|
this->error_state = err;
|
2021-05-11 11:26:12 +08:00
|
|
|
while (Callback<T>::next != this)
|
2017-05-26 04:48:44 +08:00
|
|
|
Callback<T>::next->error(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class U>
|
2021-03-11 02:06:03 +08:00
|
|
|
void sendAndDelPromiseRef(U&& value) {
|
2017-05-26 04:48:44 +08:00
|
|
|
ASSERT(canBeSet());
|
|
|
|
if (promises == 1 && !futures) {
|
|
|
|
// No one is left to receive the value, so we can just die
|
|
|
|
destroy();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
new (&value_storage) T(std::forward<U>(value));
|
|
|
|
finishSendAndDelPromiseRef();
|
|
|
|
}
|
|
|
|
|
|
|
|
void finishSendAndDelPromiseRef() {
|
|
|
|
// Call only after value_storage has already been initialized!
|
|
|
|
this->error_state = Error::fromCode(SET_ERROR_CODE);
|
|
|
|
while (Callback<T>::next != this)
|
|
|
|
Callback<T>::next->fire(this->value());
|
|
|
|
|
|
|
|
if (!--promises && !futures)
|
|
|
|
destroy();
|
|
|
|
}
|
|
|
|
|
|
|
|
void sendAndDelPromiseRef(Never) {
|
|
|
|
ASSERT(canBeSet());
|
|
|
|
this->error_state = Error::fromCode(NEVER_ERROR_CODE);
|
|
|
|
if (!--promises && !futures)
|
|
|
|
destroy();
|
|
|
|
}
|
|
|
|
|
|
|
|
void sendErrorAndDelPromiseRef(Error err) {
|
|
|
|
ASSERT(canBeSet() && int16_t(err.code()) > 0);
|
|
|
|
if (promises == 1 && !futures) {
|
|
|
|
// No one is left to receive the value, so we can just die
|
|
|
|
destroy();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this->error_state = err;
|
|
|
|
while (Callback<T>::next != this)
|
|
|
|
Callback<T>::next->error(err);
|
|
|
|
|
|
|
|
if (!--promises && !futures)
|
|
|
|
destroy();
|
|
|
|
}
|
|
|
|
|
|
|
|
void addPromiseRef() { promises++; }
|
|
|
|
void addFutureRef() { futures++; }
|
|
|
|
|
|
|
|
void delPromiseRef() {
|
|
|
|
if (promises == 1) {
|
|
|
|
if (futures && canBeSet()) {
|
|
|
|
sendError(broken_promise());
|
2021-03-11 02:06:03 +08:00
|
|
|
ASSERT(promises == 1); // Once there is only one promise, there is no one else with the right to change
|
|
|
|
// the promise reference count
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
promises = 0;
|
|
|
|
if (!futures)
|
|
|
|
destroy();
|
2021-03-11 02:06:03 +08:00
|
|
|
} else
|
2017-05-26 04:48:44 +08:00
|
|
|
--promises;
|
|
|
|
}
|
|
|
|
void delFutureRef() {
|
|
|
|
if (!--futures) {
|
|
|
|
if (promises)
|
|
|
|
cancel();
|
|
|
|
else
|
|
|
|
destroy();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int getFutureReferenceCount() const { return futures; }
|
|
|
|
int getPromiseReferenceCount() const { return promises; }
|
|
|
|
|
2020-10-09 00:31:19 +08:00
|
|
|
virtual void destroy() { delete this; }
|
|
|
|
virtual void cancel() {}
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
void addCallbackAndDelFutureRef(Callback<T>* cb) {
|
|
|
|
// We are always *logically* dropping one future reference from this, but if we are adding a first callback
|
|
|
|
// we also need to add one (since futures is defined as being +1 if there are any callbacks), so net nothing
|
|
|
|
if (Callback<T>::next != this)
|
|
|
|
delFutureRef();
|
|
|
|
cb->insert(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void addYieldedCallbackAndDelFutureRef(Callback<T>* cb) {
|
2021-03-11 02:06:03 +08:00
|
|
|
// Same contract as addCallbackAndDelFutureRef, except that the callback is placed at the end of the callback
|
|
|
|
// chain rather than at the beginning
|
2017-05-26 04:48:44 +08:00
|
|
|
if (Callback<T>::next != this)
|
|
|
|
delFutureRef();
|
|
|
|
cb->insertBack(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void addCallbackChainAndDelFutureRef(Callback<T>* cb) {
|
|
|
|
if (Callback<T>::next != this)
|
|
|
|
delFutureRef();
|
|
|
|
cb->insertChain(this);
|
|
|
|
}
|
|
|
|
|
2020-10-08 06:55:11 +08:00
|
|
|
void unwait() override { delFutureRef(); }
|
|
|
|
void fire(T const&) override { ASSERT(false); }
|
2017-05-26 04:48:44 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
class Promise;
|
|
|
|
|
|
|
|
template <class T>
|
2021-03-11 02:06:03 +08:00
|
|
|
class Future {
|
2017-05-26 04:48:44 +08:00
|
|
|
public:
|
|
|
|
T const& get() const { return sav->get(); }
|
|
|
|
T getValue() const { return get(); }
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
bool isValid() const { return sav != 0; }
|
|
|
|
bool isReady() const { return sav->isSet(); }
|
|
|
|
bool isError() const { return sav->isError(); }
|
2021-03-25 09:57:24 +08:00
|
|
|
// returns true if get can be called on this future (counterpart of canBeSet on Promises)
|
|
|
|
bool canGet() const { return isValid() && isReady() && !isError(); }
|
2017-05-26 04:48:44 +08:00
|
|
|
Error& getError() const {
|
|
|
|
ASSERT(isError());
|
|
|
|
return sav->error_state;
|
|
|
|
}
|
|
|
|
|
|
|
|
Future() : sav(0) {}
|
|
|
|
Future(const Future<T>& rhs) : sav(rhs.sav) {
|
2021-03-11 02:06:03 +08:00
|
|
|
if (sav)
|
|
|
|
sav->addFutureRef();
|
|
|
|
// if (sav->endpoint.isValid()) cout << "Future copied for " << sav->endpoint.key << endl;
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
2020-06-10 08:33:41 +08:00
|
|
|
Future(Future<T>&& rhs) noexcept : sav(rhs.sav) {
|
2017-05-26 04:48:44 +08:00
|
|
|
rhs.sav = 0;
|
2021-03-11 02:06:03 +08:00
|
|
|
// if (sav->endpoint.isValid()) cout << "Future moved for " << sav->endpoint.key << endl;
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
2021-03-11 02:06:03 +08:00
|
|
|
Future(const T& presentValue) : sav(new SAV<T>(1, 0)) { sav->send(presentValue); }
|
|
|
|
Future(T&& presentValue) : sav(new SAV<T>(1, 0)) { sav->send(std::move(presentValue)); }
|
|
|
|
Future(Never) : sav(new SAV<T>(1, 0)) { sav->send(Never()); }
|
|
|
|
Future(const Error& error) : sav(new SAV<T>(1, 0)) { sav->sendError(error); }
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2019-02-18 06:39:16 +08:00
|
|
|
#ifndef NO_INTELLISENSE
|
2021-03-11 02:06:03 +08:00
|
|
|
template <class U>
|
2019-02-18 06:39:16 +08:00
|
|
|
Future(const U&, typename std::enable_if<std::is_assignable<T, U>::value, int*>::type = 0) {}
|
|
|
|
#endif
|
|
|
|
|
2017-05-26 04:48:44 +08:00
|
|
|
~Future() {
|
2021-03-11 02:06:03 +08:00
|
|
|
// if (sav && sav->endpoint.isValid()) cout << "Future destroyed for " << sav->endpoint.key << endl;
|
|
|
|
if (sav)
|
|
|
|
sav->delFutureRef();
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
void operator=(const Future<T>& rhs) {
|
2021-03-11 02:06:03 +08:00
|
|
|
if (rhs.sav)
|
|
|
|
rhs.sav->addFutureRef();
|
|
|
|
if (sav)
|
|
|
|
sav->delFutureRef();
|
2017-05-26 04:48:44 +08:00
|
|
|
sav = rhs.sav;
|
|
|
|
}
|
2020-06-10 08:33:41 +08:00
|
|
|
void operator=(Future<T>&& rhs) noexcept {
|
2017-05-26 04:48:44 +08:00
|
|
|
if (sav != rhs.sav) {
|
2021-03-11 02:06:03 +08:00
|
|
|
if (sav)
|
|
|
|
sav->delFutureRef();
|
2017-05-26 04:48:44 +08:00
|
|
|
sav = rhs.sav;
|
|
|
|
rhs.sav = 0;
|
|
|
|
}
|
|
|
|
}
|
2021-03-11 02:06:03 +08:00
|
|
|
bool operator==(const Future& rhs) { return rhs.sav == sav; }
|
|
|
|
bool operator!=(const Future& rhs) { return rhs.sav != sav; }
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
void cancel() {
|
2021-03-11 02:06:03 +08:00
|
|
|
if (sav)
|
|
|
|
sav->cancel();
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void addCallbackAndClear(Callback<T>* cb) {
|
|
|
|
sav->addCallbackAndDelFutureRef(cb);
|
|
|
|
sav = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void addYieldedCallbackAndClear(Callback<T>* cb) {
|
|
|
|
sav->addYieldedCallbackAndDelFutureRef(cb);
|
|
|
|
sav = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void addCallbackChainAndClear(Callback<T>* cb) {
|
|
|
|
sav->addCallbackChainAndDelFutureRef(cb);
|
|
|
|
sav = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int getFutureReferenceCount() const { return sav->getFutureReferenceCount(); }
|
|
|
|
int getPromiseReferenceCount() const { return sav->getPromiseReferenceCount(); }
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
explicit Future(SAV<T>* sav) : sav(sav) {
|
|
|
|
// if (sav->endpoint.isValid()) cout << "Future created for " << sav->endpoint.key << endl;
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
SAV<T>* sav;
|
|
|
|
friend class Promise<T>;
|
|
|
|
};
|
|
|
|
|
|
|
|
// This class is used by the flow compiler when generating code around wait statements to avoid confusing situations
|
|
|
|
// regarding Futures.
|
|
|
|
//
|
|
|
|
// For example, the following is legal with Future but not with StrictFuture:
|
|
|
|
//
|
|
|
|
// Future<T> x = ...
|
|
|
|
// T result = wait(x); // This is the correct code
|
2021-03-11 02:06:03 +08:00
|
|
|
// Future<T> result = wait(x); // This is legal if wait() generates Futures, but it's probably wrong. It's a compilation
|
|
|
|
// error if wait() generates StrictFutures.
|
2017-05-26 04:48:44 +08:00
|
|
|
template <class T>
|
|
|
|
class StrictFuture : public Future<T> {
|
|
|
|
public:
|
|
|
|
inline StrictFuture(Future<T> const& f) : Future<T>(f) {}
|
|
|
|
inline StrictFuture(Never n) : Future<T>(n) {}
|
2021-03-11 02:06:03 +08:00
|
|
|
|
2017-05-26 04:48:44 +08:00
|
|
|
private:
|
|
|
|
StrictFuture(T t) {}
|
|
|
|
StrictFuture(Error e) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class T>
|
2020-11-24 03:40:24 +08:00
|
|
|
class Promise final {
|
2017-05-26 04:48:44 +08:00
|
|
|
public:
|
|
|
|
template <class U>
|
2021-03-11 02:06:03 +08:00
|
|
|
void send(U&& value) const {
|
2017-05-26 04:48:44 +08:00
|
|
|
sav->send(std::forward<U>(value));
|
|
|
|
}
|
|
|
|
template <class E>
|
2021-03-11 02:06:03 +08:00
|
|
|
void sendError(const E& exc) const {
|
|
|
|
sav->sendError(exc);
|
|
|
|
}
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
Future<T> getFuture() const {
|
|
|
|
sav->addFutureRef();
|
|
|
|
return Future<T>(sav);
|
|
|
|
}
|
2020-08-20 08:32:11 +08:00
|
|
|
bool isSet() const { return sav->isSet(); }
|
|
|
|
bool canBeSet() const { return sav->canBeSet(); }
|
2020-08-28 06:31:24 +08:00
|
|
|
|
2020-08-20 08:32:11 +08:00
|
|
|
bool isValid() const { return sav != nullptr; }
|
2017-05-26 04:48:44 +08:00
|
|
|
Promise() : sav(new SAV<T>(0, 1)) {}
|
2021-03-11 02:06:03 +08:00
|
|
|
Promise(const Promise& rhs) : sav(rhs.sav) { sav->addPromiseRef(); }
|
2020-08-20 08:32:11 +08:00
|
|
|
Promise(Promise&& rhs) noexcept : sav(rhs.sav) { rhs.sav = 0; }
|
2020-07-21 02:34:18 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
~Promise() {
|
|
|
|
if (sav)
|
|
|
|
sav->delPromiseRef();
|
|
|
|
}
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
void operator=(const Promise& rhs) {
|
2021-03-11 02:06:03 +08:00
|
|
|
if (rhs.sav)
|
|
|
|
rhs.sav->addPromiseRef();
|
|
|
|
if (sav)
|
|
|
|
sav->delPromiseRef();
|
2017-05-26 04:48:44 +08:00
|
|
|
sav = rhs.sav;
|
|
|
|
}
|
2020-06-10 08:33:41 +08:00
|
|
|
void operator=(Promise&& rhs) noexcept {
|
2017-05-26 04:48:44 +08:00
|
|
|
if (sav != rhs.sav) {
|
2021-03-11 02:06:03 +08:00
|
|
|
if (sav)
|
|
|
|
sav->delPromiseRef();
|
2017-05-26 04:48:44 +08:00
|
|
|
sav = rhs.sav;
|
|
|
|
rhs.sav = 0;
|
|
|
|
}
|
|
|
|
}
|
2021-03-11 02:06:03 +08:00
|
|
|
void reset() { *this = Promise<T>(); }
|
|
|
|
void swap(Promise& other) { std::swap(sav, other.sav); }
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
// Beware, these operations are very unsafe
|
2021-03-11 02:06:03 +08:00
|
|
|
SAV<T>* extractRawPointer() {
|
|
|
|
auto ptr = sav;
|
|
|
|
sav = nullptr;
|
|
|
|
return ptr;
|
|
|
|
}
|
2017-05-26 04:48:44 +08:00
|
|
|
explicit Promise<T>(SAV<T>* ptr) : sav(ptr) {}
|
|
|
|
|
|
|
|
int getFutureReferenceCount() const { return sav->getFutureReferenceCount(); }
|
|
|
|
int getPromiseReferenceCount() const { return sav->getPromiseReferenceCount(); }
|
|
|
|
|
|
|
|
private:
|
2021-03-11 02:06:03 +08:00
|
|
|
SAV<T>* sav;
|
2017-05-26 04:48:44 +08:00
|
|
|
};
|
|
|
|
|
2021-06-20 00:47:13 +08:00
|
|
|
template <class T>
|
|
|
|
struct NotifiedQueue : private SingleCallback<T>, FastAllocated<NotifiedQueue<T>> {
|
|
|
|
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<T>::next==this || (queue.empty() && !error.isValid())
|
|
|
|
std::queue<T, Deque<T>> queue;
|
|
|
|
Promise<Void> onEmpty;
|
|
|
|
Error error;
|
|
|
|
|
|
|
|
NotifiedQueue(int futures, int promises) : futures(futures), promises(promises), onEmpty(nullptr) {
|
|
|
|
SingleCallback<T>::next = this;
|
|
|
|
}
|
|
|
|
|
|
|
|
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(); }
|
|
|
|
|
|
|
|
virtual T pop() {
|
|
|
|
if (queue.empty()) {
|
|
|
|
if (error.isValid())
|
|
|
|
throw error;
|
|
|
|
throw internal_error();
|
|
|
|
}
|
|
|
|
auto copy = std::move(queue.front());
|
|
|
|
queue.pop();
|
|
|
|
if (onEmpty.isValid() && queue.empty()) {
|
|
|
|
Promise<Void> hold = onEmpty;
|
|
|
|
onEmpty = Promise<Void>(nullptr);
|
|
|
|
hold.send(Void());
|
|
|
|
}
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class U>
|
|
|
|
void send(U&& value) {
|
|
|
|
if (error.isValid())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (SingleCallback<T>::next != this) {
|
|
|
|
SingleCallback<T>::next->fire(std::forward<U>(value));
|
|
|
|
} else {
|
|
|
|
queue.emplace(std::forward<U>(value));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void sendError(Error err) {
|
|
|
|
if (error.isValid())
|
|
|
|
return;
|
|
|
|
|
|
|
|
this->error = err;
|
|
|
|
if (shouldFireImmediately()) {
|
|
|
|
SingleCallback<T>::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<T>* cb) {
|
|
|
|
ASSERT(SingleCallback<T>::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); }
|
|
|
|
|
|
|
|
protected:
|
|
|
|
T popImpl() {
|
|
|
|
if (queue.empty()) {
|
|
|
|
if (error.isValid())
|
|
|
|
throw error;
|
|
|
|
throw internal_error();
|
|
|
|
}
|
|
|
|
auto copy = std::move(queue.front());
|
|
|
|
queue.pop();
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool hasError() { return error.isValid(); }
|
|
|
|
|
|
|
|
bool shouldFireImmediately() { return SingleCallback<T>::next != this; }
|
|
|
|
};
|
|
|
|
|
2017-05-26 04:48:44 +08:00
|
|
|
template <class T>
|
|
|
|
class FutureStream {
|
|
|
|
public:
|
2021-03-11 02:06:03 +08:00
|
|
|
bool isValid() const { return queue != 0; }
|
|
|
|
bool isReady() const { return queue->isReady(); }
|
2017-05-26 04:48:44 +08:00
|
|
|
bool isError() const {
|
2021-03-11 02:06:03 +08:00
|
|
|
// This means that the next thing to be popped is an error - it will be false if there is an error in the stream
|
|
|
|
// but some actual data first
|
2017-05-26 04:48:44 +08:00
|
|
|
return queue->isError();
|
|
|
|
}
|
|
|
|
void addCallbackAndClear(SingleCallback<T>* cb) {
|
|
|
|
queue->addCallbackAndDelFutureRef(cb);
|
|
|
|
queue = 0;
|
|
|
|
}
|
2020-08-28 06:31:24 +08:00
|
|
|
FutureStream() : queue(nullptr) {}
|
2017-05-26 04:48:44 +08:00
|
|
|
FutureStream(const FutureStream& rhs) : queue(rhs.queue) { queue->addFutureRef(); }
|
2020-06-10 08:33:41 +08:00
|
|
|
FutureStream(FutureStream&& rhs) noexcept : queue(rhs.queue) { rhs.queue = 0; }
|
2021-03-11 02:06:03 +08:00
|
|
|
~FutureStream() {
|
|
|
|
if (queue)
|
|
|
|
queue->delFutureRef();
|
|
|
|
}
|
2017-05-26 04:48:44 +08:00
|
|
|
void operator=(const FutureStream& rhs) {
|
|
|
|
rhs.queue->addFutureRef();
|
2021-03-11 02:06:03 +08:00
|
|
|
if (queue)
|
|
|
|
queue->delFutureRef();
|
2017-05-26 04:48:44 +08:00
|
|
|
queue = rhs.queue;
|
|
|
|
}
|
2020-06-10 08:33:41 +08:00
|
|
|
void operator=(FutureStream&& rhs) noexcept {
|
2017-05-26 04:48:44 +08:00
|
|
|
if (rhs.queue != queue) {
|
2021-03-11 02:06:03 +08:00
|
|
|
if (queue)
|
|
|
|
queue->delFutureRef();
|
2017-05-26 04:48:44 +08:00
|
|
|
queue = rhs.queue;
|
|
|
|
rhs.queue = 0;
|
|
|
|
}
|
|
|
|
}
|
2021-03-11 02:06:03 +08:00
|
|
|
bool operator==(const FutureStream& rhs) { return rhs.queue == queue; }
|
|
|
|
bool operator!=(const FutureStream& rhs) { return rhs.queue != queue; }
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
T pop() { return queue->pop(); }
|
2017-05-26 04:48:44 +08:00
|
|
|
Error getError() {
|
|
|
|
ASSERT(queue->isError());
|
|
|
|
return queue->error;
|
|
|
|
}
|
|
|
|
|
|
|
|
explicit FutureStream(NotifiedQueue<T>* queue) : queue(queue) {}
|
|
|
|
|
|
|
|
private:
|
|
|
|
NotifiedQueue<T>* queue;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class Request>
|
2020-07-16 07:33:01 +08:00
|
|
|
decltype(std::declval<Request>().reply) const& getReplyPromise(Request const& r) {
|
|
|
|
return r.reply;
|
|
|
|
}
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-06-20 00:47:13 +08:00
|
|
|
template <class Request>
|
|
|
|
auto const& getReplyPromiseStream(Request const& r) {
|
|
|
|
return r.reply;
|
|
|
|
}
|
|
|
|
|
2017-05-26 04:48:44 +08:00
|
|
|
// Neither of these implementations of REPLY_TYPE() works on both MSVC and g++, so...
|
|
|
|
#ifdef __GNUG__
|
2020-07-16 07:33:01 +08:00
|
|
|
#define REPLY_TYPE(RequestType) decltype(getReplyPromise(std::declval<RequestType>()).getFuture().getValue())
|
|
|
|
//#define REPLY_TYPE(RequestType) decltype( getReplyFuture( std::declval<RequestType>() ).getValue() )
|
2017-05-26 04:48:44 +08:00
|
|
|
#else
|
|
|
|
template <class T>
|
|
|
|
struct ReplyType {
|
|
|
|
// Doing this calculation directly in the return value declaration for PromiseStream<T>::getReply()
|
|
|
|
// breaks IntelliSense in VS2010; this is a workaround.
|
2020-07-16 07:33:01 +08:00
|
|
|
typedef decltype(std::declval<T>().reply.getFuture().getValue()) Type;
|
2017-05-26 04:48:44 +08:00
|
|
|
};
|
2021-03-11 02:06:03 +08:00
|
|
|
template <class T>
|
|
|
|
class ReplyPromise;
|
2017-05-26 04:48:44 +08:00
|
|
|
template <class T>
|
|
|
|
struct ReplyType<ReplyPromise<T>> {
|
|
|
|
typedef T Type;
|
|
|
|
};
|
|
|
|
#define REPLY_TYPE(RequestType) typename ReplyType<RequestType>::Type
|
|
|
|
#endif
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
class PromiseStream {
|
|
|
|
public:
|
|
|
|
// stream.send( request )
|
|
|
|
// Unreliable at most once delivery: Delivers request unless there is a connection failure (zero or one times)
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
void send(const T& value) const { queue->send(value); }
|
|
|
|
void send(T&& value) const { queue->send(std::move(value)); }
|
|
|
|
void sendError(const Error& error) const { queue->sendError(error); }
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
// stream.getReply( request )
|
2021-03-11 02:06:03 +08:00
|
|
|
// Reliable at least once delivery: Eventually delivers request at least once and returns one of the replies if
|
|
|
|
// communication is possible. Might deliver request
|
2017-05-26 04:48:44 +08:00
|
|
|
// more than once.
|
|
|
|
// If a reply is returned, request was or will be delivered one or more times.
|
|
|
|
// If cancelled, request was or will be delivered zero or more times.
|
|
|
|
template <class X>
|
|
|
|
Future<REPLY_TYPE(X)> getReply(const X& value) const {
|
|
|
|
send(value);
|
|
|
|
return getReplyPromise(value).getFuture();
|
|
|
|
}
|
|
|
|
template <class X>
|
2019-06-25 17:47:35 +08:00
|
|
|
Future<REPLY_TYPE(X)> getReply(const X& value, TaskPriority taskID) const {
|
2017-05-26 04:48:44 +08:00
|
|
|
setReplyPriority(value, taskID);
|
|
|
|
return getReplyPromise(value).getFuture();
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class X>
|
|
|
|
Future<X> getReply() const {
|
|
|
|
return getReply(Promise<X>());
|
|
|
|
}
|
|
|
|
template <class X>
|
2019-06-25 17:47:35 +08:00
|
|
|
Future<X> getReplyWithTaskID(TaskPriority taskID) const {
|
2017-05-26 04:48:44 +08:00
|
|
|
Promise<X> reply;
|
|
|
|
reply.getEndpoint(taskID);
|
|
|
|
return getReply(reply);
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
FutureStream<T> getFuture() const {
|
|
|
|
queue->addFutureRef();
|
|
|
|
return FutureStream<T>(queue);
|
|
|
|
}
|
2017-05-26 04:48:44 +08:00
|
|
|
PromiseStream() : queue(new NotifiedQueue<T>(0, 1)) {}
|
|
|
|
PromiseStream(const PromiseStream& rhs) : queue(rhs.queue) { queue->addPromiseRef(); }
|
2020-06-10 08:33:41 +08:00
|
|
|
PromiseStream(PromiseStream&& rhs) noexcept : queue(rhs.queue) { rhs.queue = 0; }
|
2017-05-26 04:48:44 +08:00
|
|
|
void operator=(const PromiseStream& rhs) {
|
|
|
|
rhs.queue->addPromiseRef();
|
2021-03-11 02:06:03 +08:00
|
|
|
if (queue)
|
|
|
|
queue->delPromiseRef();
|
2017-05-26 04:48:44 +08:00
|
|
|
queue = rhs.queue;
|
|
|
|
}
|
2020-06-10 08:33:41 +08:00
|
|
|
void operator=(PromiseStream&& rhs) noexcept {
|
2017-05-26 04:48:44 +08:00
|
|
|
if (queue != rhs.queue) {
|
2021-03-11 02:06:03 +08:00
|
|
|
if (queue)
|
|
|
|
queue->delPromiseRef();
|
2017-05-26 04:48:44 +08:00
|
|
|
queue = rhs.queue;
|
|
|
|
rhs.queue = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
~PromiseStream() {
|
|
|
|
if (queue)
|
|
|
|
queue->delPromiseRef();
|
2021-03-11 02:06:03 +08:00
|
|
|
// queue = (NotifiedQueue<T>*)0xdeadbeef;
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
bool operator==(const PromiseStream<T>& rhs) const { return queue == rhs.queue; }
|
2017-05-26 04:48:44 +08:00
|
|
|
bool isEmpty() const { return !queue->isReady(); }
|
|
|
|
|
2021-06-20 00:47:13 +08:00
|
|
|
Future<Void> onEmpty() {
|
|
|
|
if (isEmpty()) {
|
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
if (!queue->onEmpty.isValid()) {
|
|
|
|
queue->onEmpty = Promise<Void>();
|
|
|
|
}
|
|
|
|
return queue->onEmpty.getFuture();
|
|
|
|
}
|
|
|
|
|
2017-05-26 04:48:44 +08:00
|
|
|
private:
|
|
|
|
NotifiedQueue<T>* queue;
|
|
|
|
};
|
|
|
|
|
2021-06-20 00:47:13 +08:00
|
|
|
// Neither of these implementations of REPLY_TYPE() works on both MSVC and g++, so...
|
|
|
|
#ifdef __GNUG__
|
|
|
|
#define REPLYSTREAM_TYPE(RequestType) decltype(getReplyPromiseStream(std::declval<RequestType>()).getFuture().pop())
|
|
|
|
#else
|
|
|
|
template <class T>
|
|
|
|
struct ReplyStreamType {
|
|
|
|
// Doing this calculation directly in the return value declaration for PromiseStream<T>::getReply()
|
|
|
|
// breaks IntelliSense in VS2010; this is a workaround.
|
|
|
|
typedef decltype(std::declval<T>().reply.getFuture().pop()) Type;
|
|
|
|
};
|
|
|
|
template <class T>
|
|
|
|
class ReplyPromiseStream;
|
|
|
|
template <class T>
|
|
|
|
struct ReplyStreamType<ReplyPromiseStream<T>> {
|
|
|
|
typedef T Type;
|
|
|
|
};
|
|
|
|
#define REPLYSTREAM_TYPE(RequestType) typename ReplyStreamType<RequestType>::Type
|
|
|
|
#endif
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// extern int actorCount;
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
template <class T>
|
|
|
|
static inline void destruct(T& t) {
|
|
|
|
t.~T();
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ReturnValue>
|
2020-12-08 06:15:25 +08:00
|
|
|
struct Actor : SAV<ReturnValue> {
|
2021-03-11 02:06:03 +08:00
|
|
|
int8_t actor_wait_state; // -1 means actor is cancelled; 0 means actor is not waiting; 1-N mean waiting in callback
|
|
|
|
// group #
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-05-11 11:26:12 +08:00
|
|
|
Actor() : SAV<ReturnValue>(1, 1), actor_wait_state(0) { /*++actorCount;*/
|
2020-12-08 06:15:25 +08:00
|
|
|
}
|
2020-12-10 01:19:59 +08:00
|
|
|
//~Actor() { --actorCount; }
|
2017-05-26 04:48:44 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
template <>
|
2020-12-08 06:15:25 +08:00
|
|
|
struct Actor<void> {
|
2017-05-26 04:48:44 +08:00
|
|
|
// This specialization is for a void actor (one not returning a future, hence also uncancellable)
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
int8_t actor_wait_state; // 0 means actor is not waiting; 1-N mean waiting in callback group #
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-05-11 11:26:12 +08:00
|
|
|
Actor() : actor_wait_state(0) { /*++actorCount;*/
|
2020-12-08 06:15:25 +08:00
|
|
|
}
|
2020-12-10 01:19:59 +08:00
|
|
|
//~Actor() { --actorCount; }
|
2017-05-26 04:48:44 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
template <class ActorType, int CallbackNumber, class ValueType>
|
|
|
|
struct ActorCallback : Callback<ValueType> {
|
2021-05-11 11:26:12 +08:00
|
|
|
void fire(ValueType const& value) override { static_cast<ActorType*>(this)->a_callback_fire(this, value); }
|
|
|
|
void error(Error e) override { static_cast<ActorType*>(this)->a_callback_error(this, e); }
|
2017-05-26 04:48:44 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
template <class ActorType, int CallbackNumber, class ValueType>
|
|
|
|
struct ActorSingleCallback : SingleCallback<ValueType> {
|
2021-05-11 11:26:12 +08:00
|
|
|
void fire(ValueType const& value) override { static_cast<ActorType*>(this)->a_callback_fire(this, value); }
|
|
|
|
void fire(ValueType&& value) override { static_cast<ActorType*>(this)->a_callback_fire(this, std::move(value)); }
|
|
|
|
void error(Error e) override { static_cast<ActorType*>(this)->a_callback_error(this, e); }
|
2017-05-26 04:48:44 +08:00
|
|
|
};
|
2021-03-11 02:06:03 +08:00
|
|
|
inline double now() {
|
|
|
|
return g_network->now();
|
|
|
|
}
|
|
|
|
inline Future<Void> delay(double seconds, TaskPriority taskID = TaskPriority::DefaultDelay) {
|
|
|
|
return g_network->delay(seconds, taskID);
|
|
|
|
}
|
|
|
|
inline Future<Void> delayUntil(double time, TaskPriority taskID = TaskPriority::DefaultDelay) {
|
|
|
|
return g_network->delay(std::max(0.0, time - g_network->now()), taskID);
|
|
|
|
}
|
|
|
|
inline Future<Void> delayJittered(double seconds, TaskPriority taskID = TaskPriority::DefaultDelay) {
|
|
|
|
return g_network->delay(seconds * (FLOW_KNOBS->DELAY_JITTER_OFFSET +
|
|
|
|
FLOW_KNOBS->DELAY_JITTER_RANGE * deterministicRandom()->random01()),
|
|
|
|
taskID);
|
|
|
|
}
|
|
|
|
inline Future<Void> yield(TaskPriority taskID = TaskPriority::DefaultYield) {
|
|
|
|
return g_network->yield(taskID);
|
|
|
|
}
|
|
|
|
inline bool check_yield(TaskPriority taskID = TaskPriority::DefaultYield) {
|
|
|
|
return g_network->check_yield(taskID);
|
|
|
|
}
|
2019-05-11 05:01:52 +08:00
|
|
|
|
2018-10-20 01:30:13 +08:00
|
|
|
#include "flow/genericactors.actor.h"
|
2017-05-26 04:48:44 +08:00
|
|
|
#endif
|