/**
 * Delete an item from the cache
 * @param key the key of the item to delete
 * @param nkey the length of the key
 * @return true if the item was deleted from the cache
 */
bool delete_item(const void* key, size_t nkey) {
  ib_trx_t transaction= ib_trx_begin(IB_TRX_REPEATABLE_READ);

  bool ret= do_delete_item(transaction, key, nkey);

  if (ret)
  {
    /* object found. commit transaction */
    ib_err_t error= ib_trx_commit(transaction);
    if (error != DB_SUCCESS)
    {
      fprintf(stderr, "Failed to delete key:\n\t%s\n",
              ib_strerror(error));
      ret= false;
    }
  }
  else
  {
    ib_err_t error= ib_trx_rollback(transaction);
    if (error != DB_SUCCESS)
      fprintf(stderr, "Failed to roll back the transaction:\n\t%s\n",
              ib_strerror(error));
  }

  return ret;
}
Exemple #2
0
static void innostore_drv_stop(ErlDrvData handle)
{
    PortState* state = (PortState*)handle;

    // Grab the worker lock, in case we have an job running
    erl_drv_mutex_lock(state->worker_lock);

    // Signal the shutdown and wait until the current operation has completed
    state->shutdown_flag = 1;
    erl_drv_cond_signal(state->worker_cv);

    while (state->op)
    {
        erl_drv_cond_wait(state->worker_cv, state->worker_lock);
    }

    // If the port state is not marked as READY, close the cursor and abort the txn
    if (state->port_state != STATE_READY)
    {
        ib_cursor_close(state->cursor);
        ib_trx_rollback(state->txn);
    }

    // No pending jobs and we have the lock again -- join our worker thread
    erl_drv_cond_signal(state->worker_cv);
    erl_drv_mutex_unlock(state->worker_lock);
    erl_drv_thread_join(state->worker, 0);

    // Cleanup
    erl_drv_cond_destroy(state->worker_cv);
    erl_drv_mutex_destroy(state->worker_lock);
    driver_free(handle);
}
/**
 * Flush the entire cache
 * @param when when the cache should be flushed (0 == immediately)
 */
void flush(uint32_t when __attribute__((unused))) 
{
  /* @TODO implement support for when != 0 */
  ib_trx_t transaction= ib_trx_begin(IB_TRX_REPEATABLE_READ);
  ib_crsr_t cursor= NULL;
	ib_err_t err= DB_SUCCESS;

  checked(ib_cursor_open_table(tablename, transaction, &cursor));
  checked(ib_cursor_first(cursor));
  checked(ib_cursor_lock(cursor, IB_LOCK_X));

  do 
  {
    checked(ib_cursor_delete_row(cursor));
  } while ((err= ib_cursor_next(cursor)) == DB_SUCCESS);

  if (err != DB_END_OF_INDEX)
  {
    fprintf(stderr, "Failed to flush the cache: %s\n", ib_strerror(err));
    goto error_exit;
  }
  ib_cursor_close(cursor);
  cursor= NULL;
  checked(ib_trx_commit(transaction));
  return;

 error_exit:
  if (cursor != NULL)
    ib_cursor_close(cursor);

  ib_err_t error= ib_trx_rollback(transaction);
  if (error != DB_SUCCESS)
    fprintf(stderr, "Failed to roll back the transaction:\n\t%s\n",
            ib_strerror(error));
}
Exemple #4
0
/*********************************************************************
CREATE TABLE T(C1 INT, C2 VARCHAR(10), C3 BLOB); */
static
ib_err_t
create_table(
/*=========*/
	const char*	dbname,			/*!< in: database name */
	const char*	name)			/*!< in: table name */
{
	ib_trx_t	ib_trx;
	ib_id_t		table_id = 0;
	ib_err_t	err = DB_SUCCESS;
	ib_tbl_sch_t	ib_tbl_sch = NULL;
	char		table_name[IB_MAX_TABLE_NAME_LEN];

#ifdef __WIN__
	sprintf(table_name, "%s/%s", dbname, name);
#else
	snprintf(table_name, sizeof(table_name), "%s/%s", dbname, name);
#endif

	/* Pass a table page size of 0, ie., use default page size. */
	err = ib_table_schema_create(
		table_name, &ib_tbl_sch, IB_TBL_COMPACT, 0);

	assert(err == DB_SUCCESS);

	err = ib_table_schema_add_col(
		ib_tbl_sch, "c1", IB_INT, IB_COL_NONE, 0, sizeof(ib_i32_t));

	assert(err == DB_SUCCESS);

	err = ib_tbl_sch_add_varchar_col(ib_tbl_sch, "c2", 10);
	assert(err == DB_SUCCESS);

	err = ib_tbl_sch_add_blob_col(ib_tbl_sch, "c3");
	assert(err == DB_SUCCESS);

	/* create table */
	ib_trx = ib_trx_begin(IB_TRX_REPEATABLE_READ);
	err = ib_schema_lock_exclusive(ib_trx);
	assert(err == DB_SUCCESS);

	err = ib_table_create(ib_trx, ib_tbl_sch, &table_id);

	if (err == DB_SUCCESS) {
		err = ib_trx_commit(ib_trx);
	} else {
		fprintf(stderr, "Table: %s create failed: %s\n",
				table_name, ib_strerror(err));

		err = ib_trx_rollback(ib_trx);
	}
	assert(err == DB_SUCCESS);

	if (ib_tbl_sch != NULL) {
		ib_table_schema_delete(ib_tbl_sch);
	}

	return(err);
}
/**
 * Get an item from the engine
 * @param key the key to grab
 * @param nkey number of bytes in the key
 * @return pointer to the item if found
 */
