Commit cc0eeb35 authored by Maged Michael's avatar Maged Michael Committed by Facebook GitHub Bot

hazptr: Improve documentation

Summary: Improve documentation and make the description of synchronous reclamation  consistent with the current implementation.

Reviewed By: yfeldblum

Differential Revision: D28575528

fbshipit-source-id: e8f37e02d18b12a0e653264c128492a98cba6a1d
parent 41b7e6ba
...@@ -47,7 +47,7 @@ template <template <typename> class Atom = std::atomic> ...@@ -47,7 +47,7 @@ template <template <typename> class Atom = std::atomic>
class hazptr_rec; class hazptr_rec;
/// ///
/// Classes related to objects protected by hazard pointers. /// Classes related to objects protectable by hazard pointers.
/// Defined in HazptrObj.h /// Defined in HazptrObj.h
/// ///
......
...@@ -187,17 +187,14 @@ ...@@ -187,17 +187,14 @@
/// - Both can protect linked structures. Hazard pointers needs /// - Both can protect linked structures. Hazard pointers needs
/// additional link counting with low or moderate overhead for /// additional link counting with low or moderate overhead for
/// update operations, and no overhead for readers. RCU protects /// update operations, and no overhead for readers. RCU protects
/// protects linked structures automatically, because it protects /// linked structures automatically, because it implicitly protects
/// everything. /// all protectable objects.
/// ///
/// Differences from the Standard Proposal /// Differences from the Standard Proposal
/// -------------------------------------- /// --------------------------------------
/// - The latest standard proposal is in wg21.link/p0566. /// - The latest standard proposal is in wg21.link/p1121. The
/// - This library's API differs from the standard proposal because: /// substance of the proposal was frozen around October 2017, but
/// (a) the standard proposal is changing based on committee /// there were subsequent API changes based on committee feadback.
/// feedback, and (b) this library provides additional
/// fast-evolving features based on usage experience that do not
/// have corressponding proposed standard wording.
/// - The main differences are: /// - The main differences are:
/// o This library uses an extra atomic template parameter for /// o This library uses an extra atomic template parameter for
/// testing and debugging. /// testing and debugging.
...@@ -213,3 +210,5 @@ ...@@ -213,3 +210,5 @@
/// proposal. /// proposal.
/// o Link counting support and protection of linked structures is /// o Link counting support and protection of linked structures is
/// not part of the current standard proposal. /// not part of the current standard proposal.
/// o The standard proposal does not include cohorts and the
/// associated synchronous reclamation capabilities.
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
#pragma once #pragma once
#include <atomic> #include <atomic>
#include <unordered_set> // for hash set in bulk_reclaim #include <unordered_set>
#include <folly/Memory.h> #include <folly/Memory.h>
#include <folly/Portability.h> #include <folly/Portability.h>
...@@ -36,6 +36,8 @@ namespace folly { ...@@ -36,6 +36,8 @@ namespace folly {
namespace detail { namespace detail {
/** Threshold for the number of retired objects to trigger
asynchronous reclamation. */
constexpr int hazptr_domain_rcount_threshold() { constexpr int hazptr_domain_rcount_threshold() {
return 1000; return 1000;
} }
...@@ -49,58 +51,46 @@ constexpr int hazptr_domain_rcount_threshold() { ...@@ -49,58 +51,46 @@ constexpr int hazptr_domain_rcount_threshold() {
* *
* Most user code need not specify any domains. * Most user code need not specify any domains.
* *
* Notes on destruction order, tagged objects, locking and deadlock * Notes on destruction order and tagged objects:
* avoidance: * - Tagged objects support reclamation order guarantees (i.e.,
* - Tagged objects support reclamation order guarantees. A call to * synchronous reclamation). A call to cleanup_cohort_tag(tag)
* cleanup_cohort_tag(tag) guarantees that all objects with the * guarantees that all objects with the specified tag are reclaimed
* specified tag are reclaimed before the function returns. * before the function returns.
* - Due to the strict order, access to the set of tagged objects
* needs synchronization and care must be taken to avoid deadlock.
* - There are two types of reclamation operations to consider: * - There are two types of reclamation operations to consider:
* - Type A: A Type A reclamation operation is triggered by meeting * - Asynchronous reclamation: It is triggered by meeting some
* some threshold. Reclaimed objects may have different * threshold for the number of retired objects or the time since
* tags. Hazard pointers are checked and only unprotected objects * the last asynchronous reclamation. Reclaimed objects may have
* are reclaimed. This type is expected to be expensive but * different tags or no tags. Hazard pointers are checked and only
* infrequent and the cost is amortized over a large number of * unprotected objects are reclaimed. This type is expected to be
* reclaimed objects. This type is needed to guarantee an upper * expensive but infrequent and the cost is amortized over a large
* bound on unreclaimed reclaimable objects. * number of reclaimed objects. This type is needed to guarantee
* - Type B: A Type B reclamation operation is triggered by a call * an upper bound on unreclaimed reclaimable objects.
* to the function cleanup_cohort_tag for a specific tag. All * - Synchronous reclamation: It is invoked by calling
* objects with the specified tag must be reclaimed * cleanup_cohort_tag for a specific tag. All objects with the
* unconditionally before returning from such a function * specified tag must be reclaimed unconditionally before
* call. Hazard pointers are not checked. This type of reclamation * returning from such a function call. Hazard pointers are not
* operation is expected to be inexpensive and may be invoked more * checked. This type of reclamation operation is expected to be
* frequently than Type A. * inexpensive and may be invoked more frequently than
* - Tagged retired objects are kept in a single list in the domain * asynchronous reclamation.
* structure, named tagged_. * - Tagged retired objects are kept in a sharded list in the domain
* - Both Type A and Type B of reclamation pop all the objects in * structure.
* tagged_ and sort them into two sets of reclaimable and * - Both asynchronous and synchronous reclamation pop all the
* unreclaimable objects. The objects in the reclaimable set are * objects in the tagged list(s) and sort them into two sets of
* reclaimed and the objects in the unreclaimable set are pushed * reclaimable and unreclaimable objects. The objects in the
* back in tagged_. * reclaimable set are reclaimed and the objects in the
* - The tagged_ list is locked between popping all objects and * unreclaimable set are pushed back in the tagged list(s).
* - The tagged list(s) are locked between popping all objects and
* pushing back unreclaimable objects, in order to guarantee that * pushing back unreclaimable objects, in order to guarantee that
* Type B operations do not miss any objects that match the * synchronous reclamation operations do not miss any objects.
* specified tag. * - Asynchronous reclamation can release the lock(s) on the tagged
* - A Type A operation cannot release the lock on the tagged_ list * list(s) before reclaiming reclaimable objects, because it pushes
* before reclaiming reclaimable objects, to prevent concurrent * reclaimable tagged objects in their respective cohorts, which
* Type B operations from returning before the reclamation of * would handle concurrent synchronous reclamation of such objects
* objects with matching tags. * properly.
* - A Type B operation can release the lock on tagged_ before * - Synchronous reclamation operations can release the lock on the
* reclaiming objects because the set of reclaimable objects by * tagged list shard before reclaiming objects because the sets of
* Type B operations are disjoint. * reclaimable objects by different synchronous reclamation
* - The lock on the tagged_ list is re-entrant, to prevent deadlock * operations are disjoint.
* when reclamation in a Type A operation requires a Type B
* reclamation operation to complete.
* - The implementation allows only one pattern of re-entrance: An
* inner Type B inside an outer Type A.
* - An inner Type B operation must have access and ability to modify
* the outer Type A operation's set of reclaimable objects and
* their children objects in order not to miss objects that match
* the specified tag. Hence, Type A operations use data members,
* unprotected_ and children_, to keep track of these objects
* between reclamation steps and to provide inner Type B operations
* access to these objects.
*/ */
template <template <typename> class Atom> template <template <typename> class Atom>
class hazptr_domain { class hazptr_domain {
...@@ -563,7 +553,7 @@ class hazptr_domain { ...@@ -563,7 +553,7 @@ class hazptr_domain {
void free_hazptr_recs() { void free_hazptr_recs() {
/* Leak the hazard pointers for the default domain to avoid /* Leak the hazard pointers for the default domain to avoid
destruction order issues with thread caches. */ destruction order issues with thread caches. */
if (this == &default_hazptr_domain<Atom>()) { if (this == &default_hazptr_domain<Atom>()) {
return; return;
} }
...@@ -632,7 +622,7 @@ class hazptr_domain { ...@@ -632,7 +622,7 @@ class hazptr_domain {
/*** Full fence ***/ asymmetricHeavyBarrier(AMBFlags::EXPEDITED); /*** Full fence ***/ asymmetricHeavyBarrier(AMBFlags::EXPEDITED);
auto rec = hazptrs_.load(std::memory_order_acquire); auto rec = hazptrs_.load(std::memory_order_acquire);
/* Part 1 - read hazard pointer values into private search structure */ /* Part 1 - read hazard pointer values into private search structure */
std::unordered_set<const void*> hashset; // TOTO: lock-free fixed hash set std::unordered_set<const void*> hashset;
for (; rec; rec = rec->next()) { for (; rec; rec = rec->next()) {
hashset.insert(rec->hazptr()); hashset.insert(rec->hazptr());
} }
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#include <folly/synchronization/detail/HazptrUtils.h> #include <folly/synchronization/detail/HazptrUtils.h>
/// ///
/// Classes related to objects protected by hazard pointers. /// Classes related to objects protectable by hazard pointers.
/// ///
namespace folly { namespace folly {
...@@ -36,14 +36,14 @@ namespace folly { ...@@ -36,14 +36,14 @@ namespace folly {
/** /**
* hazptr_obj * hazptr_obj
* *
* Private base class for objects protected by hazard pointers. * Private base class for objects protectable by hazard pointers.
* *
* Data members: * Data members:
* - next_: link to next object in private singly linked lists. * - next_: link to next object in private singly linked lists.
* - reclaim_: reclamation function for this object. * - reclaim_: reclamation function for this object.
* - cohort_tag_: A pointer to a cohort (a linked list where the * - cohort_tag_: A pointer to a cohort (where the object is to be
* object is to be pushed when retired). It can also be used as a * pushed when retired). It can also be used as a tag (see
* tag (see below). See details below. * below).
* *
* Cohorts, Tags, Tagged Objects, and Untagged Objects: * Cohorts, Tags, Tagged Objects, and Untagged Objects:
* *
...@@ -53,27 +53,27 @@ namespace folly { ...@@ -53,27 +53,27 @@ namespace folly {
* and/or mixed with unrelated objects. * and/or mixed with unrelated objects.
* *
* - Tags: A tag is a unique identifier used for fast identification * - Tags: A tag is a unique identifier used for fast identification
* of related objects. Tags are implemented as addresses of * of related objects for synchronous reclamation. Tags are
* cohorts, with the lowest bit set (to save the space of separate * implemented as addresses of cohorts, with the lowest bit set (to
* cohort and tag data members and to differentiate from cohorts of * save the space of separate cohort and tag data members and to
* untagged objects. * differentiate from cohorts of untagged objects.
* *
* - Tagged objects: Objects are tagged for fast identification. The * - Tagged objects: Objects are tagged for fast identification. The
* primary use case is for guaranteeing the destruction of all * primary use case is for synchronous reclamation ((e.g., the
* objects with a certain tag (e.g., the destruction of all Key and * destruction of all Key and Value objects that were part of a
* Value objects that were part of a Folly ConcurrentHashMap * Folly ConcurrentHashMap instance). Member function
* instance). Member function set_cohort_tag makes an object tagged. * set_cohort_tag makes an object tagged.
* *
* - Untagged objects: Objects that do not need to be identified * - Untagged objects: Objects that do not need to be identified
* separately from unrelated objects are not tagged (to keep tagged * separately from unrelated objects are not tagged (to keep tagged
* objects uncluttered). Untagged objects may or may not be * objects uncluttered). Untagged objects may or may not be
* associated with cohorts. An example of untagged objects * associated with cohorts. An example of untagged objects
* associated with cohorts are Segment-s of Folly UnboundedQueue. * associated with cohorts are Segment-s of Folly UnboundedQueue.
* Although such objects do not need to be tagged, keeping them in * Although such objects do not need synchronous reclamation,
* cohorts helps avoid cases of a few missing objects delaying the * keeping them in cohorts helps avoid cases of a few missing
* reclamation of large numbers of link-counted objects. Objects * objects delaying the reclamation of large numbers of
* are untagged either by default or after calling * link-counted objects. Objects are untagged either by default or
* set_cohort_no_tag. * after calling set_cohort_no_tag.
* *
* - Thread Safety: Member functions set_cohort_tag and * - Thread Safety: Member functions set_cohort_tag and
* set_cohort_no_tag are not thread-safe. Thread safety must be * set_cohort_no_tag are not thread-safe. Thread safety must be
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
#include <folly/synchronization/detail/Sleeper.h> #include <folly/synchronization/detail/Sleeper.h>
/// Linked list class templates used in the hazard pointer library: /// Linked list class templates used in the hazard pointer library:
/// - linked_list: Sequential linked list that uses a pre-existing /// - linked_list: Sequential linked list that uses pre-existing
/// members next() and set_next();. /// members next() and set_next();.
/// - shared_head_tail_list: Thread-safe linked list that maintains /// - shared_head_tail_list: Thread-safe linked list that maintains
/// head and tail pointers. Supports push and pop_all. /// head and tail pointers. Supports push and pop_all.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment