Provided by: librpmem-dev_1.11.1-3build1_amd64 bug

NAME

       librpmem - remote persistent memory support library (EXPERIMENTAL)

SYNOPSIS

              #include <librpmem.h>
              cc ... -lrpmem

   Library API versioning:
              const char *rpmem_check_version(
                  unsigned major_required,
                  unsigned minor_required);

   Error handling:
              const char *rpmem_errormsg(void);

   Other library functions:
       A description of other librpmem functions can be found on the following manual pages:

       • rpmem_create(3), rpmem_persist(3)

DESCRIPTION

       librpmem  provides low-level support for remote access to persistent memory (pmem) utilizing RDMA-capable
       RNICs.  The library can be used to remotely replicate  a  memory  region  over  the  RDMA  protocol.   It
       utilizes an appropriate persistency mechanism based on the remote node's platform capabilities.  librpmem
       utilizes the ssh(1) client to authenticate a  user  on  the  remote  node,  and  for  encryption  of  the
       connection's out-of-band configuration data.  See SSH, below, for details.

       The  maximum  replicated  memory  region size can not be bigger than the maximum locked-in-memory address
       space limit.  See memlock in limits.conf(5) for more details.

       This library is for applications that use remote persistent memory directly,  without  the  help  of  any
       library-supplied  transactions or memory allocation.  Higher-level libraries that build on libpmem(7) are
       available and are recommended for most applications, see:

       • libpmemobj(7), a general use persistent memory  API,  providing  memory  allocation  and  transactional
         operations on variable-sized objects.

TARGET NODE ADDRESS FORMAT

              [<user>@]<hostname>[:<port>]

       The  target node address is described by the hostname which the client connects to, with an optional user
       name.  The user  must  be  authorized  to  authenticate  to  the  remote  machine  without  querying  for
       password/passphrase.  The optional port number is used to establish the SSH connection.  The default port
       number is 22.

REMOTE POOL ATTRIBUTES

       The rpmem_pool_attr structure describes a remote pool and is stored  in  remote  pool's  metadata.   This
       structure  must  be passed to the rpmem_create(3) function by caller when creating a pool on remote node.
       When opening the pool using rpmem_open(3) function the appropriate fields are read from  pool's  metadata
       and returned back to the caller.

              #define RPMEM_POOL_HDR_SIG_LEN    8
              #define RPMEM_POOL_HDR_UUID_LEN   16
              #define RPMEM_POOL_USER_FLAGS_LEN 16

              struct rpmem_pool_attr {
                  char signature[RPMEM_POOL_HDR_SIG_LEN];
                  uint32_t major;
                  uint32_t compat_features;
                  uint32_t incompat_features;
                  uint32_t ro_compat_features;
                  unsigned char poolset_uuid[RPMEM_POOL_HDR_UUID_LEN];
                  unsigned char uuid[RPMEM_POOL_HDR_UUID_LEN];
                  unsigned char next_uuid[RPMEM_POOL_HDR_UUID_LEN];
                  unsigned char prev_uuid[RPMEM_POOL_HDR_UUID_LEN];
                  unsigned char user_flags[RPMEM_POOL_USER_FLAGS_LEN];
              };

       The signature field is an 8-byte field which describes the pool's on-media format.

       The major field is a major version number of the pool's on-media format.

       The compat_features field is a mask describing compatibility of pool's on-media format optional features.

       The  incompat_features  field  is  a  mask  describing  compatibility  of pool's on-media format required
       features.

       The ro_compat_features field is a mask describing compatibility of pool's on-media format  features.   If
       these features are not available, the pool shall be opened in read-only mode.

       The poolset_uuid field is an UUID of the pool which the remote pool is associated with.

       The  uuid  field  is  an  UUID of a first part of the remote pool.  This field can be used to connect the
       remote pool with other pools in a list.

       The next_uuid and prev_uuid fields are UUIDs of next and previous replicas  respectively.   These  fields
       can be used to connect the remote pool with other pools in a list.

       The user_flags field is a 16-byte user-defined flags.

SSH

       librpmem  utilizes  the  ssh(1) client to login and execute the rpmemd(1) process on the remote node.  By
       default, ssh(1) is executed with the -4 option, which forces using IPv4 addressing.

       For debugging purposes, both the ssh client  and  the  commands  executed  on  the  remote  node  may  be
       overridden  by  setting the RPMEM_SSH and RPMEM_CMD environment variables, respectively.  See ENVIRONMENT
       for details.

FORK

       The ssh(1) client is executed by rpmem_open(3) and rpmem_create(3) after forking a  child  process  using
       fork(2).  The application must take this into account when using wait(2) and waitpid(2), which may return
       the PID of the ssh(1) process executed by librpmem.

       If fork(2) support is not enabled  in  libibverbs,  rpmem_open(3)  and  rpmem_create(3)  will  fail.   By
       default,  fabric(7) initializes libibverbs with fork(2) support by calling the ibv_fork_init(3) function.
       See fi_verbs(7) for more details.

