6.3. C++

6.3.1. Quick Reference

Return Type Name Arguments
const_iterator;
qdb_error_t const_iterator::last_error() (void) const;
bool const_iterator::valid() (void) const;
const_reverse_iterator;
qdb_error_t const_reverse_iterator::last_error() (void) const;
bool const_reverse_iterator::valid() (void) const;
handle;
const_iterator handle::begin() (void);
const_iterator handle::end() (void);
const_reverse_iterator handle::rbegin() (void);
const_reverse_iterator handle::rend() (void);
void handle::close() (void);
bool handle::connected() (void) const;
void handle::set_timeout() (int timeout);
qdb_error_t handle::connect() (const char * host, unsigned short int port);
size_t handle::multi_connect() (qdb_remote_node_t servers, size_t count);
qdb_error_t handle::put() (const char * alias, const char * content, size_t content_length, qdb_time_t expiry_time);
qdb_error_t handle::update() (const char * alias, const char * content, size_t content_length, qdb_time_t expiry_time);
qdb_error_t handle::get() (const char * alias, char * content, size_t * content_length);
api_buffer_ptr handle::get() (const char * alias, qdb_error_t & error);
api_buffer_ptr handle::get_remove() (const char * alias, qdb_error_t & error);
api_buffer_ptr handle::get_update() (const char * alias, const char * update_content, size_t update_content_length, qdb_time_t expiry_time, qdb_error_t & error);
api_buffer_ptr handle::compare_and_swap() (const char * alias, const char * new_value, size_t new_value_length, const char * comparand, size_t comparand_length, qdb_time_t expiry_time, qdb_error_t & error);
qdb_error_t handle::remove() (const char * alias);
qdb_error_t handle::remove_if() (const char * alias, const char * comparand, size_t comparand_length);
qdb_error_t handle::remove_all() (void);
size_t handle::run_batch() (qdb_operation_t operations, size_t operations_count);
std::vector handle::prefix_get() (const char * prefix, qdb_error_t & error);
qdb_error_t handle::expires_at() (const char * alias, qdb_time_t expiry_time);
qdb_error_t handle::expires_from_now() (const char * alias, qdb_time_t expiry_delta);
qdb_error_t handle::get_expiry_time() (const char * alias, qdb_time_t & expiry_time);
qdb_error_t handle::node_status() (const qdb_remote_node_t & node, qdb_error_t & error);
qdb_error_t handle::node_config() (const qdb_remote_node_t & node, qdb_error_t & error);
qdb_error_t handle::node_topology() (const qdb_remote_node_t & node, qdb_error_t & error);
qdb_error_t handle::stop_node() (const qdb_remote_node_t & node, const char * reason);
handle_ptr;
api_buffer;
const char * api_buffer::data() (void) const;
size_t api_buffer::size() (void) const;
api_buffer_ptr;

6.3.2. Introduction

The quasardb C++ API is a wrapper around the C API that brings convenience and flexibility without sacrificing performance. Behaviour is similar to that of the C API (see C).

6.3.3. Installing

The C++ API package consists of one header and is included in the C API package (see C). Both the C and C++ header files must be linked into the client executable, but no additional linking is required.

6.3.4. Header file

All functions, typedefs and enums are made available in the include/qdb/client.hpp header file. All classes and methods reside in the qdb namespace.

6.3.5. Exceptions

The quasardb C++ API does not throw any exception on its behalf, however situations such as low memory conditions may cause exceptions to be thrown.

6.3.6. The handle object

The handle object is non-copiable. Move semantics are supported through rvalue references but must be enabled by setting the QDBAPI_RVALUE_SUPPORT macro to 1. For example:

#define QDBAPI_RVALUE_SUPPORT 1
#include <qdb/client.hpp>

Handle objects can be used directly with the C API thanks to the overload of the cast operator. They will evaluate to false when not initialized:

qdb::handle h;
// some code...
if (!h) // true if h isn't initialized
{
    // ...
}

// initialization and connection

// removes the entry "myalias" if it exists
qdb_error_t r = qdb_remove(h, "myalias");
if (r != qdb_e_ok)
{
    // error management
}

Caution

Calling qdb_close() on a handle leads to undefined behaviour. Generally speaking it is advised to use the handle object’s methods rather than the C API functions. The cast operator is provided for compatibility only.

Handle objects can also be encapsulated in smart pointers. A definition as handle_ptr is available. This requires a compiler with std::shared_ptr support.

