[DEPRECATED] An ACID compliant key-value storage library in the style of dbm. It utilizes immutable B+Trees in an append-only design and is distributed under LGPL.
C Python
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


aodbm - Append Only Database Manager

An append only database manager in the style of dbm. It has both a C and a 
Python interface and is ACID compliant. Internally it uses a B+ Tree. (Being 
append only doesn't mean that you can't replace records or delete keys).

Getting Started

$ make

This will build a static and a shared library.

Python interface

# import the module
>>> import aodbm
# create a database object
>>> db = aodbm.AODBM('testdb')
# get the current version of the database
>>> version = db.current_version()
# versions updated either in place or by creating new versions
# in place:
>>> version['hello'] = 'world'
>>> version['hello']
>>> list(version)
[('hello', 'world')]
>>> del version['hello']
# new versions
>>> new_version = version.set_record('hello', 'world')
>>> new_version['hello']
>>> version['hello']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "aodbm.py", line 56, in __getitem__
    raise KeyError()
>>> newest_version = new_version.del_key('hello')
# commiting a new version is simple
>>> db.commit(new_version)
# it returns whether the operation was successful
# the operation may fail if you try to commit a version that isn't based on the 
# the current version.

C interface

You'll need to link against either the static or shared library and include the 
header file aodbm.h in order to use the C API.

Before you can do anything, you will need a handle for a database. This is 
simple to acquire, simply call aodbm_open passing the filename as a NULL 
terminated string, the second argument is for flags. There are no flags at the 
moment so just pass 0. This will return an "aodbm *", when you are done with 
the handle then close the database using aodbm_close. These functions do not do 
any filelocking so ensure that only one handle exists for a given database file 
at any time.

Once you have a handle, the next step is to obtain a reference to the most 
current version of the database. Versions are represented as "aodbm_version"s. 
Under the hood these are just "uint64_t"s, so don't worry about freeing them. 
The most current version can be found using aodbm_current.

By explicitly dealing with versions of the database, you can be sure that other 
threads will not interfere during database operations.

There are four database operations: get, set, delete and has. They appear in 
the respective functions aodbm_get, aodbm_get, aodbm_del and aodbm_has. Each 
deals with "aodbm_data *"s. The aodbm_data structure represents a piece of data 
and is defined like so:

struct aodbm_data {
    char *dat;
    size_t sz;

Each of the operations' function's first three arguments are the database 
handle, the version of the database on which to operate on and the key to which 
the operation relates to. aodbm_get return a "aodbm_data *" which is populated 
with the value at the key or NULL if the record doesn't exist. When you have 
finished using the value from this operation, you should free it with 
aodbm_free_data. aodbm_set takes one extra argument, the value to store at the 
given key. aodbm_set and aodbm_del both return the new version of the database 
that you have created.

The aodbm_data objects that you provide are not modified in any way.

Iteration is also possible. First you must create an iterator using 
aodbm_new_iterator, passing in the database handle and the version to iterate 
over. Then call aodbm_iterator_next, passing in the database handle and the 
iterator. This call is not thread-safe. It returns an aodbm_record that will be 
filled with data (a key and a value) that you should free using aodbm_free_data 
when you are finished using them. The key and value will be set to NULL when 
the end of the database is reached. When you are finished using an iterator, 
whether you have reached the end of the database or not, you should free the 
iterator with aodbm_free_iterator. The records will be given in the order they 
are stored in. The less than operator is defined like so:

Given 2 keys, a and b.
if a is shorter than b return true,
if b is shorter than a return false,
return the lexicographic ordering

Having modified the database, you will likely want to commit the changes. 
Commiting the changes means that when future requests for the current version 
are made, your new version of the database will be returned. To commit your 
changes, pass your new version as the second argument to aodbm_commit. This 
will return a boolean value which indicates whether the commit was successful. 
A commit will fail if you try to commit a version that is not based on the 
current latest version.

This only leaves two functions that haven't been covered in the public API. 
aodbm_is_based_on and aodbm_previous_version. They both do exactly what you 
think they'd do. aodbm_is_based_on takes two arguments in addition to the 
database handle and they are both aodbm_versions. It returns whether the first 
is based on the second.


You can find more information at https://sourceforge.net/apps/mediawiki/aodbm

Current Progress

It is not yet suitable for production usage. There are a few known bugs in the 
delete function and I'm going to be refactoring much of the code. I consider it 
to be of (early) beta quality.

The goal of the project is to write a storage backend for a future DBMS. It 
should therefore be:

 * Fast,
 * ACID compliant,
 * As simple as possible.

Reporting Bugs

If you find a bug then please write a unit test (in Python if possible) that 
fails and send it to me (Daniel) at Da.Waterworth@gmail.com .