Reverbrain wiki

Site Tools


elliptics:api-cc
  1. Class ioremap::elliptics::node
  2. Class ioremap::elliptics::error
  3. Class ioremap::elliptics::logger
  4. Class ioremap::elliptics::key
  5. Class ioremap::elliptics::session
  6. Class data_pointer

Class ioremap::elliptics::node

Class node is responsible for the connection with the server part.

There are several constructors in this class.

class node
{
        public:
                explicit node(const logger &l);
                node(const logger &l, struct dnet_config &cfg);
                node(const node &other);
                ~node();

                node &operator =(const node &other);

                void                        add_remote(const char *addr, const int port, const int family = AF_INET);
                void                        add_remote(const char *addr);

                void                        set_timeouts(const int wait_timeout, const int check_timeout);

                void                        set_keepalive(int idle, int cnt, int interval);

                logger get_log() const;
                struct dnet_node *        get_native();

        protected:
                std::shared_ptr<node_data> m_data;

                friend class session;
                friend class session_data;
};

Constructors:

  • The first constructor accepts a logger that will store all error messages.

  • The second constructor accepts a logger and configuration parameters for future connection.

Class node methods:

  • add_remote() methods are designed to add a connection to elliptics servers.

  • set_timeouts() method allows you to override the default values for timeouts.

  • set_keepalive() method sets keepalive idle time in seconds, number of keepalive probes and interval between them in seconds for all new connections

  • int wait_timeout — this timeout affects all transactions that we send to the cluster. You can wait for them for wait_timeout seconds - if time passes and there is no answer, we return -110. By default wait_timeout is 5 seconds.

  • int check_timeout — a separate thread which scans for timed out transactions, it also ensures that we update the routing table and checks the network connection (for example, that we have not timed out). By default — 60 seconds.

  • get_native() method allows you to get a pointer to the structure from C API.

Class key represents an abstraction over the two methods of specifying the object key:

  • Specifying an object by its name and type.

  • Specifying the object by its dnet_id from C API.

Class ioremap::elliptics::error

Class error is a base class of the exception in Elliptics.

class error : public std::exception
{
        public:
                // err must be negative value
                explicit error(int err, const std::string &message) throw();
                ~error() throw() {}

                int error_code() const;

                virtual const char *what() const throw();

                std::string error_message() const throw();

        private:
                int m_errno;
                std::string m_message;
};

There is one basic constructor in this class. It accepts an error code and error message. Also you can get from it the error code passed to it via error_code method and the error message via error_message method.

class not_found_error : public error
{
        public:
                explicit not_found_error(const std::string &message) throw();
};

class timeout_error : public error
{
        public:
                explicit timeout_error(const std::string &message) throw();
};

At the moment there are two inheritors of the class error:

  • not_found_error indicates an error saying that the object is not found and we could not get any information about this object;

  • timeout_error indicates that we’ve failed to connect to the server due to the fact that it is not responding for too long.

There are 3 methods of throwing these errors with a fairly detailed error message - throw_error methods which accept an error code from C language. These methods accept dnet_id as the optional parameter. dnet_id, with an identifier of the object and the formatted input/output in printf format.

// err must be negative value
void throw_error(int err, const char *format, ...)
        __attribute__ ((format (printf, 2, 3)));

// err must be negative value
void throw_error(int err, const struct dnet_id &id, const char *format, ...)
        __attribute__ ((format (printf, 3, 4)));

// err must be negative value
void throw_error(int err, const key &id, const char *format, ...)
        __attribute__ ((format (printf, 3, 4)));

// err must be negative value
void throw_error(int err, const uint8_t *id, const char *format, ...)
        __attribute__ ((format (printf, 3, 4)));

Class ioremap::elliptics::logger

Also the class logger was added with an adjustable logging level. It is responsible for the logging of all events in Elliptics, through it the system is logging all internal processes.

class logger
{
        public:
                explicit logger(logger_interface *interface, const int level = DNET_LOG_INFO);
                logger();
                logger(const logger &other);
                ~logger();

