# SPDX-License-Identifier: BSD-3-Clause
# Copyright 2021-2022, Intel Corporation

/** @defgroup containers Containers
  * Custom (but STL-like) containers for persistent memory.
  *
  * Persistent containers are implemented-from-scratch with optimized on-media layouts
  * and algorithms to fully exploit the potential and features of persistent memory.
  * Besides specific internal implementation details, libpmemobj-cpp persistent memory
  * containers have (where possible) the well-known STL-like interface and they work
  * with STL algorithms. Containers' methods guarantee atomicity, consistency and
  * durability. Note that every single modifier method (any one modifying the state of
  * the container, like resize or push_back) opens transaction internally and guarantees
  * full exception safety (modifications will be either committed or rolled-back
  * if an exception was thrown, or crash happened - for more info see @ref transactions).
  * There is no need for using transaction when calling modifier methods whatsoever.
  *
  * There is a separate Feature describing and listing all
  * experimental containers, see @ref experimental_containers.
  *
  * ## Rationale for implementing pmem-aware containers
  *
  * The C++ standard library containers collection is something that persistent
  * memory programmers may want to use. Containers manage the lifetime of held
  * objects through allocation/creation and deallocation/destruction with the use of
  * allocators. Implementing custom persistent allocator for C++ STL (Standard
  * Template Library) containers has two main downsides:
  *
  * Implementation details:
  * - STL containers do not use algorithms optimal from persistent memory programming point of view.
  * - Persistent memory containers should have durability and consistency properties,
  *   while not every STL method guarantees strong exception safety.
  * - Persistent memory containers should be designed with an awareness of
  *   fragmentation limitations.
  *
  * Memory layout:
  * - The STL does not guarantee that the container layout will remain unchanged in new library versions.
  *
  * Due to these obstacles, the libpmemobj-cpp contains the set of custom,
  * implemented-from-scratch containers with optimized on-media layouts and
  * algorithms to fully exploit the potential and features of persistent memory.
  * These methods guarantee atomicity, consistency and durability. Besides specific
  * internal implementation details, libpmemobj-cpp persistent memory containers
  * have the well-known STL-like interface and they work with STL algorithms.
  *
  * ## Additional resources
  * - [Blog post on pmem.io about libpmemobj-cpp persistent containers](https://pmem.io/2018/11/20/cpp-persistent-containers.html)
  * - [A blog post about array container](https://pmem.io/2018/11/02/cpp-array.html)
  * - [Very first description of (then yet experimental) vector container](https://pmem.io/2019/02/20/cpp-vector.html)
  *
  * For curious readers - back then in 2017 - there was an approach to re-use and modify the
  * STL containers to be pmem-aware. Story of implementing this experiment can be found in
  * [the blog post on pmem.io](https://pmem.io/2017/07/10/cpp-containers.html).
  * The repo with that code is now dead, but left for the reference and historical perspective.
  */

/** @defgroup experimental_containers Experimental Containers
  * PMem containers under development and/or in testing.
  *
  * It's very important to underline:
  * @note **Experimental API may change (with no backward compatibility)
  * and it should not be used in a production environment**
  *
  * A container is considered **experimental** because:
  * - it may not be a 100% functionally ready,
  * - tests are not finished and there might be some gaps/corner cases to be discovered and fixed,
  * - we may still tweak the API (if we find it's not well defined),
  * - its layout may change.
  *
  * For general containers' description please see @ref containers.
  */