struct item* get_item(const void* key, size_t nkey) 
{
  ib_trx_t transaction= ib_trx_begin(IB_TRX_SERIALIZABLE);
  struct item* ret= do_get_item(transaction, key, nkey);
  ib_err_t error= ib_trx_rollback(transaction);

  if (error != DB_SUCCESS)
    fprintf(stderr, "Failed to roll back the transaction:\n\t%s\n",
            ib_strerror(error));

  return ret;
}
Exemple #6
0
/*********************************************************************
Tests creating a index with a name that InnoDB uses for temporary indexs
@return	DB_SUCCESS or error code */
static
ib_err_t
test_create_temp_index(
/*=============*/
	const char*     dbname,
	const char*	name,	/*!< in: table name */
	const char*	col_name)	/*!< in: column name */
{
	ib_err_t	err;
	ib_trx_t	ib_trx;
	ib_id_t		index_id = 0;
	ib_idx_sch_t	ib_idx_sch = NULL;
	char		index_name[IB_MAX_TABLE_NAME_LEN];
	char		table_name[IB_MAX_TABLE_NAME_LEN];

#ifdef __WIN__
	sprintf(table_name, "%s/%s", dbname, name);
#else
	snprintf(table_name, sizeof(table_name), "%s/%s", dbname, name);
#endif

	ib_trx = ib_trx_begin(IB_TRX_REPEATABLE_READ);

	err = ib_schema_lock_exclusive(ib_trx);
	assert(err == DB_SUCCESS);

#ifdef __WIN__
	sprintf(index_name, "%c%s_%s", TEMP_INDEX_PREFIX, table_name, col_name);
#else
	snprintf(index_name, sizeof(index_name), "%c%s_%s", TEMP_INDEX_PREFIX,
		table_name, col_name);
#endif
	err = ib_index_schema_create(
		ib_trx, index_name, table_name, &ib_idx_sch);

	assert(err == DB_INVALID_INPUT);

	if (ib_idx_sch != NULL) {
		ib_index_schema_delete(ib_idx_sch);
		ib_idx_sch = NULL;
	}

	if (err == DB_SUCCESS) {
		err = ib_trx_commit(ib_trx);
	} else {
		err = ib_trx_rollback(ib_trx);
	}
	assert(err == DB_SUCCESS);

	return(err);
}
Exemple #7
0
/*********************************************************************
Create a secondary indexes on a table.
@return	DB_SUCCESS or error code */
static
ib_err_t
create_sec_index(
/*=============*/
	const char*	table_name,	/*!< in: table name */
	const char*	col_name,	/*!< in: column name */
	int		prefix_len)	/*!< in: prefix index length */

{
	ib_err_t	err;
	ib_trx_t	ib_trx;
	ib_id_t		index_id = 0;
	ib_idx_sch_t	ib_idx_sch = NULL;
	char		index_name[IB_MAX_TABLE_NAME_LEN];

	ib_trx = ib_trx_begin(IB_TRX_REPEATABLE_READ);

	err = ib_schema_lock_exclusive(ib_trx);
	assert(err == DB_SUCCESS);

#ifdef __WIN__
	sprintf(index_name, "%s_%s", table_name, col_name);
#else
	snprintf(index_name, sizeof(index_name), "%s_%s", table_name, col_name);
#endif
	err = ib_index_schema_create(
		ib_trx, index_name, table_name, &ib_idx_sch);

	assert(err == DB_SUCCESS);

	err = ib_index_schema_add_col(ib_idx_sch, col_name, prefix_len);
	assert(err == DB_SUCCESS);

	err = ib_index_create(ib_idx_sch, &index_id);

	if (ib_idx_sch != NULL) {
		ib_index_schema_delete(ib_idx_sch);
		ib_idx_sch = NULL;
	}

	if (err == DB_SUCCESS) {
		err = ib_trx_commit(ib_trx);
	} else {
		err = ib_trx_rollback(ib_trx);
	}
	assert(err == DB_SUCCESS);

	return(err);
}
/**
 * Create the database schema.
 * @return true if the database schema was created without any problems
 *         false otherwise.
 */
