Tutorial

Creating Databases

To create a new Database in an Environment, you need a valid Environment handle. Then call ups_env_create_db with this Environment handle.

ups_status_t
ups_env_create_db (ups_env_t *env, ups_db_t **db, uint16_t name,
            uint32_t flags, ups_parameter_t *params);

API reference of ups_env_create_db

The third parameter of ups_env_create_db is the name of the new Database – a unique identifier in this Environment. The values 0 and everything above (including) 0xf000 are reserved and forbidden to use.

The last parameter of ups_env_create_db, param, is another variable length parameter list. It’s worth pointing out that there is a number of interesting settings that you can (should) set in order to improve the performance of upscaledb. More precisely, you can describe your key and record data, and upscaledb will automatically optimize its internal memory structures for your data. These settings are optional, but they are essential if you want to max out the performance. Here’s a list of possible options - look at the API documentation of ups_env_create_db for a more authoritative list.

The parameter UPS_PARAM_KEY_TYPE describes the key type; the following values are available:

  • UPS_TYPE_UINT8: keys are 8 bit (1 byte) characters
  • UPS_TYPE_UINT16: keys are 16 bit (2 byte) numbers
  • UPS_TYPE_UINT32: keys are 32 bit (4 byte) numbers
  • UPS_TYPE_UINT64: keys are 64 bit (8 byte) numbers
  • UPS_TYPE_REAL32: keys are 32 bit (single precision) floating point numbers
  • UPS_TYPE_REAL64: keys are 64 bit (double precision) floating point numbers
  • UPS_TYPE_BINARY: keys are arbitrary binary data, and sorted with a built-in sort function based on memcmp (); use UPS_PARAM_KEY_SIZE to specify a constant key size, otherwise the keys have variable length
  • UPS_TYPE_CUSTOM: same as UPS_TYPE_BINARY, but uses a user-provided callback function for sorting. Can be used in combination with UPS_PARAM_KEY_SIZE

In addition, you can use UPS_PARAM_RECORD_SIZE to specify a fixed record size, if all your records have the same size. If your record size and key size are small enough, then @@upscaledb will squeeze the records into the B-Tree instead of allocating extra blob storage. This can have a tremendous performance advantage. (You can use the tool upsinfo_ to check whether the records are stored inline or not.)

Here is a short example, copied from samples/env1.c. It creates a database for 32bit (4 byte) numeric keys.

#define DBNAME_CUSTOMER 1

ups_db_t *db;
ups_status_t st;
ups_parameter_t param[] = {
  {UPS_PARAM_KEY_TYPE, UPS_TYPE_UINT32},
  {0, 0}
};

st = ups_env_create_db(env, &db, DBNAME_CUSTOMER, 0, &param[0]);
if (st != UPS_SUCCESS) {
  printf ("error %d (%s)\n", st, ups_strerror (st));
  exit (–1);
}

You can now use the Database handle as you normally do, i.e. for Cursor operations or inserting/erasing values etc. To close the Database, use ups_db_close.

Creating a Record Number Database

Record Number Databases automatically assign keys in ascending order to newly inserted Database items. This can be compared to the “auto-increment” column in an SQL database. The first item to be inserted gets the key “1”, the second gets “2”, the third “3” etc.

These keys are automatically assigned by upscaledb. Therefore, when inserting items to a Record Number Database, ups_db_insert and ups_cursor_insert expect either “empty” keys (with size 0 and data pointing to NULL), or a user-allocated 8-byte key. The file samples/db4.c demonstrates the use of Record Number Databases.

To create a Record Number Database, call ups_env_create_db with the flag UPS_RECORD_NUMBER.

Here is a small snippet showing how to create a Record Number Database:

st = ups_env_create_db(env, &db, DBNAME_CUSTOMER, UPS_RECORD_NUMBER, 0);
if (st != UPS_SUCCESS) {
  printf ("error %d (%s)\n", st, ups_strerror (st));
  exit (–1);
}

Renaming a Database in an Environment

You can rename Databases in an Environment with ups_env_rename_db. This function is declared as follows:

ups_status_t
ups_env_rename_db (ups_env_t *env, uint16_t oldname,
            uint16_t newname, uint32_t flags);

API reference for ups_env_rename_db

No error occurs if the Database with the original name is already open.

The function returns UPS_DATABASE_NOT_FOUND if the Database with the old name is not found, and UPS_DATABASE_ALREADY_EXISTS if a Database with the new name already exists.

Removing a Database from an Environment

Unlike calls to ups_env_rename_db, ups_env_erase_db makes sure that the Database, which you want to delete, is not open. If the Database is still open, error UPS_DATABASE_ALREADY_OPEN is returned. Otherwise, the Database is deleted from the Environment. This can be a costly operation, because all the allocated file pages are moved to the freelist, in order to reuse them at a later stage.

ups_status_t
ups_env_erase_db (ups_env_t *env, uint16_t name, uint32_t flags);

API reference for ups_env_erase_db

It is not possible to call this function on an In-Memory Environment. For In-Memory Environments, it is sufficient to just close the Database with ups_db_close. This will immediately free all allocated memory blocks.

Closing an Environment

To close an Environment, use ups_env_close. The handle will be invalidated, and all allocated resources are released.

The flag UPS_AUTO_CLEANUP automatically closes all open Databases (and their Cursors) of this Environment. Otherwise you have to call ups_db_close for each opened Database to avoid memory leaks.

ups_status_t ups_env_close (ups_env_t *env, uint32_t flags);

API reference for ups_env_close

The following code will close the Environment handle and all associated Database handles.

st = ups_env_close (env, UPS_AUTO_CLEANUP);
if (st != UPS_SUCCESS) {
  printf ("error %d (%s)\n", st, ups_strerror (st));
  exit (–1);
}