git » nmdb » master » tree

[master] / bindings / d / nmdb.d

/*
 * Digital Mars D programming language bindings for the nmdb C library.
 * Alberto Bertogli (albertito@blitiri.com.ar)
 */

module nmdb;

import nmdb_ll;


/* Exception to raise when a key can't be found. It'd be better to use the
 * same D arrays use (ArrayBoundsException) but it's designed for compiler
 * use, and the lack of a standard exception hierarchy sucks. */
class KeyNotFound : Exception {
	this(char[] s) {
		super(s);
	}
}


/* Operation modes */
enum {
	MODE_NORMAL = 1,
	MODE_CACHE = 2,
	MODE_SYNC = 3,
}


class DB
{
	private nmdb_t *db;
	int mode = MODE_NORMAL;


	this()
	{
		db = nmdb_init();
	}

	~this()
	{
		nmdb_free(db);
	}

	void add_tipc_server(int port = -1)
	{
		int r = nmdb_add_tipc_server(db, port);
		if (r == 0) {
			throw new Exception("Can't add server");
		}
	}

	void add_tcp_server(char[] addr, int port = -1)
	{
		int r = nmdb_add_tcp_server(db, cast(ubyte *) addr.ptr, port);
		if (r == 0) {
			throw new Exception("Can't add server");
		}
	}

	void add_udp_server(char[] addr, int port = -1)
	{
		int r = nmdb_add_udp_server(db, cast(ubyte *) addr.ptr, port);
		if (r == 0) {
			throw new Exception("Can't add server");
		}
	}

	void add_sctp_server(char[] addr, int port = -1)
	{
		int r = nmdb_add_sctp_server(db, cast(ubyte *) addr.ptr, port);
		if (r == 0) {
			throw new Exception("Can't add server");
		}
	}

	private char[] do_get(char[] key, int mode)
	{
		ptrdiff_t size;
		ubyte* k = cast(ubyte *) key.ptr;
		auto v = new char[64 * 1024];

		if (mode == MODE_NORMAL || mode == MODE_SYNC) {
			size = nmdb_get(db, k, key.length,
					cast(ubyte *) v, v.length);
		} else if (mode == MODE_CACHE) {
			size = nmdb_cache_get(db, k, key.length,
					cast(ubyte *) v, v.length);
		} else {
			throw new Exception("Invalid mode");
		}

		if (size == -1) {
			throw new KeyNotFound("Key not found: " ~ key);
		} else if (size <= -2) {
			throw new Exception("Can't get value");
		}

		// resize using D's magic
		v.length = cast(size_t) size;

		return v;
	}

	private void do_set(char[] key, char[] val, int mode)
	{
		ubyte* k = cast(ubyte *) key.ptr;
		ubyte* v = cast(ubyte *) val.ptr;
		int res = 0;

		if (mode == MODE_NORMAL) {
			res = nmdb_set(db, k, key.length, v, val.length);
		} else if (mode == MODE_SYNC) {
			res = nmdb_set_sync(db, k, key.length,
					v, val.length);
		} else if (mode == MODE_CACHE) {
			res = nmdb_cache_set(db, k, key.length,
					v, val.length);
		} else {
			throw new Exception("Invalid mode");
		}

		if (res != 1) {
			throw new Exception("Can't set value");
		}
	}

	private int do_del(char[] key, int mode)
	{
		ubyte* k = cast(ubyte *) key.ptr;
		int res = 0;

		if (mode == MODE_NORMAL) {
			res = nmdb_del(db, k, key.length);
		} else if (mode == MODE_SYNC) {
			res = nmdb_del_sync(db, k, key.length);
		} else if (mode == MODE_CACHE) {
			res = nmdb_cache_del(db, k, key.length);
		} else {
			throw new Exception("Invalid mode");
		}
		return res;
	}

	private int do_cas(char[] key, char[] oldval, char[] newval,
			int mode)
	{
		ubyte* k = cast(ubyte *) key.ptr;
		ubyte* ov = cast(ubyte *) oldval.ptr;
		ubyte* nv = cast(ubyte *) newval.ptr;
		int res = 0;

		if (mode == MODE_NORMAL || mode == MODE_SYNC) {
			res = nmdb_cas(db, k, key.length,
					ov, oldval.length,
					nv, newval.length);
		} else if (mode == MODE_CACHE) {
			res = nmdb_cache_cas(db, k, key.length,
					ov, oldval.length,
					nv, newval.length);
		} else {
			throw new Exception("Invalid mode");
		}
		return res;
	}

	private int do_incr(char[] key, long increment, long *newval,
			int mode)
	{
		ubyte* k = cast(ubyte *) key.ptr;
		int res = 0;

		if (mode == MODE_NORMAL || mode == MODE_SYNC) {
			res = nmdb_incr(db, k, key.length, increment, newval);
		} else if (mode == MODE_CACHE) {
			res = nmdb_cache_incr(db, k, key.length, increment,
					newval);
		} else {
			throw new Exception("Invalid mode");
		}
		return res;
	}


	char[] get(char[] key)
	{
		return do_get(key, mode);
	}

	char[] get_normal(char[] key)
	{
		return do_get(key, MODE_NORMAL);
	}

	char[] cache_get(char[] key)
	{
		return do_get(key, MODE_CACHE);
	}


	void set(char[] key, char[] val)
	{
		return do_set(key, val, mode);
	}

	void set_normal(char[] key, char[] val)
	{
		return do_set(key, val, MODE_NORMAL);
	}

	void set_sync(char[] key, char[] val)
	{
		return do_set(key, val, MODE_SYNC);
	}

	void cache_set(char[] key, char[] val)
	{
		return do_set(key, val, MODE_CACHE);
	}


	int remove(char[] key)
	{
		return do_del(key, mode);
	}

	int remove_normal(char[] key)
	{
		return do_del(key, MODE_NORMAL);
	}

	int remove_sync(char[] key)
	{
		return do_del(key, MODE_SYNC);
	}

	int cache_remove(char[] key)
	{
		return do_del(key, MODE_CACHE);
	}


	int cas(char[] key, char[] oldval, char[] newval)
	{
		return do_cas(key, oldval, newval, mode);
	}

	int cas_normal(char[] key, char[] oldval, char[] newval)
	{
		return do_cas(key, oldval, newval, MODE_NORMAL);
	}

	int cache_cas(char[] key, char[] oldval, char[] newval)
	{
		return do_cas(key, oldval, newval, MODE_CACHE);
	}


	int incr(char[] key, long increment, long *newval)
	{
		return do_incr(key, increment, newval, mode);
	}

	int incr_normal(char[] key, long increment, long *newval)
	{
		return do_incr(key, increment, newval, MODE_NORMAL);
	}

	int cache_incr(char[] key, long increment, long *newval)
	{
		return do_incr(key, increment, newval, MODE_CACHE);
	}


	char[] opIndex(char[] key)
	{
		return get(key);
	}

	void opIndexAssign(char[] val, char[] key)
	{
		return set(key, val);
	}

	bool opIn_r(char[] key)
	{
		try {
			get(key);
		} catch (KeyNotFound(s)) {
			return false;
		}
		return true;
	}

}