4a707580fbc01726e5c4228344d58b1ce067b88d
[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-2016
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         /// Level statistics
116         typedef feldman_hashset::level_statistics level_statistics;
117
118     protected:
119         //@cond
120         typedef typename maker::cxx_node_allocator cxx_node_allocator;
121         typedef std::unique_ptr< value_type, typename maker::node_disposer > scoped_node_ptr;
122         //@endcond
123
124     public:
125         /// Creates empty set
126         /**
127             @param head_bits: 2<sup>head_bits</sup> specifies the size of head array, minimum is 4.
128             @param array_bits: 2<sup>array_bits</sup> specifies the size of array node, minimum is 2.
129
130             Equation for \p head_bits and \p array_bits:
131             \code
132             sizeof(hash_type) * 8 == head_bits + N * array_bits
133             \endcode
134             where \p N is multi-level array depth.
135         */
136         FeldmanHashSet( size_t head_bits = 8, size_t array_bits = 4 )
137             : base_class( head_bits, array_bits )
138         {}
139
140         /// Destructs the set and frees all data
141         ~FeldmanHashSet()
142         {}
143
144         /// Inserts new element
145         /**
146             The function creates an element with copy of \p val value and then inserts it into the set.
147
148             The type \p Q should contain as minimum the complete hash for the element.
149             The object of \ref value_type should be constructible from a value of type \p Q.
150             In trivial case, \p Q is equal to \ref value_type.
151
152             Returns \p true if \p val is inserted into the set, \p false otherwise.
153
154             The function locks RCU internally.
155         */
156         template <typename Q>
157         bool insert( Q const& val )
158         {
159             scoped_node_ptr sp( cxx_node_allocator().New( val ));
160             if ( base_class::insert( *sp )) {
161                 sp.release();
162                 return true;
163             }
164             return false;
165         }
166
167         /// Inserts new element
168         /**
169             The function allows to split creating of new item into two part:
170             - create item with key only
171             - insert new item into the set
172             - if inserting is success, calls \p f functor to initialize value-fields of \p val.
173
174             The functor signature is:
175             \code
176                 void func( value_type& val );
177             \endcode
178             where \p val is the item inserted. User-defined functor \p f should guarantee that during changing
179             \p val no any other changes could be made on this set's item by concurrent threads.
180             The user-defined functor is called only if the inserting is success.
181
182             The function locks RCU internally.
183         */
184         template <typename Q, typename Func>
185         bool insert( Q const& val, Func f )
186         {
187             scoped_node_ptr sp( cxx_node_allocator().New( val ));
188             if ( base_class::insert( *sp, f )) {
189                 sp.release();
190                 return true;
191             }
192             return false;
193         }
194
195         /// Updates the element
196         /**
197             The operation performs inserting or replacing with lock-free manner.
198
199             If the \p val key not found in the set, then the new item created from \p val
200             will be inserted into the set iff \p bInsert is \p true.
201             Otherwise, if \p val is found, it is replaced with new item created from \p val
202             and previous item is disposed.
203             In both cases \p func functor is called.
204
205             The functor \p Func signature:
206             \code
207                 struct my_functor {
208                     void operator()( value_type& cur, value_type * prev );
209                 };
210             \endcode
211             where:
212             - \p cur - current element
213             - \p prev - pointer to previous element with such hash. \p prev is \p nullptr
214                  if \p cur was just inserted.
215
216             The functor may change non-key fields of the \p item; however, \p func must guarantee
217             that during changing no any other modifications could be made on this item by concurrent threads.
218
219             Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
220             i.e. the item has been inserted or updated,
221             \p second is \p true if the new item has been added or \p false if the item with key equal to \p val
222             already exists.
223         */
224         template <typename Q, typename Func>
225         std::pair<bool, bool> update( Q const& val, Func func, bool bInsert = true )
226         {
227             scoped_node_ptr sp( cxx_node_allocator().New( val ));
228             std::pair<bool, bool> bRes = base_class::do_update( *sp, func, bInsert );
229             if ( bRes.first )
230                 sp.release();
231             return bRes;
232         }
233
234         /// Inserts data of type \p value_type created in-place from <tt>std::forward<Args>(args)...</tt>
235         /**
236             Returns \p true if inserting successful, \p false otherwise.
237         */
238         template <typename... Args>
239         bool emplace( Args&&... args )
240         {
241             scoped_node_ptr sp( cxx_node_allocator().MoveNew( std::forward<Args>(args)... ));
242             if ( base_class::insert( *sp )) {
243                 sp.release();
244                 return true;
245             }
246             return false;
247         }
248
249         /// Deletes the item from the set
250         /**
251             The function searches \p hash in the set,
252             deletes the item found, and returns \p true.
253             If that item is not found the function returns \p false.
254
255             RCU should not be locked. The function locks RCU internally.
256         */
257         bool erase( hash_type const& hash )
258         {
259             return base_class::erase( hash );
260         }
261
262         /// Deletes the item from the set
263         /**
264             The function searches \p hash in the set,
265             call \p f functor with item found, and deltes the element from the set.
266
267             The \p Func interface is
268             \code
269             struct functor {
270                 void operator()( value_type& item );
271             };
272             \endcode
273
274             If \p hash is not found the function returns \p false.
275
276             RCU should not be locked. The function locks RCU internally.
277         */
278         template <typename Func>
279         bool erase( hash_type const& hash, Func f )
280         {
281             return base_class::erase( hash, f );
282         }
283
284         /// Extracts the item with specified \p hash
285         /**
286             The function searches \p hash in the set,
287             unlinks it from the set, and returns \ref cds::urcu::exempt_ptr "exempt_ptr" pointer to the item found.
288             If the item with key equal to \p key is not found the function returns an empty \p exempt_ptr.
289
290             RCU \p synchronize method can be called. RCU should NOT be locked.
291             The function does not call the disposer for the item found.
292             The disposer will be implicitly invoked when the returned object is destroyed or when
293             its \p release() member function is called.
294             Example:
295             \code
296             typedef cds::container::FeldmanHashSet< cds::urcu::gc< cds::urcu::general_buffered<> >, foo, my_traits > set_type;
297             set_type theSet;
298             // ...
299
300             typename set_type::exempt_ptr ep( theSet.extract( 5 ));
301             if ( ep ) {
302                 // Deal with ep
303                 //...
304
305                 // Dispose returned item.
306                 ep.release();
307             }
308             \endcode
309         */
310         exempt_ptr extract( hash_type const& hash )
311         {
312             return base_class::extract( hash );
313         }
314
315         /// Finds an item by it's \p hash
316         /**
317             The function searches the item by \p hash and calls the functor \p f for item found.
318             The interface of \p Func functor is:
319             \code
320             struct functor {
321                 void operator()( value_type& item );
322             };
323             \endcode
324             where \p item is the item found.
325
326             The functor may change non-key fields of \p item. Note that the functor is only guarantee
327             that \p item cannot be disposed during the functor is executing.
328             The functor does not serialize simultaneous access to the set's \p item. If such access is
329             possible you must provide your own synchronization schema on item level to prevent unsafe item modifications.
330
331             The function returns \p true if \p hash is found, \p false otherwise.
332         */
333         template <typename Func>
334         bool find( hash_type const& hash, Func f )
335         {
336             return base_class::find( hash, f );
337         }
338
339         /// Checks whether the set contains \p hash
340         /**
341             The function searches the item by its \p hash
342             and returns \p true if it is found, or \p false otherwise.
343         */
344         bool contains( hash_type const& hash )
345         {
346             return base_class::contains( hash );
347         }
348
349         /// Finds an item by it's \p hash and returns the item found
350         /**
351             The function searches the item by its \p hash
352             and returns the pointer to the item found.
353             If \p hash is not found the function returns \p nullptr.
354
355             RCU should be locked before the function invocation.
356             Returned pointer is valid only while RCU is locked.
357
358             Usage:
359             \code
360             typedef cds::container::FeldmanHashSet< your_template_params >  my_set;
361             my_set theSet;
362             // ...
363             {
364                 // lock RCU
365                 my_set::rcu_lock lock;
366
367                 foo * p = theSet.get( 5 );
368                 if ( p ) {
369                     // Deal with p
370                     //...
371                 }
372             }
373             \endcode
374         */
375         value_type * get( hash_type const& hash )
376         {
377             return base_class::get( hash );
378         }
379
380         /// Clears the set (non-atomic)
381         /**
382             The function unlink all data node from the set.
383             The function is not atomic but is thread-safe.
384             After \p %clear() the set may not be empty because another threads may insert items.
385         */
386         void clear()
387         {
388             base_class::clear();
389         }
390
391         /// Checks if the set is empty
392         /**
393             Emptiness is checked by item counting: if item count is zero then the set is empty.
394             Thus, the correct item counting feature is an important part of the set implementation.
395         */
396         bool empty() const
397         {
398             return base_class::empty();
399         }
400
401         /// Returns item count in the set
402         size_t size() const
403         {
404             return base_class::size();
405         }
406
407         /// Returns const reference to internal statistics
408         stat const& statistics() const
409         {
410             return base_class::statistics();
411         }
412
413         /// Returns the size of head node
414         size_t head_size() const
415         {
416             return base_class::head_size();
417         }
418
419         /// Returns the size of the array node
420         size_t array_node_size() const
421         {
422             return base_class::array_node_size();
423         }
424
425         /// Collects tree level statistics into \p stat
426         /**
427             The function traverses the set and collects statistics for each level of the tree
428             into \p feldman_hashset::level_statistics struct. The element of \p stat[i]
429             represents statistics for level \p i, level 0 is head array.
430             The function is thread-safe and may be called in multi-threaded environment.
431
432             Result can be useful for estimating efficiency of hash functor you use.
433         */
434         void get_level_statistics(std::vector< feldman_hashset::level_statistics>& stat) const
435         {
436             base_class::get_level_statistics(stat);
437         }
438
439     public:
440         ///@name Thread-safe iterators
441         ///@{
442         /// Bidirectional iterator
443         /** @anchor cds_container_FeldmanHashSet_rcu_iterators
444             The set supports thread-safe iterators: you may iterate over the set in multi-threaded environment
445             under explicit RCU lock.
446             RCU lock requirement means that inserting or searching is allowed but you must not erase the items from the set
447             since erasing under RCU lock can lead to a deadlock. However, another thread can call \p erase() safely
448             while your thread is iterating.
449
450             A typical example is:
451             \code
452             struct foo {
453                 uint32_t    hash;
454                 // ... other fields
455                 uint32_t    payload; // only for example
456             };
457             struct set_traits: cds::container::feldman_hashset::traits
458             {
459                 struct hash_accessor {
460                     uint32_t operator()( foo const& src ) const
461                     {
462                         retur src.hash;
463                     }
464                 };
465             };
466
467             typedef cds::urcu::gc< cds::urcu::general_buffered<>> rcu;
468             typedef cds::container::FeldmanHashSet< rcu, foo, set_traits > set_type;
469
470             set_type s;
471
472             // ...
473
474             // iterate over the set
475             {
476                 // lock the RCU.
477                 typename set_type::rcu_lock l; // scoped RCU lock
478
479                 // traverse the set
480                 for ( auto i = s.begin(); i != s.end(); ++i ) {
481                     // deal with i. Remember, erasing is prohibited here!
482                     i->payload++;
483                 }
484             } // at this point RCU lock is released
485             \endcode
486
487             Each iterator object supports the common interface:
488             - dereference operators:
489                 @code
490                 value_type [const] * operator ->() noexcept
491                 value_type [const] & operator *() noexcept
492                 @endcode
493             - pre-increment and pre-decrement. Post-operators is not supported
494             - equality operators <tt>==</tt> and <tt>!=</tt>.
495                 Iterators are equal iff they point to the same cell of the same array node.
496                 Note that for two iterators \p it1 and \p it2 the condition <tt> it1 == it2 </tt>
497                 does not entail <tt> &(*it1) == &(*it2) </tt>: welcome to concurrent containers
498
499             @note It is possible the item can be iterated more that once, for example, if an iterator points to the item
500             in an array node that is being splitted.
501         */
502         typedef typename base_class::iterator               iterator;
503         typedef typename base_class::const_iterator         const_iterator; ///< @ref cds_container_FeldmanHashSet_rcu_iterators "bidirectional const iterator" type
504         typedef typename base_class::reverse_iterator       reverse_iterator;       ///< @ref cds_container_FeldmanHashSet_rcu_iterators "bidirectional reverse iterator" type
505         typedef typename base_class::const_reverse_iterator const_reverse_iterator; ///< @ref cds_container_FeldmanHashSet_rcu_iterators "bidirectional reverse const iterator" type
506
507         /// Returns an iterator to the beginning of the set
508         iterator begin()
509         {
510             return base_class::begin();
511         }
512
513         /// Returns an const iterator to the beginning of the set
514         const_iterator begin() const
515         {
516             return base_class::begin();
517         }
518
519         /// Returns an const iterator to the beginning of the set
520         const_iterator cbegin()
521         {
522             return base_class::cbegin();
523         }
524
525         /// 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.
526         iterator end()
527         {
528             return base_class::end();
529         }
530
531         /// 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.
532         const_iterator end() const
533         {
534             return base_class::end();
535         }
536
537         /// 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.
538         const_iterator cend()
539         {
540             return base_class::cend();
541         }
542
543         /// Returns a reverse iterator to the first element of the reversed set
544         reverse_iterator rbegin()
545         {
546             return base_class::rbegin();
547         }
548
549         /// Returns a const reverse iterator to the first element of the reversed set
550         const_reverse_iterator rbegin() const
551         {
552             return base_class::rbegin();
553         }
554
555         /// Returns a const reverse iterator to the first element of the reversed set
556         const_reverse_iterator crbegin()
557         {
558             return base_class::crbegin();
559         }
560
561         /// Returns a reverse iterator to the element following the last element of the reversed set
562         /**
563             It corresponds to the element preceding the first element of the non-reversed container.
564             This element acts as a placeholder, attempting to access it results in undefined behavior.
565         */
566         reverse_iterator rend()
567         {
568             return base_class::rend();
569         }
570
571         /// Returns a const reverse iterator to the element following the last element of the reversed set
572         /**
573             It corresponds to the element preceding the first element of the non-reversed container.
574             This element acts as a placeholder, attempting to access it results in undefined behavior.
575         */
576         const_reverse_iterator rend() const
577         {
578             return base_class::rend();
579         }
580
581         /// Returns a const reverse iterator to the element following the last element of the reversed set
582         /**
583             It corresponds to the element preceding the first element of the non-reversed container.
584             This element acts as a placeholder, attempting to access it results in undefined behavior.
585         */
586         const_reverse_iterator crend()
587         {
588             return base_class::crend();
589         }
590     ///@}
591     };
592
593 }} // namespace cds::container
594
595 #endif // #ifndef CDSLIB_CONTAINER_FELDMAN_HASHSET_RCU_H