Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions doc/developer-guide/api/functions/TSPluginDSOReloadEnable.en.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
.. 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:: ../../../common.defs

.. default-domain:: c

TSPluginDSOReloadEnable
*************************

Control whether this plugin will take part in the remap dynamic reload preocess (remap.config)

Synopsis
========

.. code-block:: cpp

#include <ts/ts.h>

.. function:: TSReturnCode TSPluginDSOReloadEnable(int enabled)

Description
===========

This function provides the ability to enable/disable programmatically the plugin
dynamic reloading when the same Dynamic Shared Object (DSO) is also used as a remap plugin.
This overrides :ts:cv:`proxy.config.plugin.dynamic_reload_mode`.

.. warning:: This function should be called from within :func:`TSPluginInit`

The function will return :type:`TS_ERROR` in any of the following cases:
- The function was not called from within :func:`TSPluginInit`
- TS is unable to get the canonical path from the plugin's path.

See Also
========

:manpage:`TSAPI(3ts)`
14 changes: 14 additions & 0 deletions include/ts/ts.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,20 @@ int TSTrafficServerVersionGetPatch(void);
*/
tsapi TSReturnCode TSPluginRegister(const TSPluginRegistrationInfo *plugin_info);

/**
This function provides the ability to enable/disable programmatically
the plugin dynamic reloading when the same Dynamic Shared Object (DSO)
is also used as a remap plugin. This overrides `proxy.config.plugin.dynamic_reload_mode`
configuration variable.

@param enabled boolean flag. 0/false will disable the reload on the caller plugin.
@return TS_ERROR if the function is not called from within TSPluginInit or if TS is
unable to get the canonical path from the plugin's path. TS_SUCCESS otherwise.

@note This function should be called from within TSPluginInit
*/
tsapi TSReturnCode TSPluginDSOReloadEnable(int enabled);

/* --------------------------------------------------------------------------
Files */
/**
Expand Down
49 changes: 48 additions & 1 deletion proxy/http/remap/PluginDso.cc
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ PluginDso::LoadedPlugins::remove(PluginDso *plugin)
}

/* check if need to reload the plugin DSO
* if dynamic reload not enabled: check if plugin Dso with same effective path aready loaded
* if dynamic reload not enabled: check if plugin Dso with same effective path already loaded
* if dynamic reload enabled: check if plugin Dso with same effective path and same time stamp already loaded
* return pointer to already loaded plugin if found, else return null
*/
Expand Down Expand Up @@ -361,4 +361,51 @@ PluginDso::LoadedPlugins::indicatePostReload(bool reloadSuccessful, const std::u
}
}

bool
PluginDso::LoadedPlugins::addPluginPathToDsoOptOutTable(std::string_view pluginPath)
{
std::error_code ec;
auto effectivePath = fs::canonical(fs::path{pluginPath}, ec);

if (ec) {
PluginError("Error getting the canonical path: %s", ec.message().c_str());
return false;
}

{
SCOPED_MUTEX_LOCK(lock, _mutex, this_ethread());
_optoutDsoReloadPlugins.push_front(DisableDSOReloadPluginInfo{effectivePath});
}

return true;
}

void
PluginDso::LoadedPlugins::removePluginPathFromDsoOptOutTable(std::string_view pluginPath)
{
std::error_code ec;
auto effectivePath = fs::canonical(fs::path{pluginPath}, ec);

if (ec) {
PluginError("Error getting the canonical path: %s", ec.message().c_str());
return;
}

{
SCOPED_MUTEX_LOCK(lock, _mutex, this_ethread());
_optoutDsoReloadPlugins.remove_if([&effectivePath](auto const &info) { return info.dsoEffectivePath == effectivePath; });
}
}

bool
PluginDso::LoadedPlugins::isPluginInDsoOptOutTable(const fs::path &effectivePath)
{
SCOPED_MUTEX_LOCK(lock, _mutex, this_ethread());
const auto found = std::find_if(std::begin(this->_optoutDsoReloadPlugins), std::end(this->_optoutDsoReloadPlugins),
[&effectivePath](const auto &info) { return info.dsoEffectivePath == effectivePath; });

// if is found, then the plugin opt out.
return (found != std::end(this->_optoutDsoReloadPlugins));
}

