/* * PROGRAM: JRD Access Method * MODULE: RecordNumber.h * DESCRIPTION: Handler class for table record number * * 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 Nickolay Samofatov * for the Firebird Open Source RDBMS project. * * Copyright (c) 2004 Nickolay Samofatov * and all contributors signed below. * * All Rights Reserved. * Contributor(s): ______________________________________. * * * $Id: RecordNumber.h,v 1.4 2004-10-27 09:28:26 aafemt Exp $ * */ #ifndef JRD_RECORDNUMBER_H #define JRD_RECORDNUMBER_H const SINT64 EMPTY_NUMBER = QUADCONST(0); const SINT64 BOF_NUMBER = QUADCONST(-1); // This class is to be used everywhere you may need to handle record numbers. We // deliberately not define implicit conversions to and from integer to allow // compiler check errors on our migration path from 32-bit to 64-bit record // numbers. class RecordNumber { public: // Default constructor. inline RecordNumber() : value(EMPTY_NUMBER) {} // Copy constructor inline RecordNumber(const RecordNumber& from) : value(from.value) {} // Explicit constructor from 64-bit record number value inline explicit RecordNumber(SINT64 number) : value(number) {} // Assignment operator inline RecordNumber& operator =(const RecordNumber& from) { value = from.value; return *this; } inline bool operator ==(const RecordNumber& other) const { return value == other.value; } inline bool operator !=(const RecordNumber& other) const { return value != other.value; } inline bool operator > (const RecordNumber& other) const { return value > other.value; } inline bool operator < (const RecordNumber& other) const { return value < other.value; } inline bool operator >= (const RecordNumber& other) const { return value >= other.value; } inline bool operator <= (const RecordNumber& other) const { return value <= other.value; } inline void decrement() { value--; } inline void increment() { value++; } inline SINT64 getValue() const { return value; } inline void setValue(SINT64 avalue) { value = avalue; } bool isBof() const { return value == BOF_NUMBER; } bool isEmpty() const { return value == EMPTY_NUMBER; } inline bool checkNumber( USHORT records_per_page, // ~400 (8k page) USHORT data_pages_per_pointer_page // ~2000 (8k page) ) const { // We limit record number value to 40 bits and make sure decomposed value // fits into 3 USHORTs. This all makes practical table size limit (not // counting allocation threshold and overhead) roughtly equal to: // 16k page - 20000 GB // 8k page - 10000 GB // 4k page - 2500 GB // 2k page - 600 GB // 1k page - 150 GB // Large page size values are recommended for large databases because // page allocators are generally linear. return value < QUADCONST(0x10000000000) && value < (SINT64) MAX_USHORT * records_per_page * data_pages_per_pointer_page; } inline void decompose( USHORT records_per_page, // ~400 (8k page) USHORT data_pages_per_pointer_page, // ~2000 (8k page) SSHORT& line, SSHORT& slot, USHORT& pp_sequence ) const { line = value % records_per_page; const ULONG sequence = value / records_per_page; slot = sequence % data_pages_per_pointer_page; pp_sequence = sequence / data_pages_per_pointer_page; } inline void compose( USHORT records_per_page, // ~400 (8k page) USHORT data_pages_per_pointer_page, // ~2000 (8k page) SSHORT line, SSHORT slot, USHORT pp_sequence ) { value = (((SINT64) pp_sequence) * data_pages_per_pointer_page + slot) * records_per_page + line; } // Handle encoding of record number for RDB$DB_KEY and BLOB ID structure. // bid_number array has special alignment requirement - its second byte must // be 4-byte aligned. This is generally not a problem because this routine is // called for BID or DB_KEY structure member which is already aligned // appropriately. inline void bid_encode(UCHAR* bid_number) const { // BLOB ID is stored in database thus we do encode large record numbers // in a manner which preserves backward compatibility with older ODS. // The same applies to bid_decode routine below. // Store lower 32 bits of number *reinterpret_cast(bid_number + 1) = value; // Store high 8 bits of number bid_number[0] = value >> 32; } inline void bid_decode(const UCHAR* bid_number) { value = *reinterpret_cast(bid_number + 1) + (((UINT64) bid_number[0]) << 32); } private: // Use signed value because negative values are widely used as flags in the // engine. Since page number is the signed 32-bit integer and it is also may // be stored in this structure we want sign extension to take place. SINT64 value; }; #endif // JRD_RECORDNUMBER_H