1/*
2 * Copyright 2011-present Facebook, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <folly/TimeoutQueue.h>
18#include <algorithm>
19#include <vector>
20
21namespace folly {
22
23TimeoutQueue::Id
24TimeoutQueue::add(int64_t now, int64_t delay, Callback callback) {
25 Id id = nextId_++;
26 timeouts_.insert({id, now + delay, -1, std::move(callback)});
27 return id;
28}
29
30TimeoutQueue::Id
31TimeoutQueue::addRepeating(int64_t now, int64_t interval, Callback callback) {
32 Id id = nextId_++;
33 timeouts_.insert({id, now + interval, interval, std::move(callback)});
34 return id;
35}
36
37int64_t TimeoutQueue::nextExpiration() const {
38 return (
39 timeouts_.empty() ? std::numeric_limits<int64_t>::max()
40 : timeouts_.get<BY_EXPIRATION>().begin()->expiration);
41}
42
43bool TimeoutQueue::erase(Id id) {
44 return timeouts_.get<BY_ID>().erase(id);
45}
46
47int64_t TimeoutQueue::runInternal(int64_t now, bool onceOnly) {
48 auto& byExpiration = timeouts_.get<BY_EXPIRATION>();
49 int64_t nextExp;
50 do {
51 const auto end = byExpiration.upper_bound(now);
52 std::vector<Event> expired;
53 std::move(byExpiration.begin(), end, std::back_inserter(expired));
54 byExpiration.erase(byExpiration.begin(), end);
55 for (const auto& event : expired) {
56 // Reinsert if repeating, do this before executing callbacks
57 // so the callbacks have a chance to call erase
58 if (event.repeatInterval >= 0) {
59 timeouts_.insert({event.id,
60 now + event.repeatInterval,
61 event.repeatInterval,
62 event.callback});
63 }
64 }
65
66 // Call callbacks
67 for (const auto& event : expired) {
68 event.callback(event.id, now);
69 }
70 nextExp = nextExpiration();
71 } while (!onceOnly && nextExp <= now);
72 return nextExp;
73}
74
75} // namespace folly
76