/* * Copyright (C) 2021 ScyllaDB */ /* * SPDX-License-Identifier: LicenseRef-ScyllaDB-Source-Available-1.0 */ #pragma once #include #include #include /// Invokes a factory to produce an object, but sequentially: only one fiber at a time may be executing the /// factory. Any other fiber requesting the object will wait for the existing factory invocation to finish, then /// copy the result. /// /// TODO: Move to Seastar. template class sequential_producer { public: using factory_t = std::function()>; using time_point = seastar::shared_future::time_point; private: factory_t _factory; seastar::shared_future _churning; ///< Resolves when the previous _factory call completes. public: sequential_producer(factory_t&& f) : _factory(std::move(f)) { clear(); } seastar::future operator()(time_point timeout = time_point::max()) { if (_churning.available()) { _churning = _factory(); } return _churning.get_future(timeout); } seastar::future operator()(seastar::abort_source& as) { if (_churning.available()) { _churning = _factory(); } return _churning.get_future(as); } void clear() { _churning = seastar::make_exception_future( std::logic_error("initial future used in sequential_producer")); } };