                logger &operator =(const logger &other);

                void                 log(const int level, const char *msg);
                int                        get_log_level();
                struct dnet_log                *get_native();

        protected:
                std::shared_ptr<logger_data> m_data;
};

The constructor of the class logger accepts a pointer to the implementation of the class logger_interface, which is responsible for implementing the error output.

class logger_interface
{
        public:
                virtual ~logger_interface() {}

                virtual void log(const int level, const char *msg) = 0;
};

The second parameter of the class logger — an integer value specifying the log level (int level), which is set via the enum and indicates whether to log only errors or other less important messages as well, etc.

Class logger has 3 methods:

  • log() method when it is called messages are written to the log.

  • get_log_level() method, which allows to query for the logger’s log level.

  • dnet_log() method allows to get a pointer to the structure of C API.

The class logger has only one implementation — the class file_logger, which in turn implements the paradigm of writing logs to the file.

class file_logger : public logger
{
        public:
                explicit file_logger(const char *file, const int level = DNET_LOG_INFO);
                ~file_logger();
};

The constructor of file_logger class accepts two arguments:

  • file — the path to the file;

  • level = DNET_LOG_INFO — log level.

If for some reason we could not open the file for writing an exceprion will be thrown with the path to that file.

Class ioremap::elliptics::key

class key
{
        public:
                key();
                key(const std::string &remote, int type = 0);
                key(const struct dnet_id &id);
                key(const key &other);
                key &operator = (const key &other);
                ~key();

                bool operator==(const key &other) const;
                bool operator <(const key &other) const;

                bool by_id() const;
                const std::string &remote() const;
                int type() const;
                const struct dnet_id &id() const;
                std::string to_string() const;

                void transform(session &sess);

        private:
                bool m_by_id;
                std::string m_remote;
                int m_type;
                struct dnet_id m_id;
};

The class key has multiple constructors:

  • default creates an empty key;

  • accept a file name and an optional type (number of a column for columnar storage - soon will be removed);

  • accepts a dnet_id.

Keys are comparable and can be compared with < or = for the sorting.

Methods:

  • Using by_id() method you can check if it was created from a file name or from dnet_id - if the object of class key was create from dnet_id, then by_id() returns «true», otherwise — «false».

  • Using remote() method you can get the file name.

  • Using type() method type you can find out a file type. In this case, if it was created using the constructor from a file name, the type will be taken from one passed to the constructor. If it was created from dnet_id, then the type will be taken from the corresponding structure. Here, the type is the number of a column at the columnar storage (supported only in eblob-backend and soon it will be removed completely).

  • The id() method returns dnet_id structure. In this case, if the key was generated by the file name, this method will throw an exception, unless you call transform() method on a key that takes the session as input, and generates dnet_id using the algorithms specified in the session.

  • The to_string() method returns either the file name (if the key has been generated from it), or the first ten bytes from an id.

Class ioremap::elliptics::session

Class session.

Class session is a temporary object that should be created only for a single connection. It should be lightweight and should not impose significant costs to create it. As the only argument of the constructor it accepts a node created earlier.

The session has several attributes:

  1. The list of groups the session trying to make a request. There is no group by default.

  2. cflags — command flags. By default — 0.

  3. ioflags — input/output flags. By default — 0.

  4. Filter. Previously Elliptics was filtering the responses with errors and returned to user only the successful responses. Now with filters you can specify the behavior. By default — a positive filter (it accept only server responses with zero error code).

  5. Checkers. Previously Elliptics assumed that an operation is successful (except remove request) if at least one response was positive, now a default behavior for all commands is the same: the operation is not successful only if there is no successful response. You can override this behavior.

  6. Exception policy — configure exception behavior and exception safety guarantees. You can flexibly define in which cases Elliptics has the right to throw an exception, and in which cases not. By default it does not throw an exception if the command has failed to reach the server (no active connection to the server side), or if there is any critical error. You can make Elliptics to throw an exception when you calling wait method or get method in async_result. You can also determine whether Elliptics throw an exception or not when you’re working with the iterators results. And also you can make Elliptics never throw the exceptions. By default Elliptics throws exceptions in iterators in case there was an error with wait method or get method in async_result.