6.3.7. Connecting to a cluster

The connection requires a handle object and is done with the handle::connect() method:

qdb::handle h;
qdb_error_t r = h.connect("127.0.0.1", 2836);

Connect will both initialize the handle and connect to the cluster. If the connection failed, the handle will be reset. Note that when the handle object goes out of scope, the connection will be terminated and the handle will be released.

Caution

Concurrent calls to connect on the same handle object leads to undefined behaviour.

6.3.8. Adding and getting data to and from a cluster

Although one may use the handle object with the C API, using the handle object’s methods is recommended. For example, to put and get an entry, the C++ way:

const char in_data[10];

qdb_error_t r = h.put("entry", in_data, 0);
if (r != qdb_e_ok)
{
    // error management
}

// ...

char out_data[10];
qdb_error_t = r = h.get("entry", out_data, 10);
if (r != qdb_e_ok)
{
    // error management
}

The largest difference between the C and C++ get calls are their memory allocation lifetimes. The C call qdb_get_buffer() allocates a buffer of the needed size and must be explicitly freed. The C++ handle.get() method uses uses smart pointers to manage allocations lifetime.

In C, one would write:

char * allocated_content = 0;
size_t allocated_content_length = 0;
r = qdb_get_buffer(handle, "entry", &allocated_content, &allocated_content_length);
if (r != qdb_e_ok)
{
    // error management
}

// ...
// later
// ...

qdb_free_buffer(allocated_content);

In C++, one writes:

qdb_error_t r = qdb_e_ok;
qdb::api_buffer_ptr allocated_content = h.get("entry", r);
if (r != qdb_e_ok)
{
    // error management
}

// allocated_content will be released when its usage count reaches zero

6.3.9. The api_buffer object

The api_buffer object is designed to be used via a smart pointer - whose definition is provided - and is returned by methods from the handle object. It is possible to access the managed buffer directly (read-only) and query its size (see api_buffer::data() and api_buffer::size()).

6.3.10. Closing a connection

A connection can be explicitly closed and the handle released with the handle::close() method:

h.close();

Note that when the handle object is destroyed, handle::close() is automatically called.

Caution

The usage of qdb_close() with handle object results in undefined behaviour.

6.3.11. Expiry

Expiry is set with handle::expires_at() and expires_from_now(). It is obtained with handle::get_expiry_time(). Expiry time is always in seconds, either relative to epoch (January 1st, 1970 00:00 UTC) when using handle::expires_at() or relative to the call time when using expires_from_now().

Danger

The behavior of expires_from_now() is undefined if the time zone or the clock of the client computer is improperly configured.

To set the expiry time of an entry to 1 minute, relative to the call time:

char content[100];

// ...

r = h.put("myalias", content, sizeof(content), 0);
if (r != qdb_error_ok)
{
    // error management
}

r = h.expires_from_now("myalias", 60);
if (r != qdb_error_ok)
{
    // error management
}

To prevent an entry from ever expiring:

r = h.expires_at("myalias", 0);
if (r != qdb_error_ok)
{
    // error management
}

By default, entries do not expire. To obtain the expiry time of an existing entry:

qdb_time_t expiry_time = 0;
r = h.get_expiry_time("myalias", &expiry_time);
if (r != qdb_error_ok)
{
    // error management
}

6.3.13. Batch operations

Batch operations are used similarly as in C, except a method handle::run_batch() is provided for convenience.

6.3.14. Iteration

Iteration on the cluster’s entries can be done forward and backward.

An STL-like iterator API is provided which is compatible with STL algorithms:

// forward loop
std::for_each(h.begin(), h.end(), [](const qdb::const_iterator::value_type & v)
{
    // work on the entry
    // v.first is an std::string refering to the entry's alias
    // v.second is qdb::api_buffer_ptr with the entry's content
});

// backward loop
std::for_each(h.rbegin(), h.rend(), [](const qdb::const_reverse_iterator::value_type & v) { /* work on the entry */ });

There is however a significant difference with regular STL iterators: since entries are accessed remotely, an error may prevent the next entry from being retrieved, in which case the iterator will be considered to have reached the “end” of the iteration.

It is however possible to query the last error through the last_error() member function. The qdb_e_alias_not_found indicates the normal end of the iteration whereas other error statuses indicate that the iteration could not successfully complete. It is up to the programmer to decide what to do in case of error.

