在storage/spartan目录创建
spartan_data.cc
spartan_data.h
spartan_index.cc
spartan_index.h
- 拷贝example目录修改为spartan,并将含example关键字修改为spartan
- 修改CMakeLists.txt,添加spartan_data.cc
- 将spartan_data.h添加到ha_spartan.h中
- 重新make && make install
INSTALL PLUGIN spartan SONAME 'ha_spartan.so';
mysql> show plugins;
+------------+--------+----------------+---------------+---------+
| Name | Status | Type | Library | License |
+------------+--------+----------------+---------------+---------+
| binlog | ACTIVE | STORAGE ENGINE | NULL | GPL |
| ARCHIVE | ACTIVE | STORAGE ENGINE | NULL | GPL |
| BLACKHOLE | ACTIVE | STORAGE ENGINE | NULL | GPL |
| CSV | ACTIVE | STORAGE ENGINE | NULL | GPL |
| MEMORY | ACTIVE | STORAGE ENGINE | NULL | GPL |
| InnoDB | ACTIVE | STORAGE ENGINE | NULL | GPL |
| MyISAM | ACTIVE | STORAGE ENGINE | NULL | GPL |
| MRG_MYISAM | ACTIVE | STORAGE ENGINE | NULL | GPL |
| EXAMPLE | ACTIVE | STORAGE ENGINE | ha_example.so | GPL |
| SPARTAN | ACTIVE | STORAGE ENGINE | ha_spartan.so | GPL |
+------------+--------+----------------+---------------+---------+
10 rows in set (0.00 sec)
修改my_config.h,添加如下内容:
/*BEGIN GUOSONG MODIFICATION*/
#define WITH_SPARTAN_STORAGE_ENGINE 1
/*END GUOSONG MODIFICATION*/
修改handler.h,添加如下内容:
enum legacy_db_type
{
...
DB_TYPE_SPARTAN_DB,
DB_TYPE_FIRST_DYNAMIC=42,
DB_TYPE_DEFAULT=127 // Must be last
...
}
#include "spartan_data.h"
class Spartan_share : public Handler_share {
public:
mysql_mutex_t mutex;
THR_LOCK lock;
Spartan_share();
~Spartan_share()
{
/*BEGIN GUOSONG MODIFICATION*/
if(data_class != NULL)
delete data_class;
data_class = NULL;
/*END GUOSONG MODIFICATION*/
thr_lock_delete(&lock);
mysql_mutex_destroy(&mutex);
}
/*BEGIN GUOSONG MODIFICATION*/
Spartan_data *data_class;
/*END GUOSONG MODIFICATION*/
};
Spartan_share::Spartan_share()
{
thr_lock_init(&lock);
mysql_mutex_init(ex_key_mutex_Spartan_share_mutex,
¦ ¦ ¦ ¦ &mutex, MY_MUTEX_INIT_FAST);
/*BEGIN GUOSONG MODIFICATION*/
data_class = new Spartan_data();
/*END GUOSONG MODIFICATION*/
}
/*BEGIN GUOSONG MODIFICATION*/
#define SDE_EXT ".sde"
#define SDI_EXT ".sdi"
/*END GUOSONG MODIFICATION*/
static const char *ha_spartan_exts[] = {
/*BEGIN GUOSONG MODIFICATION*/
SDE_EXT,
SDI_EXT,
/*END GUOSONG MODIFICATION*/
NullS
};
int ha_spartan::create(const char *name, TABLE *table_arg,
¦ ¦ ¦ ¦ ¦ HA_CREATE_INFO *create_info)
{
DBUG_ENTER("ha_spartan::create");
/*
This is not implemented but we want someone to be able to see that it
works.
*/
/*BEGIN GUOSONG MODIFICATION*/
char name_buff[FN_REFLEN];
if(!(share = get_share()))
¦ DBUG_RETURN(1);
if(share->data_class->create_table(fn_format(name_buff, name, "",SDE_EXT,
¦ ¦ ¦ ¦ MY_REPLACE_EXT|MY_UNPACK_FILENAME)))
¦ DBUG_RETURN(-1);
share->data_class->close_table();
/*END GUOSONG MODIFICATION*/
DBUG_RETURN(0);
}
int ha_spartan::open(const char *name, int mode, uint test_if_locked)
{
DBUG_ENTER("ha_spartan::open");
/*BEGIN GUOSONG MODIFICATION*/
Spartan_share *share;
char name_buff[FN_REFLEN];
if (!(share = get_share()))
DBUG_RETURN(1);
share->data_class->open_table(fn_format(name_buff, name, "", SDE_EXT,
MY_REPLACE_EXT|MY_UNPACK_FILENAME));
/*if (!(share = get_share()))
DBUG_RETURN(1);*/
/*END GUOSONG MODIFICATION*/
thr_lock_data_init(&share->lock,&lock,NULL);
DBUG_RETURN(0);
}
int ha_spartan::delete_table(const char *name)
{
DBUG_ENTER("ha_spartan::delete_table");
/* This is not implemented but we want someone to be able that it works. */
/*BEGIN GUOSONG MODIFICATION*/
char name_buff[FN_REFLEN];
my_delete(fn_format(name_buff, name, "",
SDE_EXT,MY_REPLACE_EXT|MY_UNPACK_FILENAME), MYF(0));
/*END GUOSONG MODIFICATION*/
DBUG_RETURN(0);
}
int ha_spartan::rename_table(const char * from, const char * to)
{
/*BEGIN GUOSONG MODIFICATION*/
char data_from[FN_REFLEN];
char data_to[FN_REFLEN];
int i = 0;
DBUG_ENTER("ha_spartan::rename_table ");
/*i = my_copy(fn_format(data_from, from, "", SDE_EXT,
MY_REPLACE_EXT|MY_UNPACK_FILENAME),
fn_format(data_to, to,"",SDE_EXT,
MY_REPLACE_EXT|MY_UNPACK_FILENAME), MYF(0));*/
my_delete(data_from, MYF(0));
DBUG_RETURN(i);
/*DBUG_RETURN(HA_ERR_WRONG_COMMAND);*/
}
mysql> show create table t1\G
*************************** 1. row ***************************
Table: t1
Create Table: CREATE TABLE `t1` (
`a` int(11) DEFAULT NULL
) ENGINE=spartan DEFAULT CHARSET=utf8
mysql> system ls -lh ./data/test/t1.*
-rw-rw---- 1 my5627 mysql 8.4K May 8 16:37 ./data/test/t1.frm
-rw-rw---- 1 my5627 my5627 0 May 8 17:10 ./data/test/t1.sde
class ha_spartan: public handler
{
THR_LOCK_DATA lock; ///< MySQL lock
Spartan_share *share; ///< Shared lock info
Spartan_share *get_share(); ///< Get the share
/*BEGIN GUOSONG MODIFICATION*/
/*data文件scan的时候文件fd当前位置pos*/
off_t current_position;
/*END GUOSONG MODIFICATION*/
...
}
int ha_spartan::rnd_init(bool scan)
{
DBUG_ENTER("ha_spartan::rnd_init");
/*START GUOSONG MODIFICATION*/
current_position = 0;
stats.records = 0;
ref_length = sizeof(long long);
/*END GUOSONG MODIFICATION*/
DBUG_RETURN(0);
}
进行table scan的时候一定出现设置.
遍历每个行的时候会访问. 从数据文件中获取每一行数据,并检测是否到文件尾部.
int ha_spartan::rnd_next(uchar *buf)
{
int rc;
DBUG_ENTER("ha_spartan::rnd_next");
MYSQL_READ_ROW_START(table_share->db.str, table_share->table_name.str,
TRUE);
/*BEGIN GUOSONG MODIFICATION*/
rc = share->data_class->read_row(buf, table->s->rec_buff_length,
current_position);
if (rc != -1)
current_position = (off_t)share->data_class->cur_position();
else
DBUG_RETURN(HA_ERR_END_OF_FILE);
stats.records++;
/*END GUOSONG MODIFICATION*/
/*rc= HA_ERR_END_OF_FILE;*/
MYSQL_READ_ROW_DONE(rc);
DBUG_RETURN(rc);
}
void ha_spartan::position(const uchar *record)
{
DBUG_ENTER("ha_spartan::position");
/*BEGIN GUOSONG MODIFICATION*/
my_store_ptr(ref, ref_length, current_position);
/*END GUOSONG MODIFICATION*/
DBUG_VOID_RETURN;
}
int ha_spartan::rnd_pos(uchar *buf, uchar *pos)
{
int rc;
DBUG_ENTER("ha_spartan::rnd_pos");
MYSQL_READ_ROW_START(table_share->db.str, table_share->table_name.str,
TRUE);
ha_statistic_increment(&SSV::ha_read_rnd_next_count);
current_position = (off_t)my_get_ptr(pos, ref_length);
rc = share->data_class->read_row(buf, current_position, -1);
/*rc= HA_ERR_WRONG_COMMAND;*/
MYSQL_READ_ROW_DONE(rc);
DBUG_RETURN(rc);
}
int ha_spartan::info(uint flag)
{
DBUG_ENTER("ha_spartan::info");
if(stats.records<2)
stats.records = 2;
DBUG_RETURN(0);
}
int ha_spartan::write_row(uchar *buf)
{
DBUG_ENTER("ha_spartan::write_row");
/*
spartan of a successful write_row. We don't store the data
anywhere; they are thrown away. A real implementation will
probably need to do something with 'buf'. We report a success
here, to pretend that the insert was successful.
*/
long long pos;
ha_statistic_increment(&SSV::ha_write_count);
mysql_mutex_lock(&share->mutex);
pos = share->data_class->write_row(buf, table->s->rec_buff_length);
mysql_mutex_unlock(&share->mutex);
DBUG_RETURN(0);
}
mysql> show create table t\G
*************************** 1. row ***************************
Table: t
Create Table: CREATE TABLE `t` (
`col_a` int(11) DEFAULT NULL,
`col_b` varchar(10) NOT NULL DEFAULT ' '
) ENGINE=spartan DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
mysql> insert into t values(1, "test1");
Query OK, 1 row affected (0.02 sec)
mysql> insert into t values(1, "test2");
Query OK, 1 row affected (0.00 sec)
mysql> insert into t values(2, "test2");
Query OK, 1 row affected (0.01 sec)
mysql> insert into t values(4, "test4");
Query OK, 1 row affected (0.01 sec)
mysql> select * from t;
+-------+-------+
| col_a | col_b |
+-------+-------+
| 1 | test1 |
| 1 | test2 |
| 2 | test2 |
| 4 | test4 |
+-------+-------+
4 rows in set (0.00 sec)
int ha_spartan::update_row(const uchar *old_data, uchar *new_data)
{
DBUG_ENTER("ha_spartan::update_row");
mysql_mutex_lock(&share->mutex);
share->data_class->update_row((uchar*)old_data, new_data,
table->s->rec_buff_length, current_position -
share->data_class->row_size(table->s->rec_buff_length));
mysql_mutex_unlock(&share->mutex);
DBUG_RETURN(0);
}
int ha_spartan::delete_row(const uchar *buf)
{
DBUG_ENTER("ha_spartan::delete_row");
mysql_mutex_lock(&share->mutex);
share->data_class->delete_row((uchar*)buf,
table->s->rec_buff_length,
current_position -
share->data_class->row_size(table->s->rec_buff_length));
mysql_mutex_unlock(&share->mutex);
DBUG_RETURN(0);
}
int ha_spartan::delete_all_rows()
{
DBUG_ENTER("ha_spartan::delete_all_rows");
mysql_mutex_lock(&share->mutex);
share->data_class->trunc_table();
mysql_mutex_unlock(&share->mutex);
DBUG_RETURN(0);
}
int ha_spartan::truncate()
{
DBUG_ENTER("ha_spartan::truncate");
mysql_mutex_lock(&share->mutex);
share->data_class->trunc_table();
mysql_mutex_unlock(&share->mutex);
DBUG_RETURN(0);
}
SET(SPARTAN_PLUGIN_STATIC "spartan")
SET(SPARTAN_PLUGIN_DYNAMIC "spartan")
SET(SPARTAN_SOURCES ha_spartan.cc spartan_data.cc spartan_index.cc)
MYSQL_ADD_PLUGIN(spartan ${SPARTAN_SOURCES} STORAGE_ENGINE MODULE_ONLY)
TARGET_LINK_LIBRARIES(spartan mysys)
之前出现过生成的ha_spartan.so找不到my_copy的问题,可以通过最后一行解决,更多参考cmake 添加头文件目录,链接动态、静态库
#include "spartan_index.h"
class Spartan_share : public Handler_share {
public:
mysql_mutex_t mutex;
THR_LOCK lock;
Spartan_share();
~Spartan_share()
{
/*BEGIN GUOSONG MODIFICATION*/
if(data_class != NULL)
delete data_class;
if(index_class != NULL)
delete index_class;
data_class = NULL;
index_class = NULL;
/*END GUOSONG MODIFICATION*/
thr_lock_delete(&lock);
mysql_mutex_destroy(&mutex);
}
/*BEGIN GUOSONG MODIFICATION*/
Spartan_data *data_class;
Spartan_index *index_class;
/*END GUOSONG MODIFICATION*/
};
class ha_spartan: public handler
{
THR_LOCK_DATA lock; ///< MySQL lock
Spartan_share *share; ///< Shared lock info
Spartan_share *get_share(); ///< Get the share
/*BEGIN GUOSONG MODIFICATION*/
/*data文件scan的时候文件fd当前位置pos*/
off_t current_position;
/*END GUOSONG MODIFICATION*/
public:
ha_spartan(handlerton *hton, TABLE_SHARE *table_arg);
~ha_spartan()
{
}
const char *index_type(uint inx) { return "Spartan_index"; }
ulonglong table_flags() const
{
return HA_NO_BLOBS | HA_NO_AUTO_INCREMENT| HA_BINLOG_STMT_CAPABLE;
}
ulong index_flags(uint inx, uint part, bool all_parts) const
{
return (HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE|
HA_READ_ORDER | HA_KEYREAD_ONLY);
}
uint max_supported_record_length() const { return HA_MAX_REC_LENGTH; }
uint max_supported_keys() const { return 1; }
uint max_supported_key_parts() const { return 1; }
uint max_supported_key_length() const { return 128; }
mysql> show create table t_idx\G
*************************** 1. row ***************************
Table: t_idx
Create Table: CREATE TABLE `t_idx` (
`col_a` int(11) NOT NULL DEFAULT '0',
`col_b` varchar(10) NOT NULL DEFAULT ' ',
PRIMARY KEY (`col_a`)
) ENGINE=Spartan DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
mysql> show index from t_idx\G
*************************** 1. row ***************************
Table: t_idx
Non_unique: 0
Key_name: PRIMARY
Seq_in_index: 1
Column_name: col_a
Collation: A
Cardinality: NULL
Sub_part: NULL
Packed: NULL
Null:
Index_type: Spartan_index
Comment:
Index_comment:
1 row in set (0.00 sec)
- ha_spartan::open
- ha_spartan::create
- ha_spartan::close
- ha_spartan::get_key
- ha_spartan::get_key_len
- ha_spartan::index_key_map
- ha_spartan::update_row
- ha_spartan::write_row
- ha_spartan::delete_row
- ha_spartan::delete_table
- ha_spartan::rename_table
- ha_spartan::index_next
- ha_spartan::index_prev
- ha_spartan::index_first
- ha_spartan::index_last
具体可以参考文件上述函数的位置.
mysql> select * from t_idx where col_a >=10;
+-------+--------+
| col_a | col_b |
+-------+--------+
| 10 | test10 |
| 11 | test11 |
| 12 | test12 |
+-------+--------+
Breakpoint 3, ha_spartan::index_next (this=0x7fff340284b0, buf=0x7fff34028700 "\n") at /home/guosong/source/mysql-5.6.27/storage/spartan/ha_spartan.cc:539
539 uchar *key = 0;
(gdb) bt
#0 ha_spartan::index_next (this=0x7fff340284b0, buf=0x7fff34028700 "\n") at /home/guosong/source/mysql-5.6.27/storage/spartan/ha_spartan.cc:539
#1 0x0000000000652497 in handler::ha_index_next (this=0x7fff340284b0, buf=0x7fff34028700 "\n") at /home/guosong/source/mysql-5.6.27/sql/handler.cc:2812
#2 0x000000000065a435 in handler::read_range_next (this=0x7fff340284b0) at /home/guosong/source/mysql-5.6.27/sql/handler.cc:6740
#3 0x000000000065846c in handler::multi_range_read_next (this=0x7fff340284b0, range_info=0x7ffff7f64bb0) at /home/guosong/source/mysql-5.6.27/sql/handler.cc:5843
#4 0x000000000098c648 in QUICK_RANGE_SELECT::get_next (this=0x7fff3402c630) at /home/guosong/source/mysql-5.6.27/sql/opt_range.cc:10644
#5 0x00000000009a638c in rr_quick (info=0x7fff3402e6a8) at /home/guosong/source/mysql-5.6.27/sql/records.cc:369
#6 0x00000000007c2bdd in sub_select (join=0x7fff34005c18, join_tab=0x7fff3402e618, end_of_records=false)
at /home/guosong/source/mysql-5.6.27/sql/sql_executor.cc:1259
#7 0x00000000007c25c0 in do_select (join=0x7fff34005c18) at /home/guosong/source/mysql-5.6.27/sql/sql_executor.cc:933
#8 0x00000000007c0473 in JOIN::exec (this=0x7fff34005c18) at /home/guosong/source/mysql-5.6.27/sql/sql_executor.cc:194
#9 0x000000000082342c in mysql_execute_select (thd=0x4a76b80, select_lex=0x4a79118, free_join=true) at /home/guosong/source/mysql-5.6.27/sql/sql_select.cc:1100
#10 0x0000000000823743 in mysql_select (thd=0x4a76b80, tables=0x7fff34005288, wild_num=1, fields=..., conds=0x7fff340059b8, order=0x4a792e0, group=0x4a79218,
having=0x0, select_options=2147748608, result=0x7fff34005bf0, unit=0x4a78ad0, select_lex=0x4a79118) at /home/guosong/source/mysql-5.6.27/sql/sql_select.cc:1221
#11 0x0000000000821758 in handle_select (thd=0x4a76b80, result=0x7fff34005bf0, setup_tables_done_option=0) at /home/guosong/source/mysql-5.6.27/sql/sql_select.cc:110
#12 0x00000000007fa835 in execute_sqlcom_select (thd=0x4a76b80, all_tables=0x7fff34005288) at /home/guosong/source/mysql-5.6.27/sql/sql_parse.cc:5134
#13 0x00000000007f2f90 in mysql_execute_command (thd=0x4a76b80) at /home/guosong/source/mysql-5.6.27/sql/sql_parse.cc:2656
#14 0x00000000007fd42e in mysql_parse (thd=0x4a76b80, rawbuf=0x7fff34005070 "select * from t_idx where col_a >=10", length=36, parser_state=0x7ffff7f66700)
at /home/guosong/source/mysql-5.6.27/sql/sql_parse.cc:6386
#15 0x00000000007efdc5 in dispatch_command (command=COM_QUERY, thd=0x4a76b80, packet=0x4b531b1 "", packet_length=36)
at /home/guosong/source/mysql-5.6.27/sql/sql_parse.cc:1340
#16 0x00000000007eed93 in do_command (thd=0x4a76b80) at /home/guosong/source/mysql-5.6.27/sql/sql_parse.cc:1037
#17 0x00000000007b4d4a in do_handle_one_connection (thd_arg=0x4a76b80) at /home/guosong/source/mysql-5.6.27/sql/sql_connect.cc:982
#18 0x00000000007b4825 in handle_one_connection (arg=0x4a76b80) at /home/guosong/source/mysql-5.6.27/sql/sql_connect.cc:898
#19 0x0000000000b2a799 in pfs_spawn_thread (arg=0x4ae5ef0) at /home/guosong/source/mysql-5.6.27/storage/perfschema/pfs.cc:1860
#20 0x00007ffff7bc7df3 in start_thread () from /lib64/libpthread.so.0
#21 0x00007ffff6c9c2cd in clone () from /lib64/libc.so.6