8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-31 23:23:04 +01:00
firebird-mirror/src/utilities/rebuild/rebuild.cpp

1204 lines
29 KiB
C++
Raw Normal View History

2001-05-23 15:26:42 +02:00
/*
* PROGRAM: JRD Rebuild scrambled database
2003-11-10 10:16:38 +01:00
* MODULE: rebuild.cpp
2001-05-23 15:26:42 +02:00
* DESCRIPTION: Main routine for analyzing and rebuilding database
*
* 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): ______________________________________.
*/
2002-06-29 10:49:39 +02:00
#include "../jrd/common.h"
#include "firebird.h"
2004-04-29 00:36:29 +02:00
#include <stdio.h>
2001-05-23 15:26:42 +02:00
#include <errno.h>
#include <string.h>
2001-05-23 15:26:42 +02:00
2003-11-08 17:40:17 +01:00
#include "../jrd/ibase.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/jrd.h"
#include "../jrd/jrd_time.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/pag.h"
#include "../jrd/tra.h"
2003-07-15 04:43:36 +02:00
#include "../utilities/rebuild/rebuild.h"
#include "../utilities/rebuild/rebui_proto.h"
#include "../utilities/rebuild/rmet_proto.h"
#include "../utilities/rebuild/rstor_proto.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/dmp_proto.h"
#include "../jrd/gds_proto.h"
#ifndef O_RDWR
#include <fcntl.h>
#endif
Database dbb_struct;
thread_db tdbb_struct, *gdbb;
PageControl dim;
jrd_tra dull;
2001-05-23 15:26:42 +02:00
const ULONG* tips;
2001-05-23 15:26:42 +02:00
2004-04-29 00:36:29 +02:00
FILE* dbg_file;
2001-05-23 15:26:42 +02:00
2003-08-26 20:46:31 +02:00
static void checksum(RBDB, ULONG, ULONG, bool);
2001-05-23 15:26:42 +02:00
static USHORT compute_checksum(RBDB, PAG);
static void db_error(int);
2004-04-29 00:36:29 +02:00
static void dump(FILE *, RBDB, ULONG, ULONG, UCHAR);
static void dump_tips(FILE *, RBDB);
static void format_header(RBDB, header_page*, int, ULONG, ULONG, ULONG, ULONG);
static void format_index_root(index_root_page*, int, SSHORT, SSHORT);
static void format_pointer(pointer_page*, int, SSHORT, SSHORT, bool, SSHORT, SLONG *);
static void format_pip(page_inv_page*, int, int);
static void format_tip(tx_inv_page*, int, SLONG);
static void get_next_file(RBDB, header_page*);
static void get_range(TEXT***, const TEXT* const* const, ULONG*, ULONG*);
static void get_switch(TEXT**, SWC);
static header_page* open_database(RBDB, ULONG);
2004-04-29 00:36:29 +02:00
static void print_db_header(FILE*, const header_page*);
2001-05-23 15:26:42 +02:00
static void rebuild(RBDB);
2004-04-29 00:36:29 +02:00
static void write_headers(FILE*, RBDB, ULONG, ULONG);
2001-05-23 15:26:42 +02:00
2003-08-26 20:46:31 +02:00
static bool sw_rebuild;
static bool sw_print;
static bool sw_store;
static bool sw_dump_pages;
static bool sw_checksum;
static bool sw_fudge;
static bool sw_fix;
static bool sw_dump_tips;
2001-05-23 15:26:42 +02:00
static const ULONG PPG_NUMBERS[] =
{
5897, 6058, 5409, 6199, 6200, 6220, 6221,
2001-05-23 15:26:42 +02:00
4739, 4868, 6332, 6333, 6329, 6359, 6751,
6331, 6392, 6806, 6819, 6820, 6866, 6875,
6876, 7019, 7284, 7430, 7431, 7757, 6893,
6894, 7408, 8308, 8309, 1036, 9120, 4528,
4563, 4572, 0, 0
};
int main( int argc, char *argv[])
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* m a i n
*
**************************************
*
* Functional description
* Parse and interpret command line, then do a variety
* of things.
*
**************************************/
TEXT out_file[128];
2001-05-23 15:26:42 +02:00
2004-04-29 00:36:29 +02:00
dbg_file = stdout;
2003-08-26 20:46:31 +02:00
sw_rebuild = sw_print = sw_store = sw_dump_pages = sw_checksum = false;
sw_dump_tips = sw_fudge = sw_fix = false;
2001-05-23 15:26:42 +02:00
ULONG c_lower_bound, c_upper_bound, d_lower_bound, d_upper_bound,
p_lower_bound, p_upper_bound, pg_size;
2001-05-23 15:26:42 +02:00
pg_size = p_lower_bound = c_lower_bound = d_lower_bound = 0;
p_upper_bound = c_upper_bound = d_upper_bound = BIG_NUMBER;
USHORT pg_type = 0;
2001-05-23 15:26:42 +02:00
const TEXT* const* const end = argv + argc;
2001-05-23 15:26:42 +02:00
++argv;
struct swc switch_space;
SWC token = &switch_space;
2001-05-23 15:26:42 +02:00
RBDB rbdb = NULL;
header_page* header = NULL;
TEXT* ascii_out = NULL;
TEXT* db_in = NULL;
2001-05-23 15:26:42 +02:00
while (argv < end) {
get_switch(argv, token);
argv++;
if (!token->swc_switch)
db_in = token->swc_string;
else {
switch (*token->swc_string) {
case 'b':
pg_size = atoi(*argv++);
break;
case 'c':
2003-08-26 20:46:31 +02:00
sw_checksum = true;
2001-05-23 15:26:42 +02:00
get_range(&argv, end, &c_lower_bound, &c_upper_bound);
break;
case 'd':
if ((argv < end) && (!strcmp(*argv, "tips"))) {
argv++;
2003-08-26 20:46:31 +02:00
sw_dump_tips = true;
2001-05-23 15:26:42 +02:00
}
else
2003-08-26 20:46:31 +02:00
sw_dump_pages = true;
2001-05-23 15:26:42 +02:00
get_range(&argv, end, &d_lower_bound, &d_upper_bound);
break;
case 'f':
2003-08-26 20:46:31 +02:00
sw_fix = true;
2001-05-23 15:26:42 +02:00
break;
case 'o':
if (argv < end) {
get_switch(argv, token);
if (token->swc_switch)
break;
strcpy(out_file, token->swc_string);
ascii_out = out_file;
argv++;
}
case 'p':
2003-08-26 20:46:31 +02:00
sw_print = true;
2001-05-23 15:26:42 +02:00
get_range(&argv, end, &p_lower_bound, &p_upper_bound);
break;
case 'r':
2003-08-26 20:46:31 +02:00
sw_rebuild = true;
2001-05-23 15:26:42 +02:00
break;
case 's':
2003-08-26 20:46:31 +02:00
sw_store = true;
2001-05-23 15:26:42 +02:00
break;
case 't':
pg_type = atoi(*argv++);
break;
}
}
}
if (db_in) {
2008-03-05 09:40:20 +01:00
rbdb = (RBDB) RBDB_alloc((SLONG) (sizeof(struct rbdb) + strlen(db_in) + 1));
2001-05-23 15:26:42 +02:00
strcpy(rbdb->rbdb_file.fil_name, db_in);
rbdb->rbdb_file.fil_length = strlen(db_in);
if (header = open_database(rbdb, pg_size))
get_next_file(rbdb, header);
/* some systems don't care for this write sharing stuff... */
if (rbdb && (sw_dump_tips || sw_dump_pages)) {
RBDB_close(rbdb);
if (rbdb->rbdb_valid)
tips = RMET_tips(db_in);
RBDB_open(rbdb);
}
}
gdbb = &tdbb_struct;
gdbb->tdbb_database = &dbb_struct;
gdbb->tdbb_transaction = &dull;
dull.tra_number = header->hdr_next_transaction;
gdbb->tdbb_database->dbb_max_records = (rbdb->rbdb_page_size
- sizeof(struct data_page)) /
(sizeof(data_page::dpg_repeat) + OFFSETA(RHD, rhd_data));
2001-05-23 15:26:42 +02:00
gdbb->tdbb_database->dbb_pcontrol = &dim;
gdbb->tdbb_database->dbb_dp_per_pp = (rbdb->rbdb_page_size
- OFFSETA(pointer_page*, ppg_page)) * 8 / 34;
2001-05-23 15:26:42 +02:00
gdbb->tdbb_database->dbb_pcontrol->pgc_bytes = rbdb->rbdb_page_size
- OFFSETA(page_inv_page*, pip_bits);
2001-05-23 15:26:42 +02:00
gdbb->tdbb_database->dbb_pcontrol->pgc_ppp =
gdbb->tdbb_database->dbb_pcontrol->pgc_bytes * 8;
gdbb->tdbb_database->dbb_pcontrol->pgc_tpt =
(rbdb->rbdb_page_size - OFFSETA(tx_inv_page*, tip_transactions)) * 4;
2001-05-23 15:26:42 +02:00
gdbb->tdbb_database->dbb_pcontrol->pgc_pip = 1;
if (ascii_out)
2004-04-29 00:36:29 +02:00
dbg_file = fopen(ascii_out, "w");
2001-05-23 15:26:42 +02:00
if (sw_print && rbdb && header)
write_headers(dbg_file, rbdb, p_lower_bound, p_upper_bound);
if (sw_store && rbdb && header)
RSTORE(rbdb);
if (sw_checksum && rbdb && header)
checksum(rbdb, c_lower_bound, c_upper_bound, sw_fix);
if (sw_dump_tips && rbdb && header)
dump_tips(dbg_file, rbdb);
if (sw_dump_pages && rbdb && header)
dump(dbg_file, rbdb, d_lower_bound, d_upper_bound, pg_type);
if (sw_rebuild && rbdb && header)
rebuild(rbdb);
if (ascii_out)
2004-04-29 00:36:29 +02:00
fclose(dbg_file);
2001-05-23 15:26:42 +02:00
if (rbdb)
RBDB_close(rbdb);
while (rbdb) {
RBDB next_db = rbdb->rbdb_next;
2001-05-23 15:26:42 +02:00
if (rbdb->rbdb_buffer1)
gds__free(rbdb->rbdb_buffer1);
if (rbdb->rbdb_buffer2)
gds__free(rbdb->rbdb_buffer2);
gds__free(rbdb);
rbdb = next_db;
}
return 0;
2001-05-23 15:26:42 +02:00
}
2007-11-12 16:18:49 +01:00
#ifdef HPUX
PAG CCH_fetch(WIN * x, USHORT y, int z)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* C C H _ f e t c h
*
**************************************
*
* Functional description
* This routine lets me link in
* DMP.C from JRD without having the
* linker piss all over it.
*
**************************************/
}
PAG CCH_release(WIN * x)
{
/**************************************
*
* C C H _ f e t c h
*
**************************************
*
* Functional description
* This routine lets me link in
* DMP.C from JRD without having the
* linker piss all over it.
*
**************************************/
}
#endif
2008-03-05 09:40:20 +01:00
void* RBDB_alloc(SLONG size)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* R B D B _ a l l o c
*
**************************************
*
* Functional description
* Allocate and zero a piece of memory.
*
**************************************/
2008-03-05 09:40:20 +01:00
return memset(gds__alloc(size), 0, size);
2001-05-23 15:26:42 +02:00
}
void RBDB_close( RBDB rbdb)
{
/**************************************
*
* R B D B _ c l o s e
*
**************************************
*
* Functional description
*
**************************************/
for (; rbdb; rbdb = rbdb->rbdb_next)
close(rbdb->rbdb_file.fil_file);
}
void RBDB_open( RBDB rbdb)
{
/**************************************
*
* R B D B _ o p e n
*
**************************************
*
* Functional description
* Open a database file.
*
**************************************/
2009-01-03 10:14:29 +01:00
if ((rbdb->rbdb_file.fil_file = open(rbdb->rbdb_file.fil_name, O_RDWR, 0)) == -1)
{
2001-05-23 15:26:42 +02:00
db_error(errno);
}
2001-05-23 15:26:42 +02:00
}
PAG RBDB_read(RBDB rbdb, SLONG page_number)
{
/**************************************
*
* R B D B _ r e a d
*
**************************************
*
* Functional description
* Read a database page.
*
**************************************/
int file = rbdb->rbdb_file.fil_file;
2001-05-23 15:26:42 +02:00
2007-11-17 01:38:16 +01:00
const FB_UINT64 offset = ((FB_UINT64) page_number) * ((FB_UINT64) rbdb->rbdb_page_size);
2002-06-29 10:49:39 +02:00
if (lseek (file, offset, 0) == -1)
2001-05-23 15:26:42 +02:00
db_error(errno);
SSHORT length = rbdb->rbdb_page_size;
for (char* p = (SCHAR *) rbdb->rbdb_buffer1;
length > 0;)
{
const SSHORT l = read(file, p, length);
2001-05-23 15:26:42 +02:00
if (l < 0)
db_error(errno);
else if (l == 0)
return NULL;
p += l;
length -= l;
}
rbdb->rbdb_file.fil_file = file;
return rbdb->rbdb_buffer1;
}
void RBDB_write( RBDB rbdb, PAG page, SLONG page_number)
{
/**************************************
*
* R B D B _ w r i t e ( u n i x )
*
**************************************
*
* Functional description
* Write a database page.
*
**************************************/
page->pag_checksum = compute_checksum(rbdb, page);
const ULONG page_size = rbdb->rbdb_page_size;
int fd = rbdb->rbdb_file.fil_file;
2001-05-23 15:26:42 +02:00
2007-11-17 01:38:16 +01:00
const FB_UINT64 offset = ((FB_UINT64) page_number) * ((FB_UINT64) page_size);
2002-06-29 10:49:39 +02:00
if (lseek (fd, offset, 0) == -1)
2001-05-23 15:26:42 +02:00
db_error(errno);
if (write(fd, page, page_size) == -1)
db_error(errno);
}
2003-08-26 20:46:31 +02:00
static void checksum( RBDB rbdb, ULONG lower, ULONG upper, bool sw_fix)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* c h e c k s u m
*
**************************************
*
* Functional description
* read, compute, check, and correct
* checksums in this database.
*
**************************************/
TEXT s[128];
for (ULONG page_number = lower; page_number <= upper; page_number++) {
pag* page = RBDB_read(rbdb, page_number);
if (!page)
2001-05-23 15:26:42 +02:00
return;
const USHORT old_checksum = page->pag_checksum;
const USHORT new_checksum = compute_checksum(rbdb, page);
2001-05-23 15:26:42 +02:00
if (sw_fix)
page->pag_checksum = new_checksum;
if (new_checksum == old_checksum)
sprintf(s, "checksum %5d is OK", old_checksum);
else
sprintf(s, "stored checksum %5d\tcomputed checksum %5d\t%s",
old_checksum, new_checksum, (sw_fix) ? "fixed" : "");
2004-04-29 00:36:29 +02:00
printf("page %9d\t%s\n", page_number, s);
2001-05-23 15:26:42 +02:00
}
}
static USHORT compute_checksum( RBDB rbdb, PAG page)
{
/**************************************
*
* c o m p u t e _ c h e c k s u m
*
**************************************
*
* Functional description
* compute checksum for a V3 page.
*
**************************************/
const ULONG* const end = (ULONG *) ((SCHAR *) page + rbdb->rbdb_page_size);
const USHORT old_checksum = page->pag_checksum;
2001-05-23 15:26:42 +02:00
page->pag_checksum = 0;
const ULONG* p = (ULONG *) page;
ULONG checksum = 0;
2001-05-23 15:26:42 +02:00
do {
checksum += *p++;
checksum += *p++;
checksum += *p++;
checksum += *p++;
checksum += *p++;
checksum += *p++;
checksum += *p++;
checksum += *p++;
} while (p < end);
2001-05-23 15:26:42 +02:00
page->pag_checksum = old_checksum;
if (checksum)
return checksum;
/* If the page is all zeros, return an artificial checksum */
for (p = (ULONG *) page; p < end;)
2008-03-05 09:40:20 +01:00
{
2001-05-23 15:26:42 +02:00
if (*p++)
return checksum;
2008-03-05 09:40:20 +01:00
}
2001-05-23 15:26:42 +02:00
/* Page is all zeros -- invent a checksum */
return 12345;
}
static void db_error( int status)
{
/**************************************
*
* d b _ e r r o r
*
**************************************
*
* Functional description
*
**************************************/
2004-04-29 00:36:29 +02:00
printf(strerror(status));
2001-05-23 15:26:42 +02:00
exit(FINI_ERROR);
}
static void dump(
2004-04-29 00:36:29 +02:00
FILE * file,
2001-05-23 15:26:42 +02:00
RBDB rbdb, ULONG lower, ULONG upper, UCHAR pg_type)
{
/**************************************
*
2008-12-05 02:20:14 +01:00
* d u m p
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
* dump the contents of some page
* or pages in the database.
*
**************************************/
ULONG sequence = 0;
2001-05-23 15:26:42 +02:00
if (rbdb->rbdb_last_page && upper == BIG_NUMBER)
upper = rbdb->rbdb_last_page;
PAG page;
2001-05-23 15:26:42 +02:00
while (page = RBDB_read(rbdb, lower)) {
if (page->pag_type == pag_transactions && tips) {
for (const ULONG* tip = tips; tip[sequence]; sequence++) {
2001-05-23 15:26:42 +02:00
if (tip[sequence] == lower)
break;
else if (!tip[sequence]) {
sequence = 0;
break;
}
}
}
else
sequence = 0;
if (pg_type && (page->pag_type != pg_type)) {
2004-04-29 00:36:29 +02:00
printf("\nChanging page %d type from %d to %d\n", lower,
2001-05-23 15:26:42 +02:00
page->pag_type, pg_type);
page->pag_type = pg_type;
}
DMP_fetched_page(page, lower, sequence, rbdb->rbdb_page_size);
const ULONG* p = (ULONG *) page;
for (const ULONG* const end = p + (rbdb->rbdb_page_size / sizeof(ULONG)) - 1;
!*p && p < end; p++); // empty loop body
2001-05-23 15:26:42 +02:00
if (!*p)
2004-04-29 00:36:29 +02:00
printf(" Page is all zeroes.\n");
2001-05-23 15:26:42 +02:00
if (sw_fudge)
RBDB_write(rbdb, page, lower);
if (++lower > upper)
break;
}
}
2004-04-29 00:36:29 +02:00
static void dump_tips( FILE * file, RBDB rbdb)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
2008-12-05 02:20:14 +01:00
* d u m p _ t i p s
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
* dump the contents of tip pages
* in the database.
*
**************************************/
if (!tips)
2004-04-29 00:36:29 +02:00
printf("not enough database. Store headers and look there\n");
2001-05-23 15:26:42 +02:00
PAG page;
ULONG sequence = 1;
for (const ULONG* tip = tips; *tip && (page = RBDB_read(rbdb, *tip));
2001-05-23 15:26:42 +02:00
sequence++)
{
2001-05-23 15:26:42 +02:00
DMP_fetched_page(page, *tip++, sequence, rbdb->rbdb_page_size);
}
2001-05-23 15:26:42 +02:00
}
static void format_header(
RBDB rbdb,
header_page* page,
2001-05-23 15:26:42 +02:00
int page_size,
ULONG oldest, ULONG active, ULONG next, ULONG imp)
{
/**************************************
*
* f o r m a t _ h e a d e r
*
**************************************
*
* Functional description
* Format a header page from inputs
*
**************************************/
memset(page, 0, page_size);
page->hdr_page_size = page_size;
page->pag_type = pag_header;
page->hdr_ods_version = ODS_VERSION | ODS_TYPE_CURRENT;
2001-05-23 15:26:42 +02:00
page->hdr_PAGES = 2;
page->hdr_oldest_transaction = oldest;
page->hdr_oldest_active = active;
page->hdr_next_transaction = next;
page->hdr_implementation = imp;
page->pag_checksum = compute_checksum(rbdb, page);
2001-05-23 15:26:42 +02:00
}
static void format_index_root(
index_root_page* page,
2001-05-23 15:26:42 +02:00
int page_size, SSHORT relation_id, SSHORT count)
{
/**************************************
*
* f o r m a t _ i n d e x _ r o o t
*
**************************************
*
* Functional description
* Format an index root page, without any indexes for a start
*
**************************************/
memset(page, 0, page_size);
page->pag_type = pag_root;
2001-05-23 15:26:42 +02:00
page->irt_relation = relation_id;
page->irt_count = count;
}
static void format_pointer(
pointer_page* page,
2001-05-23 15:26:42 +02:00
int page_size,
SSHORT relation_id,
SSHORT sequence,
bool eof, SSHORT count, SLONG * page_vector)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* f o r m a t _ p o i n t e r
*
**************************************
*
* Functional description
* Format a pointer page. In addition of the buffer and page size,
* we need a relation id, a pointer page sequence (within relation),
* a flag indicated whether this is the last pointer page for the
* relation, and a count and vector of pages to point to.
*
**************************************/
memset(page, 0, page_size);
page->pag_type = pag_pointer;
2001-05-23 15:26:42 +02:00
page->ppg_sequence = sequence;
page->ppg_relation = relation_id;
page->ppg_count = count;
page->ppg_min_space = 0;
page->ppg_max_space = count;
if (eof)
page->pag_flags |= ppg_eof;
2001-05-23 15:26:42 +02:00
memcpy(page->ppg_page, page_vector, count * sizeof(SLONG));
}
static void format_pip( page_inv_page* page, int page_size, int last_flag)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* f o r m a t _ p i p
*
**************************************
*
* Functional description
* Fake a fully RBDB_allocated (all pages RBDB_allocated) page inventory
2008-12-05 02:20:14 +01:00
* page.
2001-05-23 15:26:42 +02:00
*
**************************************/
page->pag_type = pag_pages;
page->pag_flags = 0;
2001-05-23 15:26:42 +02:00
/* Set all page bits to zero, indicating RBDB_allocated */
const SSHORT bytes = page_size - OFFSETA(page_inv_page*, pip_bits);
2001-05-23 15:26:42 +02:00
memset(page->pip_bits, 0, bytes);
/* If this is the last pip, make sure the last page (which
will become the next pip) is marked free. When the
time comes to RBDB_allocate the next page, that page will
be formatted as the next pip. */
if (last_flag)
page->pip_bits[bytes - 1] |= 1 << 7;
}
static void format_tip( tx_inv_page* page, int page_size, SLONG next_page)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* f o r m a t _ t i p
*
**************************************
*
* Functional description
* Fake a fully commit transaction inventory page.
*
**************************************/
page->pag_type = pag_transactions;
page->pag_flags = 0;
2001-05-23 15:26:42 +02:00
/* The "next" tip page number is included for redundancy, but is not actually
read by the engine, so can be safely left zero. If known, it would nice
2008-12-05 02:20:14 +01:00
to supply it.
2001-05-23 15:26:42 +02:00
*/
page->tip_next = next_page;
/* Code for committed transaction is 3, so just fill all
bytes with -1 */
const SSHORT bytes = page_size - OFFSETA(tx_inv_page*, tip_transactions);
2001-05-23 15:26:42 +02:00
memset(page->tip_transactions, -1, bytes);
}
static void get_next_file( RBDB rbdb, header_page* header)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g e t _ n e x t _ f i l e
*
**************************************
*
* Functional description
* If there's another file as part of
* this database, get it now.
*
**************************************/
RBDB* next = &rbdb->rbdb_next;
const UCHAR* p = header->hdr_data;
for (const UCHAR* const end = p + header->hdr_page_size;
2001-05-23 15:26:42 +02:00
p < end && *p != HDR_end; p += 2 + p[1])
{
if (*p == HDR_file)
{
RBDB next_rbdb = (RBDB) RBDB_alloc(sizeof(rbdb) + (SSHORT) p[1]);
2001-05-23 15:26:42 +02:00
next_rbdb->rbdb_file.fil_length = (SSHORT) p[1];
strncpy(next_rbdb->rbdb_file.fil_name, p + 2, (SSHORT) p[1]);
*next = next_rbdb;
next = &next_rbdb->rbdb_next;
break;
}
}
2001-05-23 15:26:42 +02:00
}
static void get_range(
TEXT*** argv,
const TEXT* const* const end, ULONG* lower, ULONG* upper)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g e t _ r a n g e
*
**************************************
*
* Functional description
* get a range out of the argument
* vector;
*
**************************************/
struct swc token_space;
SWC token = &token_space;
2001-05-23 15:26:42 +02:00
if (*argv < end) {
get_switch(*argv, token);
if (token->swc_switch)
return;
++*argv;
TEXT c = 0;
const TEXT* p;
2001-05-23 15:26:42 +02:00
for (p = token->swc_string; *p; p++)
if (*p < '0' || *p > '9') {
c = *p;
*p++ = 0;
break;
}
*upper = *lower = (ULONG) atoi(token->swc_string);
if (*p && (c == ':' || c == ',')) {
if (*p == '*')
*upper = BIG_NUMBER;
else
*upper = (ULONG) atoi(p);
return;
}
}
if (*argv < end) {
get_switch(*argv, token);
if (token->swc_switch)
return;
2008-12-05 02:20:14 +01:00
if ((*token->swc_string == ':') || (*token->swc_string == ','))
2006-04-06 10:18:53 +02:00
{
const TEXT* p = token->swc_string;
2001-05-23 15:26:42 +02:00
if (*++p) {
if (*p == '*')
*upper = BIG_NUMBER;
else
*upper = (ULONG) atoi(p);
}
else if (*argv++ < end) {
get_switch(*argv, token);
if (token->swc_switch)
return;
}
}
if (*token->swc_string == '*')
*upper = BIG_NUMBER;
else
*upper = (ULONG) atoi(token->swc_string);
*argv++;
}
}
static void get_switch( TEXT** argv, SWC token)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g e t _ s w i t c h
*
**************************************
*
* Functional description
* get the next argument in the argument
* vector;
*
**************************************/
token->swc_string = *argv;
if (*token->swc_string == '-') {
token->swc_switch = TRUE;
token->swc_string++;
}
else
token->swc_switch = FALSE;
const int temp = strlen(token->swc_string) - 1;
2001-05-23 15:26:42 +02:00
if (token->swc_string[temp] == ',') {
token->swc_string[temp] = '\0';
token->swc_comma = TRUE;
}
else
token->swc_comma = FALSE;
}
static header_page* open_database( RBDB rbdb, ULONG pg_size)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* o p e n _ d a t a b a s e
*
**************************************
*
* Functional description
* Open a database and setup the
* rbdb. Return a pointer to the
* header page page header;
*
**************************************/
UCHAR temp[1024];
RBDB_open(rbdb);
rbdb->rbdb_page_size = sizeof(temp);
rbdb->rbdb_buffer1 = (PAG) temp;
rbdb->rbdb_valid = TRUE;
header_page* header = (header_page*) RBDB_read(rbdb, (SLONG) 0);
2001-05-23 15:26:42 +02:00
if (header->pag_type != pag_header) {
2004-04-29 00:36:29 +02:00
printf("header page has wrong type, expected %d found %d!\n",
pag_header, header->pag_type);
2001-05-23 15:26:42 +02:00
rbdb->rbdb_valid = FALSE;
}
if (header->hdr_ods_version != ODS_VERSION | ODS_TYPE_CURRENT) {
printf("Wrong ODS version, expected %d type %04x, encountered %d type %04x.\n",
2008-12-05 02:20:14 +01:00
ODS_VERSION, ODS_TYPE_CURRENT,
header->hdr_ods_version & ~ODS_TYPE_MASK,
header->hdr_ods_version & ODS_TYPE_MASK
);
2001-05-23 15:26:42 +02:00
rbdb->rbdb_valid = FALSE;
}
if (pg_size && (pg_size != header->hdr_page_size)) {
2004-04-29 00:36:29 +02:00
printf("Using page size %d\n", pg_size);
2001-05-23 15:26:42 +02:00
header->hdr_page_size = pg_size;
rbdb->rbdb_valid = FALSE;
}
else if (!header->hdr_page_size) {
2004-04-29 00:36:29 +02:00
printf("Using page size 1024\n");
2001-05-23 15:26:42 +02:00
header->hdr_page_size = 1024;
rbdb->rbdb_valid = FALSE;
}
2004-04-29 00:36:29 +02:00
printf("\nDatabase \"%s\"\n\n", rbdb->rbdb_file.fil_name);
2001-05-23 15:26:42 +02:00
rbdb->rbdb_page_size = header->hdr_page_size;
rbdb->rbdb_map_count = rbdb->rbdb_map_length / rbdb->rbdb_page_size;
rbdb->rbdb_buffer1 = (PAG) RBDB_alloc(rbdb->rbdb_page_size);
rbdb->rbdb_buffer2 = (PAG) RBDB_alloc(rbdb->rbdb_page_size);
return header;
}
2004-04-29 00:36:29 +02:00
static void print_db_header( FILE* file, const header_page* header)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p r i n t _ d b _ h e a d e r
*
**************************************
*
* Functional description
* Print database header page.
*
**************************************/
2004-04-29 00:36:29 +02:00
fprintf(file, "Database header page information:\n");
fprintf(file, " Page size\t\t\t%d\n", header->hdr_page_size);
2008-12-05 02:20:14 +01:00
fprintf(file, " ODS version\t\t\t%d type %04x\n",
header->hdr_ods_version & ~ODS_TYPE_MASK,
header->hdr_ods_version & ODS_TYPE_MASK);
2004-04-29 00:36:29 +02:00
fprintf(file, " PAGES\t\t\t%d\n", header->hdr_PAGES);
fprintf(file, " next page\t\t\t%d\n", header->hdr_next_page);
fprintf(file, " Oldest transaction\t\t%ld\n",
2001-05-23 15:26:42 +02:00
header->hdr_oldest_transaction);
2004-04-29 00:36:29 +02:00
fprintf(file, " Oldest active\t\t%ld\n", header->hdr_oldest_active);
fprintf(file, " Oldest snapshot\t\t%ld\n",
2001-05-23 15:26:42 +02:00
header->hdr_oldest_snapshot);
2004-04-29 00:36:29 +02:00
fprintf(file, " Next transaction\t\t%ld\n",
2001-05-23 15:26:42 +02:00
header->hdr_next_transaction);
2004-04-29 00:36:29 +02:00
fprintf(file, " Data pages per pointer page\t%ld\n",
2001-05-23 15:26:42 +02:00
gdbb->tdbb_database->dbb_dp_per_pp);
2004-04-29 00:36:29 +02:00
fprintf(file, " Max records per page\t%ld\n",
2001-05-23 15:26:42 +02:00
gdbb->tdbb_database->dbb_max_records);
/*
2004-04-29 00:36:29 +02:00
fprintf (" Sequence number %d\n", header->hdr_sequence);
fprintf (" Creation date \n", header->hdr_creation_date);
2001-05-23 15:26:42 +02:00
*/
2004-04-29 00:36:29 +02:00
fprintf(file, " Next attachment ID\t\t%ld\n",
2001-05-23 15:26:42 +02:00
header->hdr_attachment_id);
2004-04-29 00:36:29 +02:00
fprintf(file, " Implementation ID\t\t%ld\n",
2001-05-23 15:26:42 +02:00
header->hdr_implementation);
2004-04-29 00:36:29 +02:00
fprintf(file, " Shadow count\t\t%ld\n", header->hdr_shadow_count);
2001-05-23 15:26:42 +02:00
2003-12-31 06:36:12 +01:00
tm time;
isc_decode_timestamp(header->hdr_creation_date, &time);
2001-05-23 15:26:42 +02:00
2004-04-29 00:36:29 +02:00
fprintf(file, " Creation date:\t\t%s %d, %d %d:%02d:%02d\n",
2003-12-31 06:36:12 +01:00
FB_SHORT_MONTHS[time.tm_mon], time.tm_mday, time.tm_year + 1900,
2001-05-23 15:26:42 +02:00
time.tm_hour, time.tm_min, time.tm_sec);
2004-04-29 00:36:29 +02:00
fprintf(file, " Cache buffers\t\t%ld\n", header->hdr_cache_buffers);
fprintf(file, " Bumped transaction\t\t%ld\n",
2001-05-23 15:26:42 +02:00
header->hdr_bumped_transaction);
2004-04-29 00:36:29 +02:00
fprintf(file, "\n Variable header data:\n");
2001-05-23 15:26:42 +02:00
2003-12-31 06:36:12 +01:00
SLONG number;
2008-12-05 02:20:14 +01:00
2003-12-31 06:36:12 +01:00
const UCHAR* p = header->hdr_data;
for (const UCHAR* const end = p + header->hdr_page_size;
2001-05-23 15:26:42 +02:00
p < end && *p != HDR_end; p += 2 + p[1])
2003-12-31 06:36:12 +01:00
{
2001-05-23 15:26:42 +02:00
switch (*p) {
case HDR_root_file_name:
2004-04-29 00:36:29 +02:00
fprintf(file, "\tRoot file name: %*s\n", p[1], p + 2);
2001-05-23 15:26:42 +02:00
break;
/*
2001-05-23 15:26:42 +02:00
case HDR_journal_server:
2004-04-29 00:36:29 +02:00
fprintf(file, "\tJournal server: %*s\n", p[1], p + 2);
2001-05-23 15:26:42 +02:00
break;
*/
2001-05-23 15:26:42 +02:00
case HDR_file:
2004-04-29 00:36:29 +02:00
fprintf(file, "\tContinuation file: %*s\n", p[1], p + 2);
2001-05-23 15:26:42 +02:00
break;
case HDR_last_page:
2007-11-17 11:18:10 +01:00
memcpy(&number, p + 2, sizeof(number));
2004-04-29 00:36:29 +02:00
fprintf(file, "\tLast logical page: %ld\n", number);
2001-05-23 15:26:42 +02:00
break;
/*
2001-05-23 15:26:42 +02:00
case HDR_unlicensed:
2007-11-17 11:18:10 +01:00
memcpy(&number, p + 2, sizeof(number));
2004-04-29 00:36:29 +02:00
fprintf(file, "\tUnlicensed accesses: %ld\n", number);
2001-05-23 15:26:42 +02:00
break;
*/
2001-05-23 15:26:42 +02:00
case HDR_sweep_interval:
2007-11-17 11:18:10 +01:00
memcpy(&number, p + 2, sizeof(number));
2004-04-29 00:36:29 +02:00
fprintf(file, "\tSweep interval: %ld\n", number);
2001-05-23 15:26:42 +02:00
break;
case HDR_log_name:
2004-04-29 00:36:29 +02:00
fprintf(file, "\tReplay logging file: %*s\n", p[1], p + 2);
2001-05-23 15:26:42 +02:00
break;
/*
2001-05-23 15:26:42 +02:00
case HDR_journal_file:
2004-04-29 00:36:29 +02:00
fprintf(file, "\tJournal file: %*s\n", p[1], p + 2);
2001-05-23 15:26:42 +02:00
break;
*/
2001-05-23 15:26:42 +02:00
case HDR_password_file_key:
2004-04-29 00:36:29 +02:00
fprintf(file, "\tPassword file key: (can't print)\n");
2001-05-23 15:26:42 +02:00
break;
/*
2001-05-23 15:26:42 +02:00
case HDR_backup_info:
2004-04-29 00:36:29 +02:00
fprintf(file, "\tBackup info: (can't print)\n");
2001-05-23 15:26:42 +02:00
break;
case HDR_cache_file:
2004-04-29 00:36:29 +02:00
fprintf(file, "\tShared cache file: %*s\n", p[1], p + 2);
2001-05-23 15:26:42 +02:00
break;
*/
2001-05-23 15:26:42 +02:00
default:
2004-04-29 00:36:29 +02:00
fprintf(file, "\tUnrecognized option %d, length %d\n", p[0],
2001-05-23 15:26:42 +02:00
p[1]);
}
2003-12-31 06:36:12 +01:00
}
2001-05-23 15:26:42 +02:00
2004-04-29 00:36:29 +02:00
fprintf(file, "\n\n");
2001-05-23 15:26:42 +02:00
}
static void rebuild( RBDB rbdb)
{
/**************************************
*
2008-12-05 02:20:14 +01:00
* r e b u i l d
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
* Write out an improved database.
*
**************************************/
2003-12-31 06:36:12 +01:00
const ULONG page_size = rbdb->rbdb_page_size;
pag* page = rbdb->rbdb_buffer1;
2003-12-31 06:36:12 +01:00
const ULONG* page_numbers = PPG_NUMBERS;
for (ULONG number = 5898; (number < 5899) && (page = RBDB_read(rbdb, number));
number++)
{
pointer_page* pointer = (pointer_page*) page;
/* format_pointer (page, page_size, 25, 3, true, 37, page_numbers); */
2001-05-23 15:26:42 +02:00
RBDB_write(rbdb, page, number);
}
}
static void write_headers(
2004-04-29 00:36:29 +02:00
FILE* file, RBDB rbdb, ULONG lower, ULONG upper)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* w r i t e _ h e a d e r s
*
**************************************
*
* Functional description
* Print out the page headers.
*
**************************************/
2003-12-31 06:36:12 +01:00
pag* page;
for (ULONG page_number = lower;
2001-05-23 15:26:42 +02:00
(page_number <= upper) && (page = RBDB_read(rbdb, page_number));
2003-12-31 06:36:12 +01:00
page_number++)
{
2004-04-29 00:36:29 +02:00
fprintf(file, "page %d, ", page_number);
2001-05-23 15:26:42 +02:00
switch (page->pag_type) {
case pag_header:
2004-04-29 00:36:29 +02:00
fprintf(file, "header page, checksum %d\n",
2001-05-23 15:26:42 +02:00
page->pag_checksum);
print_db_header(file, (header_page*) page);
2001-05-23 15:26:42 +02:00
break;
case pag_pages:
2003-12-31 06:36:12 +01:00
{
2004-04-29 00:36:29 +02:00
fprintf(file, "page inventory page, checksum %d\n",
2001-05-23 15:26:42 +02:00
page->pag_checksum);
page_inv_page* pip = (page_inv_page*) page;
2004-04-29 00:36:29 +02:00
fprintf(file, "\tlowest free page %d\n\n", pip->pip_min);
2001-05-23 15:26:42 +02:00
break;
2003-12-31 06:36:12 +01:00
}
2001-05-23 15:26:42 +02:00
case pag_transactions:
2004-04-29 00:36:29 +02:00
fprintf(file, "TIP page, checksum %d\n", page->pag_checksum);
fprintf(file, "\tnext tip for database %ld\n\n",
((tx_inv_page*) page)->tip_next);
2001-05-23 15:26:42 +02:00
break;
case pag_pointer:
2003-12-31 06:36:12 +01:00
{
2004-04-29 00:36:29 +02:00
fprintf(file, "pointer page, checksum %d\n",
2001-05-23 15:26:42 +02:00
page->pag_checksum);
const pointer_page* pointer = (pointer_page*) page;
2004-04-29 00:36:29 +02:00
fprintf(file,
2001-05-23 15:26:42 +02:00
"\trelation %d, sequence %ld, next pip %ld, active slots %d\n",
pointer->ppg_relation, pointer->ppg_sequence,
pointer->ppg_next, pointer->ppg_count);
2004-04-29 00:36:29 +02:00
fprintf(file,
2001-05-23 15:26:42 +02:00
"\tfirst slot with space %d, last slot with space %d\n",
pointer->ppg_min_space, pointer->ppg_max_space);
2004-04-29 00:36:29 +02:00
fprintf(file, "\t%s\n",
2004-12-16 04:03:13 +01:00
(pointer->pag_flags & ppg_eof) ?
"last pointer for relation\n" : "");
2001-05-23 15:26:42 +02:00
break;
2003-12-31 06:36:12 +01:00
}
2001-05-23 15:26:42 +02:00
case pag_data:
2003-12-31 06:36:12 +01:00
{
2004-04-29 00:36:29 +02:00
fprintf(file, "data page, checksum %d\n", page->pag_checksum);
const data_page* data = (data_page*) page;
2004-04-29 00:36:29 +02:00
fprintf(file,
2001-05-23 15:26:42 +02:00
"\trelation %d, sequence %ld, records on page %d\n",
data->dpg_relation, data->dpg_sequence,
data->dpg_count);
2004-04-29 00:36:29 +02:00
fprintf(file, "\t%s%s%s%s\n",
2004-12-16 04:03:13 +01:00
(data->pag_flags & dpg_orphan) ? "orphan " : "",
(data->pag_flags & dpg_full) ? "full " : "",
2004-12-16 04:03:13 +01:00
(data->pag_flags & dpg_large) ?
"contains a large object" : "",
(data->pag_flags) ? "\n" : "");
2001-05-23 15:26:42 +02:00
break;
2003-12-31 06:36:12 +01:00
}
2001-05-23 15:26:42 +02:00
case pag_root:
2003-12-31 06:36:12 +01:00
{
2004-04-29 00:36:29 +02:00
fprintf(file, "index root page, checksum %d\n",
2001-05-23 15:26:42 +02:00
page->pag_checksum);
const index_root_page* index_root = (index_root_page*) page;
2004-04-29 00:36:29 +02:00
fprintf(file, "\trelation %d, number of indexes %d\n\n",
2001-05-23 15:26:42 +02:00
index_root->irt_relation, index_root->irt_count);
break;
2003-12-31 06:36:12 +01:00
}
2001-05-23 15:26:42 +02:00
case pag_index:
2003-12-31 06:36:12 +01:00
{
2004-04-29 00:36:29 +02:00
fprintf(file, "btree page (bucket), checksum %d\n",
2001-05-23 15:26:42 +02:00
page->pag_checksum);
const btree_page* bucket = (btree_page*) page;
2004-04-29 00:36:29 +02:00
fprintf(file, "\trelation %d, right sibling bucket: %ld,\n",
2001-05-23 15:26:42 +02:00
bucket->btr_relation, bucket->btr_sibling);
2004-04-29 00:36:29 +02:00
fprintf(file, "\tdata length %d, index id %d, level %d\n",
2001-05-23 15:26:42 +02:00
bucket->btr_length, bucket->btr_id, bucket->btr_level);
2004-04-29 00:36:29 +02:00
fprintf(file, "\t%s%s%s\n",
2004-12-16 04:03:13 +01:00
(bucket->pag_flags & btr_leftmost) ? "leftmost " : "",
(bucket->pag_flags & btr_not_prop) ?
"all duplicates " : "",
(bucket->Pag_flags & btr_marked) ?
"marked for delete" : "");
2001-05-23 15:26:42 +02:00
break;
2003-12-31 06:36:12 +01:00
}
2001-05-23 15:26:42 +02:00
case pag_blob:
2003-12-31 06:36:12 +01:00
{
2004-04-29 00:36:29 +02:00
fprintf(file, "blob page, checksum %d\n", page->pag_checksum);
const blob_page* blob = (blob_page*) page;
2004-04-29 00:36:29 +02:00
fprintf(file, "\tlead page: %ld, sequence: %ld, length: %d\n",
2001-05-23 15:26:42 +02:00
blob->blp_lead_page, blob->blp_sequence,
blob->blp_length);
2004-04-29 00:36:29 +02:00
fprintf(file, "\tcontains %s\n",
2004-12-16 04:03:13 +01:00
(blob->pag_flags & blp_pointers) ? "pointers" : "data");
2001-05-23 15:26:42 +02:00
break;
2003-12-31 06:36:12 +01:00
}
2008-12-05 02:20:14 +01:00
2001-05-23 15:26:42 +02:00
case pag_ids:
2004-04-29 00:36:29 +02:00
fprintf(file, "generator page, checksum %d\n\n",
2001-05-23 15:26:42 +02:00
page->pag_checksum);
break;
case pag_log:
2004-04-29 00:36:29 +02:00
fprintf(dbg_file, "write-ahead log info page, checksum %d\n\n",
2001-05-23 15:26:42 +02:00
page->pag_checksum);
break;
default:
2004-04-29 00:36:29 +02:00
fprintf(file, "unknown page type\n\n");
2001-05-23 15:26:42 +02:00
break;
}
}
}
2003-12-31 06:36:12 +01:00