/*
 *  call-seq:
 *     lmc.clear -> Qnil
 *
 *  Clears content of hashtable.
 */
static mrb_value Cache__clear(mrb_state *mrb, mrb_value self)
{
  local_memcache_t *lmc = get_Cache(mrb, self);
  if (!local_memcache_clear(lmc))
    rb_lmc_raise_exception(mrb, &lmc->error);
  return mrb_nil_value();
}
/* :nodoc: */
static mrb_value Cache_init(mrb_state *mrb, mrb_value self)
{
  mrb_value o;
  mrb_get_args(mrb, "o", &o);
  lmc_check_dict(mrb, o);
  lmc_error_t e;
  rb_lmc_handle_t *h;

  local_memcache_t *l = local_memcache_create(rstring_ptr_null(mrb_hash_get(mrb, o, lmc_rb_sym_namespace(mrb))),
                                              rstring_ptr_null(mrb_hash_get(mrb, o, lmc_rb_sym_filename(mrb))),
                                              double_value(mrb, mrb_hash_get(mrb, o, lmc_rb_sym_size_mb(mrb))),
                                              size_t_value(mrb_hash_get(mrb, o, lmc_rb_sym_min_alloc_size(mrb))), &e);

  if (!l)
    rb_lmc_raise_exception(mrb, &e);

  h = (rb_lmc_handle_t *)DATA_PTR(self);
  if (h) {
    mrb_free(mrb, h);
  }
  DATA_TYPE(self) = &lmc_cache_type;
  DATA_PTR(self) = NULL;

  h = (rb_lmc_handle_t *)mrb_malloc(mrb, sizeof(rb_lmc_handle_t));
  if (!h) {
    mrb_raise(mrb, E_RUNTIME_ERROR, "memory allocation error");
  }

  h->lmc = l;
  h->open = 1;

  DATA_PTR(self) = h;

  return self;
}
/*
 *  call-seq:
 *     lmc.close()   ->   Qnil
 *
 *  Releases hashtable.
 */
static mrb_value Cache__close(mrb_state *mrb, mrb_value self)
{
  lmc_error_t e;
  rb_lmc_handle_t *h = DATA_PTR(self);
  if (!local_memcache_free(rb_lmc_check_handle_access(mrb, h), &e))
    rb_lmc_raise_exception(mrb, &e);
  h->open = 0;
  return mrb_nil_value();
}
/* 
 *  call-seq:
 *     lmc.close()   ->   Qnil
 *
 *  Releases hashtable.
 */
static VALUE LocalMemCache__close(VALUE obj) {
  lmc_error_t e;
  rb_lmc_handle_t *h;
  Data_Get_Struct(obj, rb_lmc_handle_t, h);
  if (!local_memcache_free(rb_lmc_check_handle_access(h), &e)) 
      rb_lmc_raise_exception(&e);
  h->open = 0;
  return Qnil;
}
/* 
 *  call-seq:
 *     lmc.set(key, value)   ->   Qnil
 *     lmc[key]=value        ->   Qnil
 *
 *  Set value for key in hashtable.  Value and key will be converted to
 *  string.
 */
static VALUE LocalMemCache__set(VALUE obj, VALUE key, VALUE value) {
  local_memcache_t *lmc = get_LocalMemCache(obj);
  lmc_rb_str_d_t k, v;
  rstring_acquire(key, &k);
  rstring_acquire(value, &v);
  if (!local_memcache_set(lmc, k.cstr, k.len, v.cstr, v.len)) { 
    rb_lmc_raise_exception(&lmc->error); 
  }
  return Qnil;
}
/*
 * call-seq: LocalMemCache.check(*args)
 *
 * Tries to repair a corrupt namespace.  Usually one doesn't call this method
 * directly, it's invoked automatically when operations time out.
 *
 * valid options are 
 * [:namespace] 
 * [:filename] 
 *
 * The memory pool must be specified by either setting the :filename or
 * :namespace option. 
 */
