8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-23 10:03:03 +01:00

Backport from master:

Optimized hash function for lock manager and hash join
Notes:
- lock print extension is not backported
- Alex, please review linux build. I did not include changes in builds/posix/make.rules here as i'm not sure it is required
This commit is contained in:
hvlad 2016-12-30 02:11:24 +02:00
parent 8ca97fb718
commit 52d9a05a0f
15 changed files with 261 additions and 88 deletions

View File

@ -25,3 +25,8 @@ WARN_FLAGS=-Wall -Wno-switch -Wno-parentheses -Wno-unknown-pragmas -Wno-unused-v
PROD_FLAGS=$(COMMON_FLAGS) $(OPTIMIZE_FLAGS)
#DEV_FLAGS=-DUSE_VALGRIND -p $(COMMON_FLAGS) $(WARN_FLAGS)
DEV_FLAGS=-p $(COMMON_FLAGS) $(WARN_FLAGS)
# This file must be compiled with SSE4.2 support
%/CRC32C.o: COMMON_FLAGS += -msse4
CXXFLAGS := $(CXXFLAGS) -std=c++11

View File

@ -25,3 +25,8 @@ WARN_FLAGS=-Wall -Wno-switch -Wno-parentheses -Wno-unknown-pragmas -Wno-unused-v
PROD_FLAGS=$(COMMON_FLAGS) $(OPTIMIZE_FLAGS)
#DEV_FLAGS=-DUSE_VALGRIND $(COMMON_FLAGS) $(WARN_FLAGS) -fmax-errors=8
DEV_FLAGS=$(COMMON_FLAGS) $(WARN_FLAGS) -fmax-errors=8
# This file must be compiled with SSE4.2 support
%/CRC32C.o: COMMON_FLAGS += -msse4
CXXFLAGS := $(CXXFLAGS) -std=c++11

View File

@ -30,6 +30,7 @@
<ClCompile Include="..\..\..\src\common\classes\ClumpletWriter.cpp" />
<ClCompile Include="..\..\..\src\common\classes\DbImplementation.cpp" />
<ClCompile Include="..\..\..\src\common\classes\fb_string.cpp" />
<ClCompile Include="..\..\..\src\common\classes\Hash.cpp" />
<ClCompile Include="..\..\..\src\common\classes\ImplementHelper.cpp" />
<ClCompile Include="..\..\..\src\common\classes\init.cpp" />
<ClCompile Include="..\..\..\src\common\classes\InternalMessageBuffer.cpp" />
@ -49,6 +50,16 @@
<ClCompile Include="..\..\..\src\common\config\ConfigCache.cpp" />
<ClCompile Include="..\..\..\src\common\config\config_file.cpp" />
<ClCompile Include="..\..\..\src\common\config\dir_list.cpp" />
<ClCompile Include="..\..\..\src\common\CRC32C.cpp">
<IntrinsicFunctions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</IntrinsicFunctions>
<IntrinsicFunctions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</IntrinsicFunctions>
<IntrinsicFunctions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</IntrinsicFunctions>
<IntrinsicFunctions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</IntrinsicFunctions>
<DebugInformationFormat Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">ProgramDatabase</DebugInformationFormat>
<DebugInformationFormat Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">ProgramDatabase</DebugInformationFormat>
<DebugInformationFormat Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">ProgramDatabase</DebugInformationFormat>
<DebugInformationFormat Condition="'$(Configuration)|$(Platform)'=='Release|x64'">ProgramDatabase</DebugInformationFormat>
</ClCompile>
<ClCompile Include="..\..\..\src\common\cvt.cpp" />
<ClCompile Include="..\..\..\src\common\db_alias.cpp" />
<ClCompile Include="..\..\..\src\common\dllinst.cpp" />

View File

@ -210,6 +210,12 @@
<ClCompile Include="..\..\..\src\common\Tokens.cpp">
<Filter>common</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\common\classes\Hash.cpp">
<Filter>classes</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\common\CRC32C.cpp">
<Filter>classes</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\src\common\xdr_proto.h">

View File

@ -30,6 +30,7 @@
<ClCompile Include="..\..\..\src\common\classes\ClumpletWriter.cpp" />
<ClCompile Include="..\..\..\src\common\classes\DbImplementation.cpp" />
<ClCompile Include="..\..\..\src\common\classes\fb_string.cpp" />
<ClCompile Include="..\..\..\src\common\classes\Hash.cpp" />
<ClCompile Include="..\..\..\src\common\classes\ImplementHelper.cpp" />
<ClCompile Include="..\..\..\src\common\classes\init.cpp" />
<ClCompile Include="..\..\..\src\common\classes\InternalMessageBuffer.cpp" />
@ -49,6 +50,12 @@
<ClCompile Include="..\..\..\src\common\config\ConfigCache.cpp" />
<ClCompile Include="..\..\..\src\common\config\config_file.cpp" />
<ClCompile Include="..\..\..\src\common\config\dir_list.cpp" />
<ClCompile Include="..\..\..\src\common\CRC32C.cpp">
<IntrinsicFunctions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</IntrinsicFunctions>
<EnableEnhancedInstructionSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
<IntrinsicFunctions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</IntrinsicFunctions>
<EnableEnhancedInstructionSet Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
</ClCompile>
<ClCompile Include="..\..\..\src\common\cvt.cpp" />
<ClCompile Include="..\..\..\src\common\db_alias.cpp" />
<ClCompile Include="..\..\..\src\common\dllinst.cpp" />

