# Create/Open Persistent Databases in C

> To create or open a persistent database, the application first specifies memory device(s), and database parameters that are then passed to the `mco_db_open_dev()` API.

> The database parameters are specified in a `mco_db_params_t` structure that consists of many elements to determine runtime behavior. The `mco_db_params_init()` API is called to initialize the database parameters with default values.

> The key elements of this structure for persistent databases are:

> mem_page_size | The size in bytes of the database object and index pages
> disk_page_size | The size of the persistent storage page for this database (Must be a power of two and at least eight times the `mem_page_size`
> db_max_connections | The total number of connections allowed to the database
> disk_max_database_size | The max disk space required
> file_extension_quantum | The allocation block size for the database runtime to use when increasing the size of database file (can help to reduce file fragmentation)
> db_log_type | The database log file type (Must be one of the following values: `REDO_LOG` , `UNDO_LOG` or `NO_LOG)`
> log_params | Initial log settings specified in the `mco_log_params_t`
> mode_mask | The database open mode flags
> license_key | Normally this is not specified. But, if required, a license key is provided by McObject Support

> ## Parameter Settings

> Please refer to the general guidelines discussed in the Creating Databases page for determining the proper values for structure elements `mem_page_size, disk_page_size, db_max_connections, disk_max_database_size` and `db_log_type`.

> For C applications there are some additional factors to be aware of which are discussed in the following sections.

> ### disk_max_database_size and File Extension Quantum

> The maximum database size is passed as a parameter to `mco_db_open_dev()`. Depending on the target platform, this parameter might be an unsigned long integer value, or an unsigned long long integer. (In either case, it is of type `mco_offset_t` which can be found in `mco_spec.h`. The sentinel value `MCO_INFINITE_DATABASE_SIZE` can be passed if the maximum database size is not known.

> The `disk_max_database_size` element specifies the maximum amount of persistent media space consumed. The database run-time will report `MCO_E_DISK_SPACE_EXHAUSTED` or `MCO_ERR_DISK_SPACE_EXHAUSTED` to the transaction that causes this threshold to be exceeded (depending on whether the release or debug libraries, respectively are linked in). The `file_extension_quantum` element is used to determine the amount of persistent media space to allocate when extending a file (up to `disk_max_database_size`). By making this a multiple of the `disk_page_size` file fragmentation can be reduced and locality of references may be improved.

> The function `mco_disk_info()` can be used to collect information about the current state of the database and log file: 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.

> ### Log Parameters and Transaction Commit Policy

> The `log_params` element is a structure that allows fine tuning the logging strategy. (see Setting the Log File type for a more detailed discussion).

> The log file size is set by calling mco_disk_set_log_params(). (This function must be called after `mco_db_open_dev()` which establishes the transaction logging policy).

> Applications set the commit policy by calling the `mco_disk_transaction_policy()` function with one of the following values: `MCO_COMMIT_SYNC_FLUSH, MCO_COMMIT_BUFFERED, MCO_COMMIT_DELAYED`, or `MCO_COMMIT_NO_SYNC`. (Please see the Persistent Database I/O page for detailed explanations.)

> Note that if the `MCO_COMMIT_NO_SYNC` policy is selected, the application can explicitly force the cache to be flushed to the media by calling function `mco_disk_flush()`.

> Note that `mco_disk_flush()`must be called outside the scope of a transaction. If called from inside a transaction, it will return an error code.

> ### Recovering Unused Data Storage Space

> When the MVCC transaction manager is used, in the case of a crash, a persistent database can contain undeleted old versions and working copies of database objects. Their presence will not break the consistency of the database and doesn't prevent the normal working of an application, but does unnecessarily consume space. Detecting these stale object versions requires a complete scan of the database. For this reason the recovery process doesn't perform this function automatically. Instead, the removal of the unused versions is performed explicitly by calling the `mco_disk_database_vacuum()` function:

>         MCO_RET mco_disk_database_vacuum(mco_db_h con);

> Note that `mco_disk_database_vacuum()` requires exclusive access to the database, so no operations can be performed on the database until the vacuum operation is complete and the function has returned control back to the application.

> Alternatively, the application can enable the repair process by setting the `MCO_DB_MODE_MVCC_AUTO_VACUUM` mode mask in the `mco_db_params_t` when calling `mco_db_open_dev()`.

> ## Mode mask

> The `mode_mask` element is a bitmask used to specify any combination of runtime options. (See Database Open Modes for a detailed description of the possible options).

> ## Database Creation Example

> Typical application code to create a persistent database could look like the following:

>         #define  DATABASE_SEGMENT_SIZE 300 * 1024
>         #define  MEMORY_PAGE_SIZE 128
>         #define PSTORAGE_PAGE_SIZE 4096
>         char * db_name = "diskdb";

>         int main(int argc, char* argv[])
>         {
>             MCO_RET            rc;
>             mco_device_t       dev[4];
>             mco_db_params_t    db_params;
>             ...
>             mco_runtime_start();
>             ...
>             mco_db_params_init ( &db_params );
>             db_params.mem_page_size      = MEMORY_PAGE_SIZE; /* Set page size for the in-memory part */
>             db_params.disk_page_size     = PSTORAGE_PAGE_SIZE;  /* Set page size for persistent storage */
>             db_params.db_max_connections = 1;                /* Set total number of connections to the database */
>             db_params.db_log_type        = UNDO_LOG;            /* Set log type */
>             ...
>             rc = mco_db_open_dev(db_name, diskdb_get_dictionary(), dev, 4, &db_params );
>             if ( MCO_S_OK == rc ) {
>                 // Connect to database and perform database operations
>                 ...
>                 mco_db_close(db_name);
>             }
>             ...
>             mco_runtime_stop();
>         }