| /** @file |
| |
| Config reload execution logic - schedules async reload work on ET_TASK. |
| |
| @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. |
| */ |
| |
| #include "mgmt/config/ConfigReloadExecutor.h" |
| #include "mgmt/config/FileManager.h" |
| #include "mgmt/config/ReloadCoordinator.h" |
| |
| #include "iocore/eventsystem/Continuation.h" |
| #include "iocore/eventsystem/Tasks.h" |
| #include "iocore/eventsystem/EventProcessor.h" |
| |
| #include "records/RecCore.h" |
| |
| #include "tscore/Diags.h" |
| |
| namespace |
| { |
| DbgCtl dbg_ctl_config{"config.reload"}; |
| |
| /** |
| * Continuation that executes the actual config reload work. |
| * This runs on ET_TASK thread to avoid blocking the main RPC thread. |
| */ |
| struct ReloadWorkContinuation : public Continuation { |
| int |
| handleEvent(int /* etype */, void * /* data */) |
| { |
| bool failed{false}; |
| auto current_task = ReloadCoordinator::Get_Instance().get_current_task(); |
| |
| Dbg(dbg_ctl_config, "Executing config reload work"); |
| |
| if (current_task) { |
| Dbg(dbg_ctl_config, "Reload task token: %s", current_task->get_token().c_str()); |
| } |
| |
| // This will tell each changed file to reread itself. If some module is waiting |
| // for a record to be reloaded, it will be notified and the file update will happen |
| // at each module's logic. |
| // Each module will get a ConfigContext object which will be used to track the reload progress. |
| if (auto err = FileManager::instance().rereadConfig(); !err.empty()) { |
| Dbg(dbg_ctl_config, "rereadConfig failed"); |
| failed = true; |
| } |
| |
| // Force-flush pending record callbacks. rereadConfig() marks records as |
| // sync-required via RecSetSyncRequired(), but the actual on_record_change |
| // callbacks normally wait for the next config_update_cont tick (~3s). |
| // Flushing here fires those callbacks immediately so record-triggered |
| // handlers can reserve their subtasks before handleEvent() returns. |
| // RecExecConfigUpdateCbs clears the sync-required flag so the next |
| // config_update_cont tick is a no-op for these records. |
| RecFlushConfigUpdateCbs(); |
| Dbg(dbg_ctl_config, "Flushed pending record update callbacks"); |
| |
| Dbg(dbg_ctl_config, "Invoking plugin callbacks"); |
| // If any callback was registered (TSMgmtUpdateRegister) for config notifications, |
| // then it will eventually be notified. |
| FileManager::instance().invokeConfigPluginCallbacks(); |
| |
| Dbg(dbg_ctl_config, "Reload work completed, failed=%s", failed ? "true" : "false"); |
| |
| delete this; |
| return failed ? EVENT_ERROR : EVENT_DONE; |
| } |
| |
| ReloadWorkContinuation() : Continuation(new_ProxyMutex()) { SET_HANDLER(&ReloadWorkContinuation::handleEvent); } |
| }; |
| |
| } // namespace |
| |
| namespace config |
| { |
| |
| void |
| schedule_reload_work(std::chrono::milliseconds delay) |
| { |
| Dbg(dbg_ctl_config, "Scheduling reload work with %lldms delay", static_cast<long long>(delay.count())); |
| eventProcessor.schedule_in(new ReloadWorkContinuation(), HRTIME_MSECONDS(delay.count()), ET_TASK); |
| } |
| |
| } // namespace config |