8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-22 14: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:
Vlad Khorsun 2024-11-12 13:00:25 +02:00
parent 8ca2314355
commit df885d5935
12 changed files with 514 additions and 21 deletions

View File

@ -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

View File

@ -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! */
}; };

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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),

View File

@ -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;
} }

View File

@ -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;

View File

@ -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:

View File

@ -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);

View File

@ -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);