2005-08-16 15:39:26 +02:00
|
|
|
/*
|
|
|
|
* The contents of this file are subject to the Initial
|
|
|
|
* Developer's 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.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed AS IS,
|
|
|
|
* 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 Dmitry Yemanov
|
|
|
|
* for the Firebird Open Source RDBMS project.
|
|
|
|
*
|
|
|
|
* Copyright (c) 2005 Dmitry Yemanov <dimitr@users.sf.net>
|
|
|
|
* and all contributors signed below.
|
|
|
|
*
|
|
|
|
* All Rights Reserved.
|
|
|
|
* Contributor(s): ______________________________________.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "firebird.h"
|
|
|
|
#include "../jrd/ods.h"
|
|
|
|
#include "../jrd/ods_proto.h"
|
|
|
|
|
2015-10-19 15:32:02 +02:00
|
|
|
using namespace Firebird;
|
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
|
|
|
const FB_SIZE_T NEXT_INDEX = 0;
|
|
|
|
const FB_SIZE_T OIT_INDEX = 1;
|
|
|
|
const FB_SIZE_T OAT_INDEX = 2;
|
|
|
|
const FB_SIZE_T OST_INDEX = 3;
|
|
|
|
}
|
|
|
|
|
2005-08-16 15:39:26 +02:00
|
|
|
namespace Ods {
|
|
|
|
|
|
|
|
bool isSupported(USHORT majorVersion, USHORT minorVersion)
|
|
|
|
{
|
|
|
|
const bool isFirebird = (majorVersion & ODS_FIREBIRD_FLAG);
|
|
|
|
majorVersion &= ~ODS_FIREBIRD_FLAG;
|
|
|
|
|
2009-11-24 12:42:56 +01:00
|
|
|
if (!isFirebird)
|
|
|
|
return false;
|
|
|
|
|
2005-08-16 15:39:26 +02:00
|
|
|
// Support current ODS of the engine
|
|
|
|
if (majorVersion == ODS_VERSION &&
|
|
|
|
minorVersion >= ODS_RELEASED &&
|
|
|
|
minorVersion <= ODS_CURRENT)
|
2008-12-05 02:20:14 +01:00
|
|
|
{
|
2005-08-16 15:39:26 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Do not support anything else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-07-17 20:48:46 +02:00
|
|
|
ULONG bytesBitPIP(ULONG page_size)
|
2009-12-21 00:13:01 +01:00
|
|
|
{
|
2014-07-17 23:17:15 +02:00
|
|
|
return static_cast<ULONG>(page_size - offsetof(page_inv_page, pip_bits[0]));
|
2009-12-21 00:13:01 +01:00
|
|
|
}
|
|
|
|
|
2014-07-17 20:48:46 +02:00
|
|
|
ULONG pagesPerPIP(ULONG page_size)
|
2009-12-21 00:13:01 +01:00
|
|
|
{
|
|
|
|
return bytesBitPIP(page_size) * 8;
|
|
|
|
}
|
|
|
|
|
2014-07-17 20:48:46 +02:00
|
|
|
ULONG pagesPerSCN(ULONG page_size)
|
2009-12-21 00:13:01 +01:00
|
|
|
{
|
|
|
|
return pagesPerPIP(page_size) / BITS_PER_LONG;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We must ensure that pagesPerSCN items can fit into scns_page::scn_pages array.
|
|
|
|
// We can't use fb_assert() here in ods.h so it is placed at pag.cpp
|
|
|
|
|
2014-07-17 20:48:46 +02:00
|
|
|
ULONG maxPagesPerSCN(ULONG page_size)
|
2009-12-21 00:13:01 +01:00
|
|
|
{
|
2014-07-17 23:17:15 +02:00
|
|
|
return static_cast<ULONG>((page_size - offsetof(scns_page, scn_pages[0])) / sizeof(((scns_page*)NULL)->scn_pages));
|
2009-12-21 00:13:01 +01:00
|
|
|
}
|
|
|
|
|
2014-07-17 20:48:46 +02:00
|
|
|
ULONG transPerTIP(ULONG page_size)
|
2009-12-21 00:13:01 +01:00
|
|
|
{
|
2014-07-17 23:17:15 +02:00
|
|
|
return static_cast<ULONG>((page_size - offsetof(tx_inv_page, tip_transactions[0])) * 4);
|
2009-12-21 00:13:01 +01:00
|
|
|
}
|
|
|
|
|
2014-07-17 20:48:46 +02:00
|
|
|
ULONG gensPerPage(ULONG page_size)
|
2009-12-21 00:13:01 +01:00
|
|
|
{
|
2014-07-17 23:17:15 +02:00
|
|
|
return static_cast<ULONG>((page_size - offsetof(generator_page, gpg_values[0])) /
|
2014-07-17 20:48:46 +02:00
|
|
|
sizeof(((generator_page*) NULL)->gpg_values));
|
2009-12-21 00:13:01 +01:00
|
|
|
}
|
|
|
|
|
2014-07-17 20:48:46 +02:00
|
|
|
ULONG dataPagesPerPP(ULONG page_size)
|
2009-12-21 00:13:01 +01:00
|
|
|
{
|
2014-09-19 00:31:53 +02:00
|
|
|
// Compute the number of data pages per pointer page. Each data page requires
|
|
|
|
// a 32 bit pointer (BITS_PER_LONG) and a 8 bit control field (PPG_DP_BITS_NUM).
|
2014-10-12 04:25:02 +02:00
|
|
|
// Also, don't allow extent of data pages (8 pages) to cross PP boundary to
|
2014-09-19 00:31:53 +02:00
|
|
|
// simplify code a bit.
|
2009-12-21 00:13:01 +01:00
|
|
|
|
2014-09-19 00:31:53 +02:00
|
|
|
ULONG ret = static_cast<ULONG>((page_size - offsetof(pointer_page, ppg_page[0])) * 8 / (BITS_PER_LONG + PPG_DP_BITS_NUM));
|
|
|
|
return ret & (~7);
|
2009-12-21 00:13:01 +01:00
|
|
|
}
|
|
|
|
|
2014-07-17 20:48:46 +02:00
|
|
|
ULONG maxRecsPerDP(ULONG page_size)
|
2009-12-21 00:13:01 +01:00
|
|
|
{
|
|
|
|
// Compute the number of records that can fit on a page using the
|
|
|
|
// size of the record index (dpb_repeat) and a record header. This
|
|
|
|
// gives an artificially high number, reducing the density of db_keys.
|
|
|
|
|
2014-07-20 04:19:06 +02:00
|
|
|
ULONG max_records = static_cast<ULONG>(
|
|
|
|
(page_size - sizeof(data_page)) / (sizeof(data_page::dpg_repeat) + offsetof(rhd, rhd_data[0])));
|
2009-12-21 00:13:01 +01:00
|
|
|
|
|
|
|
// Artificially reduce density of records to test high bits of record number
|
|
|
|
// max_records = 32000;
|
|
|
|
|
|
|
|
// Optimize record numbers for new 64-bit sparse bitmap implementation
|
|
|
|
// We need to measure if it is beneficial from performance point of view.
|
|
|
|
// Price is slightly reduced density of record numbers, but for
|
|
|
|
// ODS11 it doesn't matter because record numbers are 40-bit.
|
|
|
|
// Benefit is ~1.5 times smaller sparse bitmaps on average and faster bitmap iteration.
|
|
|
|
|
2014-07-28 15:01:10 +02:00
|
|
|
//max_records = FB_ALIGN(max_records, 64);
|
2009-12-21 00:13:01 +01:00
|
|
|
|
|
|
|
return max_records;
|
|
|
|
}
|
|
|
|
|
2014-07-17 20:48:46 +02:00
|
|
|
ULONG maxIndices(ULONG page_size)
|
2009-12-21 00:13:01 +01:00
|
|
|
{
|
|
|
|
// Compute the number of index roots that will fit on an index root page,
|
|
|
|
// assuming that each index has only one key
|
|
|
|
|
2014-07-17 23:17:15 +02:00
|
|
|
return static_cast<ULONG>((page_size - offsetof(index_root_page, irt_rpt[0])) /
|
2014-07-17 20:48:46 +02:00
|
|
|
(sizeof(index_root_page::irt_repeat) + sizeof(irtd)));
|
2009-12-21 00:13:01 +01:00
|
|
|
}
|
|
|
|
|
2012-06-28 13:46:21 +02:00
|
|
|
Firebird::string pagtype(UCHAR type)
|
|
|
|
{
|
|
|
|
// Print pretty name for database page type
|
|
|
|
|
|
|
|
const char* nameArray[pag_max + 1] = {
|
|
|
|
"purposely undefined",
|
|
|
|
"database header",
|
|
|
|
"page inventory",
|
|
|
|
"transaction inventory",
|
|
|
|
"pointer",
|
|
|
|
"data",
|
|
|
|
"index root",
|
|
|
|
"index B-tree",
|
|
|
|
"blob",
|
|
|
|
"generators",
|
|
|
|
"SCN inventory"
|
|
|
|
};
|
|
|
|
|
|
|
|
Firebird::string rc;
|
|
|
|
if (type < FB_NELEM(nameArray))
|
|
|
|
rc = nameArray[type];
|
|
|
|
else
|
|
|
|
rc.printf("unknown (%d)", type);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2015-10-19 15:32:02 +02:00
|
|
|
TraNumber getNT(const header_page* page)
|
|
|
|
{
|
|
|
|
return (TraNumber) page->hdr_tra_high[NEXT_INDEX] << BITS_PER_LONG | page->hdr_next_transaction;
|
|
|
|
}
|
|
|
|
|
|
|
|
TraNumber getOIT(const header_page* page)
|
|
|
|
{
|
|
|
|
return (TraNumber) page->hdr_tra_high[OIT_INDEX] << BITS_PER_LONG | page->hdr_oldest_transaction;
|
|
|
|
}
|
|
|
|
|
|
|
|
TraNumber getOAT(const header_page* page)
|
|
|
|
{
|
|
|
|
return (TraNumber) page->hdr_tra_high[OAT_INDEX] << BITS_PER_LONG | page->hdr_oldest_active;
|
|
|
|
}
|
|
|
|
|
|
|
|
TraNumber getOST(const header_page* page)
|
|
|
|
{
|
|
|
|
return (TraNumber) page->hdr_tra_high[OST_INDEX] << BITS_PER_LONG | page->hdr_oldest_snapshot;
|
|
|
|
}
|
|
|
|
|
|
|
|
void writeNT(header_page* page, TraNumber number)
|
|
|
|
{
|
|
|
|
page->hdr_next_transaction = (ULONG) (number & MAX_ULONG);
|
|
|
|
const SLONG high_word = number >> BITS_PER_LONG;
|
|
|
|
fb_assert(high_word <= MAX_USHORT);
|
|
|
|
page->hdr_tra_high[NEXT_INDEX] = (USHORT) high_word;
|
|
|
|
}
|
|
|
|
|
|
|
|
void writeOIT(header_page* page, TraNumber number)
|
|
|
|
{
|
|
|
|
page->hdr_oldest_transaction = (ULONG) (number & MAX_ULONG);
|
|
|
|
const SLONG high_word = number >> BITS_PER_LONG;
|
|
|
|
fb_assert(high_word <= MAX_USHORT);
|
|
|
|
page->hdr_tra_high[OIT_INDEX] = (USHORT) high_word;
|
|
|
|
}
|
|
|
|
|
|
|
|
void writeOAT(header_page* page, TraNumber number)
|
|
|
|
{
|
|
|
|
page->hdr_oldest_active = (ULONG) (number & MAX_ULONG);
|
|
|
|
const SLONG high_word = number >> BITS_PER_LONG;
|
|
|
|
fb_assert(high_word <= MAX_USHORT);
|
|
|
|
page->hdr_tra_high[OAT_INDEX] = (USHORT) high_word;
|
|
|
|
}
|
|
|
|
|
|
|
|
void writeOST(header_page* page, TraNumber number)
|
|
|
|
{
|
|
|
|
page->hdr_oldest_snapshot = (ULONG) (number & MAX_ULONG);
|
|
|
|
const SLONG high_word = number >> BITS_PER_LONG;
|
|
|
|
fb_assert(high_word <= MAX_USHORT);
|
|
|
|
page->hdr_tra_high[OST_INDEX] = (USHORT) high_word;
|
|
|
|
}
|
|
|
|
|
|
|
|
TraNumber getTraNum(const void* ptr)
|
|
|
|
{
|
|
|
|
rhd* const record = (rhd*) ptr;
|
|
|
|
USHORT high_word = 0;
|
|
|
|
|
|
|
|
if (record->rhd_flags & rhd_long_tranum)
|
|
|
|
{
|
|
|
|
high_word = (record->rhd_flags & rhd_incomplete) ?
|
|
|
|
((rhdf*) ptr)->rhdf_tra_high : ((rhde*) ptr)->rhde_tra_high;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ((TraNumber) high_word << BITS_PER_LONG) | record->rhd_transaction;
|
|
|
|
}
|
|
|
|
|
|
|
|
void writeTraNum(void* ptr, TraNumber number, FB_SIZE_T header_size)
|
|
|
|
{
|
|
|
|
rhd* const record = (rhd*) ptr;
|
|
|
|
|
|
|
|
record->rhd_transaction = (ULONG) (number & MAX_ULONG);
|
|
|
|
|
|
|
|
const SLONG high_word = number >> BITS_PER_LONG;
|
|
|
|
fb_assert(high_word <= MAX_USHORT);
|
|
|
|
|
|
|
|
if (high_word)
|
|
|
|
record->rhd_flags |= rhd_long_tranum;
|
|
|
|
|
|
|
|
if (record->rhd_flags & rhd_long_tranum)
|
|
|
|
{
|
|
|
|
if (record->rhd_flags & rhd_incomplete)
|
|
|
|
{
|
|
|
|
fb_assert(header_size == RHDF_SIZE);
|
|
|
|
((rhdf*) ptr)->rhdf_tra_high = (USHORT) high_word;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fb_assert(header_size == RHDE_SIZE);
|
|
|
|
((rhde*) ptr)->rhde_tra_high = (USHORT) high_word;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-08-16 15:39:26 +02:00
|
|
|
} // namespace
|