/** @defgroup transactions Transactions
  * Transactional approach to store data on pmem.
  *
  * ## General info about transactions
  *
  * The heart of the libpmemobj are transactions. A transaction is defined as series of operations on
  * **persistent memory objects** that either all occur, or nothing occurs. In particular, if the execution
  * of a transaction is interrupted by a power failure or a system crash, it is guaranteed that after
  * system restart, all the changes made as a part of the uncompleted transaction will be rolled back,
  * restoring the consistent state of the memory pool from the moment when the transaction was started.
  *
  * @note Any operations not using libpmemobj-cpp API (like `int x = 5` or `malloc()`) used within
  * transaction will not be a part ot the transaction and won't be rolled back on failure! To properly
  * store variables on pmem use @ref primitives , to allocate data on pmem see @ref allocation functions.
  *
  * In C++ bindings (*this library*) transactions were designed (in comparison to C API)
  * to be as developer-friendly as possible. Even though libpmemobj++ are the bindings you should not
  * mix these two APIs - using libpmemobj (C API) in C++ application will not work!
  *
  * Let's take a look at the following snippet:
  *
  * @snippet transaction/transaction.cpp general_tx_example
  *
  * Code above is an example how automatic transaction can look like.
  * After object creation there are a few statements executed within a transaction.
  * Transaction will be committed during *tx* object's destruction at the end of the scope.
  *
  * It's worth noticing that @ref pmem::obj::flat_transaction is recommended to use over @ref pmem::obj::basic_transaction.
  * An extra explanation is provided inline an example in @ref pmem::obj::flat_transaction description.
  *
  * Mentioned above transactions are handled through two internal classes:
  *
  * - **manual** transactions has to be committed explicitly, otherwise it will abort.
  * All operations between creating and destroying the transaction
  * object are treated as performed in a transaction block and
  * can be rolled back.
  * The best way to use manual transactions is by
  * @ref pmem::obj::transaction::run, which is used in example above.
  *
  * - **automatic** transactions are only available in C++17. All operations
  * between creating and destroying the transaction object are treated as
  * performed in a transaction block and can be rolled back.
  * If you have a C++17 compliant compiler, the automatic transaction will
  * commit and abort automatically depending on the context of object's destruction.
  *
  * In both approaches one of the parameters is the `locks`. They are held for the entire duration
  * of the transaction and they are released at the end of the scope - so within the `catch` block,
  * they are already unlocked.
  *
  * If you want to read more and see example usages of both, you have to see
  * flat or basic transaction documentation, because each implementation may differ.
  *
  * ## Lifecycle and stages:
  *
  * When you are using transaction API a transaction can be in one of the following states:
  * - *TX_STAGE_NONE* - no open transaction in this thread
  * - *TX_STAGE_WORK* - the transaction in progress
  * - *TX_STAGE_ONCOMMIT* - the transaction is successfully committed
  * - *TX_STAGE_FINALLY* - ready for clean up
  * - *TX_STAGE_ONABORT* - starting the transaction failed or transaction aborted
  *
  * Moving from one stage to another is possible under some conditions, but
  * in libpmemobj-cpp it's transparent for user, so please focus on relationships between stages.
  * Look at the diagram below:
  *
  * ![lifecycle](https://pmem.io/images/posts/lifecycle.png "Transaction lifecycle")
  *
  * To be more familiar with functions used in diagram read e.g. **pmemobj_tx_begin**(3) manpage
  * (C API for [libpmemobj](https://pmem.io/pmdk/libpmemobj/), link below in *Additional resources*).
  *
  * If you need to read general information about transaction move to the *Additional resources* section.
  *
  * ## Example of flat_transaction
  * For comparison with the previous snippet, here is a code snippet of
  * @ref pmem::obj::flat_transaction which is listed below with basic explanation inline.
  * @snippet transaction/transaction.cpp tx_nested_struct_example
  * If you read the inline comments you should be able to notice the difference
  * between @ref pmem::obj::flat_transaction and @ref pmem::obj::basic_transaction.
  * For more examples please look at the
  * [examples directory](https://github.com/pmem/libpmemobj-cpp/tree/master/examples) in libpmemobj-cpp repository.
  *
  * ## Additional resources
  * - [pmemobj_tx_begin(3) manpage with transaction description (C API)](https://pmem.io/pmdk/manpages/linux/master/libpmemobj/pmemobj_tx_begin.3)
  * - [blog post about transactions](https://pmem.io/2016/05/25/cpp-07.html)
  * - [blog post about transactional allocations](https://pmem.io/2016/05/19/cpp-06.html)
  */

/** @defgroup allocation Allocation
  * Functions and classes to support allocations on pmem
  *
  * Libpmemobj-cpp introduced special functions for allocating objects and arrays
  * of objects on persistent memory, with ease. For all `make_persistent` specializations
  * there are also `delete_persistent` counterparts. The latter are used to free memory
  * of previously allocated objects or arrays, and calling their destructors. Each
  * specialization comes in two versions - atomic and transactional. First one is
  * distinguished with `_atomic` suffix (e.g. `make_persistent_atomic()`) and should not
  * be called within an active transaction - it may lead to undefined behavior in case
  * of transaction's rollback. On the other hand, transactional functions will throw
  * an exception if called outside of an active transaction.
  *
  * For more flexibly approach we introduced pmem::obj::allocator class, which implements
  * the concept of C++ Allocator. Allocation and deallocation using this class can only
  * happen within an active transactions.
  *
  * The *typical use case* of data allocation on pmem would be:
  * @snippet make_persistent/make_persistent.cpp make_example
  *
  * For allocator usage see pmem::obj::experimental::inline_string example:
  * @snippet inline_string/inline_string.cpp inline_string_example
  */

/** @defgroup data_view Data View
  * Various views of persistent objects
  *
  * Classes listed on this page provide (often simplified) views of persistent data.
  * They are delivered to ease the usage or for better performance. Please,
  * take a look at description of each class to get the details of their behavior.
  */