All methods in Elliptics return an async_result object. async_result is a container that provides access to the server results. It collects the properties of filter values (checker and exception policy) from a session. After that, you can not change these properties.

async_result has several ways of an interaction with it.

Asynchronous way of working

Asynchronous work with async_result() is in the family of connect() methods. There are three types of connect() methods:

  1. The first connect accepts two functors: the first is called upon receipt of all server responses that have passed through the filter, the second is called with the last answer or when it turns out there won’t be any answers, and it contains error_info with information about the message, its text description and errno code.

  2. The second connect accepts a functor that consists of two arguments: the first argument is a vector of all results, the second is error_info structure. In that case, Elliptics aggregates all received server responses, puts them in a vector and after that Elliptics will call the final functor. As the first argument it will pass the variety of responses, and as the second the information about success or failure of the operation.

  3. The third connect allows you to do the bunches of async_result() methods. For example if you need to pass all data collected from one async_result() to another async_result() via the creation of intermediate async_result_holder().

Also async_result has an error() method. When the operation ends that method returns the information about an operation’s success. So if you will turn off exceptions in the wait() method and get() method you can get async_result(), call the wait() method and check the operation status. After that you can call get() method to process the data, given what we already know (that the operation was completed successfully or not).

Synchronous way of working

It’s similar to how previously the synchronous methods acted in Elliptics. Now, this behavior can be achieved in the following way: we call any method, for example, write_data() that returns us an async_result(). Then you can call wait() method that blocks the current thread and waits until you’ve received all server responses. Then you can call the get() method that returns all of the results obtained by the server, passing through the filter and set previously in the session. In this case, if at the time of calling get() method all server results were not received, the thread will be blocked until we receive all responses. This achieves a synchronization of called method.

Also to work with the synchronous code, there are get() and get_one() methods that allow you to get the first positive response from a variety of responses from the server. This is useful if you are working with read_data() method and read_latest() method or If we interested in at least one positive response that contains the data in it.

Iterators is another way of synchronous work with async_result(). async_result() method has begin() method and end() method that returns, respectively, iterators pointing at the first not processed server answer and at the index after the last answer. This iterator is a standard STL-like input iterator, and it blocks the call of the dereference operators or assignment in all cases, if it is not enough data to process them.

Thus, the code will be blocked until we receive server response. That behavior allows you not to waste the memory by receiving all responses from the server and by processing them as they become available, while maintaining the synchronous appearance of the code. This is useful when you call start_iterator() method.

