# Monitoring Database Storage in C

> As mentioned in the Monitoring In-Memory Database Storage page, eXtremeDB provides statistics APIs to check the amount of memory actually in use and the free memory available, and a callback mechanism for embedded applications that must react when used memory space hits a threshold.

> Also the Database Calculator API is provided to help estimate database storage requirements.

> ## Class Statistics APIs

> There are simple reporting functions, `mco_db_free_pages()`, `mco_db_total_pages()` and mco_db_page_size() that return the total number of free pages, the total number of available (originally allocated) pages and the current page size for a database connection respectively.

>         MCO_RET mco_db_free_pages(	/*IN*/ mco_db_h db, /*OUT*/ uint4 *freepages);

>         MCO_RET mco_db_total_pages(	/*IN*/ mco_db_h db, /*OUT*/ uint4 *totalpages);

>         MCO_RET mco_db_page_size(	/*IN*/ mco_db_h db, /*OUT*/ uint2 * page_size);

> Applications can also collect statistics via the `mco_class_stat_get()` function. This function takes a transaction handle and a class code, and returns statistics data for the class in the `mco_class_stat` structure:

>         MCO_RET  mco_class_stat_get(/*IN*/ mco_trans_h t, /*IN*/ uint2 class_code,
>                         /*OUT*/ mco_class_stat_h stat);

> The `mco_class_stat` structure has the following definition:

>         typedef struct mco_class_stat_t_
>         {
>             mco_counter_t objects_num;
>             mco_counter32_t core_pages; /* pages used for all data except blobs */
>             mco_counter32_t blob_pages; /* pages used by blobs */
>             mco_counter32_t seq_pages; /* pages used by sequences */
>             mco_counter_t core_space;   /* in bytes, not counting blobs */
>         } mco_class_stat_t, * mco_class_stat_h;

> ## Index Statistics APIs

> The following two functions can be called to obtain index statistics at runtime:

>         MCO_RET mco_index_stat_num (mco_trans_h t, uint2 * pnidx);

>         MCO_RET mco_index_stat_get (mco_trans_h t, uint2   index, mco_index_stat_t * stat);

> Runtime statistics are reported for the given index in the `mco_index_stat_t` structure which has the following definition:

>         typedef struct mco_index_stat_tree_t_
>         {
>             mco_counter_t levels_num;             /* tree height */
>             mco_counter_t duplicates_num;         /* number of duplicates */
>         } mco_index_stat_tree_t;

> ## Allocation Callback

> The following function supplements the runtime statistics functions described above:

>         void mco_register_alloc_callback(mco_db_h db, mco_alloc_callback_t callback,
>                             mco_alloc_callback_threshold_kind_t threshold_kind,
>                             mco_offs_t           threshold_value);

> where the callback function to be registered has the following prototype:

>         typedef void (*mco_alloc_callback_t)(mco_db_h db, mco_offs_t used);

> This function provides the means for the application to react when a memory threshold is met. The threshold criteria are useful for implementing an application's "garbage collectors" (when unlimited size databases are used) to avoid running out of disk space, etc. The possible values for `mco_alloc_callback_threshold_kind_t` (enumerated in `mco.h`) are as follows:

> MCO_ALLOC_PERCENT_USED | Fire the callback function when database memory load hits the specified threshold
> MCO_ALLOC_FREE_LEFT | Track memory usage and fire the callback when there is less remaining memory than the specified threshold (in bytes)
> MCO_ALLOC_DELTA_USED | Fire the callback each time `threshold_value` bytes are allocated
> MCO_ALLOC_USED | Fire the callback when memory consumption reaches the given threshold

> Regarding `MCO_ALLOC_DELTA_USED`, further explanation may be helpful. Suppose `threshold_value` is `1024` the following runtime behavior would be triggered:

> > 1. The program creates an object of 600 bytes. Nothing happens.

> > 2. The program creates another 600 byte object. The callback routine will be called because total memory consumption increased by 1,200 bytes (more than the threshold).

> > 3. Create another 600 byte object. Nothing happens again.

> > 4. And another 600 byte object. The callback will be called again.

> It is possible to register two different callbacks, one for the transient data and one for persistent data. To un-register the callback, `mco_register_alloc_callback()` should be called with `NULL` as the callback. When it is necessary to pass any application specific data into the callback, this is done through the connection context created via `mco_db_connect_ctx()`. The callback registration is per connection and the callback functions are called when memory is allocated from the connection that registered the callback.

> Note that It is important that applications must not free the database memory from the callback function itself. Instead it is recommended to either notify a different garbage collection thread, or simply set a "global" flag by the callback function and periodically check the flag from the main application thread.

> ## Database Calculator

> In addition to the runtime statistics described above, eXtremeDB provides the possibility of obtaining runtime information about any database class, including the memory that will be used by that class at runtime, its indexes and the size of dynamic objects. This information allows applications to optimize schema designs, choose the optimal page sizes and other storage and performance parameters.

> To obtain this information a `calculator` object is attached to the specified database and classes are registered with the calculator. The application provides the calculator with the number of objects expected to be stored for each class. The calculator API is also provided so that applications can use it at runtime if so desired.

> eXtremeDB packages also include the source code of a complete application called `dbcalc` that demonstrates the calculator API and can be used by developers to inspect their databases.

> ## Persistent Databases

> eXtremeDB provides additional APIs to monitor database storage on persistent media and a callback mechanism for embedded applications that must react when used memory space hits a threshold.

> Applications can call the function `mco_disk_info()` to get information about the current state of the database and log files. The function returns structure `mco_disk_info_t` which contains the size of the log file in bytes, the size of the database file in bytes and the amount of space that is actually used in the database file.

>         void mco_disk_info(mco_db_h con, mco_disk_info_t * info);

> ### Disk Allocation Callback

> The following function supplements the `mco_disk_info()` function described above:

>         void mco_register_disk_alloc_callback(mco_db_h db, mco_alloc_callback_t callback,
>                                 mco_alloc_callback_threshold_kind_t threshold_kind,
>                                 mco_offs_t           threshold_value);

> This registration function operates exactly as `mco_register_alloc_callback()` except that it is used to register callbacks for the persistent class allocator.