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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
content / browser / cache_storage / cache_storage_scheduler.h [blame]
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_CACHE_STORAGE_CACHE_STORAGE_SCHEDULER_H_
#define CONTENT_BROWSER_CACHE_STORAGE_CACHE_STORAGE_SCHEDULER_H_
#include <map>
#include <vector>
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/memory/weak_ptr.h"
#include "base/task/sequenced_task_runner.h"
#include "content/browser/cache_storage/cache_storage_scheduler_types.h"
#include "content/common/content_export.h"
namespace content {
class CacheStorageOperation;
CONTENT_EXPORT BASE_DECLARE_FEATURE(kCacheStorageParallelOps);
// TODO(jkarlin): Support operation identification so that ops can be checked in
// DCHECKs.
// CacheStorageScheduler runs the scheduled callbacks sequentially. Add an
// operation by calling ScheduleOperation() with your callback. Once your
// operation is done be sure to call CompleteOperationAndRunNext() to schedule
// the next operation.
class CONTENT_EXPORT CacheStorageScheduler {
public:
// TODO(estade): remove `task_runner` which is invariably the same one that
// `CacheStorageScheduler` is constructed and operated on (i.e. the "current
// default").
CacheStorageScheduler(CacheStorageSchedulerClient client_type,
scoped_refptr<base::SequencedTaskRunner> task_runner);
CacheStorageScheduler(const CacheStorageScheduler&) = delete;
CacheStorageScheduler& operator=(const CacheStorageScheduler&) = delete;
virtual ~CacheStorageScheduler();
// Create a scheduler-unique identifier for an operation to be scheduled.
// This value must be passed to the ScheduleOperation(),
// CompleteOperationAndRunNext(), and WrapCallbackToRunNext() methods.
CacheStorageSchedulerId CreateId();
// Adds the operation to the tail of the queue and starts it if possible.
// A unique identifier must be provided via the CreateId() method. The
// mode determines whether the operation should run exclusively by itself
// or can safely run in parallel with other shared operations. Note that the
// operation may be executed either synchronously or asynchronously.
void ScheduleOperation(CacheStorageSchedulerId id,
CacheStorageSchedulerMode mode,
CacheStorageSchedulerOp op_type,
CacheStorageSchedulerPriority priority,
base::OnceClosure closure);
// Call this after each operation completes. It cleans up the operation
// associated with the given id. If may also start the next set of
// operations.
void CompleteOperationAndRunNext(CacheStorageSchedulerId id);
// Returns true if there are any running or pending operations.
bool ScheduledOperations() const;
// Returns true if the scheduler is currently running an exclusive operation.
bool IsRunningExclusiveOperation() const;
// Wraps |callback| to also call CompleteOperationAndRunNext.
template <typename... Args>
base::OnceCallback<void(Args...)> WrapCallbackToRunNext(
CacheStorageSchedulerId id,
base::OnceCallback<void(Args...)> callback) {
return base::BindOnce(&CacheStorageScheduler::RunNextContinuation<Args...>,
weak_ptr_factory_.GetWeakPtr(), id,
std::move(callback));
}
protected:
// virtual for testing
virtual void DispatchOperationTask(base::OnceClosure task);
private:
// Maybe start running the next operation depending on the current
// set of running operations and the mode of the next operation.
void MaybeRunOperation();
template <typename... Args>
void RunNextContinuation(CacheStorageSchedulerId id,
base::OnceCallback<void(Args...)> callback,
Args... args) {
// Grab a weak ptr to guard against the scheduler being deleted during the
// callback.
base::WeakPtr<CacheStorageScheduler> scheduler =
weak_ptr_factory_.GetWeakPtr();
std::move(callback).Run(std::forward<Args>(args)...);
if (scheduler)
CompleteOperationAndRunNext(id);
}
scoped_refptr<base::SequencedTaskRunner> task_runner_;
// Managed as a heap using std::push_heap and std::pop_heap. We do not
// use std::priority_queue since it does not support moving the contained
// unique_ptr out when the operation begins execution.
std::vector<std::unique_ptr<CacheStorageOperation>> pending_operations_;
std::map<CacheStorageSchedulerId, std::unique_ptr<CacheStorageOperation>>
running_operations_;
const CacheStorageSchedulerClient client_type_;
CacheStorageSchedulerId next_id_ = 0;
// Number of shared/exclusive operations currently running.
int num_running_shared_ = 0;
int num_running_exclusive_ = 0;
// Whether the control flow is already inside `MaybeRunOperation()`. Used to
// prevent recursion.
bool in_maybe_run_ = false;
SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtrFactory<CacheStorageScheduler> weak_ptr_factory_{this};
};
} // namespace content
#endif // CONTENT_BROWSER_CACHE_STORAGE_CACHE_STORAGE_SCHEDULER_H_