aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/clickhouse/src/IO/ResourceRequest.h
blob: 989349148cfa80b240aa1e673e1de8f4093ac00a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#pragma once

#include <base/types.h>
#include <limits>

namespace DB
{

// Forward declarations
class ISchedulerQueue;
class ISchedulerConstraint;

/// Cost in terms of used resource (e.g. bytes for network IO)
using ResourceCost = Int64;
constexpr ResourceCost ResourceCostMax = std::numeric_limits<int>::max();

/// Timestamps (nanoseconds since epoch)
using ResourceNs = UInt64;

/*
 * Request for a resource consumption. The main moving part of the scheduling subsystem.
 * Resource requests processing workflow:
 *
 * ----1=2222222222222=3=4=555555555555555=6-----> time
 *     ^     ^         ^ ^          ^      ^
 *     |     |         | |          |      |
 *  enqueue wait dequeue execute consume finish
 *
 *  1) Request is enqueued using ISchedulerQueue::enqueueRequest().
 *  2) Request competes with others for access to a resource; effectively just waiting in a queue.
 *  3) Scheduler calls ISchedulerNode::dequeueRequest() that returns the request.
 *  4) Callback ResourceRequest::execute() is called to provide access to the resource.
 *  5) The resource consumption is happening outside of the scheduling subsystem.
 *  6) request->constraint->finishRequest() is called when consumption is finished.
 *
 * Steps (5) and (6) can be omitted if constraint is not used by the resource.
 *
 * Request can be created on stack or heap.
 * Request ownership is done outside of the scheduling subsystem.
 * After (6) request can be destructed safely.
 *
 * Request cancelling is not supported yet.
 */
class ResourceRequest
{
public:
    /// Cost of request execution; should be filled before request enqueueing.
    /// NOTE: If cost is not known in advance, credit model can be used:
    /// NOTE: for the first request use 1 and
    ResourceCost cost;

    /// Request outcome
    /// Should be filled during resource consumption
    bool successful;

    /// Scheduler node to be notified on consumption finish
    /// Auto-filled during request enqueue/dequeue
    ISchedulerConstraint * constraint;

    /// Timestamps for introspection
    ResourceNs enqueue_ns;
    ResourceNs execute_ns;
    ResourceNs finish_ns;

    explicit ResourceRequest(ResourceCost cost_ = 1)
    {
        reset(cost_);
    }

    void reset(ResourceCost cost_)
    {
        cost = cost_;
        successful = true;
        constraint = nullptr;
        enqueue_ns = 0;
        execute_ns = 0;
        finish_ns = 0;
    }

    virtual ~ResourceRequest() = default;

    /// Callback to trigger resource consumption.
    /// IMPORTANT: it is called from scheduler thread and must be fast,
    /// just triggering start of a consumption, not doing the consumption itself
    /// (e.g. setting an std::promise or creating a job in a thread pool)
    virtual void execute() = 0;
};

}