8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-29 06:43:03 +01:00
firebird-mirror/src/utilities/stats.epp

377 lines
8.6 KiB
Plaintext
Raw Normal View History

2001-05-23 15:26:42 +02:00
/*
* PROGRAM: JRD Access Method
* MODULE: stats.epp
2001-05-23 15:26:42 +02:00
* 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"
2003-11-08 17:40:17 +01:00
#include "../jrd/ibase.h"
2001-05-23 15:26:42 +02:00
DATABASE DB = "yachts.lnk";
2009-01-09 02:50:54 +01:00
extern void* gds__alloc();
extern SLONG gds__vax_integer();
2001-05-23 15:26:42 +02:00
2004-05-17 02:21:46 +02:00
const SSHORT ITEM_seq_reads = 0;
const SSHORT ITEM_idx_reads = 1;
const SSHORT ITEM_inserts = 2;
const SSHORT ITEM_updates = 3;
const SSHORT ITEM_deletes = 4;
const SSHORT ITEM_backouts = 5;
const SSHORT ITEM_purges = 6;
const SSHORT ITEM_expunges = 7;
const SSHORT ITEM_count = 8;
2001-05-23 15:26:42 +02:00
struct fb_stats
{
2001-05-23 15:26:42 +02:00
SSHORT stats_count;
2009-05-25 09:32:39 +02:00
SSHORT stats_items; // Number of item per relation
2001-05-23 15:26:42 +02:00
SLONG stats_counts[1];
};
typedef int (print_callback)(SCHAR*, SSHORT, SSHORT, const SCHAR* const*, const SLONG*);
2001-05-23 15:26:42 +02:00
static fb_stats* expand_stats(fb_stats** ptr, SSHORT count);
2009-05-27 03:36:00 +02:00
static int get_counts(ISC_STATUS* status_vector, const SCHAR* info, SSHORT length,
2009-05-25 09:32:39 +02:00
fb_stats** stats_ptr, SSHORT item);
static int print_line(SCHAR* arg, SSHORT relation_id, SSHORT count,
const SCHAR* const* headers, const SLONG* counts);
2001-05-23 15:26:42 +02:00
static const SCHAR info_request[] =
{
2003-11-08 17:40:17 +01:00
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
2001-05-23 15:26:42 +02:00
};
static const SCHAR* headers[] =
{
2001-05-23 15:26:42 +02:00
"S-Reads",
"I-Reads",
"Inserts",
"Updates",
"Deletes",
"Backouts",
"Purges",
"Expunges"
};
static int* database_handle;
static int* request_handle;
2001-05-23 15:26:42 +02:00
2009-01-03 20:02:04 +01:00
void stats_analyze(const fb_stats* before, const fb_stats* after, print_callback callback, SCHAR* arg)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* s t a t s _ a n a l y z e
*
**************************************
*
* Functional description
*
**************************************/
2003-12-31 06:36:12 +01:00
SLONG delta[ITEM_count];
2001-05-23 15:26:42 +02:00
if (!after)
return;
2003-12-31 06:36:12 +01:00
const SLONG* const end = delta + ITEM_count;
2001-05-23 15:26:42 +02:00
2003-12-31 06:36:12 +01:00
const SLONG* tail2 = 0;
if (before) {
2001-05-23 15:26:42 +02:00
tail2 = before->stats_counts;
2003-12-31 06:36:12 +01:00
}
2001-05-23 15:26:42 +02:00
2003-12-31 06:36:12 +01:00
SSHORT relation_id = 0
for (const SLONG* tail = after->stats_counts; relation_id < after->stats_count; ++relation_id)
2003-12-31 06:36:12 +01:00
{
SLONG total = 0;
2009-05-25 09:32:39 +02:00
for (SLONG* p = delta; p < end;)
{
2001-05-23 15:26:42 +02:00
total += *tail;
*p++ = *tail++;
}
if (before && relation_id < before->stats_count)
2009-05-25 09:32:39 +02:00
for (SLONG* p = delta; p < end;)
{
2001-05-23 15:26:42 +02:00
total -= *tail2;
*p++ -= *tail2++;
}
2003-12-31 06:36:12 +01:00
if (total) {
2001-05-23 15:26:42 +02:00
(*callback) (arg, relation_id, ITEM_count, headers, delta);
2003-12-31 06:36:12 +01:00
}
2001-05-23 15:26:42 +02:00
}
}
int stats_fetch(SLONG *status_vector, int **db_handle, fb_stats** stats_ptr)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* s t a t s _ f e t c h
*
**************************************
*
* Functional description
* Gather statistics.
*
**************************************/
2003-12-31 06:36:12 +01:00
SCHAR info_buffer[4096];
2001-05-23 15:26:42 +02:00
if (isc_database_info(status_vector, db_handle, sizeof(info_request), info_request,
sizeof(info_buffer), info_buffer))
2003-09-12 18:49:38 +02:00
{
return status_vector[1];
}
2001-05-23 15:26:42 +02:00
fb_stats* stats = *stats_ptr;
2003-12-31 06:36:12 +01:00
if (stats)
2001-05-23 15:26:42 +02:00
zap_longs(stats->stats_counts, stats->stats_count * ITEM_count);
else
stats = expand_stats(stats_ptr, 64);
2009-05-25 09:32:39 +02:00
if (!stats)
{
2003-11-08 17:40:17 +01:00
status_vector[0] = isc_arg_gds;
status_vector[1] = isc_virmemexh;
status_vector[2] = isc_arg_end;
2001-05-23 15:26:42 +02:00
return status_vector[1];
}
2003-12-31 06:36:12 +01:00
const SCHAR* const end = info_buffer + sizeof(info_buffer);
for (const SCHAR* p = info_buffer; p < end && *p != isc_info_end;)
{
2003-12-31 06:36:12 +01:00
const SSHORT length = gds__vax_integer(p + 1, 2);
SSHORT item = -1;
switch (*p)
{
2003-11-08 17:40:17 +01:00
case isc_info_read_seq_count:
2001-05-23 15:26:42 +02:00
item = ITEM_seq_reads;
break;
2003-11-08 17:40:17 +01:00
case isc_info_read_idx_count:
2001-05-23 15:26:42 +02:00
item = ITEM_idx_reads;
break;
2003-11-08 17:40:17 +01:00
case isc_info_insert_count:
2001-05-23 15:26:42 +02:00
item = ITEM_inserts;
break;
2003-11-08 17:40:17 +01:00
case isc_info_update_count:
2001-05-23 15:26:42 +02:00
item = ITEM_updates;
break;
2003-11-08 17:40:17 +01:00
case isc_info_delete_count:
2001-05-23 15:26:42 +02:00
item = ITEM_deletes;
break;
2003-11-08 17:40:17 +01:00
case isc_info_backout_count:
2001-05-23 15:26:42 +02:00
item = ITEM_backouts;
break;
2003-11-08 17:40:17 +01:00
case isc_info_purge_count:
2001-05-23 15:26:42 +02:00
item = ITEM_purges;
break;
2003-11-08 17:40:17 +01:00
case isc_info_expunge_count:
2001-05-23 15:26:42 +02:00
item = ITEM_expunges;
break;
}
2009-05-25 09:32:39 +02:00
if (item >= 0)
{
2001-05-23 15:26:42 +02:00
if (get_counts(status_vector, p + 3, length, stats_ptr, item))
break;
p += 3 + length;
}
2009-05-25 09:32:39 +02:00
}
// MOD I have added this just to compile - it matches the for loop
// but will need to be checkout out before actually being used
2001-05-23 15:26:42 +02:00
return status_vector[1];
}
int stats_print(int **db_handle, int **tr_handle, const fb_stats* before, const fb_stats* after)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* s t a t s _ p r i n t
*
**************************************
*
* Functional description
*
**************************************/
if (request_handle && database_handle != *db_handle)
2003-11-08 17:40:17 +01:00
isc_release_request(gds__status, &request_handle);
2001-05-23 15:26:42 +02:00
db = database_handle = *db_handle;
gds__trans = *tr_handle;
2003-12-31 06:36:12 +01:00
SLONG init = 0;
2001-05-23 15:26:42 +02:00
stats_analyze(before, after, print_line, &init);
2001-12-24 03:51:06 +01:00
return 0;
2001-05-23 15:26:42 +02:00
}
static fb_stats* expand_stats(fb_stats** ptr, SSHORT count)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* e x p a n d _ s t a t s
*
**************************************
*
* Functional description
* Make sure vector is big enough.
*
**************************************/
2009-05-25 09:32:39 +02:00
// If the thing is already big enough, don't do anything
fb_stats* old = *ptr;
2003-12-31 06:36:12 +01:00
if (old && old->stats_count < count)
2001-05-23 15:26:42 +02:00
return old;
count += 20;
const SLONG length = sizeof(fb_stats) + (ITEM_count * count - 1) * sizeof(SLONG);
fb_stats* stats = (fb_stats*) gds__alloc(length);
2009-05-25 09:32:39 +02:00
// FREE: apparently never freed
if (!stats) // NOMEM: out of memory
return NULL; // leave *ptr unchanged
2001-05-23 15:26:42 +02:00
zap_longs(stats->stats_counts, count * ITEM_count);
stats->stats_count = count;
stats->stats_items = ITEM_count;
2009-05-25 09:32:39 +02:00
if (old)
{
2003-12-31 06:36:12 +01:00
SLONG* p = stats->stats_counts;
const SLONG* q = old->stats_counts;
const SLONG* const end = q + ITEM_count * old->stats_count;
while (q < end) {
2001-05-23 15:26:42 +02:00
*p++ = *q++;
2003-12-31 06:36:12 +01:00
}
2001-05-23 15:26:42 +02:00
gds__free(old);
}
return *ptr = stats;
}
2009-05-25 09:32:39 +02:00
static int get_counts(ISC_STATUS *status_vector, const SCHAR *info, SSHORT length,
fb_stats** stats_ptr, SSHORT item)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g e t _ c o u n t s
*
**************************************
*
* Functional description
* Pick up operation counts from information items.
*
**************************************/
fb_stats* stats = *stats_ptr;
2001-05-23 15:26:42 +02:00
2003-12-31 06:36:12 +01:00
const SCHAR* p = info;
2009-05-25 09:32:39 +02:00
for (const SCHAR* const end = p + length; p < end; p += 6)
{
2003-12-31 06:36:12 +01:00
const SSHORT relation_id = gds__vax_integer(p, 2);
2009-05-25 09:32:39 +02:00
if (relation_id >= stats->stats_count)
{
2009-07-03 12:44:55 +02:00
if (!expand_stats(&stats, relation_id))
{
2003-11-08 17:40:17 +01:00
status_vector[0] = isc_arg_gds;
status_vector[1] = isc_virmemexh;
status_vector[2] = isc_arg_end;
2001-05-23 15:26:42 +02:00
return status_vector[1];
}
2003-12-31 06:36:12 +01:00
}
stats->stats_counts[relation_id * ITEM_count + item] = gds__vax_integer(p + 2, 4);
2001-05-23 15:26:42 +02:00
}
2009-01-18 12:29:24 +01:00
// CVC: Maybe this line is missing here? This function may relocate the pointer.
// Otherwise the caller may be using deallocated memory in the next iteration.
*stats_ptr = stats;
2001-05-23 15:26:42 +02:00
return status_vector[1];
}
static int print_line(SCHAR* arg, SSHORT relation_id, SSHORT count,
const SCHAR* const* headers, const SLONG* counts)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p r i n t _ l i n e
*
**************************************
*
* Functional description
* Display data.
*
**************************************/
2009-05-25 09:32:39 +02:00
if (!*arg)
{
2001-05-23 15:26:42 +02:00
*arg = 1;
2004-04-29 00:36:29 +02:00
printf("%32s ", " ");
for (SSHORT n = count; n; --n)
printf("%10s", *headers++);
2003-12-31 06:36:12 +01:00
}
2004-04-29 00:36:29 +02:00
printf("\n");
2001-05-23 15:26:42 +02:00
}
2003-12-31 06:36:12 +01:00
// This didn't work previously! GDML uses uppercased keywords.
FOR (REQUEST_HANDLE request_handle)
x IN RDB$RELATIONS
WITH x.RDB$RELATION_ID EQ relation_id
2004-04-29 00:36:29 +02:00
printf("%32s", x.rdb$relation_name);
2003-12-31 06:36:12 +01:00
for (const SLONG* const end = counts + count; counts < end; counts++) {
2004-04-29 00:36:29 +02:00
printf("%10d", *counts);
2003-12-31 06:36:12 +01:00
}
2004-04-29 00:36:29 +02:00
printf("\n");
2003-12-31 06:36:12 +01:00
END_FOR
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
return 0;
2001-05-23 15:26:42 +02:00
}
2003-12-31 06:36:12 +01:00
static int zap_longs(SLONG* ptr, SSHORT count)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* z a p _ l o n g s
*
**************************************
*
* Functional description
* Zero a bunch of SLONGwords.
*
**************************************/
2009-07-03 12:44:55 +02:00
if (count > 0)
{
2003-12-31 06:36:12 +01:00
do {
2001-05-23 15:26:42 +02:00
*ptr++ = 0;
2003-12-31 06:36:12 +01:00
} while (--count);
}
2001-12-24 03:51:06 +01:00
return 0;
2001-05-23 15:26:42 +02:00
}