Cancellation of a RequestContext requires coordination from multiple threads that may hold references to the context: 1. Disk threads that are currently processing a range for this context. 2. Caller threads that are waiting in GetNext(). Each thread that currently has a reference to the request context must notice the cancel, cancel any pending operations involving the context and remove the con
| 281 | // DecrementDiskRefCount(). After the last disk thread has called DecrementDiskRefCount(), |
| 282 | // cancellation is done and it is safe to unregister the context. |
| 283 | void RequestContext::Cancel() { |
| 284 | // Callbacks are collected in this vector and invoked while no lock is held. |
| 285 | vector<WriteRange::WriteDoneCallback> write_callbacks; |
| 286 | vector<RemoteOperRange::RemoteOperDoneCallback> remote_oper_callbacks; |
| 287 | { |
| 288 | unique_lock<mutex> lock(lock_); |
| 289 | DCHECK(Validate()) << endl << DebugString(); |
| 290 | |
| 291 | // Already being cancelled |
| 292 | if (state_ == RequestContext::Cancelled) return; |
| 293 | |
| 294 | // The reader will be put into a cancelled state until call cleanup is complete. |
| 295 | state_ = RequestContext::Cancelled; |
| 296 | |
| 297 | // Clear out all request ranges from queues for this reader. Cancel the scan |
| 298 | // ranges and invoke the write range callbacks to propagate the cancellation. |
| 299 | for (ScanRange* range : active_scan_ranges_) { |
| 300 | range->CancelInternal(CONTEXT_CANCELLED, false); |
| 301 | } |
| 302 | active_scan_ranges_.clear(); |
| 303 | for (PerDiskState& disk_state : disk_states_) { |
| 304 | RequestRange* range; |
| 305 | while ((range = disk_state.in_flight_ranges()->Dequeue()) != nullptr) { |
| 306 | if (range->request_type() == RequestType::WRITE) { |
| 307 | write_callbacks.push_back(static_cast<WriteRange*>(range)->callback()); |
| 308 | } |
| 309 | } |
| 310 | while (disk_state.unstarted_scan_ranges()->Dequeue() != nullptr); |
| 311 | WriteRange* write_range; |
| 312 | while ((write_range = disk_state.unstarted_write_ranges()->Dequeue()) != nullptr) { |
| 313 | write_callbacks.push_back(write_range->callback()); |
| 314 | } |
| 315 | |
| 316 | RemoteOperRange* oper_range; |
| 317 | while ((oper_range = disk_state.unstarted_remote_file_oper_ranges()->Dequeue()) |
| 318 | != nullptr) { |
| 319 | remote_oper_callbacks.push_back(oper_range->callback()); |
| 320 | } |
| 321 | } |
| 322 | // Clear out the lists of scan ranges. |
| 323 | while (ready_to_start_ranges_.Dequeue() != nullptr); |
| 324 | while (cached_ranges_.Dequeue() != nullptr); |
| 325 | |
| 326 | // Ensure that the reader is scheduled on all disks (it may already be scheduled on |
| 327 | // some). The disk threads will notice that the context is cancelled and do any |
| 328 | // required cleanup for the disk state. |
| 329 | for (int i = 0; i < disk_states_.size(); ++i) { |
| 330 | disk_states_[i].ScheduleContext(lock, this, i); |
| 331 | } |
| 332 | } |
| 333 | |
| 334 | for (const WriteRange::WriteDoneCallback& write_callback: write_callbacks) { |
| 335 | write_callback(CONTEXT_CANCELLED); |
| 336 | } |
| 337 | |
| 338 | for (const RemoteOperRange::RemoteOperDoneCallback& oper_callback : |
| 339 | remote_oper_callbacks) { |
| 340 | oper_callback(CONTEXT_CANCELLED); |
nothing calls this directly
no test coverage detected