mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-24 09:23:03 +01:00
359 lines
7.8 KiB
Plaintext
359 lines
7.8 KiB
Plaintext
/*
|
|
* PROGRAM: JRD Access Method
|
|
* MODULE: stats.epp
|
|
* DESCRIPTION: Record statistics manager
|
|
*
|
|
* The contents of this file are subject to the Interbase Public
|
|
* License Version 1.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.Inprise.com/IPL.html
|
|
*
|
|
* Software distributed under the License is distributed on an
|
|
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
|
|
* or implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* The Original Code was created by Inprise Corporation
|
|
* and its predecessors. Portions created by Inprise Corporation are
|
|
* Copyright (C) Inprise Corporation.
|
|
*
|
|
* All Rights Reserved.
|
|
* Contributor(s): ______________________________________.
|
|
*/
|
|
|
|
#include "firebird.h"
|
|
#include "../jrd/y_ref.h"
|
|
#include "../jrd/ibase.h"
|
|
|
|
DATABASE DB = "yachts.lnk";
|
|
|
|
extern SCHAR *gds__alloc();
|
|
extern SLONG gds__vax_integer();
|
|
|
|
#define ITEM_seq_reads 0
|
|
#define ITEM_idx_reads 1
|
|
#define ITEM_inserts 2
|
|
#define ITEM_updates 3
|
|
#define ITEM_deletes 4
|
|
#define ITEM_backouts 5
|
|
#define ITEM_purges 6
|
|
#define ITEM_expunges 7
|
|
#define ITEM_count 8
|
|
|
|
typedef struct stats {
|
|
SSHORT stats_count;
|
|
SSHORT stats_items; /* Number of item per relation */
|
|
SLONG stats_counts[1];
|
|
} *STATS;
|
|
|
|
static STATS expand_stats();
|
|
static int print_line();
|
|
|
|
static const SCHAR info_request[] = {
|
|
isc_info_read_seq_count,
|
|
isc_info_read_idx_count,
|
|
isc_info_insert_count,
|
|
isc_info_update_count,
|
|
isc_info_delete_count,
|
|
isc_info_backout_count,
|
|
isc_info_purge_count,
|
|
isc_info_expunge_count,
|
|
isc_info_end
|
|
};
|
|
|
|
static const SCHAR* headers[] = {
|
|
"S-Reads",
|
|
"I-Reads",
|
|
"Inserts",
|
|
"Updates",
|
|
"Deletes",
|
|
"Backouts",
|
|
"Purges",
|
|
"Expunges"
|
|
};
|
|
|
|
static int* database_handle;
|
|
static int* request_handle;
|
|
|
|
|
|
int stats_analyze(STATS before, STATS after, int(*callback)(), SCHAR *arg)
|
|
{
|
|
/**************************************
|
|
*
|
|
* s t a t s _ a n a l y z e
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
*
|
|
**************************************/
|
|
SLONG delta[ITEM_count], *p, *end, *tail, *tail2, total;
|
|
SSHORT relation_id;
|
|
|
|
if (!after)
|
|
return;
|
|
|
|
end = delta + ITEM_count;
|
|
|
|
if (before)
|
|
tail2 = before->stats_counts;
|
|
|
|
for (tail = after->stats_counts, relation_id = 0;
|
|
relation_id < after->stats_count; ++relation_id) {
|
|
total = 0;
|
|
for (p = delta; p < end;) {
|
|
total += *tail;
|
|
*p++ = *tail++;
|
|
}
|
|
if (before && relation_id < before->stats_count)
|
|
for (p = delta; p < end;) {
|
|
total -= *tail2;
|
|
*p++ -= *tail2++;
|
|
}
|
|
if (total)
|
|
(*callback) (arg, relation_id, ITEM_count, headers, delta);
|
|
}
|
|
}
|
|
|
|
|
|
int stats_fetch(SLONG *status_vector, int **db_handle, STATS *stats_ptr)
|
|
{
|
|
/**************************************
|
|
*
|
|
* s t a t s _ f e t c h
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Gather statistics.
|
|
*
|
|
**************************************/
|
|
SCHAR info_buffer[4096], *p, *end;
|
|
STATS stats;
|
|
SSHORT length, item;
|
|
|
|
if (isc_database_info(status_vector, db_handle, sizeof(info_request),
|
|
info_request, sizeof(info_buffer),
|
|
info_buffer))
|
|
{
|
|
return status_vector[1];
|
|
}
|
|
|
|
if (stats = *stats_ptr)
|
|
zap_longs(stats->stats_counts, stats->stats_count * ITEM_count);
|
|
else
|
|
stats = expand_stats(stats_ptr, 64);
|
|
|
|
if (!stats) {
|
|
status_vector[0] = isc_arg_gds;
|
|
status_vector[1] = isc_virmemexh;
|
|
status_vector[2] = isc_arg_end;
|
|
return status_vector[1];
|
|
}
|
|
|
|
for (p = info_buffer;
|
|
p < info_buffer + sizeof(info_buffer) && *p != isc_info_end;) {
|
|
length = gds__vax_integer(p + 1, 2);
|
|
item = -1;
|
|
switch (*p) {
|
|
case isc_info_read_seq_count:
|
|
item = ITEM_seq_reads;
|
|
break;
|
|
case isc_info_read_idx_count:
|
|
item = ITEM_idx_reads;
|
|
break;
|
|
case isc_info_insert_count:
|
|
item = ITEM_inserts;
|
|
break;
|
|
case isc_info_update_count:
|
|
item = ITEM_updates;
|
|
break;
|
|
case isc_info_delete_count:
|
|
item = ITEM_deletes;
|
|
break;
|
|
case isc_info_backout_count:
|
|
item = ITEM_backouts;
|
|
break;
|
|
case isc_info_purge_count:
|
|
item = ITEM_purges;
|
|
break;
|
|
case isc_info_expunge_count:
|
|
item = ITEM_expunges;
|
|
break;
|
|
}
|
|
if (item >= 0) {
|
|
if (get_counts(status_vector, p + 3, length, stats_ptr, item))
|
|
break;
|
|
p += 3 + length;
|
|
}
|
|
|
|
} /** MOD I have added this just to compile - it matches the for loop
|
|
but will need to be checkout out before actually being used */
|
|
|
|
return status_vector[1];
|
|
|
|
}
|
|
|
|
|
|
int stats_print(int **db_handle, int **tr_handle, STATS before, STATS after)
|
|
{
|
|
/**************************************
|
|
*
|
|
* s t a t s _ p r i n t
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
*
|
|
**************************************/
|
|
SLONG init;
|
|
|
|
if (request_handle && database_handle != *db_handle)
|
|
isc_release_request(gds__status, &request_handle);
|
|
|
|
db = database_handle = *db_handle;
|
|
gds__trans = *tr_handle;
|
|
init = 0;
|
|
stats_analyze(before, after, print_line, &init);
|
|
return 0;
|
|
}
|
|
|
|
|
|
static STATS expand_stats(STATS *ptr, SSHORT count)
|
|
{
|
|
/**************************************
|
|
*
|
|
* e x p a n d _ s t a t s
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Make sure vector is big enough.
|
|
*
|
|
**************************************/
|
|
STATS stats, old;
|
|
SLONG *p, *q, *end, length;
|
|
|
|
/* If the thing is already big enough, don't do nothing */
|
|
|
|
if ((old = *ptr) && old->stats_count < count)
|
|
return old;
|
|
|
|
count += 20;
|
|
length = sizeof(struct stats) + (ITEM_count * count - 1) * sizeof(SLONG);
|
|
stats = (STATS) gds__alloc(length);
|
|
/* FREE: apparently never freed */
|
|
if (!stats) /* NOMEM: out of memory */
|
|
return NULL; /* leave *ptr unchanged */
|
|
zap_longs(stats->stats_counts, count * ITEM_count);
|
|
stats->stats_count = count;
|
|
stats->stats_items = ITEM_count;
|
|
|
|
if (old) {
|
|
p = stats->stats_counts;
|
|
q = old->stats_counts;
|
|
end = q + ITEM_count * old->stats_count;
|
|
while (q < end)
|
|
*p++ = *q++;
|
|
gds__free(old);
|
|
}
|
|
|
|
return *ptr = stats;
|
|
}
|
|
|
|
|
|
static int get_counts(ISC_STATUS *status_vector, SCHAR *info, SSHORT length,
|
|
STATS *stats_ptr, SSHORT item)
|
|
{
|
|
/**************************************
|
|
*
|
|
* g e t _ c o u n t s
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Pick up operation counts from information items.
|
|
*
|
|
**************************************/
|
|
SCHAR *p, *end;
|
|
SSHORT relation_id;
|
|
STATS stats;
|
|
|
|
stats = *stats_ptr;
|
|
|
|
for (p = info, end = p + length; p < end; p += 6) {
|
|
relation_id = gds__vax_integer(p, 2);
|
|
if (relation_id >= stats->stats_count)
|
|
if (!expand_stats(&stats, relation_id)) {
|
|
status_vector[0] = isc_arg_gds;
|
|
status_vector[1] = isc_virmemexh;
|
|
status_vector[2] = isc_arg_end;
|
|
return status_vector[1];
|
|
}
|
|
stats->stats_counts[relation_id * ITEM_count + item] =
|
|
gds__vax_integer(p + 2, 4);
|
|
}
|
|
return status_vector[1];
|
|
}
|
|
|
|
|
|
static int print_line(SCHAR *arg, SSHORT relation_id, SSHORT count,
|
|
SCHAR **headers, SLONG *counts)
|
|
{
|
|
/**************************************
|
|
*
|
|
* p r i n t _ l i n e
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Display data.
|
|
*
|
|
**************************************/
|
|
SLONG *end;
|
|
SSHORT n;
|
|
|
|
if (!*arg) {
|
|
*arg = 1;
|
|
ib_printf("%32s ", " ");
|
|
if (n = count)
|
|
do
|
|
ib_printf("%10s", *headers++);
|
|
while (--n);
|
|
ib_printf("\n");
|
|
}
|
|
|
|
for (request_handle request_handle)
|
|
x in rdb$relations with x.rdb$relation_id eq relation_id
|
|
ib_printf("%32s", x.rdb$relation_name);
|
|
for (end = counts + count; counts < end; counts++)
|
|
ib_printf("%10d", *counts);
|
|
ib_printf("\n");
|
|
end_for;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int zap_longs(SLONG *ptr, SSHORT count)
|
|
{
|
|
/**************************************
|
|
*
|
|
* z a p _ l o n g s
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Zero a bunch of SLONGwords.
|
|
*
|
|
**************************************/
|
|
|
|
if (count)
|
|
do
|
|
*ptr++ = 0;
|
|
while (--count);
|
|
|
|
return 0;
|
|
}
|
|
|