Iterators’ value is a std::pair<std::string, qdb::api_buffer_ptr> which makes the manipulation of iterator associated data safe in most scenarii. Associated resources will be freed automatically through RAII.

The iterator api may throw the std::bad_alloc exception should a memory allocation fail.

Note

Although each entry is returned only once, the order in which entries are returned is undefined.

6.3.15. Reference

class const_iterator

A forward iterator.

qdb_error_t last_error(void) const
Returns:The error code of the last iterator operation
bool valid(void) const
Returns:true if the iterator is valid and points to an entry
class const_reverse_iterator

A reverse iterator.

qdb_error_t last_error(void) const
Returns:The error code of the last iterator operation
bool valid(void) const
Returns:true if the iterator is valid and points to an entry
class handle
const_iterator begin(void)
Returns:A forward iterator pointing to the first entry in the cluster.
const_iterator end(void)
Returns:A forward iterator pointing beyond the last entry in the cluster.
const_reverse_iterator rbegin(void)
Returns:A reverse iterator pointing to the last entry in the cluster.
const_reverse_iterator rend(void)
Returns:A reverse iterator pointing before the first entry in the cluster.
void close(void)

Close the handle and release all associated resources.

bool connected(void) const

Determine if the handle is connected or not.

Returns:true if the handle is connected, false otherwise
void set_timeout(int timeout)

Set the timeout, in milliseconds, for all operations.

Parameters timeout:
 The timeout, in milliseconds.
Type timeout:int
qdb_error_t connect(const char* host, unsigned short int port)

Initialize all required resources and connect to a remote host.

Parameters:
  • host – A null terminated string designating the host to connect to.
  • port – An unsigned integer designating the port to connect to.
Returns:

An error code of type qdb_error_t

size_t multi_connect(qdb_remote_node_t* servers, size_t count)

Initialize all required resources, bind the client instance to a quasardb cluster and connect to multiple nodes within. The function returns the number of successful connections. If the same node (address and port) is present several times in the input array, it will count as only one successful connection.

The user supplies an array of qdb_remote_node_t and the function updates the error member of each entry according to the result of the operation.

Only one connection to a listed node has to succeed for the connection to the cluster to be successful.

Parameters:
  • servers – An array of qdb_remote_node_t designating the nodes to connect to. The error member will be updated depending on the result of the operation.
  • count – The size of the input array.
Returns:

The number of successful connections.

qdb_error_t put(const char* alias, const char* content, size_t content_length, qdb_time_t expiry_time)

Adds an entry to the quasardb server. If the entry already exists the method will fail and will return qdb_e_alias_already_exists. Keys beginning with the string “qdb” are reserved and cannot be added to the cluster.

The handle must be initialized and connected (see connect() and multi_connect()).

Parameters:
  • alias – A pointer to a null terminated string representing the entry’s alias to create.
  • content – A pointer to a buffer that represents the entry’s content to be added to the server.
  • content_length – The length of the entry’s content, in bytes.
  • expiry_time – The absolute expiry time of the entry, in seconds, relative to epoch
Returns:

An error code of type qdb_error_t

qdb_error_t update(const char* alias, const char* content, size_t content_length, qdb_time_t expiry_time)

Updates an entry on the quasardb server. If the entry already exists, the content will be updated. If the entry does not exist, it will be created.

The handle must be initialized and connected (see connect() and multi_connect()).

Parameters:
  • alias – A pointer to a null terminated string representing the entry’s alias to update.
  • content – A pointer to a buffer that represents the entry’s content to be updated to the server.
  • content_length – The length of the entry’s content, in bytes.
  • expiry_time – The absolute expiry time of the entry, in seconds, relative to epoch
Returns:

An error code of type qdb_error_t

qdb_error_t get(const char* alias, char* content, size_t* content_length)

Retrieves an entry‘s content from the quasardb server. The caller is responsible for allocating and freeing the provided buffer.

If the entry does not exist, the method will fail and return qdb_e_alias_not_found.

If the buffer is not large enough to hold the data, the function will fail and return qdb_e_buffer_too_small. content_length will nevertheless be updated with entry size so that the caller may resize its buffer and try again.

The handle must be initialized and connected (see connect() and multi_connect()).

Parameters:
  • alias – A pointer to a null terminated string representing the entry’s alias whose content is to be retrieved.
  • content – A pointer to an user allocated buffer that will receive the entry’s content.
  • content_length – A pointer to a size_t initialized with the length of the destination buffer, in bytes. It will be updated with the length of the retrieved content, even if the buffer is not large enough to hold all the data.
