Provided by: librpma-dev_1.2.0-1_amd64 bug

NAME

       librpma - remote persistent memory access library

SYNOPSIS

             #include <librpma.h>
             cc ... -lrpma

DESCRIPTION

       librpma is a C library to simplify accessing persistent memory (PMem) on remote hosts over
       Remote Direct Memory Access (RDMA).

       The librpma library provides two possible schemes of operation: Remote Memory  Access  and
       Messaging.  Both  of  them  are available over a connection established between two peers.
       Both of these schemes can make use of PMem as well  as  DRAM  for  the  sake  of  building
       efficient and scalable Remote Persistent Memory Accessing (RPMA) applications.

REMOTE MEMORY ACCESS

       The  librpma  library  implements  four  basic  API calls dedicated for accessing a remote
       memory:

       •  rpma_read() - initiates transferring data from the remote memory to the local memory,

       •  rpma_write() - initiates transferring data from the local memory to the remote memory),

       •  rpma_atomic_write() - works like rpma_write(), but it allows transferring  8  bytes  of
          data  (RPMA_ATOMIC_WRITE_ALIGNMENT)  and  storing  them atomically in the remote memory
          (see rpma_atomic_write(3) for details and restrictions), and:

       •  rpma_flush() - initiates finalizing a transfer of data to the remote  memory.  Possible
          types of rpma_flush() operation:

          •  RPMA_FLUSH_TYPE_PERSISTENT - flush data down to the persistent domain,

          •  RPMA_FLUSH_TYPE_VISIBILITY - flush data deep enough to make it visible on the remote
             node.

       All the above functions use  the  attribute  flags  to  set  the  completion  notification
       indicator:

       •  RPMA_F_COMPLETION_ON_ERROR - generates the completion only on error

       •  RPMA_F_COMPLETION_ALWAYS  -  generates  the  completion  regardless  of a result of the
          operation.

       All of these operations are considered as  finished  when  the  respective  completion  is
       generated.

DIRECT WRITE TO PMEM

       Direct  Write  to  PMem  is  a feature of a platform and its configuration which allows an
       RDMA-capable network interface to write data to platform's PMem in a  persistent  way.  It
       may  be  impossible  because  of  e.g. caching mechanisms existing on the data's way. When
       Direct Write to PMem is impossible, operating in the  way  assuming  it  is  possible  may
       corrupt data on PMem, so this is why Direct Write to PMem is not enabled by default.

       On  the  current  Intel platforms, the only thing you have to do in order to enable Direct
       Write to PMem is turning off Intel Direct Data I/O (DDIO). Sometimes,  you  can  turn  off
       DDIO  either  globally  for  the  whole  platform  or  for a specific PCIe Root Port.  For
       details, please see the manual of your platform.

       When you have a platform which allows Direct Write to PMem, you have to  declare  this  is
       the  case  in your peer's configuration. The peer's configuration has to be transferred to
       all the peers which want to execute rpma_flush() with  RPMA_FLUSH_TYPE_PERSISTENT  against
       the platform's PMem and applied to the connection object which safeguards access to PMem.

       •  rpma_peer_cfg_set_direct_write_to_pmem() - declare Direct Write to PMem support

       •  rpma_peer_cfg_get_descriptor() - get the descriptor of the peer configuration

       •  rpma_peer_cfg_from_descriptor() - create a peer configuration from the descriptor

       •  rpma_conn_apply_remote_peer_cfg() - apply remote peer cfg to the connection

       For      details      on      how      to      use      these      APIs     please     see
       https://github.com/pmem/rpma/tree/main/examples/05-flush-to-persistent.

CLIENT OPERATION

       A client is the active side of the process of establishing a connection.  A  role  of  the
       peer  during  the  process  of establishing connection does not determine direction of the
       data flow (neither via Remote Memory Access nor via  Messaging).  After  establishing  the
       connection both peers have the same capabilities.

       The client, in order to establish a connection, has to perform the following steps:

       •  rpma_conn_req_new() - create a new outgoing connection request object

       •  rpma_conn_req_connect() - initiate processing the connection request

       •  rpma_conn_next_event() - wait for the RPMA_CONN_ESTABLISHED event

       After  establishing  the  connection  both  peers  can perform Remote Memory Access and/or
       Messaging over the connection.

       The client, in order to close a connection, has to perform the following steps:

       •  rpma_conn_disconnect() - initiate disconnection

       •  rpma_conn_next_event() - wait for the RPMA_CONN_CLOSED event

       •  rpma_conn_delete() - delete the closed connection