CAVEATS

       librpmem relies on the library destructor being called from  the  main  thread.   For  this  reason,  all
       functions  that  might  trigger  destruction  (e.g.   dlclose(3))  should  be  called in the main thread.
       Otherwise some of the resources associated with that thread might not be cleaned up properly.

       librpmem registers a pool as a single memory region.  A Chelsio T4 and  T5  hardware  can  not  handle  a
       memory region greater than or equal to 8GB due to a hardware bug.  So pool_size value for rpmem_create(3)
       and rpmem_open(3) using this hardware can not be greater than or equal to 8GB.

LIBRARY API VERSIONING

       This section describes how the library API is versioned, allowing applications to work with  an  evolving
       API.

       The  rpmem_check_version()  function is used to see if the installed librpmem supports the version of the
       library API required by an application.  The easiest way to do this is for the application to supply  the
       compile-time version information, supplied by defines in <librpmem.h>, like this:

              reason = rpmem_check_version(RPMEM_MAJOR_VERSION,
                                           RPMEM_MINOR_VERSION);
              if (reason != NULL) {
                  /* version check failed, reason string tells you why */
              }

       Any  mismatch  in  the  major  version  number  is considered a failure, but a library with a newer minor
       version number will pass this check since increasing minor versions imply backwards compatibility.

       An application can also check specifically for the existence of an interface by checking for the  version
       where  that  interface was introduced.  These versions are documented in this man page as follows: unless
       otherwise specified, all interfaces  described  here  are  available  in  version  1.0  of  the  library.
       Interfaces added after version 1.0 will contain the text introduced in version x.y in the section of this
       manual describing the feature.

       When the version check performed by rpmem_check_version()  is  successful,  the  return  value  is  NULL.
       Otherwise  the  return value is a static string describing the reason for failing the version check.  The
       string returned by rpmem_check_version() must not be modified or freed.

ENVIRONMENT

       librpmem can change its default behavior based on the following environment variables.  These are largely
       intended for testing and are not normally required.

       • RPMEM_SSH=ssh_client

       Setting this environment variable overrides the default ssh(1) client command name.

       • RPMEM_CMD=cmd

       Setting  this environment variable overrides the default command executed on the remote node using either
       ssh(1) or the alternative remote shell command specified by RPMEM_SSH.

       RPMEM_CMD can contain multiple commands separated by a vertical bar (|).   Each  consecutive  command  is
       executed  on  the remote node in order read from a pool set file.  This environment variable is read when
       the library is initialized, so RPMEM_CMD must be set prior to application launch (or prior  to  dlopen(3)
       if librpmem is being dynamically loaded).

       • RPMEM_ENABLE_SOCKETS=0|1

       Setting this variable to 1 enables using fi_sockets(7) provider for in-band RDMA connection.  The sockets
       provider does not support IPv6.  It is required to disable IPv6 system wide if RPMEM_ENABLE_SOCKETS ==  1
       and target == localhost (or any other loopback interface address) and SSH_CONNECTION variable (see ssh(1)
       for more details) contains IPv6 address after ssh to loopback interface.  By default the sockets provider
       is disabled.

       • RPMEM_ENABLE_VERBS=0|1

       Setting  this  variable  to 0 disables using fi_verbs(7) provider for in-band RDMA connection.  The verbs
       provider is enabled by default.

       • RPMEM_MAX_NLANES=num

       Limit the maximum number of lanes to num.  See LANES, in rpmem_create(3), for details.

       • RPMEM_WORK_QUEUE_SIZE=size

       Suggest the work queue size.  The effective work queue size can be greater  than  suggested  if  librpmem
       requires  it  or  it can be smaller if underlying hardware does not support the suggested size.  The work
       queue size affects the performance of communication to the remote node.  rpmem_flush(3) operations can be
       added to the work queue up to the size of this queue.  When work queue is full any subsequent call has to
       wait till the work queue will be drained.  rpmem_drain(3) and rpmem_persist(3) among  other  things  also
       drain the work queue.