Returns:

An error code of type qdb_error_t

api_buffer_ptr get(const char* alias, qdb_error_t& error)

Retrieves an entry‘s content from the quasardb server.

If the entry does not exist, the function will fail and update error to qdb_e_alias_not_found.

The function will allocate a buffer large enough to hold the entry’s content.

The handle must be initialized and connected (see connect() and multi_connect()).

Parameters:
  • alias – A pointer to a null terminated string representing the entry’s alias whose content is to be retrieved.
  • error – A reference to an error that will receive the result of the operation.
Returns:

An api_buffer_ptr holding the entry content, if it exists, a null pointer otherwise.

api_buffer_ptr get_remove(const char* alias, qdb_error_t& error)

Atomically gets an entry from the quasardb server and removes it.

If the entry does not exist, the function will fail and update error to qdb_e_alias_not_found.

The function will allocate a buffer large enough to hold the entry’s content.

The handle must be initialized and connected (see connect() and multi_connect()).

Parameters:
  • alias – A pointer to a null terminated string representing the entry’s alias whose content is to be retrieved.
  • error – A reference to an error that will receive the result of the operation.
Returns:

An api_buffer_ptr holding the entry content, if it exists, a null pointer otherwise.

api_buffer_ptr get_update(const char* alias, const char* update_content, size_t update_content_length, qdb_time_t expiry_time, qdb_error_t& error)

Atomically gets and updates (in this order) the entry on the quasardb server. The entry must already exist.

The handle must be initialized and connected (see connect() and multi_connect()).

Parameters:
  • alias – A pointer to a null terminated string representing the entry’s alias to update.
  • update_content – A pointer to a buffer that represents the entry’s content to be updated to the server.
  • update_content_length – The length of the buffer, in bytes.
  • expiry_time – The absolute expiry time of the entry, in seconds, relative to epoch
  • error – A reference to an error that will receive the result of the operation.
Returns:

An api_buffer_ptr holding the entry content, if it exists, a null pointer otherwise.

api_buffer_ptr compare_and_swap(const char* alias, const char* new_value, size_t new_value_length, const char* comparand, size_t comparand_length, qdb_time_t expiry_time, qdb_error_t& error)

Atomically compares the entry with comparand and updates it to new_value if, and only if, they match. Always return the original value of the entry.

The handle must be initialized and connected (see connect() and multi_connect()).

Parameters:
  • alias – A pointer to a null terminated string representing the entry’s alias to compare to.
  • new_value – A pointer to a buffer that represents the entry’s content to be updated to the server in case of match.
  • new_value_length – The length of the buffer, in bytes.
  • comparand – A pointer to a buffer that represents the entry’s content to be compared to.
  • comparand_length – The length of the buffer, in bytes.
  • expiry_time – The absolute expiry time of the entry, in seconds, relative to epoch
  • error – A reference to an error that will receive the result of the operation.
Returns:

An api_buffer_ptr holding the entry content, if it exists, a null pointer otherwise.

qdb_error_t remove(const char* alias)

Removes an entry from the quasardb server. If the entry does not exist, the function will fail and return qdb_e_alias_not_found.

The handle must be initialized and connected (see connect() and multi_connect()).

Parameters alias:
 A pointer to a null terminated string representing the entry’s alias to delete.
Returns:An error code of type qdb_error_t
qdb_error_t remove_if(const char* alias, const char* comparand, size_t comparand_length)

Removes an entry from the quasardb server if it matches comparand. The operation is atomic. If the entry does not exist, the function will fail and return qdb_e_alias_not_found.

The handle must be initialized and connected (see connect() and multi_connect()).

Parameters:
  • alias – A pointer to a null terminated string representing the entry’s alias to delete.
  • comparand – A pointer to a buffer that represents the entry’s content to be compared to.
  • comparand_length – The length of the buffer, in bytes.
Returns:

An error code of type qdb_error_t

qdb_error_t remove_all(void)

Removes all the entries on all the nodes of the quasardb cluster. The function returns when the command has been dispatched and executed on the whole cluster or an error occurred.

This call is not atomic; if the command cannot be dispatched on the whole cluster, it will be dispatched on as many nodes as possible and the function will return with a qdb_e_ok code.

The handle must be initialized and connected (see connect() and multi_connect()).

Returns:An error code of type qdb_error_t

Caution

