04815ee9b8ae6b3123f2d500e9c6b618150001d8
[libcds.git] / cds / container / feldman_hashset_rcu.h
1 /*
2     This file is a part of libcds - Concurrent Data Structures library
3
4     (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
5
6     Source code repo: http://github.com/khizmax/libcds/
7     Download: http://sourceforge.net/projects/libcds/files/
8
9     Redistribution and use in source and binary forms, with or without
10     modification, are permitted provided that the following conditions are met:
11
12     * Redistributions of source code must retain the above copyright notice, this
13       list of conditions and the following disclaimer.
14
15     * Redistributions in binary form must reproduce the above copyright notice,
16       this list of conditions and the following disclaimer in the documentation
17       and/or other materials provided with the distribution.
18
19     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20     AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21     IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23     FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24     DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #ifndef CDSLIB_CONTAINER_FELDMAN_HASHSET_RCU_H
32 #define CDSLIB_CONTAINER_FELDMAN_HASHSET_RCU_H
33
34 #include <cds/intrusive/feldman_hashset_rcu.h>
35 #include <cds/container/details/feldman_hashset_base.h>
36
37 namespace cds { namespace container {
38
39     /// Hash set based on multi-level array, \ref cds_urcu_desc "RCU" specialization
40     /** @ingroup cds_nonintrusive_set
41         @anchor cds_container_FeldmanHashSet_rcu
42
43         Source:
44         - [2013] Steven Feldman, Pierre LaBorde, Damian Dechev "Concurrent Multi-level Arrays:
45                  Wait-free Extensible Hash Maps"
46
47         See algorithm short description @ref cds_intrusive_FeldmanHashSet_hp "here"
48
49         @note Two important things you should keep in mind when you're using \p %FeldmanHashSet:
50         - all keys must be fixed-size. It means that you cannot use \p std::string as a key for \p %FeldmanHashSet.
51           Instead, for the strings you should use well-known hashing algorithms like <a href="https://en.wikipedia.org/wiki/Secure_Hash_Algorithm">SHA1, SHA2</a>,
52           <a href="https://en.wikipedia.org/wiki/MurmurHash">MurmurHash</a>, <a href="https://en.wikipedia.org/wiki/CityHash">CityHash</a>
53           or its successor <a href="https://code.google.com/p/farmhash/">FarmHash</a> and so on, which
54           converts variable-length strings to fixed-length bit-strings, and use that hash as a key in \p %FeldmanHashSet.
55         - \p %FeldmanHashSet uses a perfect hashing. It means that if two different keys, for example, of type \p std::string,
56           have identical hash then you cannot insert both that keys in the set. \p %FeldmanHashSet does not maintain the key,
57           it maintains its fixed-size hash value.
58
59         The set supports @ref cds_container_FeldmanHashSet_iterators "bidirectional thread-safe iterators".
60
61         Template parameters:
62         - \p RCU - one of \ref cds_urcu_gc "RCU type"
63         - \p T - a value type to be stored in the set
64         - \p Traits - type traits, the structure based on \p feldman_hashset::traits or result of \p feldman_hashset::make_traits metafunction.
65             \p Traits is the mandatory argument because it has one mandatory type - an @ref feldman_hashset::traits::hash_accessor "accessor"
66             to hash value of \p T. The set algorithm does not calculate that hash value.
67
68             @note Before including <tt><cds/intrusive/feldman_hashset_rcu.h></tt> you should include appropriate RCU header file,
69             see \ref cds_urcu_gc "RCU type" for list of existing RCU class and corresponding header files.
70
71             The set supports @ref cds_container_FeldmanHashSet_rcu_iterators "bidirectional thread-safe iterators"
72             with some restrictions.
73     */
74     template <
75         class RCU
76         , typename T
77 #ifdef CDS_DOXYGEN_INVOKED
78         , class Traits = feldman_hashset::traits
79 #else
80         , class Traits
81 #endif
82     >
83     class FeldmanHashSet< cds::urcu::gc< RCU >, T, Traits >
84 #ifdef CDS_DOXYGEN_INVOKED
85         : protected cds::intrusive::FeldmanHashSet< cds::urcu::gc< RCU >, T, Traits >
86 #else
87         : protected cds::container::details::make_feldman_hashset< cds::urcu::gc< RCU >, T, Traits >::type
88 #endif
89     {
90         //@cond
91         typedef cds::container::details::make_feldman_hashset< cds::urcu::gc< RCU >, T, Traits > maker;
92         typedef typename maker::type base_class;
93         //@endcond
94
95     public:
96         typedef cds::urcu::gc< RCU > gc; ///< RCU garbage collector
97         typedef T       value_type; ///< type of value stored in the set
98         typedef Traits  traits;     ///< Traits template parameter, see \p feldman_hashset::traits
99
100         typedef typename base_class::hash_accessor hash_accessor; ///< Hash accessor functor
101         typedef typename base_class::hash_type hash_type; ///< Hash type deduced from \p hash_accessor return type
102         typedef typename base_class::hash_comparator hash_comparator; ///< hash compare functor based on \p opt::compare and \p opt::less option setter
103
104         typedef typename traits::item_counter   item_counter;   ///< Item counter type
105         typedef typename traits::allocator      allocator;      ///< Element allocator
106         typedef typename traits::node_allocator node_allocator; ///< Array node allocator
107         typedef typename traits::memory_model   memory_model;   ///< Memory model
108         typedef typename traits::back_off       back_off;       ///< Backoff strategy
109         typedef typename traits::stat           stat;           ///< Internal statistics type
110         typedef typename traits::rcu_check_deadlock rcu_check_deadlock; ///< Deadlock checking policy
111         typedef typename gc::scoped_lock       rcu_lock;        ///< RCU scoped lock
112         static CDS_CONSTEXPR const bool c_bExtractLockExternal = false; ///< Group of \p extract_xxx functions does not require external locking
113         typedef typename base_class::exempt_ptr exempt_ptr; ///< pointer to extracted node
114
115         /// The size of hash_type in bytes, see \p feldman_hashset::traits::hash_size for explanation
116         static CDS_CONSTEXPR size_t const c_hash_size = base_class::c_hash_size;
117
118         /// Level statistics
119         typedef feldman_hashset::level_statistics level_statistics;
120
121     protected:
122         //@cond
123         typedef typename maker::cxx_node_allocator cxx_node_allocator;
124         typedef std::unique_ptr< value_type, typename maker::node_disposer > scoped_node_ptr;
125         //@endcond
126
127     public:
128         /// Creates empty set
129         /**
130             @param head_bits: 2<sup>head_bits</sup> specifies the size of head array, minimum is 4.
131             @param array_bits: 2<sup>array_bits</sup> specifies the size of array node, minimum is 2.
132
133             Equation for \p head_bits and \p array_bits:
134             \code
135             sizeof(hash_type) * 8 == head_bits + N * array_bits
136             \endcode
137             where \p N is multi-level array depth.
138         */
139         FeldmanHashSet( size_t head_bits = 8, size_t array_bits = 4 )
140             : base_class( head_bits, array_bits )
141         {}
142
143         /// Destructs the set and frees all data
144         ~FeldmanHashSet()
145         {}
146
147         /// Inserts new element
148         /**
149             The function creates an element with copy of \p val value and then inserts it into the set.
150
151             The type \p Q should contain as minimum the complete hash for the element.
152             The object of \ref value_type should be constructible from a value of type \p Q.
153             In trivial case, \p Q is equal to \ref value_type.
154
155             Returns \p true if \p val is inserted into the set, \p false otherwise.
156
157             The function locks RCU internally.
158         */
159         template <typename Q>
160         bool insert( Q const& val )
161         {
162             scoped_node_ptr sp( cxx_node_allocator().New( val ));
163             if ( base_class::insert( *sp )) {
164                 sp.release();
165                 return true;
166             }
167             return false;
168         }
169
170         /// Inserts new element
171         /**
172             The function allows to split creating of new item into two part:
173             - create item with key only
174             - insert new item into the set
175             - if inserting is success, calls \p f functor to initialize value-fields of \p val.
176
177             The functor signature is:
178             \code
179                 void func( value_type& val );
180             \endcode
181             where \p val is the item inserted. User-defined functor \p f should guarantee that during changing
182             \p val no any other changes could be made on this set's item by concurrent threads.
183             The user-defined functor is called only if the inserting is success.
184
185             The function locks RCU internally.
186         */
187         template <typename Q, typename Func>
188         bool insert( Q const& val, Func f )
189         {
190             scoped_node_ptr sp( cxx_node_allocator().New( val ));
191             if ( base_class::insert( *sp, f )) {
192                 sp.release();
193                 return true;
194             }
195             return false;
196         }
197
198         /// Updates the element
199         /**
200             The operation performs inserting or replacing with lock-free manner.
201
202             If the \p val key not found in the set, then the new item created from \p val
203             will be inserted into the set iff \p bInsert is \p true.
204             Otherwise, if \p val is found, it is replaced with new item created from \p val
205             and previous item is disposed.
206             In both cases \p func functor is called.
207
208             The functor \p Func signature:
209             \code
210                 struct my_functor {
211                     void operator()( value_type& cur, value_type * prev );
212                 };
213             \endcode
214             where:
215             - \p cur - current element
216             - \p prev - pointer to previous element with such hash. \p prev is \p nullptr
217                  if \p cur was just inserted.
218
219             The functor may change non-key fields of the \p item; however, \p func must guarantee
220             that during changing no any other modifications could be made on this item by concurrent threads.
221
222             Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
223             i.e. the item has been inserted or updated,
224             \p second is \p true if the new item has been added or \p false if the item with key equal to \p val
225             already exists.
226         */
227         template <typename Q, typename Func>
228         std::pair<bool, bool> update( Q const& val, Func func, bool bInsert = true )
229         {
230             scoped_node_ptr sp( cxx_node_allocator().New( val ));
231             std::pair<bool, bool> bRes = base_class::do_update( *sp, func, bInsert );
232             if ( bRes.first )
233                 sp.release();
234             return bRes;
235         }
236
237         /// Inserts data of type \p value_type created in-place from <tt>std::forward<Args>(args)...</tt>
238         /**
239             Returns \p true if inserting successful, \p false otherwise.
240         */
241         template <typename... Args>
242         bool emplace( Args&&... args )
243         {
244             scoped_node_ptr sp( cxx_node_allocator().MoveNew( std::forward<Args>(args)... ));
245             if ( base_class::insert( *sp )) {
246                 sp.release();
247                 return true;
248             }
249             return false;
250         }
251
252         /// Deletes the item from the set
253         /**
254             The function searches \p hash in the set,
255             deletes the item found, and returns \p true.
256             If that item is not found the function returns \p false.
257
258             RCU should not be locked. The function locks RCU internally.
259         */
260         bool erase( hash_type const& hash )
261         {
262             return base_class::erase( hash );
263         }
264
265         /// Deletes the item from the set
266         /**
267             The function searches \p hash in the set,
268             call \p f functor with item found, and deltes the element from the set.
269
270             The \p Func interface is
271             \code
272             struct functor {
273                 void operator()( value_type& item );
274             };
275             \endcode
276
277             If \p hash is not found the function returns \p false.
278
279             RCU should not be locked. The function locks RCU internally.
280         */
281         template <typename Func>
282         bool erase( hash_type const& hash, Func f )
283         {
284             return base_class::erase( hash, f );
285         }
286
287         /// Extracts the item with specified \p hash
288         /**
289             The function searches \p hash in the set,
290             unlinks it from the set, and returns \ref cds::urcu::exempt_ptr "exempt_ptr" pointer to the item found.
291             If the item with key equal to \p key is not found the function returns an empty \p exempt_ptr.
292
293             RCU \p synchronize method can be called. RCU should NOT be locked.
294             The function does not call the disposer for the item found.
295             The disposer will be implicitly invoked when the returned object is destroyed or when
296             its \p release() member function is called.
297             Example:
298             \code
299             typedef cds::container::FeldmanHashSet< cds::urcu::gc< cds::urcu::general_buffered<> >, foo, my_traits > set_type;
300             set_type theSet;
301             // ...
302
303             typename set_type::exempt_ptr ep( theSet.extract( 5 ));
304             if ( ep ) {
305                 // Deal with ep
306                 //...
307
308                 // Dispose returned item.
309                 ep.release();
310             }
311             \endcode
312         */
313         exempt_ptr extract( hash_type const& hash )
314         {
315             return base_class::extract( hash );
316         }
317
318         /// Finds an item by it's \p hash
319         /**
320             The function searches the item by \p hash and calls the functor \p f for item found.
321             The interface of \p Func functor is:
322             \code
323             struct functor {
324                 void operator()( value_type& item );
325             };
326             \endcode
327             where \p item is the item found.
328
329             The functor may change non-key fields of \p item. Note that the functor is only guarantee
330             that \p item cannot be disposed during the functor is executing.
331             The functor does not serialize simultaneous access to the set's \p item. If such access is
332             possible you must provide your own synchronization schema on item level to prevent unsafe item modifications.
333
334             The function returns \p true if \p hash is found, \p false otherwise.
335         */
336         template <typename Func>
337         bool find( hash_type const& hash, Func f )
338         {
339             return base_class::find( hash, f );
340         }
341
342         /// Checks whether the set contains \p hash
343         /**
344             The function searches the item by its \p hash
345             and returns \p true if it is found, or \p false otherwise.
346         */
347         bool contains( hash_type const& hash )
348         {
349             return base_class::contains( hash );
350         }
351
352         /// Finds an item by it's \p hash and returns the item found
353         /**
354             The function searches the item by its \p hash
355             and returns the pointer to the item found.
356             If \p hash is not found the function returns \p nullptr.
357
358             RCU should be locked before the function invocation.
359             Returned pointer is valid only while RCU is locked.
360
361             Usage:
362             \code
363             typedef cds::container::FeldmanHashSet< your_template_params >  my_set;
364             my_set theSet;
365             // ...
366             {
367                 // lock RCU
368                 my_set::rcu_lock lock;
369
370                 foo * p = theSet.get( 5 );
371                 if ( p ) {
372                     // Deal with p
373                     //...
374                 }
375             }
376             \endcode
377         */
378         value_type * get( hash_type const& hash )
379         {
380             return base_class::get( hash );
381         }
382
383         /// Clears the set (non-atomic)
384         /**
385             The function unlink all data node from the set.
386             The function is not atomic but is thread-safe.
387             After \p %clear() the set may not be empty because another threads may insert items.
388         */
389         void clear()
390         {
391             base_class::clear();
392         }
393
394         /// Checks if the set is empty
395         /**
396             Emptiness is checked by item counting: if item count is zero then the set is empty.
397             Thus, the correct item counting feature is an important part of the set implementation.
398         */
399         bool empty() const
400         {
401             return base_class::empty();
402         }
403
404         /// Returns item count in the set
405         size_t size() const
406         {
407             return base_class::size();
408         }
409
410         /// Returns const reference to internal statistics
411         stat const& statistics() const
412         {
413             return base_class::statistics();
414         }
415
416         /// Returns the size of head node
417         size_t head_size() const
418         {
419             return base_class::head_size();
420         }
421
422         /// Returns the size of the array node
423         size_t array_node_size() const
424         {
425             return base_class::array_node_size();
426         }
427
428         /// Collects tree level statistics into \p stat
429         /**
430             The function traverses the set and collects statistics for each level of the tree
431             into \p feldman_hashset::level_statistics struct. The element of \p stat[i]
432             represents statistics for level \p i, level 0 is head array.
433             The function is thread-safe and may be called in multi-threaded environment.
434
435             Result can be useful for estimating efficiency of hash functor you use.
436         */
437         void get_level_statistics(std::vector< feldman_hashset::level_statistics>& stat) const
438         {
439             base_class::get_level_statistics(stat);
440         }
441
442     public:
443         ///@name Thread-safe iterators
444         ///@{
445         /// Bidirectional iterator
446         /** @anchor cds_container_FeldmanHashSet_rcu_iterators
447             The set supports thread-safe iterators: you may iterate over the set in multi-threaded environment
448             under explicit RCU lock.
449             RCU lock requirement means that inserting or searching is allowed but you must not erase the items from the set
450             since erasing under RCU lock can lead to a deadlock. However, another thread can call \p erase() safely
451             while your thread is iterating.
452
453             A typical example is:
454             \code
455             struct foo {
456                 uint32_t    hash;
457                 // ... other fields
458                 uint32_t    payload; // only for example
459             };
460             struct set_traits: cds::container::feldman_hashset::traits
461             {
462                 struct hash_accessor {
463                     uint32_t operator()( foo const& src ) const
464                     {
465                         retur src.hash;
466                     }
467                 };
468             };
469
470             typedef cds::urcu::gc< cds::urcu::general_buffered<>> rcu;
471             typedef cds::container::FeldmanHashSet< rcu, foo, set_traits > set_type;
472
473             set_type s;
474
475             // ...
476
477             // iterate over the set
478             {
479                 // lock the RCU.
480                 typename set_type::rcu_lock l; // scoped RCU lock
481
482                 // traverse the set
483                 for ( auto i = s.begin(); i != s.end(); ++i ) {
484                     // deal with i. Remember, erasing is prohibited here!
485                     i->payload++;
486                 }
487             } // at this point RCU lock is released
488             \endcode
489
490             Each iterator object supports the common interface:
491             - dereference operators:
492                 @code
493                 value_type [const] * operator ->() noexcept
494                 value_type [const] & operator *() noexcept
495                 @endcode
496             - pre-increment and pre-decrement. Post-operators is not supported
497             - equality operators <tt>==</tt> and <tt>!=</tt>.
498                 Iterators are equal iff they point to the same cell of the same array node.
499                 Note that for two iterators \p it1 and \p it2 the condition <tt> it1 == it2 </tt>
500                 does not entail <tt> &(*it1) == &(*it2) </tt>: welcome to concurrent containers
501
502             @note It is possible the item can be iterated more that once, for example, if an iterator points to the item
503             in an array node that is being splitted.
504         */
505         typedef typename base_class::iterator               iterator;
506         typedef typename base_class::const_iterator         const_iterator; ///< @ref cds_container_FeldmanHashSet_rcu_iterators "bidirectional const iterator" type
507         typedef typename base_class::reverse_iterator       reverse_iterator;       ///< @ref cds_container_FeldmanHashSet_rcu_iterators "bidirectional reverse iterator" type
508         typedef typename base_class::const_reverse_iterator const_reverse_iterator; ///< @ref cds_container_FeldmanHashSet_rcu_iterators "bidirectional reverse const iterator" type
509
510         /// Returns an iterator to the beginning of the set
511         iterator begin()
512         {
513             return base_class::begin();
514         }
515
516         /// Returns an const iterator to the beginning of the set
517         const_iterator begin() const
518         {
519             return base_class::begin();
520         }
521
522         /// Returns an const iterator to the beginning of the set
523         const_iterator cbegin()
524         {
525             return base_class::cbegin();
526         }
527
528         /// Returns an iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
529         iterator end()
530         {
531             return base_class::end();
532         }
533
534         /// Returns a const iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
535         const_iterator end() const
536         {
537             return base_class::end();
538         }
539
540         /// Returns a const iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
541         const_iterator cend()
542         {
543             return base_class::cend();
544         }
545
546         /// Returns a reverse iterator to the first element of the reversed set
547         reverse_iterator rbegin()
548         {
549             return base_class::rbegin();
550         }
551
552         /// Returns a const reverse iterator to the first element of the reversed set
553         const_reverse_iterator rbegin() const
554         {
555             return base_class::rbegin();
556         }
557
558         /// Returns a const reverse iterator to the first element of the reversed set
559         const_reverse_iterator crbegin()
560         {
561             return base_class::crbegin();
562         }
563
564         /// Returns a reverse iterator to the element following the last element of the reversed set
565         /**
566             It corresponds to the element preceding the first element of the non-reversed container.
567             This element acts as a placeholder, attempting to access it results in undefined behavior.
568         */
569         reverse_iterator rend()
570         {
571             return base_class::rend();
572         }
573
574         /// Returns a const reverse iterator to the element following the last element of the reversed set
575         /**
576             It corresponds to the element preceding the first element of the non-reversed container.
577             This element acts as a placeholder, attempting to access it results in undefined behavior.
578         */
579         const_reverse_iterator rend() const
580         {
581             return base_class::rend();
582         }
583
584         /// Returns a const reverse iterator to the element following the last element of the reversed set
585         /**
586             It corresponds to the element preceding the first element of the non-reversed container.
587             This element acts as a placeholder, attempting to access it results in undefined behavior.
588         */
589         const_reverse_iterator crend()
590         {
591             return base_class::crend();
592         }
593     ///@}
594     };
595
596 }} // namespace cds::container
597
598 #endif // #ifndef CDSLIB_CONTAINER_FELDMAN_HASHSET_RCU_H