@ -38,7 +38,7 @@
namespace rocksdb {
namespace rocksdb {
template < typename Key , class Comparator >
template < class Comparator >
class InlineSkipList {
class InlineSkipList {
private :
private :
struct Node ;
struct Node ;
@ -52,15 +52,18 @@ class InlineSkipList {
int32_t max_height = 12 ,
int32_t max_height = 12 ,
int32_t branching_factor = 4 ) ;
int32_t branching_factor = 4 ) ;
// Allocates a key that can be passed to Insert.
char * AllocateKey ( size_t key_size ) ;
// Insert key into the list.
// Insert key into the list.
// REQUIRES: nothing that compares equal to key is currently in the list.
// REQUIRES: nothing that compares equal to key is currently in the list.
void Insert ( const Key & key ) ;
void Insert ( const char * key ) ;
// Returns true iff an entry that compares equal to key is in the list.
// Returns true iff an entry that compares equal to key is in the list.
bool Contains ( const Key & key ) const ;
bool Contains ( const char * key ) const ;
// Return estimated number of entries smaller than `key`.
// Return estimated number of entries smaller than `key`.
uint64_t EstimateCount ( const Key & key ) const ;
uint64_t EstimateCount ( const char * key ) const ;
// Iteration over the contents of a skip list
// Iteration over the contents of a skip list
class Iterator {
class Iterator {
@ -79,7 +82,7 @@ class InlineSkipList {
// Returns the key at the current position.
// Returns the key at the current position.
// REQUIRES: Valid()
// REQUIRES: Valid()
const Key & key ( ) const ;
const char * key ( ) const ;
// Advances to the next position.
// Advances to the next position.
// REQUIRES: Valid()
// REQUIRES: Valid()
@ -90,7 +93,7 @@ class InlineSkipList {
void Prev ( ) ;
void Prev ( ) ;
// Advance to the first entry with a key >= target
// Advance to the first entry with a key >= target
void Seek ( const Key & target ) ;
void Seek ( const char * target ) ;
// Position at the first entry in list.
// Position at the first entry in list.
// Final state of iterator is Valid() iff list is not empty.
// Final state of iterator is Valid() iff list is not empty.
@ -132,22 +135,25 @@ class InlineSkipList {
return max_height_ . load ( std : : memory_order_relaxed ) ;
return max_height_ . load ( std : : memory_order_relaxed ) ;
}
}
Node * NewNode ( const Key & key , int height ) ;
Node * NewNode ( const char * key , int height ) ;
int RandomHeight ( ) ;
int RandomHeight ( ) ;
bool Equal ( const Key & a , const Key & b ) const { return ( compare_ ( a , b ) = = 0 ) ; }
bool Equal ( const char * a , const char * b ) const {
return ( compare_ ( a , b ) = = 0 ) ;
}
// Return true if key is greater than the data stored in "n"
// Return true if key is greater than the data stored in "n"
bool KeyIsAfterNode ( const Key & key , Node * n ) const ;
bool KeyIsAfterNode ( const char * key , Node * n ) const ;
// Returns the earliest node with a key >= key.
// Returns the earliest node with a key >= key.
// Return nullptr if there is no such node.
// Return nullptr if there is no such node.
Node * FindGreaterOrEqual ( const Key & key ) const ;
Node * FindGreaterOrEqual ( const char * key ) const ;
// Return the latest node with a key < key.
// Return the latest node with a key < key.
// Return head_ if there is no such node.
// Return head_ if there is no such node.
// Fills prev[level] with pointer to previous node at "level" for every
// Fills prev[level] with pointer to previous node at "level" for every
// level in [0..max_height_-1], if prev is non-null.
// level in [0..max_height_-1], if prev is non-null.
Node * FindLessThan ( const Key & key , Node * * prev = nullptr ) const ;
Node * FindLessThan ( const char * key , Node * * prev = nullptr ) const ;
// Return the last node in the list.
// Return the last node in the list.
// Return head_ if list is empty.
// Return head_ if list is empty.
@ -159,11 +165,11 @@ class InlineSkipList {
} ;
} ;
// Implementation details follow
// Implementation details follow
template < typename Key , class Comparator >
template < class Comparator >
struct InlineSkipList < Key , Comparator > : : Node {
struct InlineSkipList < Comparator > : : Node {
explicit Node ( const Key & k ) : key ( k ) { }
explicit Node ( const char * k ) : key ( k ) { }
Key const key ;
const char * const key ;
// Accessors/mutators for links. Wrapped in methods so we can
// Accessors/mutators for links. Wrapped in methods so we can
// add the appropriate barriers as necessary.
// add the appropriate barriers as necessary.
@ -195,46 +201,46 @@ struct InlineSkipList<Key, Comparator>::Node {
std : : atomic < Node * > next_ [ 1 ] ;
std : : atomic < Node * > next_ [ 1 ] ;
} ;
} ;
template < typename Key , class Comparator >
template < class Comparator >
typename InlineSkipList < Key , Comparator > : : Node *
typename InlineSkipList < Comparator > : : Node * InlineSkipList < Comparator > : : NewNode (
InlineSkipList < Key , Comparator > : : NewNode ( const Key & key , int height ) {
const char * key , int height ) {
char * mem = allocator_ - > AllocateAligned (
char * mem = allocator_ - > AllocateAligned (
sizeof ( Node ) + sizeof ( std : : atomic < Node * > ) * ( height - 1 ) ) ;
sizeof ( Node ) + sizeof ( std : : atomic < Node * > ) * ( height - 1 ) ) ;
return new ( mem ) Node ( key ) ;
return new ( mem ) Node ( key ) ;
}
}
template < typename Key , class Comparator >
template < class Comparator >
inline InlineSkipList < Key , Comparator > : : Iterator : : Iterator (
inline InlineSkipList < Comparator > : : Iterator : : Iterator (
const InlineSkipList * list ) {
const InlineSkipList * list ) {
SetList ( list ) ;
SetList ( list ) ;
}
}
template < typename Key , class Comparator >
template < class Comparator >
inline void InlineSkipList < Key , Comparator > : : Iterator : : SetList (
inline void InlineSkipList < Comparator > : : Iterator : : SetList (
const InlineSkipList * list ) {
const InlineSkipList * list ) {
list_ = list ;
list_ = list ;
node_ = nullptr ;
node_ = nullptr ;
}
}
template < typename Key , class Comparator >
template < class Comparator >
inline bool InlineSkipList < Key , Comparator > : : Iterator : : Valid ( ) const {
inline bool InlineSkipList < Comparator > : : Iterator : : Valid ( ) const {
return node_ ! = nullptr ;
return node_ ! = nullptr ;
}
}
template < typename Key , class Comparator >
template < class Comparator >
inline const Key & InlineSkipList < Key , Comparator > : : Iterator : : key ( ) const {
inline const char * InlineSkipList < Comparator > : : Iterator : : key ( ) const {
assert ( Valid ( ) ) ;
assert ( Valid ( ) ) ;
return node_ - > key ;
return node_ - > key ;
}
}
template < typename Key , class Comparator >
template < class Comparator >
inline void InlineSkipList < Key , Comparator > : : Iterator : : Next ( ) {
inline void InlineSkipList < Comparator > : : Iterator : : Next ( ) {
assert ( Valid ( ) ) ;
assert ( Valid ( ) ) ;
node_ = node_ - > Next ( 0 ) ;
node_ = node_ - > Next ( 0 ) ;
}
}
template < typename Key , class Comparator >
template < class Comparator >
inline void InlineSkipList < Key , Comparator > : : Iterator : : Prev ( ) {
inline void InlineSkipList < Comparator > : : Iterator : : Prev ( ) {
// Instead of using explicit "prev" links, we just search for the
// Instead of using explicit "prev" links, we just search for the
// last node that falls before key.
// last node that falls before key.
assert ( Valid ( ) ) ;
assert ( Valid ( ) ) ;
@ -244,26 +250,26 @@ inline void InlineSkipList<Key, Comparator>::Iterator::Prev() {
}
}
}
}
template < typename Key , class Comparator >
template < class Comparator >
inline void InlineSkipList < Key , Comparator > : : Iterator : : Seek ( const Key & target ) {
inline void InlineSkipList < Comparator > : : Iterator : : Seek ( const char * target ) {
node_ = list_ - > FindGreaterOrEqual ( target ) ;
node_ = list_ - > FindGreaterOrEqual ( target ) ;
}
}
template < typename Key , class Comparator >
template < class Comparator >
inline void InlineSkipList < Key , Comparator > : : Iterator : : SeekToFirst ( ) {
inline void InlineSkipList < Comparator > : : Iterator : : SeekToFirst ( ) {
node_ = list_ - > head_ - > Next ( 0 ) ;
node_ = list_ - > head_ - > Next ( 0 ) ;
}
}
template < typename Key , class Comparator >
template < class Comparator >
inline void InlineSkipList < Key , Comparator > : : Iterator : : SeekToLast ( ) {
inline void InlineSkipList < Comparator > : : Iterator : : SeekToLast ( ) {
node_ = list_ - > FindLast ( ) ;
node_ = list_ - > FindLast ( ) ;
if ( node_ = = list_ - > head_ ) {
if ( node_ = = list_ - > head_ ) {
node_ = nullptr ;
node_ = nullptr ;
}
}
}
}
template < typename Key , class Comparator >
template < class Comparator >
int InlineSkipList < Key , Comparator > : : RandomHeight ( ) {
int InlineSkipList < Comparator > : : RandomHeight ( ) {
auto rnd = Random : : GetTLSInstance ( ) ;
auto rnd = Random : : GetTLSInstance ( ) ;
// Increase height with probability 1 in kBranching
// Increase height with probability 1 in kBranching
@ -276,16 +282,16 @@ int InlineSkipList<Key, Comparator>::RandomHeight() {
return height ;
return height ;
}
}
template < typename Key , class Comparator >
template < class Comparator >
bool InlineSkipList < Key , Comparator > : : KeyIsAfterNode ( const Key & key ,
bool InlineSkipList < Comparator > : : KeyIsAfterNode ( const char * key ,
Node * n ) const {
Node * n ) const {
// nullptr n is considered infinite
// nullptr n is considered infinite
return ( n ! = nullptr ) & & ( compare_ ( n - > key , key ) < 0 ) ;
return ( n ! = nullptr ) & & ( compare_ ( n - > key , key ) < 0 ) ;
}
}
template < typename Key , class Comparator >
template < class Comparator >
typename InlineSkipList < Key , Comparator > : : Node *
typename InlineSkipList < Comparator > : : Node *
InlineSkipList < Key , Comparator > : : FindGreaterOrEqual ( const Key & key ) const {
InlineSkipList < Comparator > : : FindGreaterOrEqual ( const char * key ) const {
// Note: It looks like we could reduce duplication by implementing
// Note: It looks like we could reduce duplication by implementing
// this function as FindLessThan(key)->Next(0), but we wouldn't be able
// this function as FindLessThan(key)->Next(0), but we wouldn't be able
// to exit early on equality and the result wouldn't even be correct.
// to exit early on equality and the result wouldn't even be correct.
@ -315,10 +321,9 @@ InlineSkipList<Key, Comparator>::FindGreaterOrEqual(const Key& key) const {
}
}
}
}
template < typename Key , class Comparator >
template < class Comparator >
typename InlineSkipList < Key , Comparator > : : Node *
typename InlineSkipList < Comparator > : : Node *
InlineSkipList < Key , Comparator > : : FindLessThan ( const Key & key ,
InlineSkipList < Comparator > : : FindLessThan ( const char * key , Node * * prev ) const {
Node * * prev ) const {
Node * x = head_ ;
Node * x = head_ ;
int level = GetMaxHeight ( ) - 1 ;
int level = GetMaxHeight ( ) - 1 ;
// KeyIsAfter(key, last_not_after) is definitely false
// KeyIsAfter(key, last_not_after) is definitely false
@ -345,9 +350,9 @@ InlineSkipList<Key, Comparator>::FindLessThan(const Key& key,
}
}
}
}
template < typename Key , class Comparator >
template < class Comparator >
typename InlineSkipList < Key , Comparator > : : Node *
typename InlineSkipList < Comparator > : : Node *
InlineSkipList < Key , Comparator > : : FindLast ( ) const {
InlineSkipList < Comparator > : : FindLast ( ) const {
Node * x = head_ ;
Node * x = head_ ;
int level = GetMaxHeight ( ) - 1 ;
int level = GetMaxHeight ( ) - 1 ;
while ( true ) {
while ( true ) {
@ -365,8 +370,8 @@ InlineSkipList<Key, Comparator>::FindLast() const {
}
}
}
}
template < typename Key , class Comparator >
template < class Comparator >
uint64_t InlineSkipList < Key , Comparator > : : EstimateCount ( const Key & key ) const {
uint64_t InlineSkipList < Comparator > : : EstimateCount ( const char * key ) const {
uint64_t count = 0 ;
uint64_t count = 0 ;
Node * x = head_ ;
Node * x = head_ ;
@ -389,8 +394,8 @@ uint64_t InlineSkipList<Key, Comparator>::EstimateCount(const Key& key) const {
}
}
}
}
template < typename Key , class Comparator >
template < class Comparator >
InlineSkipList < Key , Comparator > : : InlineSkipList ( const Comparator cmp ,
InlineSkipList < Comparator > : : InlineSkipList ( const Comparator cmp ,
Allocator * allocator ,
Allocator * allocator ,
int32_t max_height ,
int32_t max_height ,
int32_t branching_factor )
int32_t branching_factor )
@ -417,8 +422,13 @@ InlineSkipList<Key, Comparator>::InlineSkipList(const Comparator cmp,
}
}
}
}
template < typename Key , class Comparator >
template < class Comparator >
void InlineSkipList < Key , Comparator > : : Insert ( const Key & key ) {
char * InlineSkipList < Comparator > : : AllocateKey ( size_t key_size ) {
return allocator_ - > Allocate ( key_size ) ;
}
template < class Comparator >
void InlineSkipList < Comparator > : : Insert ( const char * key ) {
// fast path for sequential insertion
// fast path for sequential insertion
if ( ! KeyIsAfterNode ( key , prev_ [ 0 ] - > NoBarrier_Next ( 0 ) ) & &
if ( ! KeyIsAfterNode ( key , prev_ [ 0 ] - > NoBarrier_Next ( 0 ) ) & &
( prev_ [ 0 ] = = head_ | | KeyIsAfterNode ( key , prev_ [ 0 ] ) ) ) {
( prev_ [ 0 ] = = head_ | | KeyIsAfterNode ( key , prev_ [ 0 ] ) ) ) {
@ -469,8 +479,8 @@ void InlineSkipList<Key, Comparator>::Insert(const Key& key) {
prev_height_ = height ;
prev_height_ = height ;
}
}
template < typename Key , class Comparator >
template < class Comparator >
bool InlineSkipList < Key , Comparator > : : Contains ( const Key & key ) const {
bool InlineSkipList < Comparator > : : Contains ( const char * key ) const {
Node * x = FindGreaterOrEqual ( key ) ;
Node * x = FindGreaterOrEqual ( key ) ;
if ( x ! = nullptr & & Equal ( key , x - > key ) ) {
if ( x ! = nullptr & & Equal ( key , x - > key ) ) {
return true ;
return true ;