View File

@ -210,6 +210,12 @@
<ClCompile Include="..\..\..\src\common\Tokens.cpp">
<Filter>common</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\common\classes\Hash.cpp">
<Filter>classes</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\common\CRC32C.cpp">
<Filter>common</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\src\common\xdr_proto.h">

68
src/common/CRC32C.cpp Normal file
View File

@ -0,0 +1,68 @@
/*
* PROGRAM: Common Library
* MODULE: CRC32C.cpp
* DESCRIPTION: Hardware-accelerated hash calculation
*
* 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 Sibiryakov
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2015 Dmitry Sibiryakov
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
*/
#include "firebird.h"
// Can be used only on x86 architectures
// WARNING: With GCC must be compiled separately with -msse4.2 flag
#if defined(_M_IX86) || defined(_M_X64) || defined(__x86_64__) || defined(__i386__)
#include <nmmintrin.h>
unsigned int CRC32C(unsigned int length, const unsigned char* value)
{
unsigned int hash_value = 0;
if (length == 1)
return _mm_crc32_u8(hash_value, *value);
if (length == 2)
return _mm_crc32_u16(hash_value, *(unsigned short*) value);
while (length >= 4)
{
hash_value = _mm_crc32_u32(hash_value, *(unsigned int*) value);
value += 4;
length -= 4;
}
if (length >= 2)
{
hash_value = _mm_crc32_u16(hash_value, *(unsigned short*) value);
value += 2;
length -= 2;
}
if (length)
{
hash_value = _mm_crc32_u8(hash_value, *value);
}
return hash_value;
}
#endif // architecture check

113
src/common/classes/Hash.cpp Normal file
View File

@ -0,0 +1,113 @@
/*
* PROGRAM: Common Library
* MODULE: Hash.cpp
* DESCRIPTION: Hash of data
*
* 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.
*
* The Original Code was created by Dmitry Sibiryakov
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2015 Dmitry Sibiryakov
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
*/
#include "firebird.h"
#include "../common/classes/Hash.h"
#if defined(_M_IX86) || defined(_M_X64) || defined(__x86_64__) || defined(__i386__)
#ifdef _MSC_VER
#include <intrin.h>
#else
#include <cpuid.h>
#endif
#endif
using namespace Firebird;
unsigned int CRC32C(unsigned int length, const unsigned char* value);
namespace
{
typedef unsigned int (*hash_func_t)(unsigned int length, const UCHAR* value);
unsigned int basicHash(unsigned int length, const UCHAR* value)
{
unsigned int hash_value = 0;
UCHAR* p;
const UCHAR* q = value;
while (length >= 4)
{
p = (UCHAR*) &hash_value;
p[0] += q[0];
p[1] += q[1];
p[2] += q[2];
p[3] += q[3];
length -= 4;
q += 4;
}
p = (UCHAR*) &hash_value;
if (length >= 2)
{
p[0] += q[0];
p[1] += q[1];
length -= 2;
}
if (length)
{
q += 2;
*p += *q;
}
return hash_value;
}
#if defined(_M_IX86) || defined(_M_X64) || defined(__x86_64__) || defined(__i386__)
bool SSE4_2Supported()
{
#ifdef _MSC_VER
const int bit_SSE4_2 = 1 << 20;
// MS VC has its own definition of __cpuid
int flags[4];
__cpuid(flags, 1);
return (flags[2] & bit_SSE4_2) != 0;
#else
#if defined(__clang__) && !defined(bit_SSE4_2)
const int bit_SSE4_2 = bit_SSE42;
#endif
// GCC - its own
unsigned int eax,ebx,ecx,edx;
__cpuid(1, eax, ebx, ecx, edx);
return (ecx & bit_SSE4_2) != 0;
#endif
}
hash_func_t internalHash = SSE4_2Supported() ? CRC32C : basicHash;
#else // architecture check
hash_func_t internalHash = basicHash;
#endif // architecture check
}
unsigned int InternalHash::hash(unsigned int length, const UCHAR* value)
{
return internalHash(length, value);
}

View File