static bool create_schema(void) 
{
  ib_tbl_sch_t schema= NULL;
  ib_idx_sch_t dbindex= NULL;

  if (ib_database_create("memcached") != IB_TRUE)
  {
    fprintf(stderr, "Failed to create database\n");
    return false;
  }

  ib_trx_t transaction= ib_trx_begin(IB_TRX_SERIALIZABLE);
  ib_id_t table_id;

  checked(ib_table_schema_create(tablename, &schema, IB_TBL_COMPACT, 0));
  checked(ib_table_schema_add_col(schema, "key", IB_BLOB,
                                  IB_COL_NOT_NULL, 0, 32767));
  checked(ib_table_schema_add_col(schema, "data", IB_BLOB,
                                  IB_COL_NONE, 0, 1024*1024));
  checked(ib_table_schema_add_col(schema, "flags", IB_INT,
                                  IB_COL_UNSIGNED, 0, 4));
  checked(ib_table_schema_add_col(schema, "cas", IB_INT,
                                  IB_COL_UNSIGNED, 0, 8));
  checked(ib_table_schema_add_col(schema, "exp", IB_INT,
                                  IB_COL_UNSIGNED, 0, 4));
  checked(ib_table_schema_add_index(schema, "PRIMARY_KEY", &dbindex));
  checked(ib_index_schema_add_col(dbindex, "key", 0));
  checked(ib_index_schema_set_clustered(dbindex));
  checked(ib_schema_lock_exclusive(transaction));
  checked(ib_table_create(transaction, schema, &table_id));
  checked(ib_trx_commit(transaction));
  ib_table_schema_delete(schema);

  return true;

 error_exit:
  /* @todo release resources! */
  {
    ib_err_t error= ib_trx_rollback(transaction);
    if (error != DB_SUCCESS)
      fprintf(stderr, "Failed to roll back the transaction:\n\t%s\n",
              ib_strerror(error));
  }
  return false;
}
/**
 * Store an item in the databse
 *
 * @param item the item to store
 */
void put_item(struct item* item) 
{
  ib_trx_t transaction= ib_trx_begin(IB_TRX_SERIALIZABLE);
  if (do_put_item(transaction, item)) 
  {
    ib_err_t error= ib_trx_commit(transaction);
    if (error != DB_SUCCESS) 
    {
      fprintf(stderr, "Failed to store key:\n\t%s\n",
              ib_strerror(error));
    }
  } 
  else 
  {
    ib_err_t error= ib_trx_rollback(transaction);
    if (error != DB_SUCCESS)
      fprintf(stderr, "Failed to roll back the transaction:\n\t%s\n",
              ib_strerror(error));
  }
}
Exemple #10
0
/*********************************************************************
CREATE TABLE T(
	vchar	VARCHAR(128),
	blob	VARCHAR(n),
	count	INT,
	PRIMARY KEY(vchar); */