DEBUGGING AND ERROR HANDLING

       If  an  error  is  detected during the call to a librpmem function, the application may retrieve an error
       message describing the reason for the failure from rpmem_errormsg().  This function returns a pointer  to
       a  static  buffer containing the last error message logged for the current thread.  If errno was set, the
       error message may include a description of the corresponding error code as returned by strerror(3).   The
       error  message  buffer is thread-local; errors encountered in one thread do not affect its value in other
       threads.  The buffer is never cleared by any library function; its content is significant only  when  the
       return value of the immediately preceding call to a librpmem function indicated an error, or if errno was
       set.  The application must not modify or free the error  message  string,  but  it  may  be  modified  by
       subsequent calls to other library functions.

       Two  versions  of librpmem are typically available on a development system.  The normal version, accessed
       when a program is linked using the -lrpmem option, is optimized  for  performance.   That  version  skips
       checks that impact performance and never logs any trace information or performs any run-time assertions.

       A  second  version  of  librpmem,  accessed  when a program uses the libraries under /usr/lib/pmdk_debug,
       contains run-time assertions and trace points.  The typical way to access the debug version is to set the
       environment  variable  LD_LIBRARY_PATH  to  /usr/lib/pmdk_debug or /usr/lib64/pmdk_debug, as appropriate.
       Debugging output is controlled using the following environment variables.  These variables have no effect
       on the non-debug version of the library.

              NOTE:  On  Debian/Ubuntu  systems,  this  extra  debug  version  of  the library is shipped in the
              respective -debug Debian package and placed in the /usr/lib/$ARCH/pmdk_dbg/ directory.

       • RPMEM_LOG_LEVEL

       The value of RPMEM_LOG_LEVEL enables trace points in the debug version of the library, as follows:

       • 0 - This is the default level when RPMEM_LOG_LEVEL is not set.  No log messages  are  emitted  at  this
         level.

       • 1  -  Additional  details  on  any errors detected are logged (in addition to returning the errno-based
         errors as usual).  The same information may be retrieved using rpmem_errormsg().

       • 2 - A trace of basic operations is logged.

       • 3 - Enables a very verbose amount of function call tracing in the library.

       • 4 - Enables voluminous and fairly obscure tracing  information  that  is  likely  only  useful  to  the
         librpmem developers.

       Unless RPMEM_LOG_FILE is set, debugging output is written to stderr.

       • RPMEM_LOG_FILE

       Specifies  the  name of a file where all logging information should be written.  If the last character in
       the name is “-”, the PID of the current process will be appended to the file name when the  log  file  is
       created.  If RPMEM_LOG_FILE is not set, logging output is written to stderr.

EXAMPLE

       The following example uses librpmem to create a remote pool on given target node identified by given pool
       set name.  The associated local memory pool is zeroed and the data is made  persistent  on  remote  node.
       Upon success the remote pool is closed.

              #include <assert.h>
              #include <unistd.h>
              #include <stdio.h>
              #include <stdlib.h>
              #include <string.h>

              #include <librpmem.h>

              #define POOL_SIGNATURE  "MANPAGE"
              #define POOL_SIZE   (32 * 1024 * 1024)
              #define NLANES      4

              #define DATA_OFF    4096
              #define DATA_SIZE   (POOL_SIZE - DATA_OFF)

              static void
              parse_args(int argc, char *argv[], const char **target, const char **poolset)
              {
                  if (argc < 3) {
                      fprintf(stderr, "usage:\t%s <target> <poolset>\n", argv[0]);
                      exit(1);
                  }

                  *target = argv[1];
                  *poolset = argv[2];
              }

              static void *
              alloc_memory()
              {
                  long pagesize = sysconf(_SC_PAGESIZE);
                  if (pagesize < 0) {
                      perror("sysconf");
                      exit(1);
                  }

                  /* allocate a page size aligned local memory pool */
                  void *mem;
                  int ret = posix_memalign(&mem, pagesize, POOL_SIZE);
                  if (ret) {
                      fprintf(stderr, "posix_memalign: %s\n", strerror(ret));
                      exit(1);
                  }

                  assert(mem != NULL);

                  return mem;
              }

              int
              main(int argc, char *argv[])
              {
                  const char *target, *poolset;
                  parse_args(argc, argv, &target, &poolset);

                  unsigned nlanes = NLANES;
                  void *pool = alloc_memory();
                  int ret;

                  /* fill pool_attributes */
                  struct rpmem_pool_attr pool_attr;
                  memset(&pool_attr, 0, sizeof(pool_attr));
                  strncpy(pool_attr.signature, POOL_SIGNATURE, RPMEM_POOL_HDR_SIG_LEN);

                  /* create a remote pool */
                  RPMEMpool *rpp = rpmem_create(target, poolset, pool, POOL_SIZE,
                          &nlanes, &pool_attr);
                  if (!rpp) {
                      fprintf(stderr, "rpmem_create: %s\n", rpmem_errormsg());
                      return 1;
                  }

                  /* store data on local pool */
                  memset(pool, 0, POOL_SIZE);

                  /* make local data persistent on remote node */
                  ret = rpmem_persist(rpp, DATA_OFF, DATA_SIZE, 0, 0);
                  if (ret) {
                      fprintf(stderr, "rpmem_persist: %s\n", rpmem_errormsg());
                      return 1;
                  }

                  /* close the remote pool */
                  ret = rpmem_close(rpp);
                  if (ret) {
                      fprintf(stderr, "rpmem_close: %s\n", rpmem_errormsg());
                      return 1;
                  }

                  free(pool);

                  return 0;
              }

NOTE

       The  librpmem  API is experimental and may be subject to change in the future.  However, using the remote
       replication in libpmemobj(7) is safe and backward compatibility will be preserved.

ACKNOWLEDGEMENTS

       librpmem builds on the persistent memory programming  model  recommended  by  the  SNIA  NVM  Programming
       Technical Work Group: <https://snia.org/nvmp>

SEE ALSO

       rpmemd(1),  ssh(1),  fork(2),  dlclose(3),  dlopen(3), ibv_fork_init(3), rpmem_create(3), rpmem_drain(3),
       rpmem_flush(3), rpmem_open(3), rpmem_persist(3), strerror(3), limits.conf(5),  fabric(7),  fi_sockets(7),
       fi_verbs(7), libpmem(7), libpmemblk(7), libpmemlog(7), libpmemobj(7) and <https://pmem.io>