| /** @file |
| |
| A brief file description |
| |
| @section license License |
| |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| /**************************************************************************** |
| |
| Async Disk IO operations. |
| |
| |
| |
| ****************************************************************************/ |
| #pragma once |
| |
| #include "P_EventSystem.h" |
| #include "I_AIO.h" |
| |
| // for debugging |
| // #define AIO_STATS 1 |
| |
| static constexpr ts::ModuleVersion AIO_MODULE_INTERNAL_VERSION{AIO_MODULE_PUBLIC_VERSION, ts::ModuleVersion::PRIVATE}; |
| |
| TS_INLINE int |
| AIOCallback::ok() |
| { |
| return (off_t)aiocb.aio_nbytes == (off_t)aio_result; |
| } |
| |
| extern Continuation *aio_err_callbck; |
| |
| #if AIO_MODE == AIO_MODE_NATIVE |
| |
| struct AIOCallbackInternal : public AIOCallback { |
| int io_complete(int event, void *data); |
| AIOCallbackInternal() |
| { |
| memset((void *)&(this->aiocb), 0, sizeof(this->aiocb)); |
| SET_HANDLER(&AIOCallbackInternal::io_complete); |
| } |
| }; |
| |
| TS_INLINE int |
| AIOVec::mainEvent(int /* event */, Event *) |
| { |
| ++completed; |
| if (completed < size) |
| return EVENT_CONT; |
| else if (completed == size) { |
| SCOPED_MUTEX_LOCK(lock, action.mutex, this_ethread()); |
| if (!action.cancelled) |
| action.continuation->handleEvent(AIO_EVENT_DONE, first); |
| delete this; |
| return EVENT_DONE; |
| } |
| ink_assert(!"AIOVec mainEvent err"); |
| return EVENT_ERROR; |
| } |
| |
| #else /* AIO_MODE != AIO_MODE_NATIVE */ |
| |
| struct AIO_Reqs; |
| |
| struct AIOCallbackInternal : public AIOCallback { |
| AIO_Reqs *aio_req = nullptr; |
| ink_hrtime sleep_time = 0; |
| SLINK(AIOCallbackInternal, alink); /* for AIO_Reqs::aio_temp_list */ |
| |
| int io_complete(int event, void *data); |
| |
| AIOCallbackInternal() { SET_HANDLER(&AIOCallbackInternal::io_complete); } |
| }; |
| |
| struct AIO_Reqs { |
| Que(AIOCallback, link) aio_todo; /* queue for AIO operations */ |
| /* Atomic list to temporarily hold the request if the |
| lock for a particular queue cannot be acquired */ |
| ASLL(AIOCallbackInternal, alink) aio_temp_list; |
| ink_mutex aio_mutex; |
| ink_cond aio_cond; |
| int index = 0; /* position of this struct in the aio_reqs array */ |
| int pending = 0; /* number of outstanding requests on the disk */ |
| int queued = 0; /* total number of aio_todo requests */ |
| int filedes = 0; /* the file descriptor for the requests */ |
| int requests_queued = 0; |
| }; |
| |
| #endif // AIO_MODE == AIO_MODE_NATIVE |
| |
| TS_INLINE int |
| AIOCallbackInternal::io_complete(int event, void *data) |
| { |
| (void)event; |
| (void)data; |
| if (aio_err_callbck && !ok()) { |
| AIOCallback *err_op = new AIOCallbackInternal(); |
| err_op->aiocb.aio_fildes = this->aiocb.aio_fildes; |
| err_op->aiocb.aio_lio_opcode = this->aiocb.aio_lio_opcode; |
| err_op->mutex = aio_err_callbck->mutex; |
| err_op->action = aio_err_callbck; |
| eventProcessor.schedule_imm(err_op); |
| } |
| if (!action.cancelled) { |
| action.continuation->handleEvent(AIO_EVENT_DONE, this); |
| } |
| return EVENT_DONE; |
| } |
| |
| #ifdef AIO_STATS |
| class AIOTestData : public Continuation |
| { |
| public: |
| int num_req; |
| int num_temp; |
| int num_queue; |
| ink_hrtime start; |
| |
| int ink_aio_stats(int event, void *data); |
| |
| AIOTestData() : Continuation(new_ProxyMutex()), num_req(0), num_temp(0), num_queue(0) |
| { |
| start = ink_get_hrtime(); |
| SET_HANDLER(&AIOTestData::ink_aio_stats); |
| } |
| }; |
| #endif |
| |
| enum aio_stat_enum { |
| AIO_STAT_READ_PER_SEC, |
| AIO_STAT_KB_READ_PER_SEC, |
| AIO_STAT_WRITE_PER_SEC, |
| AIO_STAT_KB_WRITE_PER_SEC, |
| AIO_STAT_COUNT |
| }; |
| extern RecRawStatBlock *aio_rsb; |