@ -41,7 +41,7 @@ namespace Firebird
size_t sum = 0;
size_t val;
const char* data = static_cast<const char*>(value);
const UCHAR* data = static_cast<const UCHAR*>(value);
while (length >= sizeof(size_t))
{
@ -72,7 +72,6 @@ namespace Firebird
{
return hash(&value, sizeof value, hashSize);
}
};
const FB_SIZE_T DEFAULT_HASH_SIZE = 97; // largest prime number < 100
@ -82,7 +81,7 @@ namespace Firebird
typename K = C, // default key
typename KeyOfValue = DefaultKeyValue<C>, // default keygen
typename F = DefaultHash<K> > // hash function definition
class Hash
class HashTable
{
public:
// This class is supposed to be used as a BASE class for class to be hashed
@ -156,22 +155,22 @@ namespace Firebird
}; // class Entry
private:
Hash(const Hash&); // not implemented
HashTable(const HashTable&); // not implemented
public:
explicit Hash(MemoryPool&)
explicit HashTable(MemoryPool&)
: duplicates(false)
{
clean();
}
Hash()
HashTable()
: duplicates(false)
{
clean();
}
~Hash()
~HashTable()
{
// by default we let hash entries be cleaned by someone else
cleanup(NULL);
@ -255,7 +254,7 @@ namespace Firebird
private:
// disable use of default operator=
Hash& operator= (const Hash&);
HashTable& operator= (const HashTable&);
void clean()
{
@ -266,7 +265,7 @@ namespace Firebird
class iterator
{
private:
const Hash* hash;
const HashTable* hash;
FB_SIZE_T elem;
Entry* current;
@ -286,7 +285,7 @@ namespace Firebird
}
public:
explicit iterator(const Hash& h)
explicit iterator(const HashTable& h)
: hash(&h), elem(0), current(hash->data[elem])
{
next();
@ -329,7 +328,18 @@ namespace Firebird
return !(*this == h);
}
}; // class iterator
}; // class Hash
}; // class HashTable
class InternalHash
{
public:
static unsigned int hash(unsigned int length, const UCHAR* value);
static unsigned int hash(unsigned int length, const UCHAR* value, unsigned int hashSize)
{
return hash(length, value) % hashSize;
}
};
} // namespace Firebird

View File