SERVER OPERATION

       A server is the passive side of the process of establishing a connection. Note that  after
       establishing the connection both peers have the same capabilities.

       The server, in order to establish a connection, has to perform the following steps:

       •  rpma_ep_listen() - create a listening endpoint

       •  rpma_ep_next_conn_req() - obtain an incoming connection request

       •  rpma_conn_req_connect() - initiate connecting the connection request

       •  rpma_conn_next_event() - wait for the RPMA_CONN_ESTABLISHED event

       After  establishing  the  connection  both  peers  can perform Remote Memory Access and/or
       Messaging over the connection.

       The server, in order to close a connection, has to perform the following steps:

       •  rpma_conn_next_event() - wait for the RPMA_CONN_CLOSED event

       •  rpma_conn_disconnect() - disconnect the connection

       •  rpma_conn_delete() - delete the closed connection

       When no more incoming connections are expected, the server can stop waiting for them:

       •  rpma_ep_shutdown() - stop listening and delete the endpoint

MEMORY MANAGEMENT

       Every piece of memory (either volatile or persistent) must be  registered  and  its  usage
       must  be  specified  in order to be used in Remote Memory Access or Messaging. This can be
       done using the following memory management librpma functions:

       •  rpma_mr_reg() which registers a memory region and creates a local  memory  registration
          object and

       •  rpma_mr_dereg()  which  deregisters  the  memory  region  and  deletes the local memory
          registration object.

       A description of the registered memory region sometimes has to be transferred via  network
       to  the  other  side  of  the  connection.  In  order  to  do  that a network-transferable
       description of the provided memory region (called 'descriptor') has to  be  created  using
       rpma_mr_get_descriptor().  On  the  other  side  of the connection the received descriptor
       should be decoded using  rpma_mr_remote_from_descriptor().  It  creates  a  remote  memory
       region's structure that allows for Remote Memory Access.

MESSAGING

       The librpma messaging API allows transferring messages (buffers of arbitrary data) between
       the peers. Transferring messages requires preparing buffers (memory regions) on the remote
       side  to  receive  the sent data. The received data are written to those dedicated buffers
       and the sender does not have to have a respective remote memory region object  to  send  a
       message.   The memory buffers used for messaging have to be registered using rpma_mr_reg()
       prior to rpma_send() or rpma_recv() function call.

       The librpma library implements the following messaging API:

       •  rpma_send() - initiates the send operation which transfers a  message  from  the  local
          memory to other side of the connection,

       •  rpma_recv()  -  initiates  the  receive operation which prepares a buffer for a message
          sent from other side of the connection,

       •  rpma_conn_req_recv() works as rpma_recv(), but it may be used before the connection  is
          established.

       All  of  these  operations  are  considered  as finished when the respective completion is
       generated.

COMPLETIONS

       RDMA operations generate complitions that notify a user that the respective operation  has
       been completed.

       The following operations are available in librpma:

       •  IBV_WC_RDMA_READ - RMA read operation

       •  IBV_WC_RDMA_WRITE - RMA write operation

       •  IBV_WC_SEND - messaging send operation

       •  IBV_WC_RECV - messaging receive operation

       •  IBV_WC_RECV_RDMA_WITH_IMM  -  messaging  receive operation for RMA write operation with
          immediate data

       All  operations  generate  completion  on  error.   The   operations   posted   with   the
       RPMA_F_COMPLETION_ALWAYS flag also generate a completion on success.  Completion codes are
       reused from  the  libibverbs  library,  where  the  IBV_WC_SUCCESS  status  indicates  the
       successful  completion  of an operation. Completions are collected in the completion queue
       (CQ) (see the QUEUES, PERFORMANCE AND RESOURCE USE section for more details on queues).

       The librpma library implements the following API for handling completions:

       •  rpma_conn_get_cq() gets the connection's main CQ,

       •  rpma_conn_get_rcq() gets the connection's receive CQ,

       •  rpma_cq_wait() waits for an incoming completion from the specified CQ (main or  receive
          CQ) - if it succeeds the completion can be collected using rpma_cq_get_wc(),

       •  rpma_cq_get_wc() receives the next available completion of an already posted operation.

PEER

       A peer is an abstraction representing an RDMA-capable device.  All other RPMA objects have
       to be created in the context of a peer.  A peer allows one to:

       •  establish connections (Client Operation)

       •  register memory regions (Memory Management)

       •  create endpoints for listening for incoming connections (Server Operation)

       At the beginning, in order to create a peer, a user has to obtain an RDMA  device  context
       by  the given IPv4/IPv6 address using rpma_utils_get_ibv_context(). Then a new peer object
       can be created using rpma_peer_new() and deleted using rpma_peer_delete().

