Skip to content

Load trace plugins via PluginManager and allow to set requeued plugins for trace session #8707

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
5 changes: 3 additions & 2 deletions doc/README.services_extension
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,9 @@ Start user trace session :
isc_action_svc_trace_start

parameter(s)
isc_spb_trc_name : trace session name, string, optional
isc_spb_trc_cfg : trace session configuration, string, mandatory
isc_spb_trc_name : trace session name, string, optional
isc_spb_trc_cfg : trace session configuration, string, mandatory
isc_spb_trc_plugins : plugins to use for session

output
text message with status of operation :
Expand Down
1 change: 1 addition & 0 deletions doc/README.trace_services
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ Action parameters switches :
-N[AME] <string> Session name
-I[D] <number> Session ID
-C[ONFIG] <string> Trace configuration file name
-P[LUGINS] <string list> Plugins list to use for trace session

Connection parameters switches :
-SE[RVICE] <string> Service name
Expand Down
1 change: 1 addition & 0 deletions src/common/IntlParametersBlock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@ IntlParametersBlock::TagType IntlSpbStart::checkTag(UCHAR tag, const char** tagN
{
FB_IPB_TAG(isc_spb_trc_name);
FB_IPB_TAG(isc_spb_trc_cfg);
FB_IPB_TAG(isc_spb_trc_plugins);
return TAG_STRING;
}
break;
Expand Down
1 change: 1 addition & 0 deletions src/common/classes/ClumpletReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,7 @@ ClumpletReader::ClumpletType ClumpletReader::getClumpletType(UCHAR tag) const
{
case isc_spb_trc_cfg:
case isc_spb_trc_name:
case isc_spb_trc_plugins:
return StringSpb;
case isc_spb_trc_id:
return IntSpb;
Expand Down
1 change: 1 addition & 0 deletions src/include/firebird/impl/consts_pub.h
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,7 @@
#define isc_spb_trc_id 1
#define isc_spb_trc_name 2
#define isc_spb_trc_cfg 3
#define isc_spb_trc_plugins 4

/******************************************/
/* Array slice description language (SDL) */
Expand Down
2 changes: 2 additions & 0 deletions src/include/firebird/impl/msg/fbtracemgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,5 @@ FB_IMPL_MSG(FBTRACEMGR, 37, trace_switch_user_only, -901, "00", "000", "switch \
FB_IMPL_MSG(FBTRACEMGR, 38, trace_switch_param_miss, -901, "00", "000", "mandatory parameter \"@1\" for switch \"@2\" is missing")
FB_IMPL_MSG(FBTRACEMGR, 39, trace_param_act_notcompat, -901, "00", "000", "parameter \"@1\" is incompatible with action \"@2\"")
FB_IMPL_MSG(FBTRACEMGR, 40, trace_mandatory_switch_miss, -901, "00", "000", "mandatory switch \"@1\" is missing")
FB_IMPL_MSG_NO_SYMBOL(FBTRACEMGR, 41, " -P[LUGINS] <string list> Plugins list to use for trace session")
FB_IMPL_MSG_NO_SYMBOL(FBTRACEMGR, 42, " fbtracemgr -SE service_mgr -START -NAME my_trace -CONFIG my_cfg.txt -PLUGINS fbtrace,custom_plugin")
1 change: 1 addition & 0 deletions src/include/gen/Firebird.pas
Original file line number Diff line number Diff line change
Expand Up @@ -4418,6 +4418,7 @@ IProfilerStatsImpl = class(IProfilerStats)
isc_spb_trc_id = byte(1);
isc_spb_trc_name = byte(2);
isc_spb_trc_cfg = byte(3);
isc_spb_trc_plugins = byte(4);
isc_sdl_version1 = byte(1);
isc_sdl_eoc = byte(255);
isc_sdl_relation = byte(2);
Expand Down
1 change: 1 addition & 0 deletions src/jrd/svc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3134,6 +3134,7 @@ bool Service::process_switches(ClumpletReader& spb, string& switches)
{
case isc_spb_trc_cfg:
case isc_spb_trc_name:
case isc_spb_trc_plugins:
get_action_svc_string(spb, switches);
break;
case isc_spb_trc_id:
Expand Down
46 changes: 40 additions & 6 deletions src/jrd/trace/TraceCmdLine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,21 @@ namespace
printMsg(number, dummy, newLine);
}

struct MessageSet
{
const int range[2];
const std::initializer_list<int> list;

void print() const
{
for (int i = range[0]; i <= range[1]; ++i)
printMsg(i);

for (auto id = list.begin(); id != list.end(); ++id)
printMsg(*id);
}
};

[[noreturn]] void usage(UtilSvc* uSvc, const ISC_STATUS code, const char* msg1 = NULL, const char* msg2 = NULL)
{
if (uSvc->isService())
Expand Down Expand Up @@ -94,16 +109,14 @@ namespace

// If the items aren't contiguous, a scheme like in nbackup.cpp will have to be used.
// ASF: This is message codes!
constexpr int MAIN_USAGE[] = {3, 21};
constexpr int EXAMPLES[] = {22, 27};
const MessageSet MAIN_USAGE{{3, 21}, {41}};
const MessageSet EXAMPLES{{22, 27}, {42}};
constexpr int NOTES[] = {28, 29};

for (int i = MAIN_USAGE[0]; i <= MAIN_USAGE[1]; ++i)
printMsg(i);
MAIN_USAGE.print();

printf("\n");
for (int i = EXAMPLES[0]; i <= EXAMPLES[1]; ++i)
printMsg(i);
EXAMPLES.print();

printf("\n");
for (int i = NOTES[0]; i <= NOTES[1]; ++i)
Expand Down Expand Up @@ -253,6 +266,27 @@ void fbtrace(UtilSvc* uSvc, TraceSvcIntf* traceSvc)
usage(uSvc, isc_trace_param_val_miss, sw->in_sw_name);
break;

case IN_SW_TRACE_PLUGINS:
switch (action_sw->in_sw)
{
case IN_SW_TRACE_STOP:
case IN_SW_TRACE_SUSPEND:
case IN_SW_TRACE_RESUME:
case IN_SW_TRACE_LIST:
usage(uSvc, isc_trace_param_act_notcompat, sw->in_sw_name, action_sw->in_sw_name);
break;
}

if (!session.ses_plugins.empty())
usage(uSvc, isc_trace_switch_once, sw->in_sw_name);

itr++;
if (itr < argc && argv[itr])
session.ses_plugins = argv[itr];
else
usage(uSvc, isc_trace_param_val_miss, sw->in_sw_name);
break;

default:
fb_assert(false);
}
Expand Down
32 changes: 15 additions & 17 deletions src/jrd/trace/TraceConfigStorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -676,6 +676,9 @@ ULONG ConfigStorage::getSessionSize(const TraceSession& session) noexcept
if ((len = session.ses_logfile.length()))
ret += sz + len;

if ((len = session.ses_plugins.length()))
ret += sz + len;

ret += sz + sizeof(session.ses_start);

return ret;
Expand Down Expand Up @@ -717,25 +720,16 @@ void ConfigStorage::addSession(TraceSession& session)
char* p = reinterpret_cast<char*> (header) + slot->offset;
Writer writer(p, slot->size);

if (!session.ses_name.empty()) {
writer.write(tagName, session.ses_name.length(), session.ses_name.c_str());
}
if (session.ses_auth.hasData()) {
writer.writeStringIfExists(tagName, session.ses_name);
if (session.ses_auth.hasData())
writer.write(tagAuthBlock, session.ses_auth.getCount(), session.ses_auth.begin());
}
if (!session.ses_user.empty()) {
writer.write(tagUserName, session.ses_user.length(), session.ses_user.c_str());
}
if (session.ses_role.hasData()) {
writer.write(tagRole, session.ses_role.length(), session.ses_role.c_str());
}
if (!session.ses_config.empty()) {
writer.write(tagConfig, session.ses_config.length(), session.ses_config.c_str());
}
writer.writeStringIfExists(tagUserName, session.ses_user);
writer.writeStringIfExists(tagRole, session.ses_role);
writer.writeStringIfExists(tagConfig, session.ses_config);
writer.write(tagStartTS, sizeof(session.ses_start), &session.ses_start);
if (!session.ses_logfile.empty()) {
writer.write(tagLogFile, session.ses_logfile.length(), session.ses_logfile.c_str());
}
writer.writeStringIfExists(tagLogFile, session.ses_logfile);
writer.writeStringIfExists(tagPlugins, session.ses_plugins);

writer.write(tagEnd, 0, NULL);
}

Expand Down Expand Up @@ -841,6 +835,10 @@ bool ConfigStorage::readSession(const TraceCSHeader::Slot* slot, TraceSession& s
p = session.ses_role.getBuffer(len);
break;

case tagPlugins:
p = session.ses_plugins.getBuffer(len);
break;

default:
fb_assert(false);
return false;
Expand Down
9 changes: 9 additions & 0 deletions src/jrd/trace/TraceConfigStorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ class ConfigStorage final : public Firebird::GlobalStorage, public Firebird::Ipc
tagStartTS, // date+time when started
tagLogFile, // log file name, if any
tagRole, // SQL role name, if any
tagPlugins, // trace plugins list, if any
tagEnd
};

Expand Down Expand Up @@ -240,6 +241,14 @@ class ConfigStorage final : public Firebird::GlobalStorage, public Firebird::Ipc

void write(ITEM tag, ULONG len, const void* data);

inline void writeStringIfExists(const ITEM tag, const Firebird::AbstractString& data)
{
if (data.empty())
return;

write(tag, data.length(), data.c_str());
}

private:
char* m_mem;
const char* const m_end;
Expand Down
74 changes: 19 additions & 55 deletions src/jrd/trace/TraceManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,6 @@ namespace
namespace Jrd {

GlobalPtr<StorageInstance, InstanceControl::PRIORITY_DELETE_FIRST> TraceManager::storageInstance;
TraceManager::Factories* TraceManager::factories = NULL;
GlobalPtr<RWLock> TraceManager::init_factories_lock;
volatile bool TraceManager::init_factories;


bool TraceManager::check_result(ITracePlugin* plugin, const char* module, const char* function,
bool result)
Expand Down Expand Up @@ -126,51 +122,14 @@ void TraceManager::init()
{
// ensure storage is initialized
getStorage();
load_plugins();
changeNumber = 0;
}

void TraceManager::load_plugins()
{
// Initialize all trace needs to false
trace_needs = 0;

if (init_factories)
return;

WriteLockGuard guard(init_factories_lock, FB_FUNCTION);
if (init_factories)
return;

factories = FB_NEW_POOL(*getDefaultMemoryPool()) TraceManager::Factories(*getDefaultMemoryPool());
for (GetPlugins<ITraceFactory> traceItr(IPluginManager::TYPE_TRACE); traceItr.hasData(); traceItr.next())
{
FactoryInfo info;
info.factory = traceItr.plugin();
info.factory->addRef();
string name(traceItr.name());
name.copyTo(info.name, sizeof(info.name));
factories->add(info);
}

init_factories = true;
changeNumber = 0;
}


void TraceManager::shutdown()
{
if (init_factories)
{
WriteLockGuard guard(init_factories_lock, FB_FUNCTION);

if (init_factories)
{
init_factories = false;
delete factories;
factories = NULL;
}
}

getStorage()->shutdown();
}

Expand Down Expand Up @@ -224,7 +183,7 @@ void TraceManager::update_sessions()
}
else
{
trace_sessions[i].plugin->release();
trace_sessions[i].release();
trace_sessions.remove(i);
}
}
Expand Down Expand Up @@ -366,31 +325,36 @@ void TraceManager::update_session(const TraceSession& session)
}
}