@ -183,7 +183,7 @@ namespace
struct DbName;
#ifdef HAVE_ID_BY_NAME
struct Id;
typedef Hash<Id, 127, UCharBuffer, BinHash<Id>, BinHash<Id> > IdHash;
typedef HashTable<Id, 127, UCharBuffer, BinHash<Id>, BinHash<Id> > IdHash;
struct Id : public IdHash::Entry
{
@ -206,7 +206,7 @@ namespace
};
#endif
typedef Hash<DbName, 127, PathName, PathHash<DbName>, PathHash<DbName> > DbHash;
typedef HashTable<DbName, 127, PathName, PathHash<DbName>, PathHash<DbName> > DbHash;
struct DbName : public DbHash::Entry
{
DbName(MemoryPool& p, const PathName& db)
@ -234,7 +234,7 @@ namespace
};
struct AliasName;
typedef Hash<AliasName, 251, PathName, PathHash<AliasName>, PathHash<AliasName> > AliasHash;
typedef HashTable<AliasName, 251, PathName, PathHash<AliasName>, PathHash<AliasName> > AliasHash;
struct AliasName : public AliasHash::Entry
{

View File

@ -146,7 +146,7 @@ private:
};
class Map;
typedef Hash<Map, DEFAULT_HASH_SIZE, Map, DefaultKeyValue<Map>, Map> MapHash;
typedef HashTable<Map, DEFAULT_HASH_SIZE, Map, DefaultKeyValue<Map>, Map> MapHash;
class Map : public MapHash::Entry, public GlobalStorage
{

View File

@ -150,7 +150,7 @@ using namespace Firebird;
namespace Jrd {
typedef Hash<
typedef HashTable<
DeferredWork,
DEFAULT_HASH_SIZE,
DeferredWork,
@ -308,7 +308,7 @@ public:
class DfwSavePoint;
typedef Hash<
typedef HashTable<
DfwSavePoint,
DEFAULT_HASH_SIZE,
SavNumber,

View File

@ -28,6 +28,7 @@
#include "firebird.h"
#include <stdio.h>
#include "../common/classes/Hash.h"
#include "../jrd/jrd.h"
#include "../jrd/lck.h"
#include "gen/iberror.h"
@ -59,7 +60,6 @@ static void bug_lck(const TEXT*);
static bool compatible(const Lock*, const Lock*, USHORT);
static void enqueue(thread_db*, CheckStatusWrapper*, Lock*, USHORT, SSHORT);
static int external_ast(void*);
static USHORT hash_func(const UCHAR*, USHORT);
static void hash_allocate(Lock*);
static Lock* hash_get_lock(Lock*, USHORT*, Lock***);
static void hash_insert_lock(Lock*);
@ -977,38 +977,6 @@ static int external_ast(void* lock_void)
}
static USHORT hash_func(const UCHAR* value, USHORT length)
{
/**************************************
*
* h a s h
*
**************************************
*
* Functional description
* Provide a repeatable hash value based
* on the passed key.
*
**************************************/
// Hash the value, preserving its distribution as much as possible
ULONG hash_value = 0;
UCHAR* p = 0;
const UCHAR* q = value;
for (USHORT l = 0; l < length; l++)
{
if (!(l & 3))
p = (UCHAR*) &hash_value;
*p++ += *q++;
}
return (USHORT) (hash_value % LOCK_HASH_SIZE);
}
static void hash_allocate(Lock* lock)
{
/**************************************
@ -1059,7 +1027,8 @@ static Lock* hash_get_lock(Lock* lock, USHORT* hash_slot, Lock*** prior)
if (!att->att_compatibility_table)
hash_allocate(lock);
const USHORT hash_value = hash_func(lock->getKeyString(), lock->lck_length);
const USHORT hash_value =
(USHORT) InternalHash::hash(lock->lck_length, lock->getKeyString(), LOCK_HASH_SIZE);
if (hash_slot)
*hash_slot = hash_value;

View File

@ -21,6 +21,7 @@
*/
#include "firebird.h"
#include "../common/classes/Hash.h"
#include "../jrd/jrd.h"
#include "../jrd/btr.h"
#include "../jrd/req.h"
@ -249,7 +250,7 @@ class HashJoin::HashTable : public PermanentStorage
};
public:
HashTable(MemoryPool& pool, size_t streamCount, size_t tableSize = HASH_SIZE)
HashTable(MemoryPool& pool, size_t streamCount, unsigned int tableSize = HASH_SIZE)
: PermanentStorage(pool), m_streamCount(streamCount),
m_tableSize(tableSize), m_slot(0)
{
@ -265,28 +266,12 @@ public:
delete[] m_collisions;
}
size_t hash(ULONG length, const UCHAR* buffer) const
{
ULONG hash_value = 0;
UCHAR* p = NULL;
const UCHAR* q = buffer;
for (size_t l = 0; l < length; l++)
{
if (!(l & 3))
p = (UCHAR*) &hash_value;
*p++ += *q++;
}
return (hash_value % m_tableSize);
}
void put(size_t stream,
ULONG keyLength, const KeyBuffer* keyBuffer,
ULONG offset, ULONG position)
{
const size_t slot = hash(keyLength, keyBuffer->begin() + offset);
const unsigned int slot =
InternalHash::hash(keyLength, keyBuffer->begin() + offset, m_tableSize);
fb_assert(stream < m_streamCount);
fb_assert(slot < m_tableSize);
@ -304,7 +289,7 @@ public:
bool setup(ULONG length, const UCHAR* data)
{
const size_t slot = hash(length, data);
const unsigned int slot = InternalHash::hash(length, data, m_tableSize);
for (size_t i = 0; i < m_streamCount; i++)
{
@ -350,7 +335,7 @@ public:
private:
const size_t m_streamCount;
const size_t m_tableSize;
const unsigned int m_tableSize;
CollisionList** m_collisions;
size_t m_slot;
};

View File

@ -51,6 +51,7 @@
#include "../common/isc_s_proto.h"
#include "../common/config/config.h"
#include "../common/classes/array.h"
#include "../common/classes/Hash.h"
#include "../common/classes/semaphore.h"
#include "../common/classes/init.h"
#include "../common/classes/timestamp.h"
@ -2087,7 +2088,6 @@ void LockManager::debug_delay(ULONG lineno)
}
#endif
lbl* LockManager::find_lock(USHORT series,
const UCHAR* value,
USHORT length,
@ -2107,23 +2107,11 @@ lbl* LockManager::find_lock(USHORT series,
*
**************************************/
// Hash the value preserving its distribution as much as possible
ULONG hash_value = 0;
{ // scope
UCHAR* p = NULL; // silence uninitialized warning
const UCHAR* q = value;
for (USHORT l = 0; l < length; l++)
{
if (!(l & 3))
p = (UCHAR*) &hash_value;
*p++ += *q++;
}
} // scope
// See if the lock already exists
const USHORT hash_slot = *slot = (USHORT) (hash_value % m_sharedMemory->getHeader()->lhb_hash_slots);
const USHORT hash_slot = *slot =
(USHORT) InternalHash::hash(length, value, m_sharedMemory->getHeader()->lhb_hash_slots);
ASSERT_ACQUIRED;
srq* const hash_header = &m_sharedMemory->getHeader()->lhb_hash[hash_slot];