static
ib_err_t
create_table(
/*=========*/
	const char*	dbname,			/*!< in: database name */
	const char*	name)			/*!< in: table name */
{
	ib_trx_t	ib_trx;
	ib_id_t		table_id = 0;
	ib_err_t	err = DB_SUCCESS;
	ib_tbl_sch_t	ib_tbl_sch = NULL;
	ib_idx_sch_t	ib_idx_sch = NULL;
	ib_tbl_fmt_t	tbl_fmt = IB_TBL_COMPACT;
	char		table_name[IB_MAX_TABLE_NAME_LEN];

#ifdef __WIN__
	sprintf(table_name, "%s/%s", dbname, name);
#else
	snprintf(table_name, sizeof(table_name), "%s/%s", dbname, name);
#endif

	if (page_size > 0) {
		tbl_fmt = IB_TBL_COMPRESSED;

		printf("Creating compressed table with page size %d\n",
			page_size);
	}

	err = ib_table_schema_create(
		table_name, &ib_tbl_sch, tbl_fmt, page_size);

	assert(err == DB_SUCCESS);

	err = ib_table_schema_add_col(
		ib_tbl_sch, "vchar",
		IB_VARCHAR, IB_COL_NONE, 0, 128);
	assert(err == DB_SUCCESS);

	err = ib_table_schema_add_col(
		ib_tbl_sch, "blob",
		IB_BLOB, IB_COL_NONE, 0, 0);
	assert(err == DB_SUCCESS);

	err = ib_table_schema_add_col(
		ib_tbl_sch, "count",
		IB_INT, IB_COL_UNSIGNED, 0, 4);

	assert(err == DB_SUCCESS);

	err = ib_table_schema_add_index(ib_tbl_sch, "PRIMARY", &ib_idx_sch);
	assert(err == DB_SUCCESS);

	/* Set prefix length to 0. */
	err = ib_index_schema_add_col( ib_idx_sch, "vchar", 0);
	assert(err == DB_SUCCESS);

	err = ib_index_schema_set_clustered(ib_idx_sch);
	assert(err == DB_SUCCESS);

	err = ib_index_schema_set_unique(ib_idx_sch);
	assert(err == DB_SUCCESS);

	/* create table */
	ib_trx = ib_trx_begin(IB_TRX_REPEATABLE_READ);
	err = ib_schema_lock_exclusive(ib_trx);
	assert(err == DB_SUCCESS);

	err = ib_table_create(ib_trx, ib_tbl_sch, &table_id);
	if (err != DB_SUCCESS) {
		fprintf(stderr, "Warning: table create failed: %s\n",
				ib_strerror(err));
		err = ib_trx_rollback(ib_trx);
	} else {
		err = ib_trx_commit(ib_trx);
	}
	assert(err == DB_SUCCESS);

	if (ib_tbl_sch != NULL) {
		ib_table_schema_delete(ib_tbl_sch);
	}

	return(err);
}
Exemple #11
0
static void do_init_table(void* arg)
{
    PortState* state = (PortState*)arg;

    unsigned char fmt_code = UNPACK_BYTE(state->work_buffer, 0);
    // Unpack the table name (pre-formatted to be Database/TableName)
    char* table = UNPACK_STRING(state->work_buffer, 1);
    ib_id_t table_id;
    ib_tbl_fmt_t table_fmt;
    
    switch(fmt_code)
    {
      case FORMAT_REDUNDANT:
        table_fmt = IB_TBL_REDUNDANT;
        break;
      case FORMAT_COMPACT:
        table_fmt = IB_TBL_COMPACT;
        break;
      case FORMAT_DYNAMIC:
        table_fmt = IB_TBL_DYNAMIC;
        break;
      case FORMAT_COMPRESSED:
        table_fmt = IB_TBL_COMPRESSED;
        break;
      default:
        send_error_atom(state, "bad_format");
        return;
    }

    // If the table doesn't exist, create it
    if (ib_table_get_id(table, &table_id) != DB_SUCCESS)
    {
        // Start a txn for schema access and be sure to make it serializable
        ib_trx_t txn = ib_trx_begin(IB_TRX_SERIALIZABLE);
        ib_schema_lock_exclusive(txn);

        // Create the table schema
        ib_tbl_sch_t schema;
        ib_table_schema_create(table, &schema, table_fmt, 0);
        ib_table_schema_add_col(schema, "key", IB_VARBINARY, IB_COL_NONE, 0, 255);
        ib_table_schema_add_col(schema, "value", IB_BLOB, IB_COL_NONE, 0, 0);

        // Create primary index on key
        ib_idx_sch_t index;
        ib_table_schema_add_index(schema, "PRIMARY_KEY", &index);
        ib_index_schema_add_col(index, "key", 0);
        ib_index_schema_set_clustered(index);

        // Create the actual table
        ib_err_t rc = ib_table_create(txn, schema, &table_id);

        // Release the schema -- doesn't matter if table was created or not at this point
        ib_schema_unlock(txn);

        if (rc == DB_SUCCESS)
        {
            // Commit changes to schema (if any)
            ib_trx_commit(txn);
        }
        else
        {
            // Failed to create table -- rollback and exit
            ib_trx_rollback(txn);
            send_error_str(state, ib_strerror(rc));
            return;
        }
    }

    // Guaranteed at this point to have a valid table_id
    ErlDrvTermData response[] = { ERL_DRV_ATOM,   driver_mk_atom("innostore_ok"),
                                  ERL_DRV_BUF2BINARY, (ErlDrvTermData)&table_id,
                                                      (ErlDrvUInt)sizeof(table_id),
                                  ERL_DRV_TUPLE, 2};
    driver_send_term(state->port, state->port_owner, response,
                     sizeof(response) / sizeof(response[0]));
}