/** @defgroup synchronization Synchronization Primitives
  * Persistent memory resident implementation of synchronization primitives.
  *
  * In concurrent programming, we often require mechanisms for synchronizing access to shared resources.
  * Typically to solve such issues we use synchronization primitives like mutexes and condition variables.
  * As persistent memory offers bigger capacity than DRAM it may be useful to store synchronization primitives
  * on it. Unfortunately such approach may cause performance degradation due to frequent writes to a memory
  * with relatively higher latency (it's because taking a lock or signaling a conditional variable often
  * requires additional writes). Few extra words how locks can be used in libpmemobj-cpp can be found in
  * @ref transactions.
  *
  * It's worth noticing that pmem locks are automatically released on recovery or when crash happened.
  *
  * ## Additional resources
  * - [Libpmemobj-cpp - lessons learned](https://pmem.io/blog/2021/09/libpmemobj-cpp-lessons-learned)
  *   In this blog post we explain, i.a., why keeping locks on pmem is not a good idea.
  */

/** @defgroup primitives Primitives
  * Basic classes that provide PMEM-aware pointers and pool handlers.
  *
  * ## Pointers
  * There are few types to handle data on PMEM.
  * - @ref pmem::obj::persistent_ptr<T> - implements a smart pointer.
  * It encapsulates the [PMEMoid](https://pmem.io/2015/06/11/type-safety-macros.html) fat
  * pointer and provides member access, dereference and array access operators.
  * - @ref pmem::obj::experimental::self_relative_ptr<T> - implements a smart ptr.
  * It encapsulates the self-offsetted pointer and provides member access, dereference and array access operators.
  * self_relative_ptr in comparison to persistent_ptr is:
  *   - smaller in size (8B vs 16B),
  *   - can be used with atomic operations,
  *   - dereferenced faster (it's important, e.g., in loops),
  *   - allows vectorization,
  *   - if stored in a persistent memory pool, it can only points to elements within the same pool.
  * - @ref pmem::obj::p<T> - template class that can be used for all variables (except persistent pointers),
  * which are used in @ref transactions.
  * This class is not designed to be used with compound types. For that see the @ref pmem::obj::persistent_ptr.
  * - @ref pmem::obj::experimental::v<T> - property-like template class that has to be used for
  * all volatile variables that reside on persistent memory. This class ensures that the enclosed
  * type is always properly initialized by always calling the class default constructor
  * exactly once per instance of the application. This class has 8 bytes of storage overhead.
  *
  * ## Pool handles
  * Pool class provides basic operations on pmemobj [pools](https://pmem.io/2016/05/10/cpp-05.html).
  * C++ API for pools should not be mixed with C API. For example explicitly calling `pmemobj_set_user_data(pop)`
  * on pool which is handled by C++ pool object is undefined behaviour.
  *
  * There are few pool handlers:
  * - @ref pmem::obj::pool<T> - the template parameter defines the type of the root object within the pool.
  * This pool class inherits also some methods from the base class: @ref pmem::obj::pool_base.
  * Example: @snippet pool/pool.cpp pool_example
  * - @ref pmem::obj::pool_base<T> - non template, basic version of pool,
  * useful when specifying root type is not desirable. The typical usage
  * example would be:
  * @snippet pool/pool.cpp pool_base_example
  */

/** @defgroup exceptions Exceptions
  * Possible exceptions that could be thrown by the libpmemobj++.
  *
  * In runtime, some operations may fail, then all you need is to catch the exception.
  * Every pmem exception has `std::runtime_error` in its inheritance tree, which means
  * that all exceptions can be caught using just this type. Each exception contains
  * proper message with an error description.
  *
  * Look at the list on this page to explore all exceptions with their descriptions.
  *
  * Transaction handles uncaught exceptions thrown inside its scope, then aborts
  * and rethrow the previous exception. That way you never loose the original
  * exception and at the same time, the transaction state is handled
  * properly by the library.
  *
  * Let's consider following example:
  * @snippet examples/mpsc_queue/mpsc_queue.cpp mpsc_main
  *
  * There are plenty of try-catch blocks placed to handle possible errors that can occur in some
  * conditions. E.g. @ref pmem::obj::pool<T>::open can lead to @ref pmem::pool_error.
  * The next exception, **std::exception**, is placed to handle possible errors during allocation,
  * coming from @ref pmem::obj::make_persistent. Worth being careful using any new function
  * because some exceptions are not obvious, e.g., pmem::obj::pool<T>::close
  * at the end of the code, which may throw **std::logic_error**.
  *
  * You should check every function you will use in the context of possible
  * exceptions and then handle them to avoid a crash.
  */