Ptr<PluginDso::LoadedPlugins> PluginDso::_plugins;
31 changes: 31 additions & 0 deletions proxy/http/remap/PluginDso.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <unordered_map>
#include <dlfcn.h>
#include <vector>
#include <forward_list>
#include <ctime>

#include "ts/apidefs.h"
Expand Down Expand Up @@ -104,9 +105,39 @@ class PluginDso : public PluginThreadContext
void indicatePreReload(const char *factoryId);
void indicatePostReload(bool reloadSuccessful, const std::unordered_map<PluginDso *, int> &pluginUsed, const char *factoryId);

/**
* @brief Check if the opt out table contains the passed plugin's effective path.
* @return true If the plugin was marked to not participate in the dynamic reload by
* TSPluginDSOReloadEnable() API.
* @param effectivePath canonical value of the plugin's path.
*/
bool isPluginInDsoOptOutTable(const fs::path &effectivePath);
/**
* @brief Add the plugin's path to the opt out table in order to let the Plugin Factory
* that this plugin is not interested in taking part of the dynamic reloading.
* This function will store the plugin's canonical path.
* @param effectivePath Plugin's path.
* @return false if any errors converting the plugin's path to a canonical path, true otherwise.
*/
bool addPluginPathToDsoOptOutTable(std::string_view pluginPath);
/**
* @brief Removes the passed plugin's effective path from the opt out list.
* @note This is mostly used by unit test than needs to remove the plugin's effectivePath
* from the out out list.
* @param pluginPath plugin's path.
* @note This function is mainly for unit tests purposes.
*/
void removePluginPathFromDsoOptOutTable(std::string_view pluginPath);

private:
PluginList _list; /** @brief plugin list */
Ptr<ProxyMutex> _mutex; /** @brief mutex used when updating the plugin list from multiple threads */

struct DisableDSOReloadPluginInfo {
fs::path dsoEffectivePath;
};

std::forward_list<DisableDSOReloadPluginInfo> _optoutDsoReloadPlugins;
};

static const Ptr<LoadedPlugins> &
Expand Down
7 changes: 7 additions & 0 deletions proxy/http/remap/PluginFactory.cc
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,13 @@ PluginFactory::getRemapPlugin(const fs::path &configPath, int argc, char **argv,
return nullptr;
}

// The plugin may have opt out by `TSPluginDSOReloadEnable`, let's check and overwrite
if (dynamicReloadEnabled && PluginDso::loadedPlugins()->isPluginInDsoOptOutTable(effectivePath)) {
// plugin not interested to be reload.
PluginDebug(_tag, "Plugin %s not interested in taking part of the reload.", effectivePath.c_str());
dynamicReloadEnabled = false;
}

/* Only one plugin with this effective path can be loaded by a plugin factory */
RemapPluginInfo *plugin = dynamic_cast<RemapPluginInfo *>(findByEffectivePath(effectivePath, dynamicReloadEnabled));
RemapPluginInst *inst = nullptr;
Expand Down
9 changes: 9 additions & 0 deletions proxy/http/remap/PluginFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ class RemapPluginInst
* filesystem links and different dl library implementations.
*
* @note This is meant to unify the way global and remap plugins are (re)loaded (global plugin support is not implemented yet).
* @note In the case of a mixed plugin, getRemapPlugin/dynamicReloadEnabled can be internally overwritten if the plugin opt out to
* take part in the dynamic reload process.
*/
class PluginFactory
{
Expand Down Expand Up @@ -116,5 +118,12 @@ class PluginFactory
std::error_code _ec;
bool _preventiveCleaning = true;

// Hold the full path for global plugins not taking part of the dynamic reloading.
struct DisableReloadPluginInfo {
fs::path fullPath;
};

std::forward_list<DisableReloadPluginInfo> optoutPlugins;

static constexpr const char *const _tag = "plugin_factory"; /** @brief log tag used by this class */
};
Loading