This function is meant for very specific use cases and its usage is discouraged.

size_t run_batch(qdb_operation_t* operations, size_t operations_count)

Runs the provided operations in batch on the cluster. The operations are run in arbitrary order.

The handle must be initialized and connected (see connect() and multi_connect()).

Parameters:
  • operations – Pointer to an array of qdb_operations_t
  • operations_count – Size of the array, in entry count
Returns:

The number of successful operations

std::vector<std::string> prefix_get(const char* prefix, qdb_error_t& error)

Searches the cluster for all entries whose aliases start with “prefix”. The method will return a std::vector of std::string containing the aliases of matching entries.

The handle must be initialized and connected (see connect() and multi_connect()).

Parameters:
  • prefix – A pointer to a null terminated string representing the search prefix
  • error – A reference to an error that will receive the result of the operation.
Returns:

A std::vector of std::string containing the aliases of matching entries.

qdb_error_t expires_at(const char* alias, qdb_time_t expiry_time)

Sets the expiry time of an existing entry from the quasardb cluster. A value of zero means the entry never expires.

The handle must be initialized and connected (see connect() and multi_connect()).

Parameters:
  • alias – A pointer to a null terminated string representing the entry’s alias for which the expiry must be set.
  • expiry_time – Absolute time after which the entry expires
Returns:

An error code of type qdb_error_t

qdb_error_t expires_from_now(const char* alias, qdb_time_t expiry_delta)

Sets the expiry time of an existing entry from the quasardb cluster. A value of zero means the entry expires as soon as possible.

The handle must be initialized and connected (see connect() and multi_connect()).

Parameters:
  • alias – A pointer to a null terminated string representing the entry’s alias for which the expiry must be set.
  • expiry_time – Time in seconds, relative to the call time, after which the entry expires
Type expiry_time:
 

qdb_time_t

Returns:

An error code of type qdb_error_t

qdb_error_t get_expiry_time(const char* alias, qdb_time_t& expiry_time)

Retrieves the expiry time of an existing entry. A value of zero means the entry never expires.

The handle must be initialized and connected (see connect() and multi_connect()).

Parameters:
  • alias – A pointer to a null terminated string representing the entry’s alias for which the expiry must be get.
  • expiry_time – A pointer to a qdb_time_t that will receive the absolute expiry time.
Returns:

An error code of type qdb_error_t

qdb_error_t node_status(const qdb_remote_node_t& node, qdb_error_t& error)

Obtains a node status as a JSON string.

The handle must be initialized and connected (see connect() and multi_connect()).

Parameters:
  • node – A constant reference to the remote node to get the status from
  • error – A reference to an error code that will be updated according to the success of the operation
Returns:

The status of the node as a JSON string.

qdb_error_t node_config(const qdb_remote_node_t& node, qdb_error_t& error)

Obtains a node configuration as a JSON string.

The handle must be initialized and connected (see connect() and multi_connect()).

Parameters:
  • node – A constant reference to the remote node to get the configuration from
  • error – A reference to an error code that will be updated according to the success of the operation
Returns:

The configuration of the node as a JSON string.

qdb_error_t node_topology(const qdb_remote_node_t& node, qdb_error_t& error)

Obtains a node topology as a JSON string.

The handle must be initialized and connected (see connect() and multi_connect()).

Parameters:
  • node – A constant reference to the remote node to get the topology from
  • error – A reference to an error code that will be updated according to the success of the operation
Returns:

The topology of the node as a JSON string.

qdb_error_t stop_node(const qdb_remote_node_t& node, const char* reason)

Stops the node designated by its host and port number. This stop is generally effective a couple of seconds after it has been issued, enabling inflight calls to complete successfully.

The handle must be initialized and connected (see connect() and multi_connect()).

Parameters:
  • node – A constant reference to the remote node to stop
  • reason – A pointer to a null terminated string detailling the reason for the stop that will appear in the remote node’s log.
Returns:

An error code of type qdb_error_t

Caution

This function is meant for very specific use cases and its usage is discouraged.

type handle_ptr

A smart pointer to a handle object.

class api_buffer

An API allocated buffer returned by a method from the handle object. This object is meant to be used through the handle methods only.

const char* data(void) const

Access the managed buffer, read-only.

Returns:A pointer to the managed buffer.
size_t size(void) const

Gives the size of the managed buffer.

Returns:The size of the managed buffer.
type api_buffer_ptr

A smart pointer definition used by the handle object.