async_result provides the interfaces for processing the results and to set the methods for processing the data. In order to pass the data in async_result in case of user’s own implementation of their low-level user query methods, Elliptics async_result_handler() (https://github.com/reverbrain/elliptics/blob/master/include/elliptics/cppdef.h#L1563) method should be used.

Its only constructor accepts async_result, it has a «total» property, determined by set_total() and ger_total() methods that will indicate how many results we are waiting for. It has a process() method through which we pass the received server results (for example after some processing and complete() method that says « there are no more data» to async_result.

There are setters and getters for all properties — for example, get_ioflags() and set_ioflags().

The session is an object for performing the tasks such as reading files, writing files, deleting files on the servers, etc.

There are read_data(), read_data_range() and bulk_read() methods for reading the server data.

read_data() method is overloaded by several arguments. As a simple option it accepts the key and groups (group list) — where to send the request to, taken from session if absent. Accepts: the offset (by what offset Elliptics should read a file), and size (number of bytes to read, 0 — read all)

Also, there are overloads of this method for an asynchronous reading. In this case, std::function will be accepted as the first argument, which will take the result as a read_result object. All other arguments are the same.

In the asynchronous request handler the result may come from the current thread, as well as from any other.

read_data() method can accepts an additional set of arguments such as key, group or vector of groups and dnet_io_attr structure for custom queries (if the standard functionality won’t be enough).

prepare_latest() method accepts a handler (it may be a function or a method of object that will be called), which will be called with a wrapped group vector.

read_latest() method is designed to get the most relevant data by a specified key, also it knows how to read data from specific offset and specified number of bytes. If you specify that the size is zero, then all the data will be read starting at the specified offset. The syntax of this method is similar to the syntax of read_data() method.

So read_latest() method accepts the key, offset (where we should begin to read the data) and the size (amount of data to be read, zero means 'read everything') and returns async_result.

write_data() method allows you to write data to the disk. It accepts a handler as its first argument and it will receive a result. In a low-level version this method accepts the handler as the first argument, where the results will be returned, and dnet_io_control as the second argument, which allows to set the parametres of request for more detailed reading.

async_write_result write_cas(const key &id, const std::function<data_pointer (const data_pointer &)> &converter,
                uint64_t remote_offset, int count = 10);

async_write_result write_cas(const key &id, const data_pointer &file, const struct dnet_id &old_csum, uint64_t remote_offset);

write_cas() method (write compare and swap) accepts 4 arguments:

  • the key to write the data;
  • the data to be written;
  • checksum of the data that we believe are on the server by that key;
  • the offset we will write the data with.

write_cas() method accepts a handler that will be called when the result is ready as the first argument.

In all these asynchronous methods we call a method and then Elliptics library exits from this method before it ends waiting for the result from the server. The result will come later, and only then a handler will be called. The only exception is when we know that we’re not able to send the request because of some errors.

For example, we have not configured any nodes, in that case a handler will be called before exiting from this function, and then we guarantee (call parameters of callback will show that this is an error) that we didn’t send any requests to the server.

async_write_result write_prepare(const key &id, const data_pointer &file,
                                 uint64_t remote_offset, uint64_t psize);

The syntax of write_prepare() method is similar to the syntax of write_data() method. It sends the request to the server and prepares the server store to write the data with a certain size.

If we know that we want to write a 5GB file then it won’t be smart to write this 5GB at once, because if at the middle of transaction some network error occurs then we will have to rewrite all the data all over again. Therefore, we are sending a write_prepare() request, prepare the server for 5GB of data, then send it via calling write_plain() several times, for example, to send the file in 100 chunks.

async_write_result write_plain(const key &id, const data_pointer &file,
                               uint64_t remote_offset);

In this case, if some of the queries fail, it will be enough to send that part of the file, not the entire file. When all the chunks are sent, you can call the write_commit() method, which tells the server that we we’re done, and the server updates the index. If csize is not 0 server will truncate data by csize.

async_write_result write_commit(const key &id, const data_pointer &file,
                                uint64_t remote_offset, uint64_t csize);

Starting from the moment when commit is received, the data by this key will be available for reading. Up to this point you can not use it for reading.

async_write_result write_cache(const key &id, const data_pointer &file, long timeout);

write_cache() method writes the data to the disk and in the cache (or not writing on the disk, depending on the io-flag of the session). If we know that the data will be accessed frequently the it will be more effective to write it not only to the disk, but also directly into the cache, instead of caching it on the first request.

std::string lookup_address(const key &id, int group_id = 0);

lookup_address() method accepts a key and a group in which we will send a request. The method returns a string with the IP address and port separated by a colon, where in libelliptics opinion the file with this key should be stored (in the specified group).

async_lookup_result lookup(const key &id);

Lookup method accepts a key and returns the information about a given object (its size, etc.).

async_remove_result remove(const key &id);

Remove() method accepts a key. The method removes the objects with the specified key from the server.

async_stat_result stat_log();

async_stat_result stat_log(const key &id);

stat_log() method collects statistics from the servers, or from one server, if specified by the key.

async_stat_count_result stat_log_count();

stat_log_count() returns list of server command counters, i.e. how many read/write/exec and others were called. It separates client-to-server and server-to-server commands. stat_log() returns VM, LA and filesystem statistics for given node.

async_generic_result request_cmd(const transport_control &ctl);

request_cmd() is a low-level method for making any request to the server side.

void update_status(const char *addr, const int port,
                   const int family, struct dnet_node_status *status);

update_status() method updates the status of the specified node, or the status of all nodes based on a key.

async_read_result read_data_range(const struct dnet_io_attr &io, int group_id);

read_data_range() method requests to read all the keys in the range.

It accepts a dnet_io_attr structure, which describes the read request: it has an id field - start key, and a parent field, which has its own id field - the last key to query.

At the end, we receive a list of all the objects that we have been able to read. If we could not read a single object in this range - we’ll get an error message.

async_read_result remove_data_range(const struct dnet_io_attr &io, int group_id);

remove_data_range() method behaves similarly to read_data_range() method, but it deletes the data in a specified range. If something goes wrong, it returns an error.

std::vector<std::pair<struct dnet_id, struct dnet_addr> > get_routes();

get_routes() method returns a routing table, which is known to us at the moment.

async_read_result bulk_read(const std::vector<struct dnet_io_attr> &ios);
async_read_result bulk_read(const std::vector<std::string> &keys);
async_read_result bulk_read(const std::vector<key> &keys);

bulk_read() method makes the requests in parallel on all the keys, which is passed as an argument. That is, an argument he can take either a list of keys (file names) or a dnet_io_attr list. Once all the data is read, it’ll call a handler.

async_write_result bulk_write(const std::vector<dnet_io_attr> &ios, const std::vector<data_pointer> &data);
async_write_result bulk_write(const std::vector<struct dnet_io_attr> &ios, const std::vector<std::string> &data);

bulk_write() method is similar to the method bulk_read(), but it asynchronously writes the data and the result is returned when all data has been written, or we are not be able to write all the data, that is, once we know the answer to all of the requests.

const node  &get_node() const;

get_node() method allows you to get a node for which this session was created.

struct dnet_session *   get_native();

get_native() method allows you to access dnet_session of C API.

From the client's point of view, the control of the events flow happens through Elliptics session via three methods:

  • exec
  • push
  • reply

Exec initiates the flow of events. Its arguments are: an id of a machine that you need to send an event or parameters for broadcast (if id is missing or equal to zero), the name of the event and the data that has to be processed. There are a synchronous and an asynchronous API versions.

In sync version, all replies from the server are aggregated in a single array of answers and when the last event is received, the result is returned to the user. You need to pass two callbacks in the asynchronous API version.

The first callback will be called when each reply are received from the server. The second callback will be called when the last reply is received or when it becomes clear that there are no more replies because of an error on the server side (for example, if the request failed due to a timeout). Request goes to the server and to a so-called ‘worker’ after an executed exec .

Then a worker which receives an event starts to process it. It might send some events further down the event chain using the push method or it might return the result using the reply method.

A worker is a process that performs a specific code when the specific event string is received. Worker’s resources can be limited via cgroups. There will be an isolation via lxc containers in the near future.

Push accepts 4 arguments:

  • dnet_id that can be indicated in the same manner as with exec (i.e. it can be either specified or not);

  • exec_context — a class that contains the execution context of the events flow;

  • event — the name of an event that will be sent further;

  • data — the data that will be sent with an event.

It should be noted that in the case of exec the callback will be called when the last reply is received. In the case of push we pass a callback that will be called when a connection request is sent to the server. If the server is not able to start processing we’ll get an error. If the server has started to process it - push will be processed correctly without any errors.

The push won’t be able to trace the further course of events (whether a particular worker is unable to process the event, how long it handles it, etc). Push is designed for asynchronous data exchange with some worker, usually used in a chain, where each worker can send some response to the blocked client that clearly tells that the event was handled.

reply() method behaves as push method except that it doesn’t send an event further down the chain, instead it returns it to a machine that originally sent the request via exec method.

Reply accepts 3 arguments:

  • context — the execution context of the event flow;

  • data — data that returned in the reply (the result of processing events);

  • enum exec_context::final_state — it indicates progressive or final state: progressive means that it is not the last event in the stream, final - it’s the last event in the stream.

There are synchronous and asynchronous versions of the reply method and the push method. These methods return when a request is sent to the server in the synchronous version. These methods accept a callback that will be called when a request is sent to the server in the asynchronous version.

Note that the code that handles these requests can’t know whether they are successfully processed by the server or not. The maximum that they can receive is the information about the request such as ‘the request was sent to the appropriate machine and put in the queue’. It is enough for the reply method to understand that the client has received the data.

Class exec_context is an opaque wrapper over a low-level sph object. There is an enum final_state in the namespace of a class exec_context, that is sent in the reply of the session.

Class exec_context constructors:

  • default constructor (creates an empty exec-context (null) in such a way that the method will return «true»);

  • copy constructor;

  • assignment operator;

  • a constructor from data_pointer (takes raw_data and parses it for internal structures, if the operation is successful — it is constructed, otherwise it will throw an exception);

  • the construction from a pointer to an exec_context_data class, used for internal purposes;

  • a static from_raw method exists for constructing exec_context from the raw data, which is owned by the users. The copying of the data does not happen and exec_context does not free them. You need to ensure that exec_context will "live" more than its data "lives";

  • parse method — the static method for exec_context construction from data_pointer but without throwing an exception; when errors are detected, they are returnred in the second argument of this method (error).

Not static exec_context methods:

  • event — returns the name of the event;

  • data — returns the data of the event;

  • address - indicates the address of the machine that sent the event;

  • is_final - indicates to the ‘final’ flag and if it is a reply or not;

  • is_null - specifies if that context is empty or not.

The second argument in the parse method is error_info.

error_info — is a thin wrapper over Elliptics’s errors, that allows you to avoid the exceptions in many cases. error_info accepts two arguments to the constructor:

  • error code (negative errno);

  • a string that contains a text description of the error.

There are several methods in error_info:

  • code - returns error code;

  • message - returns a text of the error.

There is also a cast operator for boolean-value, which returns a value of «true» if the error is not zero. Also there is an operator "!" that returns «true», if the error is zero.

throw_error() method throws an exception constructed from the error_info data. Also there is a create_error() method that behaves similarly to throw_error() and it is a constructor of error_info().

The following methods were added in data_pointer():

  • copy() - copies the data from the arguments;

  • allocate() - allocates a memory of the specified size and returns data_pointer() to it;

  • from_raw() — constructs data_pointer from the given data, but data_pointer doesn’t own this data, only refers to it.

Returned values

Starting with version 2.21 of Elliptics the returned data from all methods had been changed. Now they return objects inherited from generic_result_holder. Since the intoduction an asynchronous API, it became necessary to save and forward exceptions. That's why in the handler passed to the asynchronous method the first call to the argument of that handler, containing the result an exception will be thrown in case of an error.

std::exception_ptr exception() const

You can check the fact of the exception existence via exception() method, which returns exception_ptr (stores a pointer to the exception). If it is empty - there is no exception. If there is an exception, and we do not want it to be thrown, we can call this method to verify that there is no exception and do something else.

class callback_result_entry
{
    public:
        callback_result_entry();
        callback_result_entry(const callback_result_entry &other);
        callback_result_entry(const std::shared_ptr<callback_result_data> &data);
        ~callback_result_entry();

        callback_result_entry &operator =(const callback_result_entry &other);

        bool is_valid() const;
        data_pointer        raw_data() const;
        struct dnet_addr    *address() const;
        struct dnet_cmd     *command() const;
        data_pointer        data() const;
        uint64_t        size() const;
        template <typename T>
        inline T        *data() const
        { return data().data<T>(); }

    protected:
        std::shared_ptr<callback_result_data> m_data;

        friend class callback;
        friend class default_callback;
};

The result may come as a single object or as a list of objects, depending on the method.

read_data() method usually returns a single result, and methods like write() and lookup() return a list. The results are always objects that inherit from callback_result_entry (a wrapper over result object, we can get the command that initiated the corresponding request, and some specific data for this request).

class read_result_entry : public callback_result_entry
{
    public:
        read_result_entry();
        read_result_entry(const read_result_entry &other);
        ~read_result_entry();

        read_result_entry &operator =(const read_result_entry &other);

        struct dnet_io_attr *io_attribute() const;
        data_pointer file() const;
};

For example, in case of a read() operation there a read_result_entry object, which allows us to get (via io_attribute() method) a pointer to dnet_io_attr structure - this structure is filled with data, with which the request was made, and modified according to the server reponse (that is, «size» field is changed, indicating the size of the data).

You can get the structure data_pointer (a wrapper over the raw data, and the data that came from the server) witn file() method.

class lookup_result_entry : public callback_result_entry
{
    public:
        lookup_result_entry();
        lookup_result_entry(const lookup_result_entry &other);
        ~lookup_result_entry();

        lookup_result_entry &operator =(const lookup_result_entry &other);

        struct dnet_addr_attr *address_attribute() const;
        struct dnet_file_info *file_info() const;
        const char *file_path() const;
}; 

lookup_result_entry is returned from the lookup() method and from write-requests. It has the following methods to access the information about the stored objects:

  • address_attribute() - the information about where they are stored;

  • file_info() - information about the size of these objects, etc.;

  • file_path() - the name of the file at the server that contains the given key. It’s relevant for eblob and file backend, because you can stream the data from them. For leveldb backend it does not make sense.

class stat_result_entry : public callback_result_entry
{
    public:
        stat_result_entry();
        stat_result_entry(const stat_result_entry &other);
        ~stat_result_entry();

        stat_result_entry &operator =(const stat_result_entry &other);

        struct dnet_stat *statistics() const;
};

A list of stat_result_entry objects is returned for stat_log() method. The stat_result_entry has a statistics() method, that in turn returns a pointer to dnet_stat structure - it holds statistical information, such as load average, free and used memory and other data.

void            stat_log_count(const std::function<void (const stat_count_result &)> &handler);

class stat_count_result_entry : public callback_result_entry
{
    public:
        stat_count_result_entry();
        stat_count_result_entry(const stat_count_result_entry &other);
        ~stat_count_result_entry();

        stat_count_result_entry &operator =(const stat_count_result_entry &other);

        struct dnet_addr_stat *statistics() const;
};

stat_log_count() method returns a list of stat_count_result_entry objects, that includes statistics() method that returns an array of operation counters on the server.

Class data_pointer

data_pointer — an object with a reference counter, which monitors the lifetime of the data that is stored in it. When the last data_pointer to the data is deleted, the data will be freed.

data_pointer has 2 constructors:

  • The first constructor accepts a pointer to the data as a 1st argument, and the size of that data as 2nd.

  • The second constructor accepts std::string, but it doesn’t copy the data from std::string, instead it stores a pointer to the data in that string, and in that case it won’t free it.

data_pointer methods:

  • skip() allows you to skip a specified number of bytes, it returns a new data_pointer that refers to the same data, but it has an offset and its size is modified. For example, if we had a data_pointer, which referred to a block of data, then skip(X) method returns a new data_pointer, which refers to the part of the block with X bytes skipped from the beginning. There is also a templated skip() method that accepts a class or a structure as an argument, in that case, it skips as many bytes as this structure takes in memory.

  • data() returns a pointer to the beginning of the data to which it refers. In case If this object was obtained by skip() method and we skipped past the container boundaries then when we try to access the data(), it will throw a «null pointer exception». If we are exactly on the boundary of the data block, it will return 0. If we have not yet reached the end of the data block, it will return a pointer to the beginning of the data block with the necessary offset (from skip() method).

Template overloading data() method accepts the data type and returns a pointer to that data type. In this case, «null pointer exception» will be thrown if the data does not fit in the remaining block of memory.

  • size() returns the size of the memory block for which the given data_pointer is responsible;

  • offset() returnes an offset from the original data block to the current data block;

  • empty() returns «true» if we have reached the boundaries of data_pointer or passed through them;

  • to_string() returns std::string constructed from the data that the given data_pointer is responsible.

elliptics/api-cc.txt · Last modified: 2014/09/09 23:51 by zbr