ReadLockGuard guard(init_factories_lock, FB_FUNCTION);
if (!factories)
return;
TraceInitInfoImpl attachInfo(session, attachment, filename);

for (FactoryInfo* info = factories->begin(); info != factories->end(); ++info)
GetPlugins<ITraceFactory> traceItr(IPluginManager::TYPE_TRACE, session.getPluginsString());
for (; traceItr.hasData(); traceItr.next())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This plain-C style syntax (for-loop iterator declared before the loop) makes sense only when iterator is needed after the end of loop. Why not:

for (GetPlugins<ITraceFactory> traceItr(IPluginManager::TYPE_TRACE, session.getPluginsString());
	traceItr.hasData(); traceItr.next())

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The line turned out to be too long. I didn't think about splitting the for operators

{
TraceInitInfoImpl attachInfo(session, attachment, filename);
FbLocalStatus status;
ITracePlugin* plugin = info->factory->trace_create(&status, &attachInfo);
ITraceFactory* factory = traceItr.plugin();

ITracePlugin* plugin = factory->trace_create(&status, &attachInfo);
if (plugin)
{
plugin->addRef();
SessionInfo sesInfo;
sesInfo.plugin = plugin;
sesInfo.factory_info = info;
sesInfo.plugin->addRef();

sesInfo.factory = factory;
sesInfo.factory->addRef();

string name(traceItr.name());
name.copyTo(sesInfo.pluginName, sizeof(sesInfo.pluginName));

sesInfo.ses_id = session.ses_id;
trace_sessions.add(sesInfo);

new_needs |= info->factory->trace_needs();
new_needs |= sesInfo.factory->trace_needs();
}
else if (status->getState() & IStatus::STATE_ERRORS)
{
string header;
header.printf("Trace plugin %s returned error on call trace_create.", info->name);
header.printf("Trace plugin %s returned error on call trace_create.", traceItr.name());
iscLogStatus(header.c_str(), &status);
}
}
Expand Down Expand Up @@ -455,13 +419,13 @@ void TraceManager::event_dsql_restart(Attachment* att, jrd_tra* transaction,
while (i < trace_sessions.getCount()) \
{ \
SessionInfo* plug_info = &trace_sessions[i]; \
if (check_result(plug_info->plugin, plug_info->factory_info->name, #METHOD, \
if (check_result(plug_info->plugin, plug_info->pluginName, #METHOD, \
plug_info->plugin->METHOD PARAMS)) \
{ \
i++; /* Move to next plugin */ \
} \
else { \
plug_info->plugin->release(); \
plug_info->release(); \
trace_sessions.remove(i); /* Remove broken plugin from the list */ \
} \
}
Expand Down
Loading
Loading