2003-12-01 11:25:41 +01:00
|
|
|
/*
|
|
|
|
* PROGRAM: JRD Access Method
|
|
|
|
* MODULE: btn.cpp
|
|
|
|
* DESCRIPTION: B-tree management code
|
|
|
|
*
|
|
|
|
* 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 Arno Brinkman
|
|
|
|
* for the Firebird Open Source RDBMS project.
|
|
|
|
*
|
|
|
|
* Copyright (c) 2003 Arno Brinkman and all contributors
|
|
|
|
* signed below.
|
|
|
|
*
|
|
|
|
* All Rights Reserved.
|
|
|
|
* Contributor(s): ______________________________________.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "firebird.h" // needed for get_long
|
|
|
|
#include "memory_routines.h" // needed for get_long
|
|
|
|
|
2008-12-05 02:20:14 +01:00
|
|
|
#include "../jrd/ods.h"
|
|
|
|
#include "../jrd/btn.h"
|
2003-12-01 11:25:41 +01:00
|
|
|
|
2012-01-26 08:01:45 +01:00
|
|
|
using namespace Jrd;
|
2004-03-20 15:57:40 +01:00
|
|
|
using namespace Ods;
|
2003-12-01 11:25:41 +01:00
|
|
|
|
2012-01-26 08:01:45 +01:00
|
|
|
USHORT IndexNode::computePrefix(const UCHAR* prevString, USHORT prevLength,
|
|
|
|
const UCHAR* string, USHORT length)
|
2003-12-01 11:25:41 +01:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* c o m p u t e P r e f i x
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2008-12-05 02:20:14 +01:00
|
|
|
* Compute and return prefix common
|
2003-12-01 11:25:41 +01:00
|
|
|
* to two strings.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-12-03 09:44:28 +01:00
|
|
|
USHORT l = MIN(prevLength, length);
|
|
|
|
if (!l) {
|
2003-12-01 11:25:41 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-12-03 09:44:28 +01:00
|
|
|
const UCHAR* p = prevString;
|
2003-12-01 11:25:41 +01:00
|
|
|
|
2009-05-01 19:21:36 +02:00
|
|
|
while (*p == *string)
|
|
|
|
{
|
2003-12-03 09:44:28 +01:00
|
|
|
++p;
|
|
|
|
++string;
|
2003-12-01 11:25:41 +01:00
|
|
|
if (!--l) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (p - prevString);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-01-26 08:01:45 +01:00
|
|
|
SLONG IndexNode::findPageInDuplicates(const btree_page* page, UCHAR* pointer,
|
|
|
|
SLONG previousNumber, RecordNumber findRecordNumber)
|
2003-12-01 11:25:41 +01:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* f i n d P a g e I n D u p l i c a t e s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Return the first page number
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-12-03 09:44:28 +01:00
|
|
|
const bool leafPage = (page->btr_level == 0);
|
2003-12-01 11:25:41 +01:00
|
|
|
|
2003-12-03 09:44:28 +01:00
|
|
|
IndexNode node, previousNode;
|
2012-01-26 08:01:45 +01:00
|
|
|
pointer = node.readNode(pointer, leafPage);
|
2003-12-01 11:25:41 +01:00
|
|
|
|
2009-05-01 19:21:36 +02:00
|
|
|
while (true)
|
|
|
|
{
|
2008-12-05 02:20:14 +01:00
|
|
|
// loop through duplicates until
|
2003-12-01 11:25:41 +01:00
|
|
|
// correct node is found.
|
|
|
|
// If this is an end bucket marker then return
|
|
|
|
// the previous passed page number.
|
2004-03-07 22:50:53 +01:00
|
|
|
if (node.isEndBucket) {
|
2003-12-01 11:25:41 +01:00
|
|
|
return previousNumber;
|
|
|
|
}
|
2004-09-24 02:11:32 +02:00
|
|
|
if (findRecordNumber <= node.recordNumber) {
|
2003-12-01 11:25:41 +01:00
|
|
|
// If first record number on page is higher
|
|
|
|
// then record number must be at the previous
|
|
|
|
// passed page number.
|
|
|
|
return previousNumber;
|
2008-12-05 02:20:14 +01:00
|
|
|
}
|
|
|
|
// Save current page number and fetch next node
|
2003-12-01 11:25:41 +01:00
|
|
|
// for comparision.
|
|
|
|
previousNumber = node.pageNumber;
|
|
|
|
previousNode = node;
|
2012-01-26 08:01:45 +01:00
|
|
|
pointer = node.readNode(pointer, leafPage);
|
2004-09-24 02:11:32 +02:00
|
|
|
|
|
|
|
// Check if pointer is still valid
|
|
|
|
//if (pointer > endPointer) {
|
|
|
|
// BUGCHECK(204); // msg 204 index inconsistent
|
|
|
|
//}
|
|
|
|
|
2008-12-05 02:20:14 +01:00
|
|
|
// We're done if end level marker is reached or this
|
2003-12-01 11:25:41 +01:00
|
|
|
// isn't a equal node anymore.
|
2008-12-05 02:20:14 +01:00
|
|
|
if ((node.isEndLevel) ||
|
|
|
|
(node.length != 0) ||
|
2003-12-01 11:25:41 +01:00
|
|
|
(node.prefix != (previousNode.length + previousNode.prefix)))
|
|
|
|
{
|
|
|
|
return previousNumber;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// We never reach this point
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-01-26 08:01:45 +01:00
|
|
|
USHORT IndexJumpNode::getJumpNodeSize() const
|
2003-12-01 11:25:41 +01:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* g e t J u m p N o d e S i z e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2008-12-05 02:20:14 +01:00
|
|
|
* Return the size needed to store
|
2003-12-01 11:25:41 +01:00
|
|
|
* this node.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
USHORT result = 0;
|
2004-03-07 22:50:53 +01:00
|
|
|
|
2009-12-22 11:30:49 +01:00
|
|
|
// Size needed for prefix
|
2012-01-26 08:01:45 +01:00
|
|
|
USHORT number = prefix;
|
2009-12-22 11:30:49 +01:00
|
|
|
if (number & 0xC000) {
|
|
|
|
result += 3;
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
2009-12-22 11:30:49 +01:00
|
|
|
else if (number & 0xFF80) {
|
|
|
|
result += 2;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
result += 1;
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
2009-12-22 11:30:49 +01:00
|
|
|
|
|
|
|
// Size needed for length
|
2012-01-26 08:01:45 +01:00
|
|
|
number = length;
|
2009-12-22 11:30:49 +01:00
|
|
|
if (number & 0xC000) {
|
|
|
|
result += 3;
|
|
|
|
}
|
|
|
|
else if (number & 0xFF80) {
|
|
|
|
result += 2;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
result += 1;
|
|
|
|
}
|
|
|
|
|
2003-12-01 11:25:41 +01:00
|
|
|
// Size needed for offset
|
2004-02-25 23:14:19 +01:00
|
|
|
// NOTE! offset can be unknown when this function is called,
|
|
|
|
// therefor we can't use a compression method.
|
2003-12-01 11:25:41 +01:00
|
|
|
result += sizeof(USHORT);
|
|
|
|
// Size needed for data
|
2012-01-26 08:01:45 +01:00
|
|
|
result += length;
|
2003-12-01 11:25:41 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-01-26 08:01:45 +01:00
|
|
|
USHORT IndexNode::getNodeSize(bool leafNode) const
|
2003-12-01 11:25:41 +01:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* g e t N o d e S i z e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2008-12-05 02:20:14 +01:00
|
|
|
* Return the size needed to store
|
2003-12-01 11:25:41 +01:00
|
|
|
* this node.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
USHORT result = 0;
|
2004-02-25 23:14:19 +01:00
|
|
|
|
2009-12-22 11:30:49 +01:00
|
|
|
// Determine flags
|
|
|
|
UCHAR internalFlags = 0;
|
2012-01-26 08:01:45 +01:00
|
|
|
if (isEndLevel) {
|
2009-12-22 11:30:49 +01:00
|
|
|
internalFlags = BTN_END_LEVEL_FLAG;
|
|
|
|
}
|
2012-01-26 08:01:45 +01:00
|
|
|
else if (isEndBucket) {
|
2009-12-22 11:30:49 +01:00
|
|
|
internalFlags = BTN_END_BUCKET_FLAG;
|
|
|
|
}
|
2012-01-26 08:01:45 +01:00
|
|
|
else if (length == 0)
|
2009-12-22 11:30:49 +01:00
|
|
|
{
|
2012-01-26 08:01:45 +01:00
|
|
|
if (prefix == 0) {
|
2009-12-22 11:30:49 +01:00
|
|
|
internalFlags = BTN_ZERO_PREFIX_ZERO_LENGTH_FLAG;
|
2004-11-19 00:00:20 +01:00
|
|
|
}
|
2009-12-22 11:30:49 +01:00
|
|
|
else {
|
|
|
|
internalFlags = BTN_ZERO_LENGTH_FLAG;
|
2004-02-25 23:14:19 +01:00
|
|
|
}
|
2009-12-22 11:30:49 +01:00
|
|
|
}
|
2012-01-26 08:01:45 +01:00
|
|
|
else if (length == 1) {
|
2009-12-22 11:30:49 +01:00
|
|
|
internalFlags = BTN_ONE_LENGTH_FLAG;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Store internal flags + 5 bits from number
|
2012-01-26 08:01:45 +01:00
|
|
|
SINT64 number = recordNumber.getValue();
|
2009-12-22 11:30:49 +01:00
|
|
|
if (number < 0) {
|
|
|
|
number = 0;
|
|
|
|
}
|
|
|
|
result++;
|
|
|
|
// If this is a END_LEVEL marker then we're done
|
2012-01-26 08:01:45 +01:00
|
|
|
if (isEndLevel) {
|
2009-12-22 11:30:49 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
number >>= 5;
|
|
|
|
// Get size for storing remaining bits for number
|
|
|
|
// 5 bytes should be enough to fit remaining 34 bits of record number
|
|
|
|
if (number & QUADCONST(0xFFF0000000)) {
|
|
|
|
result += 5;
|
|
|
|
}
|
|
|
|
else if (number & QUADCONST(0xFFFFE00000)) {
|
|
|
|
result += 4;
|
|
|
|
}
|
|
|
|
else if (number & QUADCONST(0xFFFFFFC000)) {
|
|
|
|
result += 3;
|
|
|
|
}
|
|
|
|
else if (number & QUADCONST(0xFFFFFFFF80)) {
|
|
|
|
result += 2;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
result += 1;
|
|
|
|
}
|
2004-02-25 23:14:19 +01:00
|
|
|
|
2009-12-22 11:30:49 +01:00
|
|
|
if (!leafNode)
|
|
|
|
{
|
|
|
|
// Size needed for page number
|
2012-01-26 08:01:45 +01:00
|
|
|
number = pageNumber;
|
2004-02-25 23:14:19 +01:00
|
|
|
if (number < 0) {
|
|
|
|
number = 0;
|
|
|
|
}
|
|
|
|
|
2009-12-22 11:30:49 +01:00
|
|
|
if (number & 0xF0000000) {
|
2004-02-26 01:07:37 +01:00
|
|
|
result += 5;
|
2004-02-25 23:14:19 +01:00
|
|
|
}
|
2009-12-22 11:30:49 +01:00
|
|
|
else if (number & 0xFFE00000) {
|
2004-02-26 01:07:37 +01:00
|
|
|
result += 4;
|
|
|
|
}
|
2009-12-22 11:30:49 +01:00
|
|
|
else if (number & 0xFFFFC000) {
|
2004-02-26 01:07:37 +01:00
|
|
|
result += 3;
|
|
|
|
}
|
2009-12-22 11:30:49 +01:00
|
|
|
else if (number & 0xFFFFFF80) {
|
2004-02-26 01:07:37 +01:00
|
|
|
result += 2;
|
2004-02-25 23:14:19 +01:00
|
|
|
}
|
2004-02-26 01:07:37 +01:00
|
|
|
else {
|
|
|
|
result += 1;
|
|
|
|
}
|
2009-12-22 11:30:49 +01:00
|
|
|
}
|
2004-02-26 01:07:37 +01:00
|
|
|
|
2009-12-22 11:30:49 +01:00
|
|
|
if (internalFlags != BTN_ZERO_PREFIX_ZERO_LENGTH_FLAG)
|
|
|
|
{
|
|
|
|
// Size needed for prefix
|
2012-01-26 08:01:45 +01:00
|
|
|
number = prefix;
|
2009-12-22 11:30:49 +01:00
|
|
|
if (number & 0xFFFFC000) {
|
|
|
|
result += 3;
|
2004-02-25 23:14:19 +01:00
|
|
|
}
|
2009-12-22 11:30:49 +01:00
|
|
|
else if (number & 0xFFFFFF80) {
|
|
|
|
result += 2;
|
2004-11-19 00:00:20 +01:00
|
|
|
}
|
2009-12-22 11:30:49 +01:00
|
|
|
else {
|
|
|
|
result += 1;
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
|
|
|
}
|
2009-12-22 11:30:49 +01:00
|
|
|
|
|
|
|
if ((internalFlags != BTN_ZERO_PREFIX_ZERO_LENGTH_FLAG) &&
|
|
|
|
(internalFlags != BTN_ZERO_LENGTH_FLAG) &&
|
|
|
|
(internalFlags != BTN_ONE_LENGTH_FLAG))
|
2009-05-01 19:21:36 +02:00
|
|
|
{
|
2008-12-05 02:20:14 +01:00
|
|
|
// Size needed for length
|
2012-01-26 08:01:45 +01:00
|
|
|
number = length;
|
2009-12-22 11:30:49 +01:00
|
|
|
if (number & 0xFFFFC000) {
|
|
|
|
result += 3;
|
|
|
|
}
|
|
|
|
else if (number & 0xFFFFFF80) {
|
|
|
|
result += 2;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
result += 1;
|
2004-02-25 23:14:19 +01:00
|
|
|
}
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
|
|
|
|
2012-01-26 08:01:45 +01:00
|
|
|
result += length;
|
2003-12-01 11:25:41 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-01-26 08:01:45 +01:00
|
|
|
UCHAR* IndexJumpNode::readJumpNode(UCHAR* pagePointer)
|
2003-12-01 11:25:41 +01:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* r e a d J u m p N o d e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Read a jump node from the page by the
|
|
|
|
* given pagePointer and the return the
|
|
|
|
* remaining position after the read.
|
|
|
|
*
|
|
|
|
**************************************/
|
2012-01-26 08:01:45 +01:00
|
|
|
nodePointer = pagePointer;
|
2009-12-22 11:30:49 +01:00
|
|
|
|
|
|
|
// Get prefix
|
|
|
|
UCHAR tmp = *pagePointer++;
|
2012-01-26 08:01:45 +01:00
|
|
|
prefix = (tmp & 0x7F);
|
2009-12-22 11:30:49 +01:00
|
|
|
if (tmp & 0x80)
|
2009-05-01 19:21:36 +02:00
|
|
|
{
|
2006-01-26 11:45:02 +01:00
|
|
|
tmp = *pagePointer++;
|
2012-01-26 08:01:45 +01:00
|
|
|
prefix |= (tmp & 0x7F) << 7; // We get 14 bits at this point
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
2009-12-22 11:30:49 +01:00
|
|
|
|
|
|
|
// Get length
|
|
|
|
tmp = *pagePointer++;
|
2012-01-26 08:01:45 +01:00
|
|
|
length = (tmp & 0x7F);
|
2009-12-22 11:30:49 +01:00
|
|
|
if (tmp & 0x80)
|
2009-06-21 07:46:51 +02:00
|
|
|
{
|
2009-12-22 11:30:49 +01:00
|
|
|
tmp = *pagePointer++;
|
2012-01-26 08:01:45 +01:00
|
|
|
length |= (tmp & 0x7F) << 7; // We get 14 bits at this point
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
2009-12-22 11:30:49 +01:00
|
|
|
|
2012-01-26 08:01:45 +01:00
|
|
|
offset = get_short(pagePointer);
|
2003-12-01 11:25:41 +01:00
|
|
|
pagePointer += sizeof(USHORT);
|
2012-01-26 08:01:45 +01:00
|
|
|
data = pagePointer;
|
|
|
|
pagePointer += length;
|
2003-12-01 11:25:41 +01:00
|
|
|
return pagePointer;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-01-26 08:01:45 +01:00
|
|
|
UCHAR* IndexJumpNode::writeJumpNode(UCHAR* pagePointer)
|
2003-12-01 11:25:41 +01:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* w r i t e J u m p N o d e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Write jump information to the page by the
|
|
|
|
* given pointer.
|
|
|
|
*
|
|
|
|
**************************************/
|
2012-01-26 08:01:45 +01:00
|
|
|
nodePointer = pagePointer;
|
2004-02-25 23:14:19 +01:00
|
|
|
|
2009-12-22 11:30:49 +01:00
|
|
|
// Write prefix, maximum 14 bits
|
2012-01-26 08:01:45 +01:00
|
|
|
USHORT number = prefix;
|
2009-12-22 11:30:49 +01:00
|
|
|
UCHAR tmp = (number & 0x7F);
|
|
|
|
number >>= 7;
|
|
|
|
if (number > 0) {
|
|
|
|
tmp |= 0x80;
|
|
|
|
}
|
|
|
|
*pagePointer++ = tmp;
|
|
|
|
if (tmp & 0x80)
|
|
|
|
{
|
2004-02-25 23:14:19 +01:00
|
|
|
tmp = (number & 0x7F);
|
2006-01-26 11:45:02 +01:00
|
|
|
*pagePointer++ = tmp;
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
2009-12-22 11:30:49 +01:00
|
|
|
|
|
|
|
// Write length, maximum 14 bits
|
2012-01-26 08:01:45 +01:00
|
|
|
number = length;
|
2009-12-22 11:30:49 +01:00
|
|
|
tmp = (number & 0x7F);
|
|
|
|
number >>= 7;
|
|
|
|
if (number > 0) {
|
|
|
|
tmp |= 0x80;
|
|
|
|
}
|
|
|
|
*pagePointer++ = tmp;
|
|
|
|
if (tmp & 0x80)
|
2009-06-21 07:46:51 +02:00
|
|
|
{
|
2009-12-22 11:30:49 +01:00
|
|
|
tmp = (number & 0x7F);
|
|
|
|
*pagePointer++ = tmp;
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
2009-12-22 11:30:49 +01:00
|
|
|
|
2012-01-26 08:01:45 +01:00
|
|
|
put_short(pagePointer, offset);
|
2003-12-01 11:25:41 +01:00
|
|
|
pagePointer += sizeof(USHORT);
|
2012-01-26 08:01:45 +01:00
|
|
|
memmove(pagePointer, data, length);
|
|
|
|
pagePointer += length;
|
2003-12-01 11:25:41 +01:00
|
|
|
return pagePointer;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-01-26 08:01:45 +01:00
|
|
|
UCHAR* IndexNode::writeNode(UCHAR* pagePointer, bool leafNode, bool withData)
|
2003-12-01 11:25:41 +01:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* w r i t e N o d e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Write a leaf/page node to the page by the
|
|
|
|
* given page_pointer.
|
|
|
|
*
|
|
|
|
**************************************/
|
2012-01-26 08:01:45 +01:00
|
|
|
nodePointer = pagePointer;
|
2004-02-25 23:14:19 +01:00
|
|
|
|
2009-12-22 11:30:49 +01:00
|
|
|
// AB: 2004-02-22
|
|
|
|
// To allow as much as compression possible we
|
|
|
|
// store numbers per 7 bit and the 8-th bit tell us
|
|
|
|
// if we need to go on reading or we're done.
|
|
|
|
// Also for duplicate node entries (length and prefix
|
|
|
|
// are zero) we don't store the length and prefix
|
|
|
|
// information. This will save at least 2 bytes per node.
|
2004-02-25 23:14:19 +01:00
|
|
|
|
2009-12-22 11:30:49 +01:00
|
|
|
if (!withData)
|
|
|
|
{
|
|
|
|
// First move data so we can't override it.
|
|
|
|
// For older structure node was always the same, but length
|
|
|
|
// from new structure depends on the values.
|
2012-01-26 08:01:45 +01:00
|
|
|
const USHORT offset = getNodeSize(leafNode) - length;
|
2009-12-22 11:30:49 +01:00
|
|
|
pagePointer += offset; // set pointer to right position
|
2012-01-26 08:01:45 +01:00
|
|
|
memmove(pagePointer, data, length);
|
2009-12-22 11:30:49 +01:00
|
|
|
pagePointer -= offset; // restore pointer to original position
|
|
|
|
}
|
2004-09-24 02:11:32 +02:00
|
|
|
|
2009-12-22 11:30:49 +01:00
|
|
|
// Internal flags
|
|
|
|
UCHAR internalFlags = 0;
|
2012-01-26 08:01:45 +01:00
|
|
|
if (isEndLevel) {
|
2009-12-22 11:30:49 +01:00
|
|
|
internalFlags = BTN_END_LEVEL_FLAG;
|
|
|
|
}
|
2012-01-26 08:01:45 +01:00
|
|
|
else if (isEndBucket) {
|
2009-12-22 11:30:49 +01:00
|
|
|
internalFlags = BTN_END_BUCKET_FLAG;
|
|
|
|
}
|
2012-01-26 08:01:45 +01:00
|
|
|
else if (length == 0)
|
2009-12-22 11:30:49 +01:00
|
|
|
{
|
2012-01-26 08:01:45 +01:00
|
|
|
if (prefix == 0) {
|
2009-12-22 11:30:49 +01:00
|
|
|
internalFlags = BTN_ZERO_PREFIX_ZERO_LENGTH_FLAG;
|
2004-11-19 00:00:20 +01:00
|
|
|
}
|
2009-12-22 11:30:49 +01:00
|
|
|
else {
|
|
|
|
internalFlags = BTN_ZERO_LENGTH_FLAG;
|
2004-02-25 23:14:19 +01:00
|
|
|
}
|
2009-12-22 11:30:49 +01:00
|
|
|
}
|
2012-01-26 08:01:45 +01:00
|
|
|
else if (length == 1) {
|
2009-12-22 11:30:49 +01:00
|
|
|
internalFlags = BTN_ONE_LENGTH_FLAG;
|
|
|
|
}
|
2004-09-24 02:11:32 +02:00
|
|
|
|
2012-01-26 08:01:45 +01:00
|
|
|
SINT64 number = recordNumber.getValue();
|
2009-12-22 11:30:49 +01:00
|
|
|
if (number < 0) {
|
|
|
|
number = 0;
|
|
|
|
}
|
|
|
|
// Store internal flags + 6 bits from number
|
|
|
|
UCHAR tmp = internalFlags;
|
|
|
|
*pagePointer++ = ((tmp << 5) | (number & 0x1F));
|
2004-02-25 23:14:19 +01:00
|
|
|
|
2012-01-26 08:01:45 +01:00
|
|
|
if (isEndLevel) {
|
2009-12-22 11:30:49 +01:00
|
|
|
return pagePointer;
|
|
|
|
}
|
2004-11-19 00:00:20 +01:00
|
|
|
|
2009-12-22 11:30:49 +01:00
|
|
|
// Store remaining bits from number
|
|
|
|
number >>= 5;
|
|
|
|
tmp = (number & 0x7F);
|
|
|
|
number >>= 7; //12
|
|
|
|
if (number == 0) {
|
|
|
|
*pagePointer++ = tmp;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*pagePointer++ = tmp | 0x80;
|
2004-02-25 23:14:19 +01:00
|
|
|
tmp = (number & 0x7F);
|
2009-12-22 11:30:49 +01:00
|
|
|
number >>= 7; //19
|
2004-11-19 00:00:20 +01:00
|
|
|
if (number == 0) {
|
|
|
|
*pagePointer++ = tmp;
|
2004-02-25 23:14:19 +01:00
|
|
|
}
|
2009-05-01 19:21:36 +02:00
|
|
|
else
|
|
|
|
{
|
2004-11-19 00:00:20 +01:00
|
|
|
*pagePointer++ = tmp | 0x80;
|
2004-02-25 23:14:19 +01:00
|
|
|
tmp = (number & 0x7F);
|
2009-12-22 11:30:49 +01:00
|
|
|
number >>= 7; //26
|
2004-11-19 00:00:20 +01:00
|
|
|
if (number == 0) {
|
|
|
|
*pagePointer++ = tmp;
|
2004-02-25 23:14:19 +01:00
|
|
|
}
|
2009-05-01 19:21:36 +02:00
|
|
|
else
|
|
|
|
{
|
2004-11-19 00:00:20 +01:00
|
|
|
*pagePointer++ = tmp | 0x80;
|
2004-02-25 23:14:19 +01:00
|
|
|
tmp = (number & 0x7F);
|
2009-12-22 11:30:49 +01:00
|
|
|
number >>= 7; //33
|
2004-11-19 00:00:20 +01:00
|
|
|
if (number == 0) {
|
|
|
|
*pagePointer++ = tmp;
|
2004-02-25 23:14:19 +01:00
|
|
|
}
|
2009-05-01 19:21:36 +02:00
|
|
|
else
|
|
|
|
{
|
2004-11-19 00:00:20 +01:00
|
|
|
*pagePointer++ = tmp | 0x80;
|
2004-02-25 23:14:19 +01:00
|
|
|
tmp = (number & 0x7F);
|
2009-12-22 11:30:49 +01:00
|
|
|
number >>= 7; //40
|
2004-11-19 00:00:20 +01:00
|
|
|
if (number == 0) {
|
|
|
|
*pagePointer++ = tmp;
|
2004-02-25 23:14:19 +01:00
|
|
|
}
|
2008-12-05 02:20:14 +01:00
|
|
|
/*
|
2004-11-19 00:00:20 +01:00
|
|
|
Enable this if you need more bits in record number
|
2009-05-01 19:21:36 +02:00
|
|
|
else
|
|
|
|
{
|
2004-11-19 00:00:20 +01:00
|
|
|
*pagePointer++ = tmp | 0x80;
|
2004-02-25 23:14:19 +01:00
|
|
|
tmp = (number & 0x7F);
|
2004-11-19 00:00:20 +01:00
|
|
|
number >>= 7; //47
|
|
|
|
if (number == 0) {
|
|
|
|
*pagePointer++ = tmp;
|
2004-02-25 23:14:19 +01:00
|
|
|
}
|
2009-05-01 19:21:36 +02:00
|
|
|
else
|
|
|
|
{
|
2004-11-19 00:00:20 +01:00
|
|
|
*pagePointer++ = tmp | 0x80;
|
2004-02-25 23:14:19 +01:00
|
|
|
tmp = (number & 0x7F);
|
2004-11-19 00:00:20 +01:00
|
|
|
number >>= 7; //54
|
|
|
|
if (number == 0) {
|
|
|
|
*pagePointer++ = tmp;
|
2004-02-25 23:14:19 +01:00
|
|
|
}
|
2009-05-01 19:21:36 +02:00
|
|
|
else
|
|
|
|
{
|
2004-11-19 00:00:20 +01:00
|
|
|
*pagePointer++ = tmp | 0x80;
|
2004-02-25 23:14:19 +01:00
|
|
|
tmp = (number & 0x7F);
|
2004-11-19 00:00:20 +01:00
|
|
|
number >>= 7; //61
|
|
|
|
if (number == 0) {
|
|
|
|
*pagePointer++ = tmp;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// ....
|
|
|
|
}
|
2004-02-25 23:14:19 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2004-11-19 00:00:20 +01:00
|
|
|
*/
|
2004-02-25 23:14:19 +01:00
|
|
|
}
|
|
|
|
}
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
2009-12-22 11:30:49 +01:00
|
|
|
}
|
2004-02-25 23:14:19 +01:00
|
|
|
|
2009-12-22 11:30:49 +01:00
|
|
|
if (!leafNode)
|
|
|
|
{
|
|
|
|
// Store page number for non-leaf pages
|
2012-01-26 08:01:45 +01:00
|
|
|
number = pageNumber;
|
2009-12-22 11:30:49 +01:00
|
|
|
if (number < 0) {
|
|
|
|
number = 0;
|
|
|
|
}
|
|
|
|
tmp = (number & 0x7F);
|
|
|
|
number >>= 7;
|
|
|
|
if (number > 0) {
|
|
|
|
tmp |= 0x80;
|
|
|
|
}
|
|
|
|
*pagePointer++ = tmp;
|
|
|
|
if (number > 0)
|
2009-05-01 19:21:36 +02:00
|
|
|
{
|
2004-02-25 23:14:19 +01:00
|
|
|
tmp = (number & 0x7F);
|
2009-12-22 11:30:49 +01:00
|
|
|
number >>= 7; //14
|
2004-02-25 23:14:19 +01:00
|
|
|
if (number > 0) {
|
|
|
|
tmp |= 0x80;
|
|
|
|
}
|
2006-01-26 11:45:02 +01:00
|
|
|
*pagePointer++ = tmp;
|
2009-05-01 19:21:36 +02:00
|
|
|
if (number > 0)
|
|
|
|
{
|
2004-02-25 23:14:19 +01:00
|
|
|
tmp = (number & 0x7F);
|
2009-12-22 11:30:49 +01:00
|
|
|
number >>= 7; //21
|
2004-02-25 23:14:19 +01:00
|
|
|
if (number > 0) {
|
|
|
|
tmp |= 0x80;
|
|
|
|
}
|
2006-01-26 11:45:02 +01:00
|
|
|
*pagePointer++ = tmp;
|
2009-05-01 19:21:36 +02:00
|
|
|
if (number > 0)
|
|
|
|
{
|
2004-02-25 23:14:19 +01:00
|
|
|
tmp = (number & 0x7F);
|
2009-12-22 11:30:49 +01:00
|
|
|
number >>= 7; //28
|
2004-02-25 23:14:19 +01:00
|
|
|
if (number > 0) {
|
|
|
|
tmp |= 0x80;
|
|
|
|
}
|
2006-01-26 11:45:02 +01:00
|
|
|
*pagePointer++ = tmp;
|
2009-05-01 19:21:36 +02:00
|
|
|
if (number > 0)
|
|
|
|
{
|
2009-12-22 11:30:49 +01:00
|
|
|
tmp = (number & 0x0F);
|
|
|
|
number >>= 7; //35
|
2006-01-26 11:45:02 +01:00
|
|
|
*pagePointer++ = tmp;
|
2004-02-25 23:14:19 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
2009-12-22 11:30:49 +01:00
|
|
|
}
|
2004-02-25 23:14:19 +01:00
|
|
|
|
2009-12-22 11:30:49 +01:00
|
|
|
if (internalFlags != BTN_ZERO_PREFIX_ZERO_LENGTH_FLAG)
|
|
|
|
{
|
|
|
|
// Write prefix, maximum 14 bits
|
2012-01-26 08:01:45 +01:00
|
|
|
number = prefix;
|
2009-12-22 11:30:49 +01:00
|
|
|
tmp = (number & 0x7F);
|
|
|
|
number >>= 7;
|
|
|
|
if (number > 0) {
|
|
|
|
tmp |= 0x80;
|
2004-11-19 00:00:20 +01:00
|
|
|
}
|
2009-12-22 11:30:49 +01:00
|
|
|
*pagePointer++ = tmp;
|
|
|
|
if (number > 0)
|
2004-11-19 00:00:20 +01:00
|
|
|
{
|
2004-02-25 23:14:19 +01:00
|
|
|
tmp = (number & 0x7F);
|
2006-01-26 11:45:02 +01:00
|
|
|
*pagePointer++ = tmp;
|
2008-12-05 02:20:14 +01:00
|
|
|
}
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
2006-01-26 11:45:02 +01:00
|
|
|
|
2009-12-22 11:30:49 +01:00
|
|
|
if ((internalFlags != BTN_ZERO_PREFIX_ZERO_LENGTH_FLAG) &&
|
|
|
|
(internalFlags != BTN_ZERO_LENGTH_FLAG) &&
|
|
|
|
(internalFlags != BTN_ONE_LENGTH_FLAG))
|
|
|
|
{
|
|
|
|
// Write length, maximum 14 bits
|
2012-01-26 08:01:45 +01:00
|
|
|
number = length;
|
2009-12-22 11:30:49 +01:00
|
|
|
tmp = (number & 0x7F);
|
|
|
|
number >>= 7;
|
|
|
|
if (number > 0) {
|
|
|
|
tmp |= 0x80;
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
2009-12-22 11:30:49 +01:00
|
|
|
*pagePointer++ = tmp;
|
|
|
|
if (number > 0)
|
2009-05-01 19:21:36 +02:00
|
|
|
{
|
2009-12-22 11:30:49 +01:00
|
|
|
tmp = (number & 0x7F);
|
|
|
|
*pagePointer++ = tmp;
|
2004-02-25 23:14:19 +01:00
|
|
|
}
|
2009-12-22 11:30:49 +01:00
|
|
|
}
|
2004-02-25 23:14:19 +01:00
|
|
|
|
2009-12-22 11:30:49 +01:00
|
|
|
// Store data
|
|
|
|
if (withData) {
|
2012-01-26 08:01:45 +01:00
|
|
|
memcpy(pagePointer, data, length);
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
2012-01-26 08:01:45 +01:00
|
|
|
pagePointer += length;
|
2003-12-01 11:25:41 +01:00
|
|
|
|
|
|
|
return pagePointer;
|
|
|
|
}
|