git » nmdb » master » tree

[master] / bindings / ruby / nmdb_ll.c

#include "nmdb.h"
#include <ruby.h>

static VALUE rb_mnmdb_ll;
static VALUE rb_cDB;


/* Functions for ruby memory management.
 * The "mm" prefix is used by us (not enforced by Ruby) to distinguish it from
 * the rest. */

static void mm_db_mark(nmdb_t *db)
{
}

static void mm_db_free(nmdb_t *db)
{
	nmdb_free(db);
}

static VALUE mm_db_allocate(VALUE class)
{
	nmdb_t *db = nmdb_init();

	return Data_Wrap_Struct(class, mm_db_mark, mm_db_free, db);
}


/*
 * DB methods
 */

VALUE m_add_tipc_server(VALUE self, VALUE port)
{
	nmdb_t *db;
	Data_Get_Struct(self, nmdb_t, db);

	int rv = nmdb_add_tipc_server(db, NUM2INT(port));
	return INT2NUM(rv);
}

VALUE m_add_tcp_server(VALUE self, VALUE hostname, VALUE port)
{
	nmdb_t *db;
	Data_Get_Struct(self, nmdb_t, db);

	int rv = nmdb_add_tcp_server(db, StringValuePtr(hostname),
			NUM2INT(port));
	return INT2NUM(rv);
}

VALUE m_add_udp_server(VALUE self, VALUE hostname, VALUE port)
{
	nmdb_t *db;
	Data_Get_Struct(self, nmdb_t, db);

	int rv = nmdb_add_udp_server(db, StringValuePtr(hostname),
			NUM2INT(port));
	return INT2NUM(rv);
}

VALUE m_add_sctp_server(VALUE self, VALUE hostname, VALUE port)
{
	nmdb_t *db;
	Data_Get_Struct(self, nmdb_t, db);

	int rv = nmdb_add_sctp_server(db, StringValuePtr(hostname),
			NUM2INT(port));
	return INT2NUM(rv);
}


/* Set functions */
typedef int (*setf_t) (nmdb_t *db,
		const unsigned char *k, size_t ks,
		const unsigned char *v, size_t vs);
static VALUE generic_set(VALUE self, VALUE key, VALUE val, setf_t set_func)
{
	int rv;
	unsigned char *k, *v;
	size_t ksize, vsize;
	nmdb_t *db;
	Data_Get_Struct(self, nmdb_t, db);

	k = rb_str2cstr(key, &ksize);
	v = rb_str2cstr(val, &vsize);

	rv = set_func(db, k, ksize, v, vsize);
	return INT2NUM(rv);
}

static VALUE m_set(VALUE self, VALUE key, VALUE val) {
	return generic_set(self, key, val, nmdb_set);
}

static VALUE m_set_sync(VALUE self, VALUE key, VALUE val) {
	return generic_set(self, key, val, nmdb_set_sync);
}

static VALUE m_cache_set(VALUE self, VALUE key, VALUE val) {
	return generic_set(self, key, val, nmdb_cache_set);
}


/* Get functions */
typedef ssize_t (*getf_t) (nmdb_t *db,
		const unsigned char *k, size_t ks,
		unsigned char *v, size_t vs);
VALUE generic_get(VALUE self, VALUE key, getf_t get_func)
{
	ssize_t rv;
	unsigned char *k, *v;
	size_t ksize, vsize;
	VALUE retval;
	nmdb_t *db;
	Data_Get_Struct(self, nmdb_t, db);

	k = rb_str2cstr(key, &ksize);

	v = ALLOC_N(char, (68 * 1024));

	rv = get_func(db, k, ksize, v, (68 * 1024));
	if (rv >= 0)
		retval = rb_str_new(v, rv);
	else
		/* The high level module knows and checks for this, there's no
		 * need to make the C code more complex by raising an
		 * exception. */
		retval = INT2NUM(rv);

	free(v);
	return retval;
}

VALUE m_get(VALUE self, VALUE key) {
	return generic_get(self, key, nmdb_get);
}

VALUE m_cache_get(VALUE self, VALUE key) {
	return generic_get(self, key, nmdb_cache_get);
}


/* Del functions */
typedef int (*delf_t) (nmdb_t *db, const unsigned char *k, size_t ks);
VALUE generic_del(VALUE self, VALUE key, delf_t del_func)
{
	ssize_t rv;
	unsigned char *k;
	size_t ksize;
	nmdb_t *db;
	Data_Get_Struct(self, nmdb_t, db);

	k = rb_str2cstr(key, &ksize);

	rv = del_func(db, k, ksize);
	return INT2NUM(rv);
}

