mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 16:43:03 +01:00
Collect network statistics and make it available for the user applications. (#8310)
* Make Remote provider collect wire statistics. New info items to query wire stats counters. * New ISQL commands to show wire statistics. * Remove requirement to not mix local and remote handled items in the same info request. * Follow @asfernandes suggestion about class members initialization. * Make ctor explicit, as @sim1984 suggested * Put isc_info_end into response buffer despite of its presence in info items.
This commit is contained in:
parent
8ca2314355
commit
df885d5935
@ -327,10 +327,129 @@ SQL> SET PER_TAB OFF;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
12) SET WIRE_STATS option.
|
||||||
|
|
||||||
|
Author: Vladyslav Khorsun <hvlad at users sourceforge net>
|
||||||
|
|
||||||
|
When set to ON shows wire (network) statistics after query execution.
|
||||||
|
It is set to OFF by default. The name WIRE_STATS could be shortened up to WIRE.
|
||||||
|
|
||||||
|
The statistics counters shown in two groups: 'logical' and 'physical':
|
||||||
|
- logical counters show numbers of packets in terms of Firebird wire protocol
|
||||||
|
and number of bytes send before compression and received after decompression;
|
||||||
|
- physical counters show number of physical packets and bytes send and
|
||||||
|
received over the wire, number of bytes could be affected by wire compression,
|
||||||
|
if present. Also, number of network roundtrips is shown: it is number of
|
||||||
|
changes of IO direction from 'send' to 'receive'.
|
||||||
|
|
||||||
|
Note, wire statistics is gathered by Remote provider only, i.e. it is always
|
||||||
|
zero for embedded connections. Also, it is collected by client and IO direction
|
||||||
|
(send, receive) is shown from client point of view.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
1. INET protocol with wire compression.
|
||||||
|
Set WireCompression = true in firebird.conf
|
||||||
|
|
||||||
|
>isql inet://employee
|
||||||
|
|
||||||
|
SQL> SET;
|
||||||
|
Print statistics: OFF
|
||||||
|
Print per-table stats: OFF
|
||||||
|
Print wire stats: OFF
|
||||||
|
...
|
||||||
|
|
||||||
|
SQL> SET WIRE;
|
||||||
|
SQL>
|
||||||
|
SQL> SELECT COUNT(*) FROM RDB$RELATIONS;
|
||||||
|
|
||||||
|
COUNT
|
||||||
|
=====================
|
||||||
|
67
|
||||||
|
|
||||||
|
Wire logical statistics:
|
||||||
|
send packets = 6
|
||||||
|
recv packets = 5
|
||||||
|
send bytes = 184
|
||||||
|
recv bytes = 224
|
||||||
|
Wire physical statistics:
|
||||||
|
send packets = 3
|
||||||
|
recv packets = 2
|
||||||
|
send bytes = 123
|
||||||
|
recv bytes = 88
|
||||||
|
roundtrips = 2
|
||||||
|
|
||||||
|
Note difference due to wire compression in send/recv bytes for logical and
|
||||||
|
physical stats.
|
||||||
|
|
||||||
|
|
||||||
|
2. XNET protocol (wire compression is not used).
|
||||||
|
|
||||||
|
>isql xnet://employee
|
||||||
|
|
||||||
|
SQL> SET WIRE;
|
||||||
|
SQL>
|
||||||
|
SQL> SELECT COUNT(*) FROM RDB$RELATIONS;
|
||||||
|
|
||||||
|
COUNT
|
||||||
|
=====================
|
||||||
|
67
|
||||||
|
|
||||||
|
Wire logical statistics:
|
||||||
|
send packets = 5
|
||||||
|
recv packets = 6
|
||||||
|
send bytes = 176
|
||||||
|
recv bytes = 256
|
||||||
|
Wire physical statistics:
|
||||||
|
send packets = 5
|
||||||
|
recv packets = 5
|
||||||
|
send bytes = 176
|
||||||
|
recv bytes = 256
|
||||||
|
roundtrips = 5
|
||||||
|
|
||||||
|
Note, send/recv bytes for logical and physical stats are equal.
|
||||||
|
|
||||||
|
|
||||||
|
3. Embedded connection (wire statistics is absent).
|
||||||
|
|
||||||
|
SQL> SET WIRE;
|
||||||
|
SQL>
|
||||||
|
SQL> select count(*) from rdb$relations;
|
||||||
|
|
||||||
|
COUNT
|
||||||
|
=====================
|
||||||
|
67
|
||||||
|
|
||||||
|
Wire logical statistics:
|
||||||
|
send packets = 0
|
||||||
|
recv packets = 0
|
||||||
|
send bytes = 0
|
||||||
|
recv bytes = 0
|
||||||
|
Wire physical statistics:
|
||||||
|
send packets = 0
|
||||||
|
recv packets = 0
|
||||||
|
send bytes = 0
|
||||||
|
recv bytes = 0
|
||||||
|
roundtrips = 0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
13) SHOW WIRE_STATISTICS command.
|
||||||
|
|
||||||
|
Author: Vladyslav Khorsun <hvlad at users sourceforge net>
|
||||||
|
|
||||||
|
New ISQL command that shows accumulated wire statistics. There is also
|
||||||
|
shortened alias WIRE_STATS.
|
||||||
|
|
||||||
|
The command show values of wire statistics counters, accumulated since the
|
||||||
|
connection start time. Format is the same as of SET STATS above.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Isql enhancements in Firebird v6.
|
Isql enhancements in Firebird v6.
|
||||||
---------------------------------
|
---------------------------------
|
||||||
|
|
||||||
12) EXPLAIN statement.
|
14) EXPLAIN statement.
|
||||||
|
|
||||||
Author: Adriano dos Santos Fernandes
|
Author: Adriano dos Santos Fernandes
|
||||||
|
|
||||||
@ -355,7 +474,7 @@ SQL>
|
|||||||
SQL> set term ;!
|
SQL> set term ;!
|
||||||
|
|
||||||
|
|
||||||
13) SET AUTOTERM ON/OFF
|
15) SET AUTOTERM ON/OFF
|
||||||
|
|
||||||
Author: Adriano dos Santos Fernandes
|
Author: Adriano dos Santos Fernandes
|
||||||
|
|
||||||
|
@ -178,6 +178,17 @@ enum db_info_types
|
|||||||
|
|
||||||
fb_info_parallel_workers = 149,
|
fb_info_parallel_workers = 149,
|
||||||
|
|
||||||
|
// Wire stats items, implemented by Remote provider only
|
||||||
|
fb_info_wire_out_packets = 150,
|
||||||
|
fb_info_wire_in_packets = 151,
|
||||||
|
fb_info_wire_out_bytes = 152,
|
||||||
|
fb_info_wire_in_bytes = 153,
|
||||||
|
fb_info_wire_snd_packets = 154,
|
||||||
|
fb_info_wire_rcv_packets = 155,
|
||||||
|
fb_info_wire_snd_bytes = 156,
|
||||||
|
fb_info_wire_rcv_bytes = 157,
|
||||||
|
fb_info_wire_roundtrips = 158,
|
||||||
|
|
||||||
isc_info_db_last_value /* Leave this LAST! */
|
isc_info_db_last_value /* Leave this LAST! */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4507,6 +4507,15 @@ const
|
|||||||
fb_info_username = byte(147);
|
fb_info_username = byte(147);
|
||||||
fb_info_sqlrole = byte(148);
|
fb_info_sqlrole = byte(148);
|
||||||
fb_info_parallel_workers = byte(149);
|
fb_info_parallel_workers = byte(149);
|
||||||
|
fb_info_wire_out_packets = byte(150);
|
||||||
|
fb_info_wire_in_packets = byte(151);
|
||||||
|
fb_info_wire_out_bytes = byte(152);
|
||||||
|
fb_info_wire_in_bytes = byte(153);
|
||||||
|
fb_info_wire_snd_packets = byte(154);
|
||||||
|
fb_info_wire_rcv_packets = byte(155);
|
||||||
|
fb_info_wire_snd_bytes = byte(156);
|
||||||
|
fb_info_wire_rcv_bytes = byte(157);
|
||||||
|
fb_info_wire_roundtrips = byte(158);
|
||||||
fb_info_crypt_encrypted = $01;
|
fb_info_crypt_encrypted = $01;
|
||||||
fb_info_crypt_process = $02;
|
fb_info_crypt_process = $02;
|
||||||
fb_feature_multi_statements = byte(1);
|
fb_feature_multi_statements = byte(1);
|
||||||
|
@ -577,6 +577,7 @@ public:
|
|||||||
KeepTranParams = true;
|
KeepTranParams = true;
|
||||||
TranParams->assign(DEFAULT_DML_TRANS_SQL);
|
TranParams->assign(DEFAULT_DML_TRANS_SQL);
|
||||||
PerTableStats = false;
|
PerTableStats = false;
|
||||||
|
WireStats = false;
|
||||||
ExplainCommand = false;
|
ExplainCommand = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -603,6 +604,7 @@ public:
|
|||||||
SCHAR ISQL_charset[MAXCHARSET_SIZE];
|
SCHAR ISQL_charset[MAXCHARSET_SIZE];
|
||||||
bool KeepTranParams;
|
bool KeepTranParams;
|
||||||
bool PerTableStats;
|
bool PerTableStats;
|
||||||
|
bool WireStats;
|
||||||
bool ExplainCommand;
|
bool ExplainCommand;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -5453,7 +5455,7 @@ static processing_state frontend_set(const char* cmd, const char* const* parms,
|
|||||||
exec_path_display,
|
exec_path_display,
|
||||||
sql, warning, sqlCont, heading, bail,
|
sql, warning, sqlCont, heading, bail,
|
||||||
bulk_insert, maxrows, stmtTimeout,
|
bulk_insert, maxrows, stmtTimeout,
|
||||||
keepTranParams, perTableStats,
|
keepTranParams, perTableStats, wireStats,
|
||||||
wrong
|
wrong
|
||||||
};
|
};
|
||||||
SetOptions(const optionsMap* inmap, size_t insize, int wrongval)
|
SetOptions(const optionsMap* inmap, size_t insize, int wrongval)
|
||||||
@ -5495,7 +5497,8 @@ static processing_state frontend_set(const char* cmd, const char* const* parms,
|
|||||||
{SetOptions::stmtTimeout, "LOCAL_TIMEOUT", 0},
|
{SetOptions::stmtTimeout, "LOCAL_TIMEOUT", 0},
|
||||||
{SetOptions::sqlCont, "DECFLOAT", 0},
|
{SetOptions::sqlCont, "DECFLOAT", 0},
|
||||||
{SetOptions::keepTranParams, "KEEP_TRAN_PARAMS", 9},
|
{SetOptions::keepTranParams, "KEEP_TRAN_PARAMS", 9},
|
||||||
{SetOptions::perTableStats, "PER_TABLE_STATS", 7}
|
{SetOptions::perTableStats, "PER_TABLE_STATS", 7},
|
||||||
|
{SetOptions::wireStats, "WIRE_STATS", 4}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Display current set options
|
// Display current set options
|
||||||
@ -5746,6 +5749,10 @@ static processing_state frontend_set(const char* cmd, const char* const* parms,
|
|||||||
ret = do_set_command(parms[2], &setValues.PerTableStats);
|
ret = do_set_command(parms[2], &setValues.PerTableStats);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SetOptions::wireStats:
|
||||||
|
ret = do_set_command(parms[2], &setValues.WireStats);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
//{
|
//{
|
||||||
// TEXT msg_string[MSG_LENGTH];
|
// TEXT msg_string[MSG_LENGTH];
|
||||||
@ -6372,6 +6379,7 @@ static processing_state print_sets()
|
|||||||
|
|
||||||
print_set("Print statistics:", setValues.Stats);
|
print_set("Print statistics:", setValues.Stats);
|
||||||
print_set("Print per-table stats:", setValues.PerTableStats);
|
print_set("Print per-table stats:", setValues.PerTableStats);
|
||||||
|
print_set("Print wire stats:", setValues.WireStats);
|
||||||
print_set("Echo commands:", setValues.Echo);
|
print_set("Echo commands:", setValues.Echo);
|
||||||
print_set("List format:", setValues.List);
|
print_set("List format:", setValues.List);
|
||||||
print_set("Show Row Count:", setValues.Docount);
|
print_set("Show Row Count:", setValues.Docount);
|
||||||
@ -8950,6 +8958,10 @@ static processing_state process_statement(const std::string& str)
|
|||||||
if (setValues.PerTableStats)
|
if (setValues.PerTableStats)
|
||||||
perTableStats->getStats(DB, true);
|
perTableStats->getStats(DB, true);
|
||||||
|
|
||||||
|
IsqlWireStats wireStats(DB);
|
||||||
|
if (setValues.WireStats)
|
||||||
|
wireStats.get(true);
|
||||||
|
|
||||||
// Prepare the dynamic query stored in string.
|
// Prepare the dynamic query stored in string.
|
||||||
// But put this on the DDL transaction to get maximum visibility of
|
// But put this on the DDL transaction to get maximum visibility of
|
||||||
// metadata.
|
// metadata.
|
||||||
@ -9137,6 +9149,9 @@ static processing_state process_statement(const std::string& str)
|
|||||||
if (setValues.PerTableStats)
|
if (setValues.PerTableStats)
|
||||||
perTableStats->getStats(DB, false);
|
perTableStats->getStats(DB, false);
|
||||||
|
|
||||||
|
if (setValues.WireStats)
|
||||||
|
wireStats.print(false);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -9156,6 +9171,9 @@ static processing_state process_statement(const std::string& str)
|
|||||||
if (setValues.PerTableStats)
|
if (setValues.PerTableStats)
|
||||||
perTableStats->getStats(DB, false);
|
perTableStats->getStats(DB, false);
|
||||||
|
|
||||||
|
if (setValues.WireStats)
|
||||||
|
wireStats.print(false);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -9203,6 +9221,9 @@ static processing_state process_statement(const std::string& str)
|
|||||||
if (setValues.PerTableStats)
|
if (setValues.PerTableStats)
|
||||||
perTableStats->getStats(DB, false);
|
perTableStats->getStats(DB, false);
|
||||||
|
|
||||||
|
if (setValues.WireStats)
|
||||||
|
wireStats.print(false);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -9398,6 +9419,9 @@ static processing_state process_statement(const std::string& str)
|
|||||||
if (setValues.PerTableStats)
|
if (setValues.PerTableStats)
|
||||||
perTableStats->getStats(DB, false);
|
perTableStats->getStats(DB, false);
|
||||||
|
|
||||||
|
if (setValues.WireStats)
|
||||||
|
wireStats.print(false);
|
||||||
|
|
||||||
if (pad)
|
if (pad)
|
||||||
ISQL_FREE(pad);
|
ISQL_FREE(pad);
|
||||||
if (line)
|
if (line)
|
||||||
@ -9895,3 +9919,112 @@ unsigned PerTableStats::loadRelNames(Firebird::IAttachment* att)
|
|||||||
|
|
||||||
return maxLen;
|
return maxLen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// class IsqlWireStats
|
||||||
|
|
||||||
|
bool IsqlWireStats::get(bool initial)
|
||||||
|
{
|
||||||
|
if (!m_att)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const UCHAR info[] = {
|
||||||
|
fb_info_wire_snd_packets, fb_info_wire_rcv_packets,
|
||||||
|
fb_info_wire_out_packets, fb_info_wire_in_packets,
|
||||||
|
fb_info_wire_snd_bytes, fb_info_wire_rcv_bytes,
|
||||||
|
fb_info_wire_out_bytes, fb_info_wire_in_bytes,
|
||||||
|
fb_info_wire_roundtrips,
|
||||||
|
isc_info_end
|
||||||
|
};
|
||||||
|
|
||||||
|
UCHAR buffer[128];
|
||||||
|
|
||||||
|
m_att->getInfo(fbStatus, sizeof(info), info, sizeof(buffer), buffer);
|
||||||
|
|
||||||
|
if (fbStatus->getState() & Firebird::IStatus::STATE_ERRORS)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Firebird::ClumpletReader p(Firebird::ClumpletReader::InfoResponse, buffer, sizeof(buffer));
|
||||||
|
for (; !p.isEof(); p.moveNext())
|
||||||
|
{
|
||||||
|
FB_UINT64* pField = nullptr;
|
||||||
|
switch (p.getClumpTag())
|
||||||
|
{
|
||||||
|
case fb_info_wire_snd_packets:
|
||||||
|
pField = &m_snd_packets;
|
||||||
|
break;
|
||||||
|
case fb_info_wire_rcv_packets:
|
||||||
|
pField = &m_rcv_packets;
|
||||||
|
break;
|
||||||
|
case fb_info_wire_out_packets:
|
||||||
|
pField = &m_out_packets;
|
||||||
|
break;
|
||||||
|
case fb_info_wire_in_packets:
|
||||||
|
pField = &m_in_packets;
|
||||||
|
break;
|
||||||
|
case fb_info_wire_snd_bytes:
|
||||||
|
pField = &m_snd_bytes;
|
||||||
|
break;
|
||||||
|
case fb_info_wire_rcv_bytes:
|
||||||
|
pField = &m_rcv_bytes;
|
||||||
|
break;
|
||||||
|
case fb_info_wire_out_bytes:
|
||||||
|
pField = &m_out_bytes;
|
||||||
|
break;
|
||||||
|
case fb_info_wire_in_bytes:
|
||||||
|
pField = &m_in_bytes;
|
||||||
|
break;
|
||||||
|
case fb_info_wire_roundtrips:
|
||||||
|
pField = &m_roundtrips;
|
||||||
|
break;
|
||||||
|
case isc_info_end:
|
||||||
|
break;
|
||||||
|
case isc_info_error:
|
||||||
|
// don't return false here, as we not put error into status
|
||||||
|
return true;
|
||||||
|
/* uncomment to show error (isc_infunk) instead
|
||||||
|
{
|
||||||
|
ISC_STATUS errs[3] = { isc_arg_gds, 0, isc_arg_end };
|
||||||
|
auto b = p.getBytes();
|
||||||
|
errs[1] = isc_portable_integer(b + 1, p.getClumpLength() - 1);
|
||||||
|
fbStatus->setErrors(errs);
|
||||||
|
return false;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
default:
|
||||||
|
fb_assert(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pField)
|
||||||
|
{
|
||||||
|
const FB_UINT64 val = p.getBigInt();
|
||||||
|
*pField = initial ? val : val - *pField;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsqlWireStats::print(bool initial)
|
||||||
|
{
|
||||||
|
if (!get(initial))
|
||||||
|
{
|
||||||
|
ISQL_errmsg(fbStatus);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
IUTILS_printf2(Diag, "Wire logical statistics:%s", NEWLINE);
|
||||||
|
IUTILS_printf2(Diag, " send packets = %8" SQUADFORMAT "%s", m_out_packets, NEWLINE);
|
||||||
|
IUTILS_printf2(Diag, " recv packets = %8" SQUADFORMAT "%s", m_in_packets, NEWLINE);
|
||||||
|
IUTILS_printf2(Diag, " send bytes = %8" SQUADFORMAT "%s", m_out_bytes, NEWLINE);
|
||||||
|
IUTILS_printf2(Diag, " recv bytes = %8" SQUADFORMAT "%s", m_in_bytes, NEWLINE);
|
||||||
|
|
||||||
|
IUTILS_printf2(Diag, "Wire physical statistics:%s", NEWLINE);
|
||||||
|
IUTILS_printf2(Diag, " send packets = %8" SQUADFORMAT "%s", m_snd_packets, NEWLINE);
|
||||||
|
IUTILS_printf2(Diag, " recv packets = %8" SQUADFORMAT "%s", m_rcv_packets, NEWLINE);
|
||||||
|
IUTILS_printf2(Diag, " send bytes = %8" SQUADFORMAT "%s", m_snd_bytes, NEWLINE);
|
||||||
|
IUTILS_printf2(Diag, " recv bytes = %8" SQUADFORMAT "%s", m_rcv_bytes, NEWLINE);
|
||||||
|
IUTILS_printf2(Diag, " roundtrips = %8" SQUADFORMAT "%s", m_roundtrips, NEWLINE);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
@ -312,4 +312,28 @@ struct IsqlVar
|
|||||||
TypeMix value;
|
TypeMix value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class IsqlWireStats
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit IsqlWireStats(Firebird::IAttachment* att) :
|
||||||
|
m_att(att)
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool print(bool initial);
|
||||||
|
bool get(bool initial);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
Firebird::IAttachment* m_att;
|
||||||
|
FB_UINT64 m_snd_packets = 0;
|
||||||
|
FB_UINT64 m_rcv_packets = 0;
|
||||||
|
FB_UINT64 m_out_packets = 0;
|
||||||
|
FB_UINT64 m_in_packets = 0;
|
||||||
|
FB_UINT64 m_snd_bytes = 0;
|
||||||
|
FB_UINT64 m_rcv_bytes = 0;
|
||||||
|
FB_UINT64 m_out_bytes = 0;
|
||||||
|
FB_UINT64 m_in_bytes = 0;
|
||||||
|
FB_UINT64 m_roundtrips = 0;
|
||||||
|
};
|
||||||
|
|
||||||
#endif // ISQL_ISQL_H
|
#endif // ISQL_ISQL_H
|
||||||
|
@ -116,6 +116,7 @@ static processing_state show_trigger(const SCHAR*, bool, bool);
|
|||||||
static processing_state show_users();
|
static processing_state show_users();
|
||||||
static processing_state show_users12();
|
static processing_state show_users12();
|
||||||
static void parse_package(const char* procname, MetaString& package, MetaString& procedure);
|
static void parse_package(const char* procname, MetaString& package, MetaString& procedure);
|
||||||
|
static processing_state show_wireStats();
|
||||||
|
|
||||||
const char* const spaces = " ";
|
const char* const spaces = " ";
|
||||||
static TEXT Print_buffer[512];
|
static TEXT Print_buffer[512];
|
||||||
@ -2090,7 +2091,8 @@ processing_state SHOW_metadata(const SCHAR* const* cmd, SCHAR** lcmd)
|
|||||||
role, table, view, system, index, domain, exception,
|
role, table, view, system, index, domain, exception,
|
||||||
filter, function, generator, grant, procedure, trigger,
|
filter, function, generator, grant, procedure, trigger,
|
||||||
check, database, comment, dependency, collation, security_class,
|
check, database, comment, dependency, collation, security_class,
|
||||||
users, package, publication, schema, map, wrong
|
users, package, publication, schema, map, wireStats,
|
||||||
|
wrong
|
||||||
};
|
};
|
||||||
ShowOptions(const optionsMap* inmap, size_t insize, int wrongval)
|
ShowOptions(const optionsMap* inmap, size_t insize, int wrongval)
|
||||||
: OptionsBase(inmap, insize, wrongval)
|
: OptionsBase(inmap, insize, wrongval)
|
||||||
@ -2148,7 +2150,9 @@ processing_state SHOW_metadata(const SCHAR* const* cmd, SCHAR** lcmd)
|
|||||||
{ShowOptions::package, "PACKAGES", 4},
|
{ShowOptions::package, "PACKAGES", 4},
|
||||||
{ShowOptions::schema, "SCHEMAS", 4},
|
{ShowOptions::schema, "SCHEMAS", 4},
|
||||||
{ShowOptions::map, "MAPPING", 3},
|
{ShowOptions::map, "MAPPING", 3},
|
||||||
{ShowOptions::publication, "PUBLICATIONS", 3}
|
{ShowOptions::publication, "PUBLICATIONS", 3},
|
||||||
|
{ShowOptions::wireStats, "WIRE_STATISTICS", 9},
|
||||||
|
{ShowOptions::wireStats, "WIRE_STATS", 10}
|
||||||
};
|
};
|
||||||
|
|
||||||
const ShowOptions showoptions(options, FB_NELEM(options), ShowOptions::wrong);
|
const ShowOptions showoptions(options, FB_NELEM(options), ShowOptions::wrong);
|
||||||
@ -2805,6 +2809,10 @@ processing_state SHOW_metadata(const SCHAR* const* cmd, SCHAR** lcmd)
|
|||||||
return ps_ERR;
|
return ps_ERR;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ShowOptions::wireStats:
|
||||||
|
ret = show_wireStats();
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return ps_ERR;
|
return ps_ERR;
|
||||||
} // switch
|
} // switch
|
||||||
@ -6687,3 +6695,18 @@ static processing_state show_users()
|
|||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static processing_state show_wireStats()
|
||||||
|
{
|
||||||
|
if (!DB)
|
||||||
|
{
|
||||||
|
isqlGlob.printf("No database connection.\n");
|
||||||
|
return SKIP;
|
||||||
|
}
|
||||||
|
|
||||||
|
IsqlWireStats stats(DB);
|
||||||
|
if (!stats.print(true))
|
||||||
|
return ps_ERR;
|
||||||
|
|
||||||
|
return SKIP;
|
||||||
|
}
|
@ -937,6 +937,11 @@ private:
|
|||||||
void internalDropDatabase(CheckStatusWrapper* status);
|
void internalDropDatabase(CheckStatusWrapper* status);
|
||||||
SLONG getSingleInfo(CheckStatusWrapper* status, UCHAR infoItem);
|
SLONG getSingleInfo(CheckStatusWrapper* status, UCHAR infoItem);
|
||||||
|
|
||||||
|
// Returns nullptr if all items was handled or if user buffer is full, else
|
||||||
|
// returns pointer into unused buffer space. Handled info items are removed.
|
||||||
|
unsigned char* getWireStatsInfo(UCharBuffer& info, unsigned int buffer_length,
|
||||||
|
unsigned char* buffer);
|
||||||
|
|
||||||
Rdb* rdb;
|
Rdb* rdb;
|
||||||
const PathName dbPath;
|
const PathName dbPath;
|
||||||
};
|
};
|
||||||
@ -1966,6 +1971,65 @@ IAttachment* Loopback::createDatabase(CheckStatusWrapper* status, const char* fi
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned char* Attachment::getWireStatsInfo(UCharBuffer& info, unsigned int buffer_length,
|
||||||
|
unsigned char* buffer)
|
||||||
|
{
|
||||||
|
const rem_port* const port = rdb->rdb_port;
|
||||||
|
|
||||||
|
UCHAR* ptr = buffer;
|
||||||
|
const UCHAR* const end = buffer + buffer_length;
|
||||||
|
|
||||||
|
for (auto item = info.begin(); item < info.end(); )
|
||||||
|
{
|
||||||
|
if (ptr >= end)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if (*item == isc_info_end)
|
||||||
|
{
|
||||||
|
if (info.getCount() == 1)
|
||||||
|
info.remove(item);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (*item)
|
||||||
|
{
|
||||||
|
case fb_info_wire_snd_packets:
|
||||||
|
case fb_info_wire_rcv_packets:
|
||||||
|
case fb_info_wire_out_packets:
|
||||||
|
case fb_info_wire_in_packets:
|
||||||
|
case fb_info_wire_snd_bytes:
|
||||||
|
case fb_info_wire_rcv_bytes:
|
||||||
|
case fb_info_wire_out_bytes:
|
||||||
|
case fb_info_wire_in_bytes:
|
||||||
|
case fb_info_wire_roundtrips:
|
||||||
|
{
|
||||||
|
const FB_UINT64 value = port->getStatItem(*item);
|
||||||
|
|
||||||
|
if (value <= MAX_SLONG)
|
||||||
|
ptr = fb_utils::putInfoItemInt(*item, (SLONG) value, ptr, end);
|
||||||
|
else
|
||||||
|
ptr = fb_utils::putInfoItemInt(*item, value, ptr, end);
|
||||||
|
|
||||||
|
if (!ptr)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
info.remove(item);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
item++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.isEmpty() && ptr < end)
|
||||||
|
*ptr++ = isc_info_end;
|
||||||
|
|
||||||
|
return (info.isEmpty() || (ptr >= end)) ? nullptr : ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Attachment::getInfo(CheckStatusWrapper* status,
|
void Attachment::getInfo(CheckStatusWrapper* status,
|
||||||
unsigned int item_length, const unsigned char* items,
|
unsigned int item_length, const unsigned char* items,
|
||||||
unsigned int buffer_length, unsigned char* buffer)
|
unsigned int buffer_length, unsigned char* buffer)
|
||||||
@ -1994,15 +2058,22 @@ void Attachment::getInfo(CheckStatusWrapper* status,
|
|||||||
|
|
||||||
RefMutexGuard portGuard(*port->port_sync, FB_FUNCTION);
|
RefMutexGuard portGuard(*port->port_sync, FB_FUNCTION);
|
||||||
|
|
||||||
|
UCharBuffer tempInfo(items, item_length);
|
||||||
|
UCHAR* ptr = getWireStatsInfo(tempInfo, buffer_length, buffer);
|
||||||
|
if (!ptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
buffer_length -= ptr - buffer;
|
||||||
|
|
||||||
UCHAR* temp_buffer = temp.getBuffer(buffer_length);
|
UCHAR* temp_buffer = temp.getBuffer(buffer_length);
|
||||||
|
|
||||||
info(status, rdb, op_info_database, rdb->rdb_id, 0,
|
info(status, rdb, op_info_database, rdb->rdb_id, 0,
|
||||||
item_length, items, 0, 0, buffer_length, temp_buffer);
|
tempInfo.getCount(), tempInfo.begin(), 0, 0, buffer_length, temp_buffer);
|
||||||
|
|
||||||
string version;
|
string version;
|
||||||
port->versionInfo(version);
|
port->versionInfo(version);
|
||||||
|
|
||||||
MERGE_database_info(temp_buffer, buffer, buffer_length,
|
MERGE_database_info(temp_buffer, ptr, buffer_length,
|
||||||
DbImplementation::current.backwardCompatibleImplementation(), 3, 1,
|
DbImplementation::current.backwardCompatibleImplementation(), 3, 1,
|
||||||
reinterpret_cast<const UCHAR*>(version.c_str()),
|
reinterpret_cast<const UCHAR*>(version.c_str()),
|
||||||
reinterpret_cast<const UCHAR*>(port->port_host->str_data),
|
reinterpret_cast<const UCHAR*>(port->port_host->str_data),
|
||||||
|
@ -3130,8 +3130,7 @@ static bool packet_receive(rem_port* port, UCHAR* buffer, SSHORT buffer_length,
|
|||||||
} // end scope
|
} // end scope
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
port->port_rcv_packets++;
|
port->bumpPhysStats(rem_port::RECEIVE, n);
|
||||||
port->port_rcv_bytes += n;
|
|
||||||
|
|
||||||
*length = n;
|
*length = n;
|
||||||
|
|
||||||
@ -3306,9 +3305,7 @@ static bool packet_send( rem_port* port, const SCHAR* buffer, SSHORT buffer_leng
|
|||||||
} // end scope
|
} // end scope
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
port->port_snd_packets++;
|
port->bumpPhysStats(rem_port::SEND, buffer_length);
|
||||||
port->port_snd_bytes += buffer_length;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1992,8 +1992,8 @@ static bool_t xnet_read(RemoteXdr* xdrs)
|
|||||||
{
|
{
|
||||||
// Client has written some data for us (server) to read
|
// Client has written some data for us (server) to read
|
||||||
|
|
||||||
port->port_rcv_packets++;
|
port->bumpPhysStats(rem_port::RECEIVE, xch->xch_length);
|
||||||
port->port_rcv_bytes += xch->xch_length;
|
port->bumpLogBytes(rem_port::RECEIVE, xch->xch_length); // XNET not calls REMOTE_inflate
|
||||||
|
|
||||||
xdrs->x_handy = xch->xch_length;
|
xdrs->x_handy = xch->xch_length;
|
||||||
xdrs->x_private = xdrs->x_base;
|
xdrs->x_private = xdrs->x_base;
|
||||||
@ -2049,8 +2049,8 @@ static bool_t xnet_write(RemoteXdr* xdrs)
|
|||||||
xch->xch_length = xdrs->x_private - xdrs->x_base;
|
xch->xch_length = xdrs->x_private - xdrs->x_base;
|
||||||
if (SetEvent(xcc->xcc_event_send_channel_filled))
|
if (SetEvent(xcc->xcc_event_send_channel_filled))
|
||||||
{
|
{
|
||||||
port->port_snd_packets++;
|
port->bumpPhysStats(rem_port::SEND, xch->xch_length);
|
||||||
port->port_snd_bytes += xch->xch_length;
|
port->bumpLogBytes(rem_port::SEND, xch->xch_length); // XNET not calls REMOTE_deflate
|
||||||
|
|
||||||
xdrs->x_private = xdrs->x_base;
|
xdrs->x_private = xdrs->x_base;
|
||||||
xdrs->x_handy = xch->xch_size;
|
xdrs->x_handy = xch->xch_size;
|
||||||
|
@ -303,6 +303,9 @@ bool_t xdr_protocol(RemoteXdr* xdrs, PACKET* p)
|
|||||||
|
|
||||||
const auto port = xdrs->x_public;
|
const auto port = xdrs->x_public;
|
||||||
|
|
||||||
|
if (xdrs->x_op != XDR_FREE)
|
||||||
|
port->bumpLogPackets(xdrs->x_op == XDR_ENCODE ? rem_port::SEND : rem_port::RECEIVE);
|
||||||
|
|
||||||
switch (p->p_operation)
|
switch (p->p_operation)
|
||||||
{
|
{
|
||||||
case op_reject:
|
case op_reject:
|
||||||
|
@ -1494,7 +1494,12 @@ bool REMOTE_inflate(rem_port* port, PacketReceive* packet_receive, UCHAR* buffer
|
|||||||
{
|
{
|
||||||
#ifdef WIRE_COMPRESS_SUPPORT
|
#ifdef WIRE_COMPRESS_SUPPORT
|
||||||
if (!port->port_compressed)
|
if (!port->port_compressed)
|
||||||
return packet_receive(port, buffer, buffer_length, length);
|
{
|
||||||
|
const bool ret = packet_receive(port, buffer, buffer_length, length);
|
||||||
|
if (ret)
|
||||||
|
port->bumpLogBytes(rem_port::RECEIVE, *length);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
z_stream& strm = port->port_recv_stream;
|
z_stream& strm = port->port_recv_stream;
|
||||||
strm.avail_out = buffer_length;
|
strm.avail_out = buffer_length;
|
||||||
@ -1566,16 +1571,22 @@ bool REMOTE_inflate(rem_port* port, PacketReceive* packet_receive, UCHAR* buffer
|
|||||||
fprintf(stderr, "ZLib buffer %s\n", port->port_z_data ? "has data" : "is empty");
|
fprintf(stderr, "ZLib buffer %s\n", port->port_z_data ? "has data" : "is empty");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
port->bumpLogBytes(rem_port::RECEIVE, *length);
|
||||||
return true;
|
return true;
|
||||||
#else
|
#else
|
||||||
return packet_receive(port, buffer, buffer_length, length);
|
const bool ret = packet_receive(port, buffer, buffer_length, length);
|
||||||
|
if (ret)
|
||||||
|
port->bumpLogBytes(rem_port::RECEIVE, *length);
|
||||||
|
return ret;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool REMOTE_deflate(RemoteXdr* xdrs, ProtoWrite* proto_write, PacketSend* packet_send, bool flush)
|
bool REMOTE_deflate(RemoteXdr* xdrs, ProtoWrite* proto_write, PacketSend* packet_send, bool flush)
|
||||||
{
|
{
|
||||||
#ifdef WIRE_COMPRESS_SUPPORT
|
|
||||||
rem_port* port = xdrs->x_public;
|
rem_port* port = xdrs->x_public;
|
||||||
|
port->bumpLogBytes(rem_port::SEND, xdrs->x_private - xdrs->x_base);
|
||||||
|
|
||||||
|
#ifdef WIRE_COMPRESS_SUPPORT
|
||||||
if (!(port->port_compressed && (port->port_flags & PORT_compressed)))
|
if (!(port->port_compressed && (port->port_flags & PORT_compressed)))
|
||||||
return proto_write(xdrs);
|
return proto_write(xdrs);
|
||||||
|
|
||||||
|
@ -1200,10 +1200,100 @@ struct rem_port : public Firebird::GlobalStorage, public Firebird::RefCounted
|
|||||||
|
|
||||||
UCharArrayAutoPtr port_buffer;
|
UCharArrayAutoPtr port_buffer;
|
||||||
|
|
||||||
|
|
||||||
|
enum io_direction_t {
|
||||||
|
NONE,
|
||||||
|
SEND,
|
||||||
|
RECEIVE
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
// packets over physical connection
|
||||||
FB_UINT64 port_snd_packets;
|
FB_UINT64 port_snd_packets;
|
||||||
FB_UINT64 port_rcv_packets;
|
FB_UINT64 port_rcv_packets;
|
||||||
|
// protocol packets
|
||||||
|
FB_UINT64 port_out_packets;
|
||||||
|
FB_UINT64 port_in_packets;
|
||||||
|
// bytes over physical connection
|
||||||
FB_UINT64 port_snd_bytes;
|
FB_UINT64 port_snd_bytes;
|
||||||
FB_UINT64 port_rcv_bytes;
|
FB_UINT64 port_rcv_bytes;
|
||||||
|
// bytes before/after compression
|
||||||
|
FB_UINT64 port_out_bytes;
|
||||||
|
FB_UINT64 port_in_bytes;
|
||||||
|
FB_UINT64 port_roundtrips; // number of changes of IO direction from SEND to RECEIVE
|
||||||
|
io_direction_t port_io_direction; // last direction of IO
|
||||||
|
|
||||||
|
public:
|
||||||
|
void bumpPhysStats(io_direction_t direction, ULONG count)
|
||||||
|
{
|
||||||
|
fb_assert(direction != NONE);
|
||||||
|
|
||||||
|
if (direction == SEND)
|
||||||
|
{
|
||||||
|
port_snd_packets++;
|
||||||
|
port_snd_bytes += count;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
port_rcv_packets++;
|
||||||
|
port_rcv_bytes += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (direction != port_io_direction)
|
||||||
|
{
|
||||||
|
if (port_io_direction != NONE && direction == RECEIVE)
|
||||||
|
port_roundtrips++;
|
||||||
|
port_io_direction = direction;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bumpLogBytes(io_direction_t direction, ULONG count)
|
||||||
|
{
|
||||||
|
fb_assert(direction != NONE);
|
||||||
|
|
||||||
|
if (direction == SEND)
|
||||||
|
port_out_bytes += count;
|
||||||
|
else
|
||||||
|
port_in_bytes += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bumpLogPackets(io_direction_t direction)
|
||||||
|
{
|
||||||
|
fb_assert(direction != NONE);
|
||||||
|
|
||||||
|
if (direction == SEND)
|
||||||
|
port_out_packets++;
|
||||||
|
else
|
||||||
|
port_in_packets++;
|
||||||
|
}
|
||||||
|
|
||||||
|
FB_UINT64 getStatItem(UCHAR infoItem) const
|
||||||
|
{
|
||||||
|
switch (infoItem)
|
||||||
|
{
|
||||||
|
case fb_info_wire_snd_packets:
|
||||||
|
return port_snd_packets;
|
||||||
|
case fb_info_wire_rcv_packets:
|
||||||
|
return port_rcv_packets;
|
||||||
|
case fb_info_wire_out_packets:
|
||||||
|
return port_out_packets;
|
||||||
|
case fb_info_wire_in_packets:
|
||||||
|
return port_in_packets;
|
||||||
|
case fb_info_wire_snd_bytes:
|
||||||
|
return port_snd_bytes;
|
||||||
|
case fb_info_wire_rcv_bytes:
|
||||||
|
return port_rcv_bytes;
|
||||||
|
case fb_info_wire_out_bytes:
|
||||||
|
return port_out_bytes;
|
||||||
|
case fb_info_wire_in_bytes:
|
||||||
|
return port_in_bytes;
|
||||||
|
case fb_info_wire_roundtrips:
|
||||||
|
return port_roundtrips;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef WIRE_COMPRESS_SUPPORT
|
#ifdef WIRE_COMPRESS_SUPPORT
|
||||||
z_stream port_send_stream, port_recv_stream;
|
z_stream port_send_stream, port_recv_stream;
|
||||||
@ -1243,7 +1333,9 @@ public:
|
|||||||
port_known_server_keys(getPool()), port_crypt_plugin(NULL),
|
port_known_server_keys(getPool()), port_crypt_plugin(NULL),
|
||||||
port_client_crypt_callback(NULL), port_server_crypt_callback(NULL), port_crypt_name(getPool()),
|
port_client_crypt_callback(NULL), port_server_crypt_callback(NULL), port_crypt_name(getPool()),
|
||||||
port_replicator(NULL), port_buffer(FB_NEW_POOL(getPool()) UCHAR[rpt]),
|
port_replicator(NULL), port_buffer(FB_NEW_POOL(getPool()) UCHAR[rpt]),
|
||||||
port_snd_packets(0), port_rcv_packets(0), port_snd_bytes(0), port_rcv_bytes(0)
|
port_snd_packets(0), port_rcv_packets(0), port_out_packets(0), port_in_packets(0),
|
||||||
|
port_snd_bytes(0), port_rcv_bytes(0), port_out_bytes(0), port_in_bytes(0),
|
||||||
|
port_roundtrips(0), port_io_direction(NONE)
|
||||||
{
|
{
|
||||||
addRef();
|
addRef();
|
||||||
memset(&port_linger, 0, sizeof port_linger);
|
memset(&port_linger, 0, sizeof port_linger);
|
||||||
|
Loading…
Reference in New Issue
Block a user