diff --git a/headers/private/kernel/util/OpenHashTable.h b/headers/private/kernel/util/OpenHashTable.h index 6a0969ef9d..75b4df74c0 100644 --- a/headers/private/kernel/util/OpenHashTable.h +++ b/headers/private/kernel/util/OpenHashTable.h @@ -12,12 +12,14 @@ #include -// the Definition template must have three methods: `HashKey', `Hash' and -// `Compare'. It must also define several types as shown in the following -// example: +// the Definition template must have three methods: `HashKey', `Hash', +// `Compare' and `GetLink;. It must also define several types as shown in the +// following example: // -// struct Foo { +// struct Foo : HashTableLink { // int bar; +// +// HashTableLink otherLink; // }; // // struct HashTableDefinition { @@ -29,14 +31,17 @@ // static size_t Hash(void *parent, Foo *value) { return HashKey(value->bar); } // static bool Compare(void *parent, int key, Foo *value) // { return value->bar == key; } +// static HashTableLink *GetLink(void *parent, Foo *value) +// { return value; } // }; -// This hash table implementation uses open addressing vs. the more common -// chaining. This approach is advantageous as the number of expected collisions -// is the same (property of the hash function) while not wasting one additional -// word per item and having better cache locality. The usage of quadratic -// probing reduces the effectiveness of cache locality but prevents clustering. -template +template +struct HashTableLink { + Type *fNext; +}; + +template class OpenHashTable { public: typedef typename Definition::ParentType ParentType; @@ -53,8 +58,7 @@ public: // 50 / 256 = 19.53125% OpenHashTable(const ParentType &parent, size_t initialSize = kMinimumSize) - : fParent(parent), fItemCount(0), fTable(NULL), - fDeletedToken((ValueType *)(((char *)0) - 1)) + : fParent(parent), fItemCount(0), fTable(NULL) { if (initialSize < kMinimumSize) initialSize = kMinimumSize; @@ -72,44 +76,39 @@ public: ValueType *Lookup(const KeyType &key) const { size_t index = Definition::HashKey(fParent, key) & (fTableSize - 1); - size_t f = 0; + ValueType *slot = fTable[index]; - while (true) { - ValueType *slot = fTable[index]; - - if (slot == NULL) - return NULL; - else if (!_IsDeleted(slot) - && Definition::Compare(fParent, key, slot)) - return slot; - - index = _NextSlot(f, index, fTableSize); + while (slot) { + if (Definition::Compare(fParent, key, slot)) + break; + slot = _Link(slot)->fNext; } + + return slot; } - bool Insert(ValueType *value) + void Insert(ValueType *value) { - if (fItemCount >= (fTableSize * 200 / 256)) { - if (!_Resize(fTableSize * 2)) - return false; - } + if (AutoExpand && fItemCount >= (fTableSize * 200 / 256)) + _Resize(fTableSize * 2); InsertUnchecked(value); - return true; } void InsertUnchecked(ValueType *value) { if (CheckDuplicates) { for (size_t i = 0; i < fTableSize; i++) { - if (fTable[i] == value) - panic("HashTable: item already in table"); + ValueType *bucket = fTable[i]; + while (bucket) { + if (bucket == value) + panic("Hash Table: value already in table."); + bucket = _Link(bucket)->fNext; + } } } - ValueType *previous = _Insert(fTable, fTableSize, value); - if (_IsDeleted(previous)) - fDeletedCount--; + _Insert(fTable, fTableSize, value); fItemCount++; } @@ -117,64 +116,52 @@ public: { RemoveUnchecked(value); - if (fTableSize > kMinimumSize && fItemCount < (fTableSize * 50 / 256)) + if (AutoExpand && fTableSize > kMinimumSize + && fItemCount < (fTableSize * 50 / 256)) _Resize(fTableSize / 2); } void RemoveUnchecked(ValueType *value) { size_t index = Definition::Hash(fParent, value) & (fTableSize - 1); - size_t f = 0; + ValueType *previous = NULL, *slot = fTable[index]; - while (true) { - if (fTable[index] == value) { - fTable[index] = (ValueType *)fDeletedToken; + while (slot) { + ValueType *next = _Link(slot)->fNext; + + if (value == slot) { + if (previous) + _Link(previous)->fNext = next; + else + fTable[index] = next; break; } - index = _NextSlot(f, index, fTableSize); + previous = slot; + slot = next; } if (CheckDuplicates) { for (size_t i = 0; i < fTableSize; i++) { - if (fTable[i] == value) - panic("HashTable: item removed, but still in table."); + ValueType *bucket = fTable[i]; + while (bucket) { + if (bucket == value) + panic("Hash Table: duplicate detected."); + bucket = _Link(bucket)->fNext; + } } } fItemCount--; - fDeletedCount++; } private: - ValueType *_Insert(ValueType **table, size_t tableSize, ValueType *value) + void _Insert(ValueType **table, size_t tableSize, ValueType *value) { size_t index = Definition::Hash(fParent, value) & (tableSize - 1); - size_t f = 0; - while (true) { - if (table[index] == NULL || table[index] == fDeletedToken) { - ValueType *previous = table[index]; - table[index] = value; - return previous; - } - - index = _NextSlot(f, index, tableSize); - } - - return NULL; - } - - static size_t _NextSlot(size_t &f, size_t index, size_t tableSize) - { - // quadratic probing - f++; - return (index + f) & (tableSize - 1); - } - - bool _IsDeleted(ValueType *value) const - { - return value == fDeletedToken; + _Link(value)->fNext = table[index]; + table[index] = value; } bool _Resize(size_t newSize) @@ -188,24 +175,30 @@ private: if (fTable) { for (size_t i = 0; i < fTableSize; i++) { - if (fTable[i] && !_IsDeleted(fTable[i])) - _Insert(newTable, newSize, fTable[i]); + ValueType *bucket = fTable[i]; + while (bucket) { + ValueType *next = _Link(bucket)->fNext; + _Insert(newTable, newSize, bucket); + bucket = next; + } } delete [] fTable; } fTableSize = newSize; - fDeletedCount = 0; fTable = newTable; return true; } - ParentType fParent; - size_t fTableSize, fItemCount, fDeletedCount; - ValueType **fTable; + HashTableLink *_Link(ValueType *bucket) const + { + return Definition::GetLink(fParent, bucket); + } - const ValueType *fDeletedToken; + ParentType fParent; + size_t fTableSize, fItemCount; + ValueType **fTable; }; #endif diff --git a/src/add-ons/kernel/network/protocols/tcp/EndpointManager.cpp b/src/add-ons/kernel/network/protocols/tcp/EndpointManager.cpp index 58eb7d0faa..394ad05483 100644 --- a/src/add-ons/kernel/network/protocols/tcp/EndpointManager.cpp +++ b/src/add-ons/kernel/network/protocols/tcp/EndpointManager.cpp @@ -53,6 +53,14 @@ ConnectionHashDefinition::Compare(EndpointManager *manager, const KeyType &key, } +HashTableLink * +ConnectionHashDefinition::GetLink(EndpointManager *manager, + TCPEndpoint *endpoint) +{ + return &endpoint->fConnectionHashLink; +} + + size_t EndpointHashDefinition::HashKey(EndpointManager *manager, uint16 port) { @@ -75,6 +83,14 @@ EndpointHashDefinition::Compare(EndpointManager *manager, uint16 port, } +HashTableLink * +EndpointHashDefinition::GetLink(EndpointManager *manager, + TCPEndpoint *endpoint) +{ + return &endpoint->fEndpointHashLink; +} + + EndpointManager::EndpointManager(net_domain *domain) : fDomain(domain), fConnectionHash(this), fEndpointHash(this) { @@ -141,9 +157,7 @@ EndpointManager::SetConnection(TCPEndpoint *endpoint, endpoint->LocalAddress().SetTo(*local); endpoint->PeerAddress().SetTo(peer); - if (!fConnectionHash.Insert(endpoint)) - return B_NO_MEMORY; - + fConnectionHash.Insert(endpoint); return B_OK; } @@ -170,9 +184,7 @@ EndpointManager::SetPassive(TCPEndpoint *endpoint) return EADDRINUSE; endpoint->PeerAddress().SetTo(*passive); - if (!fConnectionHash.Insert(endpoint)) - return B_NO_MEMORY; - + fConnectionHash.Insert(endpoint); return B_OK; } diff --git a/src/add-ons/kernel/network/protocols/tcp/EndpointManager.h b/src/add-ons/kernel/network/protocols/tcp/EndpointManager.h index 50d5ceae69..e11b379e85 100644 --- a/src/add-ons/kernel/network/protocols/tcp/EndpointManager.h +++ b/src/add-ons/kernel/network/protocols/tcp/EndpointManager.h @@ -33,6 +33,8 @@ struct ConnectionHashDefinition { static size_t Hash(EndpointManager *manager, TCPEndpoint *endpoint); static bool Compare(EndpointManager *manager, const KeyType &key, TCPEndpoint *endpoint); + static HashTableLink *GetLink(EndpointManager *manager, + TCPEndpoint *endpoint); }; @@ -45,6 +47,8 @@ struct EndpointHashDefinition { static size_t Hash(EndpointManager *manager, TCPEndpoint *endpoint); static bool Compare(EndpointManager *manager, uint16 port, TCPEndpoint *endpoint); + static HashTableLink *GetLink(EndpointManager *manager, + TCPEndpoint *endpoint); }; @@ -81,8 +85,8 @@ class EndpointManager : public DoublyLinkedListLinkImpl { net_domain *fDomain; - OpenHashTable fConnectionHash; - OpenHashTable fEndpointHash; + OpenHashTable fConnectionHash; + OpenHashTable fEndpointHash; benaphore fLock; }; diff --git a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp index ad52100e1c..80ad60bb85 100644 --- a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp +++ b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp @@ -74,7 +74,7 @@ #endif // Initial estimate for packet round trip time (RTT) -#define TCP_INITIAL_RTT 4000000 +#define TCP_INITIAL_RTT 2000000 // constants for the fFlags field enum { diff --git a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h index c6cd787f8d..35da4f2ab1 100644 --- a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h +++ b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h @@ -18,6 +18,7 @@ #include #include #include +#include #include @@ -134,8 +135,12 @@ class TCPEndpoint : public net_protocol { EndpointManager *fManager; - TCPEndpoint *fConnectionHashNext; - TCPEndpoint *fEndpointHashNext; + HashTableLink fConnectionHashLink; + HashTableLink fEndpointHashLink; + + friend class ConnectionHashDefinition; + friend class EndpointHashDefinition; + TCPEndpoint *fEndpointNextWithSamePort; recursive_lock fLock;