VALUE m_del(VALUE self, VALUE key) {
	return generic_del(self, key, nmdb_del);
}

VALUE m_del_sync(VALUE self, VALUE key) {
	return generic_del(self, key, nmdb_del_sync);
}

VALUE m_cache_del(VALUE self, VALUE key) {
	return generic_del(self, key, nmdb_cache_del);
}


/* CAS functions */
typedef int (*casf_t) (nmdb_t *db,
		const unsigned char *k, size_t ks,
		const unsigned char *ov, size_t ovs,
		const unsigned char *nv, size_t nvs);
static VALUE generic_cas(VALUE self, VALUE key, VALUE oldval, VALUE newval,
		casf_t cas_func)
{
	int rv;
	unsigned char *k, *ov, *nv;
	size_t ksize, ovsize, nvsize;
	nmdb_t *db;
	Data_Get_Struct(self, nmdb_t, db);

	k = rb_str2cstr(key, &ksize);
	ov = rb_str2cstr(oldval, &ovsize);
	nv = rb_str2cstr(newval, &nvsize);

	rv = cas_func(db, k, ksize, ov, ovsize, nv, nvsize);
	return INT2NUM(rv);
}

static VALUE m_cas(VALUE self, VALUE key, VALUE oldval, VALUE newval) {
	return generic_cas(self, key, oldval, newval, nmdb_cas);
}

static VALUE m_cache_cas(VALUE self, VALUE key, VALUE oldval, VALUE newval) {
	return generic_cas(self, key, oldval, newval, nmdb_cache_cas);
}


/* Increment functions */
typedef int (*incrf_t) (nmdb_t *db, const unsigned char *k, size_t ks,
		int64_t increment, int64_t *newval);
VALUE generic_incr(VALUE self, VALUE key, VALUE increment, incrf_t incr_func)
{
	ssize_t rv;
	unsigned char *k;
	size_t ksize;
	int64_t cincr, newval;
	nmdb_t *db;
	Data_Get_Struct(self, nmdb_t, db);

	k = rb_str2cstr(key, &ksize);
	cincr = rb_num2ll(increment);

	rv = incr_func(db, k, ksize, cincr, &newval);

	return rb_ary_new3(2, INT2NUM(rv), rb_ll2inum(newval));
}

VALUE m_incr(VALUE self, VALUE key, VALUE increment) {
	return generic_incr(self, key, increment, nmdb_incr);
}

VALUE m_cache_incr(VALUE self, VALUE key, VALUE increment) {
	return generic_incr(self, key, increment, nmdb_cache_incr);
}


/* Module initialization */
void Init_nmdb_ll()
{
	rb_mnmdb_ll = rb_define_module("Nmdb_ll");
	rb_cDB = rb_define_class_under(rb_mnmdb_ll, "DB", rb_cObject);
	rb_define_alloc_func(rb_cDB, mm_db_allocate);

	rb_define_method(rb_cDB, "add_tipc_server", m_add_tipc_server, 1);
	rb_define_method(rb_cDB, "add_tcp_server", m_add_tcp_server, 2);
	rb_define_method(rb_cDB, "add_udp_server", m_add_udp_server, 2);
	rb_define_method(rb_cDB, "add_sctp_server", m_add_sctp_server, 2);

	rb_define_method(rb_cDB, "set", m_set, 2);
	rb_define_method(rb_cDB, "set_sync", m_set_sync, 2);
	rb_define_method(rb_cDB, "cache_set", m_cache_set, 2);

	rb_define_method(rb_cDB, "get", m_get, 1);
	rb_define_method(rb_cDB, "cache_get", m_cache_get, 1);

	rb_define_method(rb_cDB, "del", m_del, 1);
	rb_define_method(rb_cDB, "del_sync", m_del_sync, 1);
	rb_define_method(rb_cDB, "cache_del", m_cache_del, 1);

	rb_define_method(rb_cDB, "cas", m_cas, 3);
	rb_define_method(rb_cDB, "cache_cas", m_cache_cas, 3);

	rb_define_method(rb_cDB, "incr", m_incr, 2);
	rb_define_method(rb_cDB, "cache_incr", m_cache_incr, 2);
}