Branch data Line data Source code
1 : : /* 2 : : * Copyright (C) 2026 by Thun Lu. All rights reserved. 3 : : * Author: Thun Lu <thun.lu@zohomail.cn> 4 : : * Repo: https://github.com/thun-res/vlink 5 : : * _ __ __ _ __ 6 : : * | | / / / / (_) ____ / /__ 7 : : * | | / / / / / / / __ \ / //_/ 8 : : * | |/ / / /___ / / / / / / / ,< 9 : : * |___/ /_____/ /_/ /_/ /_/ /_/|_| 10 : : * 11 : : * Licensed under the Apache License, Version 2.0 (the "License"); 12 : : * you may not use this file except in compliance with the License. 13 : : * You may obtain a copy of the License at 14 : : * 15 : : * http://www.apache.org/licenses/LICENSE-2.0 16 : : * 17 : : * Unless required by applicable law or agreed to in writing, software 18 : : * distributed under the License is distributed on an "AS IS" BASIS, 19 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 : : * See the License for the specific language governing permissions and 21 : : * limitations under the License. 22 : : */ 23 : : 24 : : #include "./impl/ack_manager.h" 25 : : 26 : : #include <memory> 27 : : #include <mutex> 28 : : 29 : : namespace vlink { 30 : : 31 : : // AckManager 32 : 178 : AckManager::AckManager() noexcept = default; 33 : : 34 : 178 : AckManager::~AckManager() noexcept = default; 35 : : 36 : 140 : AckManager::RequestPtr AckManager::create_request() noexcept { 37 : 140 : std::unique_lock manager_lock(mtx_); 38 : : 39 : 140 : auto request = std::make_shared<Request>(); 40 : : 41 : 140 : request->seq = request_seq_++; 42 : 140 : request->generation = generation_; 43 : : 44 : 140 : return request; 45 : 140 : } 46 : : 47 : 131 : bool AckManager::process(RequestPtr request, int ms, ProcessCallback&& process_callback) noexcept { 48 : 131 : auto deadline = std::chrono::steady_clock::time_point::max(); 49 : : 50 [ + + ]: 131 : if VLIKELY (ms >= 0) { 51 : 126 : deadline = std::chrono::steady_clock::now() + std::chrono::milliseconds(ms); 52 : : } 53 : : 54 : : { 55 : 131 : std::lock_guard lock(request->mtx); 56 : 131 : std::lock_guard manager_lock(mtx_); 57 : : 58 [ + + - + : 131 : if VUNLIKELY (is_interrupted_ || request->generation != generation_) { + + ] 59 : 1 : return false; 60 : : } 61 : : 62 [ - + ]: 130 : if VUNLIKELY (request->status != Request::Status::kCreated) { 63 : 0 : return false; 64 : : } 65 : : 66 : 130 : request->deadline = deadline; 67 : 130 : request->status = Request::Status::kPending; 68 : 130 : request_set_.emplace(request); 69 [ + + + + ]: 132 : } 70 : : 71 [ + - + + ]: 130 : const bool sent = process_callback && process_callback(); 72 : : 73 : 130 : std::unique_lock lock(request->mtx); 74 : : 75 : 189 : auto predicate = [&request]() -> bool { return request->status != Request::Status::kPending; }; 76 : : 77 [ + + ]: 130 : if VLIKELY (sent) { 78 [ + + ]: 127 : if VUNLIKELY (ms < 0) { 79 : 4 : request->cv.wait(lock, predicate); 80 : : } else { 81 : 123 : request->cv.wait_until(lock, request->deadline, predicate); 82 : : } 83 : : } 84 : : 85 : : { 86 : 130 : std::lock_guard manager_lock(mtx_); 87 : 130 : request_set_.erase(request); 88 : 129 : } 89 : : 90 [ + + ]: 130 : if (request->status == Request::Status::kPending) { 91 : 14 : request->status = Request::Status::kCancelled; 92 : : } 93 : : 94 [ + + + + ]: 130 : return sent && request->status == Request::Status::kAcknowledged; 95 : 130 : } 96 : : 97 : 117 : bool AckManager::notify(RequestPtr request, NotifyCallback&& notify_callback) noexcept { 98 [ + + ]: 117 : if VUNLIKELY (!request) { 99 : 1 : return false; 100 : : } 101 : : 102 : 116 : std::lock_guard lock(request->mtx); 103 : : 104 [ + + ]: 116 : if VUNLIKELY (request->status != Request::Status::kPending) { 105 : 6 : return false; 106 : : } 107 : : 108 : 110 : const auto acknowledged_at = std::chrono::steady_clock::now(); 109 : : 110 [ + + ]: 110 : if VUNLIKELY (acknowledged_at >= request->deadline) { 111 : 1 : request->status = Request::Status::kCancelled; 112 : 1 : request->cv.notify_one(); 113 : 1 : return false; 114 : : } 115 : : 116 [ + + ]: 109 : if VLIKELY (notify_callback) { 117 : 97 : notify_callback(); 118 : : } 119 : : 120 : 109 : request->status = Request::Status::kAcknowledged; 121 : 109 : request->cv.notify_one(); 122 : : 123 : 109 : return true; 124 : 116 : } 125 : : 126 : 4 : bool AckManager::remove(RequestPtr request) noexcept { 127 [ + + ]: 4 : if VUNLIKELY (!request) { 128 : 1 : return false; 129 : : } 130 : : 131 : 3 : std::lock_guard lock(request->mtx); 132 : : 133 [ + + ]: 3 : if VUNLIKELY (request->status != Request::Status::kPending) { 134 : 2 : return false; 135 : : } 136 : : 137 : : { 138 : 1 : std::lock_guard manager_lock(mtx_); 139 : : 140 [ - + ]: 1 : if (request_set_.erase(request) == 0) { 141 : 0 : return false; 142 : : } 143 [ + - ]: 1 : } 144 : : 145 : 1 : request->status = Request::Status::kCancelled; 146 : 1 : request->cv.notify_one(); 147 : : 148 : 1 : return true; 149 : 3 : } 150 : : 151 : 148 : void AckManager::clear() noexcept { 152 : 148 : decltype(request_set_) temp_set; 153 : : 154 : : { 155 : 148 : std::lock_guard manager_lock(mtx_); 156 : : 157 : 148 : is_interrupted_ = true; 158 : 148 : ++generation_; 159 : : 160 : 148 : temp_set.swap(request_set_); 161 : 148 : } 162 : : 163 [ + + ]: 154 : for (const auto& request : temp_set) { 164 : 6 : std::lock_guard lock(request->mtx); 165 [ + + ]: 6 : if (request->status == Request::Status::kPending) { 166 : 5 : request->status = Request::Status::kCancelled; 167 : 5 : request->cv.notify_all(); 168 : : } 169 : 6 : } 170 : 148 : } 171 : : 172 : 145 : void AckManager::reset_interrupted() noexcept { 173 : 145 : std::lock_guard manager_lock(mtx_); 174 : : 175 : 145 : is_interrupted_ = false; 176 : 145 : } 177 : : 178 : : } // namespace vlink