static VALUE LocalMemCache__check(VALUE klass, VALUE o) {
  lmc_check_dict(o);
  lmc_error_t e;
  if (!local_memcache_check_namespace(
      rstring_ptr_null(rb_hash_aref(o, lmc_rb_sym_namespace)), 
      rstring_ptr_null(rb_hash_aref(o, lmc_rb_sym_filename)),
      &e)) {
    rb_lmc_raise_exception(&e); 
  }
  return Qnil;
}
/*
 * call-seq: Cache.drop(*args)
 *
 * Deletes a memory pool.  If the :force option is set, locked semaphores are
 * removed as well.
 *
 * WARNING: Do only call this method with the :force option if you are sure
 * that you really want to remove this memory pool and no more processes are
 * still using it.
 *
 * If you delete a pool and other processes still have handles open on it, the
 * status of these handles becomes undefined.  There's no way for a process to
 * know when a handle is not valid anymore, so only delete a memory pool if
 * you are sure that all handles are closed.
 *
 * valid options for drop are
 * [:namespace]
 * [:filename]
 * [:force]
 *
 * The memory pool must be specified by either setting the :filename or
 * :namespace option.  The default for :force is false.
 */
static mrb_value Cache__drop(mrb_state *mrb, mrb_value self)
{
  mrb_value o;
  mrb_get_args(mrb, "o", &o);
  lmc_check_dict(mrb, o);
  lmc_error_t e;
  if (!local_memcache_drop_namespace(rstring_ptr_null(mrb_hash_get(mrb, o, lmc_rb_sym_namespace(mrb))),
                                     rstring_ptr_null(mrb_hash_get(mrb, o, lmc_rb_sym_filename(mrb))),
                                     bool_value(mrb_hash_get(mrb, o, lmc_rb_sym_force(mrb))), &e)) {
    rb_lmc_raise_exception(mrb, &e);
  }
  return mrb_nil_value();
}
/* :nodoc: */
static VALUE LocalMemCache__new2(VALUE klass, VALUE o) {
  lmc_check_dict(o);
  lmc_error_t e;
  local_memcache_t *l = local_memcache_create(
      rstring_ptr_null(rb_hash_aref(o, lmc_rb_sym_namespace)),
      rstring_ptr_null(rb_hash_aref(o, lmc_rb_sym_filename)), 
      double_value(rb_hash_aref(o, lmc_rb_sym_size_mb)),
      long_value(rb_hash_aref(o, lmc_rb_sym_min_alloc_size)), &e);
  if (!l)  rb_lmc_raise_exception(&e);
  rb_lmc_handle_t *h = calloc(1, sizeof(rb_lmc_handle_t));
  if (!h) rb_raise(rb_eRuntimeError, "memory allocation error");
  h->lmc = l;
  h->open = 1;
  return Data_Wrap_Struct(klass, NULL, rb_lmc_free_handle, h);
}
/* :nodoc: */
static void rb_lmc_cache_destructor(mrb_state *mrb, void *p)
{
  rb_lmc_handle_t *h;
  lmc_error_t e;

  h = (rb_lmc_handle_t *)p;
  if (!h || (h->open == 0) || !h->lmc)
    return;

  if (!local_memcache_free(h->lmc, &e)) {
    mrb_free(mrb, p);
    rb_lmc_raise_exception(mrb, &e);
    return;
  }

  mrb_free(mrb, p);
}
/*
 *  call-seq:
 *     lmc.set(key, value)   ->   Qnil
 *     lmc[key]=value        ->   Qnil
 *
 *  Set value for key in hashtable.  Value and key will be converted to
 *  string.
 */
static mrb_value Cache__set(mrb_state *mrb, mrb_value self)
{
  local_memcache_t *lmc = get_Cache(mrb, self);
  mrb_value key, value;
  mrb_cache_iovec_t k, v;

  mrb_get_args(mrb, "oo", &key, &value);
  if (mrb_type(key) != MRB_TT_STRING || mrb_type(value) != MRB_TT_STRING) {
    mrb_raise(mrb, E_TYPE_ERROR, "both key and value must be STRING");
  }

  mrb_cache_str_to_iovec(mrb, key, &k);
  mrb_cache_str_to_iovec(mrb, value, &v);

  if (!local_memcache_set(lmc, k.base, k.len, v.base, v.len)) {
    rb_lmc_raise_exception(mrb, &lmc->error);
  }
  return mrb_nil_value();
}
/*
 *  call-seq: 
 *     lmc.clear -> Qnil
 *
 *  Clears content of hashtable.
 */
static VALUE LocalMemCache__clear(VALUE obj) {
  local_memcache_t *lmc = get_LocalMemCache(obj);
  if (!local_memcache_clear(lmc)) rb_lmc_raise_exception(&lmc->error); 
  return Qnil;
}