The upscaledb Tutorial

Copyright © 2007–2016 Christoph Rupp

This tutorial is a WORK IN PROGRESS. Do not consider it as a finished document.

Feedback and comments are always welcome. Please send them to info@upscaledb.com.

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with Invariant Sections being “The GNU Free Documentation License”, with no Front- Cover Texts, and with no Back-Cover Texts. A copy of the license is included in the section entitled “GNU Free Documentation License”.

upscaledb in 5 minutes

To set up upscaledb: Make sure that you add the include path and library path of upscaledb to your IDE/Makefile!

#include <ups/upscaledb.h>
#include <stdio.h> // for printf
#include <stdlib.h> // for exit

Also declare a helper function which will check upscaledb's return codes and terminate the application in case of an error.

// this helper function will handle unexpected errors.
static void check_error(ups_status_t st, const char *description) {
  if (st != UPS_SUCCESS) {
    printf(“ERROR %s (%s), terminating\n", description, ups_strerror(st));

Our introductory sample will insert a few key/value pairs and then print them with a cursor. Since upscaledb uses a B-Tree as the underlying data structure, the key/value pairs will automatically be sorted.

Another helper function will insert string keys and string values ("records"). We will store the strings including the terminating zero byte.

static void
insert(ups_db_t *db, const char *key, const char *value) {
  ups_key_t k = ups_make_key((void *)key, strlen(key) + 1);
  ups_record_t r = ups_make_record((void *)record, strlen(record) + 1);

  ups_status_t st = ups_db_insert(db, 0, &k, &r, 0);
  check_error(st, "ups_db_insert");

The next few lines create an Environment with a Database. The Database will not be parameterized, which means that it can store unique, variable length keys with variable length records.

int main() {
  ups_status_t st;
  ups_env_t *env;
  ups_db_t *db;

  st = ups_env_create(&env, "test.db", 0, 0664, 0);
  check_error(st, "ups_env_create");

  st = ups_env_create_db(env, &db, 1, 0, 0);
  check_error(st, "ups_env_create_db");

Now we're ready to insert data! We will use our helper function.

  insert("one", "first record");
  insert("two", "second record");
  insert("three", "third record");
  insert("four", "fourth record");
  insert("five", "fifth record");

The Database contents can now be printed using a cursor.

  ups_cursor_t *cursor;
  st = ups_cursor_create(&cursor, db, 0, 0);
  check_error(st, "ups_cursor_create");

  // move to the first key
  ups_key_t key = {0};
  ups_record_t record = {0};
  st = ups_cursor_move(cursor, &key, &record, UPS_CURSOR_FIRST);
  check_error(st, "ups_cursor_move first");

  // print key, then move to the next and repeat
  do {
    printf("%s\t=> %s\n", (const char *)key.data, (const char
    st = ups_cursor_move(cursor, &key, &record, UPS_CURSOR_NEXT);
  } while (st != UPS_KEY_NOT_FOUND);

Done! Now close the Cursor and the Environment to avoid any resource leaks. The flag UPS_AUTO_CLEANUP will automatically close all open Database handles.

  st = ups_cursor_close(cursor);
  check_error(st, "ups_cursor_close");

  st = ups_env_close(env, UPS_AUTO_CLEANUP);
  check_error(st, "ups_env_close");

  return 0;

We hope you enjoyed your first steps with upscaledb!