blob: 186c097c2b4db060420e1ec3f8358ecf63bde8aa [file] [log] [blame]
/**********************************************************************
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
**********************************************************************/
/* -*-C++-*-
******************************************************************************
*
* File: ExBitMapTable.cpp
* RCS: $Id
* Description: ExBitMapTable class Implementation
* Created: 7/1/97
* Modified: $Author
* Language: C++
* Status: $State
*
*
*
*
******************************************************************************
*/
// ExBitMapTable.cpp - Implementation for the ExBitMapTable class.
//
// Includes
//
#include "ex_ex.h"
#include "ExBitMapTable.h"
// ExBitMapTable::ExBitMapTable
//
// Constructs an ExBitMapTable.
//
// IN : keySize - The size of the key in bytes.
// IN : dataSize - The size of a data row in bytes.
// IN : memSize - The amount of memory requested for the table.
// IN : heap - The memory allocator.
// EFFECTS: Constructs an ExBitMapTable object.
//
ExBitMapTable::ExBitMapTable(Int32 keySize, Int32 dataSize, Int32 countOffset,
Int32 memSize, CollHeap *heap)
: keySize_(keySize), dataSize_(dataSize), countOffset_(countOffset),
memSize_(memSize),
// row layout:
// data:
// key:
// filler: so nextPtr could be aligned at 4
// next ptr:
// total length a multiple of 8 so row could be aligned.
rowSize_(ROUND8(dataSize_ + ROUND4(keySize) + sizeof(char *))),
heap_(heap), memory_(NULL), maximumNumberGroups_(0),
numberHashBuckets_(0), numberGroups_(0), returnGroup_(0),
buckets_(0), groups_(0)
{
// Attempt to allocate the requested memory. If that fails, try to at
// least allocate enough memory for a few tuples. Otherwise, simply
// return and the caller will check getMaximumNumberTuples and realize
// that the table cannot store any tuples.
//
// Memory layout
//
// Hash Bucket Pointer Array - NumberHashBuckets
// [sizeof(void*)] - pointer to first group in bucket 0
// [sizeof(void*)] - pointer to first group in bucket 1
// . . .
// [sizeof(void*)] - pointer to first group in bucket NumberHashBuckets-1
// Group Memory - NumberGroups
// [rowSize] - data, key, and next for group 0
// [rowSize] - data, key, and next for group 1
// [rowSize] - data, key, and next for group NumberGroups-1
//
const Int32 minimumMemorySize = 32 * (sizeof(char*) + rowSize_);
memSize_ *= 2;
while(!memory_ && (memSize_ >= 2 * minimumMemorySize)) {
memSize_ /= 2;
memory_ = (char *)heap_->allocateMemory((size_t) memSize_, FALSE);
}
if(!memory_)
{
return;
}
// Save room for as many hash buckets as there are groups.
//
numberHashBuckets_ = ROUND2(memSize_ / (sizeof(char*) + rowSize_));
// Compute the maximum number of groups that can be stored in the table.
//
maximumNumberGroups_ = (memSize_ - sizeof(char*) * numberHashBuckets_)
/ rowSize_;
// The buckets
// BitMap at memory_. To start there is only one BitMap.
//
buckets_ = (char**)memory_;
groups_ = memory_ + sizeof(char*) * numberHashBuckets_;
// Initialize the hash buckets.
//
for(Int32 i=0; i<numberHashBuckets_; i++)
buckets_[i] = 0;
}
// ExBitMapTable::~ExBitMapTable
//
// Destructs an ExBitMapTable.
//
// EFFECTS: Destructs an ExBitMapTable object. Releases the memory
// allocated in the constructor and sets the referencing
// pointer to NULL.
//
ExBitMapTable::~ExBitMapTable() {
if(memory_) heap_->deallocateMemory(memory_);
memory_ = NULL;
}
// ExBitMapTable::reset
//
// Resets an ExBitMapTable
//
// EFFECTS: Resets all of the bitmaps and number of groups in the table.
//
void ExBitMapTable::reset() {
// Initialize the hash buckets_.
//
for(Int32 i=0; i<numberHashBuckets_; i++)
buckets_[i] = 0;
// Reset the number of groups.
//
numberGroups_ = 0;
// Also reset the return group.
//
returnGroup_ = 0;
}
// ExBitMapTable::findOrAdd
//
// Attemps to find an existing group in the table with the same key
// as _key_. If a group cannot be found, attempts to add a new group
// to the table given sufficient memory resources. Sets the member data_
// to reference the found or added group, or NULL if no match.
//
// IN : key - Pointer to the key for incoming group.
// EFFECTS: A group may be added to the table. The member data_ points
// to the matching group.
//
Int32 ExBitMapTable::findOrAdd(char *key) {
unsigned char *ukey = (unsigned char*)key;
// Compute the hash
//
UInt32 hash = 0;
Int32 i=0;
for(; i<keySize_; i++)
{
hash ^= ukey[i];
hash <<= 3;
}
hash = hash % numberHashBuckets_;
// If the bucket is empty, try to add a new group.
//
char *row = buckets_[hash];
if(!row)
{
// If no more groups can be added, return 0.
//
if(numberGroups_ >= maximumNumberGroups_) return 0;
// Set data_ and the bucket to point to the new group and
// increment the number of groups.
//
data_ = buckets_[hash] = getGroup(numberGroups_++);
// Initialize the key
//
row = getKey(data_);
for(i=0; i<keySize_; i++)
row[i] = key[i];
// Initialize the next pointer
//
*getNextPtr(data_) = 0;
// Initialize any table aggregates.
//
initAggregates();
applyAggregates();
// Return -1 to indicate that a new group was added. The
// initialization is done externally.
//
return -1;
}
char *lastRow;
while(row)
{
lastRow = row;
// Test for matching keys.
//
Int32 match = 1;
row = getKey(lastRow);
for(i=0; match && i<keySize_; i++)
if(row[i] != key[i]) match = 0;
// If a matching row is found, set data_ to point to it and
// return 0 to indicate a match.
//
if(match)
{
data_ = lastRow;
// Apply any table aggregates.
//
applyAggregates();
// Return 1 to indicate the group was matched/added.
//
return 1;
}
// Get the pointer to the next row in this hash chain.
//
row = *getNextPtr(lastRow);
}
// No matching groups were found so try to add another group.
//
// If no more groups can be added, return 0.
//
if(numberGroups_ >= maximumNumberGroups_) return 0;
// Set data_ and the next row pointer to point to the new group and
// increment the number of groups.
//
*getNextPtr(lastRow) = data_ = getGroup(numberGroups_++);
// Initialize the key
//
row = getKey(data_);
for(i=0; i<keySize_; i++)
row[i] = key[i];
// Initialize the next pointer
//
*getNextPtr(data_) = 0;
// Initialize any table aggregates.
//
initAggregates();
applyAggregates();
// Return -1 to indicate that a new group was added. The
// initialization is done externally.
//
return -1;
}