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 = absl::AnyInvocable<void()>;
23

            
24
// Actions to be passed to asyncFileManager->enqueue.
25
class AsyncFileAction {
26
public:
27
4408
  virtual ~AsyncFileAction() = default;
28

            
29
  // Performs the action represented by this instance, and captures the
30
  // result.
31
  virtual void execute() PURE;
32

            
33
  // Calls the captured callback with the captured result.
34
  virtual void onComplete() PURE;
35

            
36
  // Performs any action to undo side-effects of the execution if the callback
37
  // has not yet been called (e.g. closing a file that was just opened, removing
38
  // a hard-link that was just created).
39
  // Not necessary for things that don't make persistent resources,
40
  // e.g. cancelling a write does not have to undo the write.
41
1
  virtual void onCancelledBeforeCallback() {}
42
3717
  virtual bool hasActionIfCancelledBeforeCallback() const { return false; }
43
2
  virtual bool executesEvenIfCancelled() const { return false; }
44
};
45

            
46
// All concrete AsyncFileActions are a subclass of AsyncFileActionWithResult.
47
// The template allows for different on_complete callback signatures appropriate
48
// to each specific action.
49
//
50
// on_complete callbacks run in the AsyncFileManager's thread pool, and therefore:
51
// 1. Should avoid using variables that may be out of scope by the time the callback is called.
52
// 2. May need to lock-guard variables that can be changed in other threads.
53
// 3. Must not block significantly or do significant work - if anything time-consuming is required
54
// the result should be passed to another thread for handling.
55
template <typename T> class AsyncFileActionWithResult : public AsyncFileAction {
56
public:
57
  explicit AsyncFileActionWithResult(absl::AnyInvocable<void(T)> on_complete)
58
4081
      : on_complete_(std::move(on_complete)) {}
59

            
60
4078
  void execute() final { result_ = executeImpl(); }
61
3950
  void onComplete() final { std::move(on_complete_)(std::move(result_.value())); }
62

            
63
protected:
64
  absl::optional<T> result_;
65
  // Implementation of the actual action.
66
  virtual T executeImpl() PURE;
67

            
68
private:
69
  absl::AnyInvocable<void(T)> on_complete_;
70
};
71

            
72
} // namespace AsyncFiles
73
} // namespace Common
74
} // namespace Extensions
75
} // namespace Envoy