SYNCHRONOUS AND ASYNCHRONOUS MODES

       By default, all endpoints and connections operate in the synchronous mode where:

       •  rpma_ep_next_conn_req(),

       •  rpma_cq_wait() and

       •  rpma_conn_get_next_event()

       are blocking calls. You can make those API calls non-blocking by modifying the  respective
       file descriptors:

       •  rpma_ep_get_fd() - provides a file descriptor for rpma_ep_next_conn_req()

       •  rpma_cq_get_fd() - provides a file descriptor for rpma_cq_wait()

       •  rpma_conn_get_event_fd() - provides a file descriptor for rpma_conn_get_next_event()

       When you have a file descriptor, you can make it non-blocking using fcntl(2) as follows:

               int ret = fcntl(fd, F_GETFL);
               fcntl(fd, F_SETFL, flags | O_NONBLOCK);

       Such change makes the respective API call non-blocking automatically.

       The provided file descriptors can also be used for scalable I/O handling like epoll(7).

       Please   see   the   example   showing   how   to  make  use  of  RPMA  file  descriptors:
       https://github.com/pmem/rpma/tree/main/examples/06-multiple-connections

QUEUES, PERFORMANCE AND RESOURCE USE

       Remote Memory Access operations, Messaging operations and their Completions consume  space
       in  queues  allocated in an RDMA-capable network interface (RNIC) hardware for each of the
       connections. You must be aware of the existence of these queues:

       •  completion queue (CQ) where  completions  of  operations  are  placed,  either  when  a
          completion  was  required  by a user (RPMA_F_COMPLETION_ALWAYS) or a completion with an
          error occurred. All Remote  Memory  Access  operations  and  Messaging  operations  can
          consume CQ space.

       •  send  queue  (SQ)  where all Remote Memory Access operations and rpma_send() operations
          are placed before they are executed by RNIC.

       •  receive queue (RQ) where rpma_recv() entries are placed before they are consumed by the
          rpma_send() coming from another side of the connection.

       You must assume SQ and RQ entries occupy the place in their respective queue till:

       •  a respective operation's completion is generated or

       •  a completion of an operation, which was scheduled later, is generated.

       You must also be aware that RNIC has limited resources so it is impossible to store a very
       long set of queues for many possibly existing connections. If all of the queues  will  not
       fit  into  RNIC's resources it will start using the platform's memory for this purpose. In
       this case, the performance will be degraded because of inevitable cache misses.

       Because the length of queues has so profound impact on the performance of RPMA application
       you can configure the length of each of the queues separately for each of the connections:

       •  rpma_conn_cfg_set_cq_size() - set length of CQrpma_conn_cfg_set_sq_size() - set length of SQrpma_conn_cfg_set_rq_size() - set length of RQ

       When  the  connection  configuration  object  is  ready  it  has  to  be  used  for either
       rpma_conn_req_new() or rpma_ep_next_conn_req() for the settings to take effect.

THREAD SAFETY

       The analysis of thread safety of the librpma  library  is  described  in  details  in  the
       THREAD_SAFETY.md file:

               https://github.com/pmem/rpma/blob/main/THREAD_SAFETY.md

ON-DEMAND PAGING SUPPORT

       On-Demand-Paging (ODP) is a technique that simplifies the memory registration process (for
       example, applications no longer need to pin down the  underlying  physical  pages  of  the
       address  space  and  track the validity of the mappings). On-Demand Paging is available if
       both the hardware and the kernel support it. The detailed description of ODP can be  found
       here:

            https://community.mellanox.com/s/article/understanding-on-demand-paging--odp-x

       State  of  ODP  support  can  be checked using the rpma_utils_ibv_context_is_odp_capable()
       function that queries the RDMA device context's capabilities and checks if it supports On-
       Demand Paging.

       The  librpma library uses ODP automatically if it is supported. ODP support is required to
       register PMem memory region mapped from File System DAX (FSDAX).

DEBUGGING AND ERROR HANDLING

       If a librpma function may fail, it returns a negative error code. Checking if the returned
       value is non-negative is the only programmatically available way to verify if the API call
       succeeded.  The exact meaning of all error codes  is  described  in  the  manual  of  each
       function.

       The  librpma  library  implements the logging API which may give additional information in
       case of an error and during normal operation as well, according  to  the  current  logging
       threshold levels.

       The   function   that   will   handle   all  generated  log  messages  can  be  set  using
       rpma_log_set_function(). The logging function can be either the default  logging  function
       (built  into  the  library)  or a user-defined, thread-safe, function. The default logging
       function can write messages to syslog(3) and stderr(3). The logging threshold level can be
       set or got using rpma_log_set_threshold() or rpma_log_get_threshold() respectively.

       There     is     an    example    of    the    usage    of    the    logging    functions:
       https://github.com/pmem/rpma/tree/main/examples/log

EXAMPLES

       See https://github.com/pmem/rpma/tree/main/examples for examples of using the librpma API.

ACKNOWLEDGEMENTS

       librpma is built on the top of libibverbs and librdmacm APIs.

DEPRECATING

       Using of the API calls which are marked as deprecated should be avoided, because they will
       be removed in a new major release.

       NOTE: API calls deprecated in 0.X release will be removed in 0.(X+1) release usually.

SEE ALSO

       https://pmem.io/rpma/