Line data Source code
1 : #pragma once 2 : 3 : #include <atomic> 4 : #include <functional> 5 : 6 : #include "envoy/common/pure.h" 7 : 8 : #include "source/common/common/assert.h" 9 : 10 : namespace Envoy { 11 : namespace Extensions { 12 : namespace Common { 13 : namespace AsyncFiles { 14 : 15 : // A CancelFunction attempts to stop an action in flight. 16 : // * If the action already occurred, the CancelFunction does nothing. 17 : // * If the action is already calling the callback, CancelFunction blocks until the callback 18 : // completes. 19 : // * If the action is already executing, CancelFunction causes the removal of any resource-consuming 20 : // return value (e.g. file handles), and prevents the callback. 21 : // * If the action is still just queued, CancelFunction prevents its execution. 22 : using CancelFunction = std::function<void()>; 23 : 24 : // Actions to be passed to asyncFileManager->enqueue. 25 : class AsyncFileAction { 26 : public: 27 0 : virtual ~AsyncFileAction() = default; 28 : 29 : // Cancel the action, as much as possible. 30 : // 31 : // If the action has not been started, it will become a no-op. 32 : // 33 : // If the action has started, onCancelledBeforeCallback will be called, 34 : // and the callback will not. 35 : // 36 : // If the callback is already being called, cancel will block until the 37 : // callback has completed. 38 : // 39 : // If the action is already complete, cancel does nothing. 40 : void cancel(); 41 : 42 : // Performs the action represented by this instance, and calls the callback 43 : // on completion or on error. 44 : virtual void execute() PURE; 45 : 46 : protected: 47 : enum class State { Queued, Executing, InCallback, Done, Cancelled }; 48 : std::atomic<State> state_{State::Queued}; 49 : }; 50 : 51 : // All concrete AsyncFileActions are a subclass of AsyncFileActionWithResult. 52 : // The template allows for different on_complete callback signatures appropriate 53 : // to each specific action. 54 : // 55 : // on_complete callbacks run in the AsyncFileManager's thread pool, and therefore: 56 : // 1. Should avoid using variables that may be out of scope by the time the callback is called. 57 : // 2. May need to lock-guard variables that can be changed in other threads. 58 : // 3. Must not block significantly or do significant work - if anything time-consuming is required 59 : // the result should be passed to another thread for handling. 60 : template <typename T> class AsyncFileActionWithResult : public AsyncFileAction { 61 : public: 62 : explicit AsyncFileActionWithResult(std::function<void(T)> on_complete) 63 0 : : on_complete_(on_complete) {} 64 : 65 0 : void execute() final { 66 0 : State expected = State::Queued; 67 0 : if (!state_.compare_exchange_strong(expected, State::Executing)) { 68 0 : ASSERT(expected == State::Cancelled); 69 0 : return; 70 0 : } 71 0 : expected = State::Executing; 72 0 : T result = executeImpl(); 73 0 : if (!state_.compare_exchange_strong(expected, State::InCallback)) { 74 0 : ASSERT(expected == State::Cancelled); 75 0 : onCancelledBeforeCallback(std::move(result)); 76 0 : return; 77 0 : } 78 0 : on_complete_(std::move(result)); 79 0 : state_.store(State::Done); 80 0 : } 81 : 82 : protected: 83 : // Performs any action to undo side-effects of the execution if the callback 84 : // has not yet been called (e.g. closing a file that was just opened). 85 : // Not necessary for things that don't make persistent resources, 86 : // e.g. cancelling a write does not have to undo the write. 87 0 : virtual void onCancelledBeforeCallback(T){}; 88 : 89 : // Implementation of the actual action. 90 : virtual T executeImpl() PURE; 91 : 92 : private: 93 : std::function<void(T)> on_complete_; 94 : }; 95 : 96 : } // namespace AsyncFiles 97 : } // namespace Common 98 : } // namespace Extensions 99 : } // namespace Envoy