mirror of
https://github.com/MariaDB/server.git
synced 2025-01-29 02:05:57 +01:00
MDEV-23024 Remove Cassandra Storage Engine
Cassandra has long been non-functional, doesn't compile, etc., and development on it has halted. Since MariaDB Server 10.5, the build is disabled by default. It makes sense to remove it as it's just taking up space.
This commit is contained in:
parent
b0d2a59d9a
commit
d61c800308
26 changed files with 0 additions and 29721 deletions
|
@ -74,7 +74,6 @@ IF(FEATURE_SET)
|
|||
ENDIF()
|
||||
IF(num GREATER FEATURE_SET_large)
|
||||
SET(PLUGIN_PARTITION "STATIC")
|
||||
#SET(PLUGIN_CASSANDRA "STATIC")
|
||||
ENDIF()
|
||||
IF(num GREATER FEATURE_SET_xlarge)
|
||||
# OPTION(WITH_ALL ON)
|
||||
|
|
1
debian/rules
vendored
1
debian/rules
vendored
|
@ -82,7 +82,6 @@ endif
|
|||
-DCMAKE_SYSTEM_PROCESSOR=$(DEB_HOST_ARCH) \
|
||||
-DBUILD_CONFIG=mysql_release \
|
||||
-DPLUGIN_TOKUDB=NO \
|
||||
-DPLUGIN_CASSANDRA=NO \
|
||||
-DPLUGIN_COLUMNSTORE=YES \
|
||||
-DPLUGIN_ROCKSDB=YES \
|
||||
-DPLUGIN_AWS_KEY_MANAGEMENT=NO \
|
||||
|
|
|
@ -1,636 +0,0 @@
|
|||
drop table if exists t0, t1;
|
||||
#
|
||||
# Check variables and status counters
|
||||
#
|
||||
show status like 'cassandra%';
|
||||
Variable_name Value
|
||||
Cassandra_row_inserts 0
|
||||
Cassandra_row_insert_batches 0
|
||||
Cassandra_multiget_keys_scanned 0
|
||||
Cassandra_multiget_reads 0
|
||||
Cassandra_multiget_rows_read 0
|
||||
Cassandra_network_exceptions 0
|
||||
Cassandra_timeout_exceptions 0
|
||||
Cassandra_unavailable_exceptions 0
|
||||
show variables like 'cassandra%';
|
||||
Variable_name Value
|
||||
cassandra_default_thrift_host
|
||||
cassandra_failure_retries 3
|
||||
cassandra_insert_batch_size 100
|
||||
cassandra_multiget_batch_size 100
|
||||
cassandra_read_consistency ONE
|
||||
cassandra_rnd_batch_size 10000
|
||||
cassandra_write_consistency ONE
|
||||
#
|
||||
# Test various errors on table creation.
|
||||
#
|
||||
create table t1 (a int) engine=cassandra
|
||||
thrift_host='localhost' keyspace='foo' column_family='colfam';
|
||||
ERROR 42000: This table type requires a primary key
|
||||
create table t1 (a int primary key, b int) engine=cassandra
|
||||
thrift_host='localhost' keyspace='foo' column_family='colfam';
|
||||
ERROR HY000: Unable to connect to foreign data source: Default TException. [Keyspace foo does not exist]
|
||||
create table t1 (rowkey char(10) primary key, column1 char(10)) engine=cassandra
|
||||
thrift_host='127.0.0.2' keyspace='foo' column_family='colfam';
|
||||
ERROR HY000: Unable to connect to foreign data source: connect() failed: Connection refused [1]
|
||||
create table t1 (rowkey char(10) primary key, column1 char(10)) engine=cassandra
|
||||
thrift_host='localhost' keyspace='no_such_keyspace' column_family='colfam';
|
||||
ERROR HY000: Unable to connect to foreign data source: Default TException. [Keyspace no_such_keyspace does not exist]
|
||||
create table t1 (rowkey char(10) primary key, column1 char(10)) engine=cassandra
|
||||
thrift_host='localhost' keyspace='no_such_keyspace';
|
||||
ERROR HY000: Unable to connect to foreign data source: keyspace and column_family table options must be specified
|
||||
# Now, create a table for real and insert data
|
||||
create table t1 (pk varchar(36) primary key, data1 varchar(60), data2 bigint) engine=cassandra
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family='cf1';
|
||||
# Just in case there were left-overs from previous:
|
||||
delete from t1;
|
||||
select * from t1;
|
||||
pk data1 data2
|
||||
insert into t1 values ('rowkey10', 'data1-value', 123456);
|
||||
insert into t1 values ('rowkey11', 'data1-value2', 34543);
|
||||
insert into t1 values ('rowkey12', 'data1-value3', 454);
|
||||
select * from t1;
|
||||
pk data1 data2
|
||||
rowkey12 data1-value3 454
|
||||
rowkey10 data1-value 123456
|
||||
rowkey11 data1-value2 34543
|
||||
explain
|
||||
select * from t1 where pk='rowkey11';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 const PRIMARY PRIMARY 38 const 1
|
||||
select * from t1 where pk='rowkey11';
|
||||
pk data1 data2
|
||||
rowkey11 data1-value2 34543
|
||||
delete from t1 where pk='rowkey11';
|
||||
select * from t1;
|
||||
pk data1 data2
|
||||
rowkey12 data1-value3 454
|
||||
rowkey10 data1-value 123456
|
||||
delete from t1;
|
||||
select * from t1;
|
||||
pk data1 data2
|
||||
#
|
||||
# A query with filesort (check that table_flags() & HA_REC_NOT_IN_SEQ,
|
||||
# also check ::rnd_pos()
|
||||
#
|
||||
insert into t1 values ('rowkey10', 'data1-value', 123456);
|
||||
insert into t1 values ('rowkey11', 'data1-value2', 34543);
|
||||
insert into t1 values ('rowkey12', 'data1-value3', 454);
|
||||
select * from t1 order by data2;
|
||||
pk data1 data2
|
||||
rowkey12 data1-value3 454
|
||||
rowkey11 data1-value2 34543
|
||||
rowkey10 data1-value 123456
|
||||
delete from t1;
|
||||
drop table t1;
|
||||
#
|
||||
# MDEV-476: Cassandra: Server crashes in calculate_key_len on DELETE with ORDER BY
|
||||
#
|
||||
CREATE TABLE t1 (rowkey BIGINT PRIMARY KEY, a BIGINT) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf2';
|
||||
INSERT INTO t1 VALUES (1,1),(2,2);
|
||||
DELETE FROM t1 ORDER BY a LIMIT 1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# Batched INSERT
|
||||
#
|
||||
show variables like 'cassandra_insert_batch_size';
|
||||
Variable_name Value
|
||||
cassandra_insert_batch_size 100
|
||||
show status like 'cassandra_row_insert%';
|
||||
Variable_name Value
|
||||
Cassandra_row_inserts 8
|
||||
Cassandra_row_insert_batches 7
|
||||
CREATE TABLE t1 (rowkey BIGINT PRIMARY KEY, a BIGINT) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf2';
|
||||
delete from t1;
|
||||
INSERT INTO t1 VALUES (1,1),(2,2);
|
||||
DELETE FROM t1 ORDER BY a LIMIT 1;
|
||||
DROP TABLE t1;
|
||||
show status like 'cassandra_row_insert%';
|
||||
Variable_name Value
|
||||
Cassandra_row_inserts 10
|
||||
Cassandra_row_insert_batches 8
|
||||
# FLUSH STATUS doesn't work for our variables, just like with InnoDB.
|
||||
flush status;
|
||||
show status like 'cassandra_row_insert%';
|
||||
Variable_name Value
|
||||
Cassandra_row_inserts 10
|
||||
Cassandra_row_insert_batches 8
|
||||
#
|
||||
# Batched Key Access
|
||||
#
|
||||
# Control variable (we are not yet able to make use of MRR's buffer)
|
||||
show variables like 'cassandra_multi%';
|
||||
Variable_name Value
|
||||
cassandra_multiget_batch_size 100
|
||||
# MRR-related status variables:
|
||||
show status like 'cassandra_multi%';
|
||||
Variable_name Value
|
||||
Cassandra_multiget_keys_scanned 0
|
||||
Cassandra_multiget_reads 0
|
||||
Cassandra_multiget_rows_read 0
|
||||
CREATE TABLE t1 (rowkey BIGINT PRIMARY KEY, a BIGINT) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf2';
|
||||
delete from t1;
|
||||
INSERT INTO t1 VALUES (0,0),(1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9);
|
||||
set @tmp_jcl=@@join_cache_level;
|
||||
set join_cache_level=8;
|
||||
explain select * from t1 A, t1 B where B.rowkey=A.a;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE A ALL NULL NULL NULL NULL 1000 Using where
|
||||
1 SIMPLE B eq_ref PRIMARY PRIMARY 8 test.A.a 1 Using join buffer (flat, BKAH join); multiget_slice
|
||||
select * from t1 A, t1 B where B.rowkey=A.a;
|
||||
rowkey a rowkey a
|
||||
0 0 0 0
|
||||
1 1 1 1
|
||||
2 2 2 2
|
||||
3 3 3 3
|
||||
4 4 4 4
|
||||
5 5 5 5
|
||||
6 6 6 6
|
||||
7 7 7 7
|
||||
8 8 8 8
|
||||
9 9 9 9
|
||||
show status like 'cassandra_multi%';
|
||||
Variable_name Value
|
||||
Cassandra_multiget_keys_scanned 10
|
||||
Cassandra_multiget_reads 1
|
||||
Cassandra_multiget_rows_read 10
|
||||
insert into t1 values(1, 8);
|
||||
insert into t1 values(3, 8);
|
||||
insert into t1 values(5, 8);
|
||||
insert into t1 values(7, 8);
|
||||
select * from t1 A, t1 B where B.rowkey=A.a;
|
||||
rowkey a rowkey a
|
||||
0 0 0 0
|
||||
2 2 2 2
|
||||
4 4 4 4
|
||||
6 6 6 6
|
||||
1 8 8 8
|
||||
7 8 8 8
|
||||
8 8 8 8
|
||||
5 8 8 8
|
||||
3 8 8 8
|
||||
9 9 9 9
|
||||
show status like 'cassandra_multi%';
|
||||
Variable_name Value
|
||||
Cassandra_multiget_keys_scanned 16
|
||||
Cassandra_multiget_reads 2
|
||||
Cassandra_multiget_rows_read 16
|
||||
delete from t1;
|
||||
drop table t1;
|
||||
#
|
||||
# MDEV-480: TRUNCATE TABLE on a Cassandra table does not remove rows
|
||||
#
|
||||
CREATE TABLE t1 (rowkey BIGINT PRIMARY KEY, a BIGINT) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf2';
|
||||
INSERT INTO t1 VALUES (0,0),(1,1),(2,2);
|
||||
truncate table t1;
|
||||
select * from t1;
|
||||
rowkey a
|
||||
drop table t1;
|
||||
#
|
||||
# MDEV-494, part #1: phantom row for big full-scan selects
|
||||
#
|
||||
create table t0 (a int);
|
||||
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
|
||||
CREATE TABLE t1 (rowkey BIGINT PRIMARY KEY, a BIGINT) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf2';
|
||||
insert into t1 select A.a + 10 * B.a + 100*C.a, 12345 from t0 A, t0 B, t0 C;
|
||||
select count(*) from t1;
|
||||
count(*)
|
||||
1000
|
||||
select count(*) from t1 where a=12345;
|
||||
count(*)
|
||||
1000
|
||||
delete from t1;
|
||||
drop table t1;
|
||||
drop table t0;
|
||||
# 32-bit INT type support
|
||||
CREATE TABLE t1 (rowkey BIGINT PRIMARY KEY, intcol INT) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf3';
|
||||
insert into t1 values (10,10);
|
||||
insert into t1 values (12,12);
|
||||
delete from t1;
|
||||
drop table t1;
|
||||
#
|
||||
# Try accessing column family w/o explicitly defined columns
|
||||
#
|
||||
CREATE TABLE t1 (my_primary_key varchar(10) PRIMARY KEY) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf10';
|
||||
ERROR HY000: Internal error: target column family has no key_alias defined, PRIMARY KEY column must be named 'rowkey'
|
||||
CREATE TABLE t1 (rowkey varchar(10) PRIMARY KEY) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf10';
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# Timestamp datatype support
|
||||
#
|
||||
CREATE TABLE t2 (rowkey bigint PRIMARY KEY, datecol timestamp) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf4';
|
||||
delete from t2;
|
||||
insert into t2 values (1, '2012-08-29 01:23:45');
|
||||
select * from t2;
|
||||
rowkey datecol
|
||||
1 2012-08-29 01:23:45
|
||||
delete from t2;
|
||||
# MDEV-498: Cassandra: Inserting a timestamp does not work on a 32-bit system
|
||||
INSERT INTO t2 VALUES (10,'2012-12-12 12:12:12');
|
||||
SELECT * FROM t2;
|
||||
rowkey datecol
|
||||
10 2012-12-12 12:12:12
|
||||
delete from t2;
|
||||
#
|
||||
# (no MDEV#) Check that insert counters work correctly
|
||||
#
|
||||
create table t0 (a int);
|
||||
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
|
||||
set cassandra_insert_batch_size=10;
|
||||
insert into t2 select A.a+10*B.a, now() from t0 A, t0 B;
|
||||
inserts insert_batches
|
||||
100 10
|
||||
set cassandra_insert_batch_size=1;
|
||||
insert into t2 select A.a+10*B.a+100, now() from t0 A, t0 B;
|
||||
inserts insert_batches
|
||||
100 100
|
||||
delete from t2;
|
||||
drop table t2;
|
||||
drop table t0;
|
||||
#
|
||||
# UUID datatype support
|
||||
#
|
||||
CREATE TABLE t2 (rowkey bigint PRIMARY KEY, uuidcol char(36)) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf5';
|
||||
delete from t2;
|
||||
insert into t2 values(1,'9b5658dc-f32f-11e1-94cd-f46d046e9f09');
|
||||
insert into t2 values(2,'not-an-uuid');
|
||||
ERROR 22003: Out of range value for column 'uuidcol' at row 1
|
||||
insert into t2 values(3,'9b5658dc-f32f-11e1=94cd-f46d046e9f09');
|
||||
ERROR 22003: Out of range value for column 'uuidcol' at row 1
|
||||
insert into t2 values(4,'9b5658dc-fzzf-11e1-94cd-f46d046e9f09');
|
||||
ERROR 22003: Out of range value for column 'uuidcol' at row 1
|
||||
insert into t2 values
|
||||
(5,'9b5658dc-f11f-11e1-94cd-f46d046e9f09'),
|
||||
(6,'9b5658dc-f11f011e1-94cd-f46d046e9f09');
|
||||
ERROR 22003: Out of range value for column 'uuidcol' at row 2
|
||||
select * from t2;
|
||||
rowkey uuidcol
|
||||
1 9b5658dc-f32f-11e1-94cd-f46d046e9f09
|
||||
5 9b5658dc-f11f-11e1-94cd-f46d046e9f09
|
||||
delete from t2;
|
||||
drop table t2;
|
||||
CREATE TABLE t2 (rowkey char(36) PRIMARY KEY, col1 int) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf6';
|
||||
delete from t2;
|
||||
insert into t2 values('9b5658dc-f32f-11e1-94cd-f46d046e9f09', 1234);
|
||||
insert into t2 values('not-an-uuid', 563);
|
||||
ERROR 22003: Out of range value for column 'rowkey' at row 1
|
||||
select * from t2;
|
||||
rowkey col1
|
||||
9b5658dc-f32f-11e1-94cd-f46d046e9f09 1234
|
||||
delete from t2;
|
||||
drop table t2;
|
||||
#
|
||||
# boolean datatype support
|
||||
#
|
||||
CREATE TABLE t2 (rowkey int PRIMARY KEY, boolcol bool) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf7';
|
||||
insert into t2 values (0, 0);
|
||||
insert into t2 values (1, 1);
|
||||
select * from t2;
|
||||
rowkey boolcol
|
||||
0 0
|
||||
1 1
|
||||
delete from t2;
|
||||
drop table t2;
|
||||
#
|
||||
# Counter datatype support (read-only)
|
||||
#
|
||||
CREATE TABLE t2 (rowkey varchar(32) PRIMARY KEY, countercol bigint) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf8';
|
||||
select * from t2;
|
||||
rowkey countercol
|
||||
cnt1 1
|
||||
cnt2 100
|
||||
drop table t2;
|
||||
#
|
||||
# Check that @@cassandra_default_thrift_host works
|
||||
#
|
||||
show variables like 'cassandra_default_thrift_host';
|
||||
Variable_name Value
|
||||
cassandra_default_thrift_host
|
||||
set @tmp=@@cassandra_default_thrift_host;
|
||||
set cassandra_default_thrift_host='localhost';
|
||||
ERROR HY000: Variable 'cassandra_default_thrift_host' is a GLOBAL variable and should be set with SET GLOBAL
|
||||
set global cassandra_default_thrift_host='localhost';
|
||||
# Try creating a table without specifying thrift_host:
|
||||
CREATE TABLE t2 (rowkey varchar(32) PRIMARY KEY, countercol bigint) ENGINE=CASSANDRA
|
||||
keyspace='mariadbtest2' column_family = 'cf8';
|
||||
select * from t2;
|
||||
rowkey countercol
|
||||
cnt1 1
|
||||
cnt2 100
|
||||
drop table t2;
|
||||
set global cassandra_default_thrift_host=@tmp;
|
||||
#
|
||||
# Consistency settings
|
||||
#
|
||||
show variables like 'cassandra_%consistency';
|
||||
Variable_name Value
|
||||
cassandra_read_consistency ONE
|
||||
cassandra_write_consistency ONE
|
||||
set @tmp=@@cassandra_write_consistency;
|
||||
# Unfortunately, there is no easy way to check if setting have the effect..
|
||||
set cassandra_write_consistency='ONE';
|
||||
set cassandra_write_consistency='QUORUM';
|
||||
set cassandra_write_consistency='LOCAL_QUORUM';
|
||||
set cassandra_write_consistency='EACH_QUORUM';
|
||||
set cassandra_write_consistency='ALL';
|
||||
set cassandra_write_consistency='ANY';
|
||||
set cassandra_write_consistency='TWO';
|
||||
set cassandra_write_consistency='THREE';
|
||||
set cassandra_write_consistency=@tmp;
|
||||
#
|
||||
# varint datatype support
|
||||
#
|
||||
CREATE TABLE t2 (rowkey varchar(32) PRIMARY KEY, varint_col varbinary(32)) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf9';
|
||||
select rowkey, hex(varint_col) from t2;
|
||||
rowkey hex(varint_col)
|
||||
val-01 01
|
||||
val-0x123456 123456
|
||||
val-0x12345678 12345678
|
||||
drop table t2;
|
||||
# now, let's check what happens when MariaDB's column is not wide enough:
|
||||
CREATE TABLE t2 (rowkey varchar(32) PRIMARY KEY, varint_col varbinary(2)) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf9';
|
||||
select rowkey, hex(varint_col) from t2;
|
||||
ERROR HY000: Internal error: Unable to convert value for field `varint_col` from Cassandra's data format. Source data is 4 bytes, 0x12345678
|
||||
drop table t2;
|
||||
#
|
||||
# Decimal datatype support
|
||||
#
|
||||
CREATE TABLE t2 (rowkey varchar(32) PRIMARY KEY, decimal_col varbinary(32)) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf11';
|
||||
select rowkey, hex(decimal_col) from t2;
|
||||
rowkey hex(decimal_col)
|
||||
val_1.5 000000010F
|
||||
val_0.5 0000000105
|
||||
val_1234 0000000004D2
|
||||
drop table t2;
|
||||
#
|
||||
# Mapping TIMESTAMP -> int64
|
||||
#
|
||||
set @save_tz= @@time_zone;
|
||||
set time_zone='UTC';
|
||||
CREATE TABLE t2 (rowkey bigint PRIMARY KEY, datecol timestamp) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf4';
|
||||
insert into t2 values (1, '2012-08-29 01:23:45');
|
||||
INSERT INTO t2 VALUES (10,'2012-08-29 01:23:46');
|
||||
drop table t2;
|
||||
CREATE TABLE t2 (rowkey bigint PRIMARY KEY, datecol bigint) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf4';
|
||||
select * from t2;
|
||||
rowkey datecol
|
||||
1 1346203425000
|
||||
10 1346203426000
|
||||
delete from t2;
|
||||
drop table t2;
|
||||
set time_zone=@save_tz;
|
||||
#
|
||||
# Check whether changing parameters with ALTER TABLE works.
|
||||
#
|
||||
CREATE TABLE t2 (rowkey varchar(32) PRIMARY KEY, decimal_col varbinary(32)) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf11';
|
||||
drop table t2;
|
||||
CREATE TABLE t2 (rowkey varchar(32) PRIMARY KEY, decimal_col varbinary(32)) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf11';
|
||||
alter table t2 column_family='cf12';
|
||||
Writes made during ALTER TABLE
|
||||
0
|
||||
drop table t2;
|
||||
#
|
||||
# UPDATE command support
|
||||
#
|
||||
create table t1 (pk varchar(36) primary key, data1 varchar(60), data2 bigint) engine=cassandra
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family='cf1';
|
||||
insert into t1 values ('rowkey10', 'data1-value', 123456);
|
||||
insert into t1 values ('rowkey11', 'data1-value2', 34543);
|
||||
insert into t1 values ('rowkey12', 'data1-value3', 454);
|
||||
select * from t1;
|
||||
pk data1 data2
|
||||
rowkey12 data1-value3 454
|
||||
rowkey10 data1-value 123456
|
||||
rowkey11 data1-value2 34543
|
||||
update t1 set data1='updated-1' where pk='rowkey11';
|
||||
select * from t1;
|
||||
pk data1 data2
|
||||
rowkey12 data1-value3 454
|
||||
rowkey10 data1-value 123456
|
||||
rowkey11 updated-1 34543
|
||||
update t1 set pk='new-rowkey12' where pk='rowkey12';
|
||||
select * from t1;
|
||||
pk data1 data2
|
||||
rowkey10 data1-value 123456
|
||||
new-rowkey12 data1-value3 454
|
||||
rowkey11 updated-1 34543
|
||||
delete from t1;
|
||||
drop table t1;
|
||||
#
|
||||
# Dynamic columns support
|
||||
#
|
||||
CREATE TABLE t2 (rowkey bigint PRIMARY KEY, uuidcol blob DYNAMIC_COLUMN_STORAGE=1) ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf5';
|
||||
drop table t2;
|
||||
#error: dynamic column is not a blob
|
||||
CREATE TABLE t2 (rowkey bigint PRIMARY KEY, uuidcol char(36) DYNAMIC_COLUMN_STORAGE=1) ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf5';
|
||||
ERROR 42000: Incorrect column specifier for column 'uuidcol'
|
||||
#error: double dynamic column
|
||||
CREATE TABLE t2 (rowkey bigint PRIMARY KEY, uuidcol blob DYNAMIC_COLUMN_STORAGE=1, textcol blob DYNAMIC_COLUMN_STORAGE=1) ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf5';
|
||||
ERROR 42000: Incorrect column specifier for column 'textcol'
|
||||
#
|
||||
# Dynamic column read
|
||||
#
|
||||
CREATE TABLE t2 (rowkey bigint PRIMARY KEY, uuidcol char(36)) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf5';
|
||||
delete from t2;
|
||||
insert into t2 values(1,'9b5658dc-f32f-11e1-94cd-f46d046e9f09');
|
||||
insert into t2 values(2,'9b5658dc-f32f-11e1-94cd-f46d046e9f0a');
|
||||
drop table t2;
|
||||
CREATE TABLE t2 (rowkey bigint PRIMARY KEY, dyn blob DYNAMIC_COLUMN_STORAGE=yes) ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf5';
|
||||
select rowkey, column_list(dyn), column_get(dyn, 'uuidcol' as char) from t2;
|
||||
rowkey column_list(dyn) column_get(dyn, 'uuidcol' as char)
|
||||
1 `uuidcol` 9b5658dc-f32f-11e1-94cd-f46d046e9f09
|
||||
2 `uuidcol` 9b5658dc-f32f-11e1-94cd-f46d046e9f0a
|
||||
drop table t2;
|
||||
CREATE TABLE t2 (rowkey bigint PRIMARY KEY, uuidcol char(36)) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf5';
|
||||
delete from t2;
|
||||
drop table t2;
|
||||
#
|
||||
# Dynamic column insert
|
||||
#
|
||||
CREATE TABLE t2 (rowkey bigint PRIMARY KEY, dyn blob DYNAMIC_COLUMN_STORAGE=yes) ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf5';
|
||||
insert into t2 values (1, column_create("dyn1", 1, "dyn2", "two"));
|
||||
select rowkey, column_json(dyn) from t2;
|
||||
rowkey column_json(dyn)
|
||||
1 {"dyn1":"1","dyn2":"two"}
|
||||
delete from t2;
|
||||
drop table t2;
|
||||
# bigint
|
||||
CREATE TABLE t1 (rowkey bigint PRIMARY KEY, dyn blob DYNAMIC_COLUMN_STORAGE=yes) ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf2';
|
||||
insert into t1 values (1, column_create("dyn1", 1, "dyn2", "two", 'a', 254324));
|
||||
insert into t1 values (2, column_create("dyn1", 1, "dyn2", "two", 'a', 2543));
|
||||
select rowkey, column_json(dyn) from t1;
|
||||
rowkey column_json(dyn)
|
||||
1 {"a":254324,"dyn1":"1","dyn2":"two"}
|
||||
2 {"a":2543,"dyn1":"1","dyn2":"two"}
|
||||
delete from t1;
|
||||
drop table t1;
|
||||
# int
|
||||
CREATE TABLE t1 (rowkey bigint PRIMARY KEY, dyn blob DYNAMIC_COLUMN_STORAGE=yes) ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf3';
|
||||
insert into t1 values (1, column_create("dyn1", 1, "dyn2", "two", 'intcol', 254324));
|
||||
insert into t1 values (2, column_create("dyn1", 1, "dyn2", "two", 'intcol', 2543));
|
||||
select rowkey, column_json(dyn) from t1;
|
||||
rowkey column_json(dyn)
|
||||
1 {"dyn1":"1","dyn2":"two","intcol":254324}
|
||||
2 {"dyn1":"1","dyn2":"two","intcol":2543}
|
||||
delete from t1;
|
||||
drop table t1;
|
||||
# timestamp
|
||||
CREATE TABLE t1 (rowkey bigint PRIMARY KEY, dyn blob DYNAMIC_COLUMN_STORAGE=yes) ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf4';
|
||||
insert into t1 values (1, column_create("dyn1", 1, "dyn2", "two", 'datecol', 254324));
|
||||
insert into t1 values (2, column_create("dyn1", 1, "dyn2", "two", 'datecol', 2543));
|
||||
select rowkey, column_json(dyn) from t1;
|
||||
rowkey column_json(dyn)
|
||||
1 {"dyn1":"1","dyn2":"two","datecol":254324}
|
||||
2 {"dyn1":"1","dyn2":"two","datecol":2543}
|
||||
delete from t1;
|
||||
drop table t1;
|
||||
# boolean
|
||||
CREATE TABLE t1 (rowkey int PRIMARY KEY, dyn blob DYNAMIC_COLUMN_STORAGE=yes) ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf7';
|
||||
insert into t1 values (1, column_create("dyn1", 1, "dyn2", "two", 'boolcol', 254324));
|
||||
insert into t1 values (2, column_create("dyn1", 1, "dyn2", "two", 'boolcol', 0));
|
||||
select rowkey, column_json(dyn) from t1;
|
||||
rowkey column_json(dyn)
|
||||
1 {"dyn1":"1","dyn2":"two","boolcol":1}
|
||||
2 {"dyn1":"1","dyn2":"two","boolcol":0}
|
||||
select rowkey, column_json(dyn) from t1;
|
||||
rowkey column_json(dyn)
|
||||
1 {"dyn1":"1","dyn2":"two","boolcol":1}
|
||||
2 {"dyn1":"1","dyn2":"two","boolcol":0}
|
||||
update t1 set dyn=column_add(dyn, "dyn2", null, "dyn3", "3");
|
||||
select rowkey, column_json(dyn) from t1;
|
||||
rowkey column_json(dyn)
|
||||
1 {"dyn1":"1","dyn3":"3","boolcol":1}
|
||||
2 {"dyn1":"1","dyn3":"3","boolcol":0}
|
||||
update t1 set dyn=column_add(dyn, "dyn1", null) where rowkey= 1;
|
||||
select rowkey, column_json(dyn) from t1;
|
||||
rowkey column_json(dyn)
|
||||
1 {"dyn3":"3","boolcol":1}
|
||||
2 {"dyn1":"1","dyn3":"3","boolcol":0}
|
||||
update t1 set dyn=column_add(dyn, "dyn3", null, "a", "ddd");
|
||||
select rowkey, column_json(dyn) from t1;
|
||||
rowkey column_json(dyn)
|
||||
1 {"a":"ddd","boolcol":1}
|
||||
2 {"a":"ddd","dyn1":"1","boolcol":0}
|
||||
update t1 set dyn=column_add(dyn, "12345678901234", "ddd");
|
||||
select rowkey, column_json(dyn) from t1;
|
||||
rowkey column_json(dyn)
|
||||
1 {"a":"ddd","boolcol":1,"12345678901234":"ddd"}
|
||||
2 {"a":"ddd","dyn1":"1","boolcol":0,"12345678901234":"ddd"}
|
||||
update t1 set dyn=column_add(dyn, "12345678901234", null);
|
||||
select rowkey, column_json(dyn) from t1;
|
||||
rowkey column_json(dyn)
|
||||
1 {"a":"ddd","boolcol":1}
|
||||
2 {"a":"ddd","dyn1":"1","boolcol":0}
|
||||
update t1 set dyn=column_add(dyn, 'boolcol', null) where rowkey= 2;
|
||||
select rowkey, column_json(dyn) from t1;
|
||||
rowkey column_json(dyn)
|
||||
1 {"a":"ddd","boolcol":1}
|
||||
2 {"a":"ddd","dyn1":"1"}
|
||||
update t1 set rowkey= 3, dyn=column_add(dyn, "dyn1", null, 'boolcol', 0) where rowkey= 2;
|
||||
select rowkey, column_json(dyn) from t1;
|
||||
rowkey column_json(dyn)
|
||||
1 {"a":"ddd","boolcol":1}
|
||||
3 {"a":"ddd","boolcol":0}
|
||||
delete from t1;
|
||||
drop table t1;
|
||||
CREATE TABLE t1 (rowkey varchar(10) PRIMARY KEY, dyn blob DYNAMIC_COLUMN_STORAGE=yes) ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cfd1';
|
||||
select * from t1;
|
||||
ERROR HY000: Internal error: Unable to convert value for field `dyn` from Cassandra's data format. Name length exceed limit of 16383: 'very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_v
|
||||
drop table t1;
|
||||
CREATE TABLE t1 (rowkey int PRIMARY KEY, dyn blob DYNAMIC_COLUMN_STORAGE=yes)
|
||||
ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cfd2';
|
||||
DELETE FROM t1;
|
||||
insert into t1 values (1, column_create("dyn", 1));
|
||||
select rowkey, column_list(dyn) from t1;
|
||||
rowkey column_list(dyn)
|
||||
1 `dyn`
|
||||
delete from t1;
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 (rowkey int PRIMARY KEY, dyn blob DYNAMIC_COLUMN_STORAGE=yes)
|
||||
ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cfd2';
|
||||
insert into t1 values (1,'9b5658dc-f32f-11e1-94cd-f46d046e9f0a');
|
||||
ERROR HY000: Encountered illegal format of dynamic column string
|
||||
delete from t1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# MDEV-565: Server crashes in ha_cassandra::write_row on
|
||||
# inserting NULL into a dynamic column
|
||||
#
|
||||
CREATE TABLE t1 (rowkey int PRIMARY KEY, dyn blob DYNAMIC_COLUMN_STORAGE=yes)
|
||||
ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cfd2';
|
||||
insert into t1 values (1, NULL);
|
||||
delete from t1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# strange side effect of Cassandra - remiving all columns of primary
|
||||
# key removes all row.
|
||||
#
|
||||
CREATE TABLE t1 (rowkey int PRIMARY KEY, dyn blob DYNAMIC_COLUMN_STORAGE=yes)
|
||||
ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cfd2';
|
||||
INSERT INTO t1 VALUES(2,column_create("ab","ab"));
|
||||
select rowkey, column_json(dyn) from t1;
|
||||
rowkey column_json(dyn)
|
||||
2 {"ab":"ab"}
|
||||
UPDATE t1 set dyn=NULL;
|
||||
select rowkey, column_json(dyn) from t1;
|
||||
rowkey column_json(dyn)
|
||||
INSERT INTO t1 VALUES(2,column_create("ab","ab"));
|
||||
select rowkey, column_json(dyn) from t1;
|
||||
rowkey column_json(dyn)
|
||||
2 {"ab":"ab"}
|
||||
UPDATE t1 set dyn="";
|
||||
select rowkey, column_json(dyn) from t1;
|
||||
rowkey column_json(dyn)
|
||||
delete from t1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# MDEV-4005 #Server crashes on creating a Cassandra table
|
||||
# with a mix of static and dynamic columns
|
||||
#
|
||||
DROP TABLE IF EXISTS t1, t2;
|
||||
CREATE TABLE t1 (
|
||||
pk int primary key,
|
||||
col_int int,
|
||||
dyncol blob DYNAMIC_COLUMN_STORAGE=yes
|
||||
) ENGINE=cassandra keyspace='bug' thrift_host = '127.0.0.1' column_family='cf1';
|
||||
drop table t1;
|
||||
#
|
||||
# MDEV-4000: Mapping between Cassandra blob (BytesType) and MySQL BLOB does not work
|
||||
#
|
||||
create table t1 (rowkey int primary key, b blob ) ENGINE=CASSANDRA thrift_host = '127.0.0.1' `keyspace`='mariadbtest2' `column_family`='cf13';
|
||||
insert into t1 values (1, 'fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo-bar');
|
||||
insert into t1 values (2, 'qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq-baz');
|
||||
select * from t1;
|
||||
rowkey b
|
||||
1 fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo-bar
|
||||
2 qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq-baz
|
||||
drop table t1;
|
||||
#
|
||||
# MDEV-4001: Cassandra: server crashes in ha_cassandra::end_bulk_insert on INSERT .. SELECT with a non-existing column
|
||||
#
|
||||
create table t1 (rowkey int primary key, a int) ENGINE=cassandra thrift_host='127.0.0.1' keyspace='mariadbtest2' column_family='cf14';
|
||||
insert into t1 (a) select b from t1;
|
||||
ERROR 42S22: Unknown column 'b' in 'field list'
|
||||
drop table t1;
|
|
@ -1,16 +0,0 @@
|
|||
drop table if exists t1, t2;
|
||||
create table t1 (rowkey int primary key, a int) engine=cassandra
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family='cf1';
|
||||
create table t2 like t1;
|
||||
set global query_cache_size=1024*1024;
|
||||
select * from t1;
|
||||
rowkey a
|
||||
insert into t2 values (1,1);
|
||||
select * from t1;
|
||||
rowkey a
|
||||
1 1
|
||||
select sql_no_cache * from t1;
|
||||
rowkey a
|
||||
1 1
|
||||
drop table t1,t2;
|
||||
set global QUERY_CACHE_SIZE=0;
|
|
@ -1,14 +0,0 @@
|
|||
install soname 'ha_cassandra';
|
||||
select plugin_name,plugin_status,plugin_library from information_schema.plugins where plugin_name = 'cassandra';
|
||||
plugin_name plugin_status plugin_library
|
||||
CASSANDRA ACTIVE ha_cassandra.so
|
||||
uninstall plugin cassandra;
|
||||
select plugin_name,plugin_status,plugin_library from information_schema.plugins where plugin_name = 'cassandra';
|
||||
plugin_name plugin_status plugin_library
|
||||
install soname 'ha_cassandra';
|
||||
select plugin_name,plugin_status,plugin_library from information_schema.plugins where plugin_name = 'cassandra';
|
||||
plugin_name plugin_status plugin_library
|
||||
CASSANDRA ACTIVE ha_cassandra.so
|
||||
uninstall plugin cassandra;
|
||||
select plugin_name,plugin_status,plugin_library from information_schema.plugins where plugin_name = 'cassandra';
|
||||
plugin_name plugin_status plugin_library
|
|
@ -11,21 +11,12 @@ if (-d '../sql' && !&::using_extern()) {
|
|||
eval { symlink $src, $dst } or ::copy $src, $dst;
|
||||
}
|
||||
|
||||
sub cassandra_running() {
|
||||
return 0 if IS_WINDOWS;
|
||||
system 'echo show version | cqlsh -3 2>/dev/null >/dev/null';
|
||||
return $? == 0;
|
||||
}
|
||||
|
||||
sub skip_combinations {
|
||||
my %skip;
|
||||
$skip{'t/pam_init.inc'} = 'No pam setup for mtr'
|
||||
unless -e '/etc/pam.d/mariadb_mtr';
|
||||
$skip{'t/pam_init.inc'} = 'Not run as user owning auth_pam_tool_dir'
|
||||
unless -o $::plugindir . '/auth_pam_tool_dir';
|
||||
$skip{'t/cassandra.test'} = 'Cassandra is not running'
|
||||
unless cassandra_running();
|
||||
$skip{'t/cassandra_qcache.test'} = $skip{'t/cassandra.test'};
|
||||
%skip;
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
--plugin-load-add=$HA_CASSANDRA_SO --loose-cassandra=on
|
File diff suppressed because one or more lines are too long
|
@ -1 +0,0 @@
|
|||
--plugin-load-add=$HA_CASSANDRA_SO --loose-cassandra=on
|
|
@ -1,59 +0,0 @@
|
|||
#
|
||||
# Tests for cassandra storage engine
|
||||
#
|
||||
-- source include/have_query_cache.inc
|
||||
|
||||
if (`SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.ENGINES WHERE engine = 'cassandra' AND support IN ('YES', 'DEFAULT', 'ENABLED')`)
|
||||
{
|
||||
--skip Test requires Cassandra.
|
||||
}
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1, t2;
|
||||
--enable_warnings
|
||||
|
||||
############################################################################
|
||||
## Cassandra initialization
|
||||
############################################################################
|
||||
|
||||
# Step 1: remove the keyspace that could be left over from the previous test
|
||||
--remove_files_wildcard $MYSQLTEST_VARDIR cassandra_test_cleanup.cql
|
||||
--write_file $MYSQLTEST_VARDIR/cassandra_test_cleanup.cql
|
||||
drop keyspace mariadbtest2;
|
||||
EOF
|
||||
--error 0,1,2
|
||||
--system cqlsh -3 -f $MYSQLTEST_VARDIR/cassandra_test_cleanup.cql
|
||||
|
||||
# Step 2: create new keyspace and test column families
|
||||
--remove_files_wildcard $MYSQLTEST_VARDIR cassandra_test_init.cql
|
||||
--write_file $MYSQLTEST_VARDIR/cassandra_test_init.cql
|
||||
|
||||
CREATE KEYSPACE mariadbtest2
|
||||
WITH strategy_class = 'org.apache.cassandra.locator.SimpleStrategy'
|
||||
AND strategy_options:replication_factor='1';
|
||||
|
||||
USE mariadbtest2;
|
||||
create columnfamily cf1 ( rowkey int primary key, a int );
|
||||
EOF
|
||||
|
||||
--error 0,1,2
|
||||
--system cqlsh -3 -f $MYSQLTEST_VARDIR/cassandra_test_init.cql
|
||||
|
||||
############################################################################
|
||||
## The test itsef:
|
||||
############################################################################
|
||||
|
||||
create table t1 (rowkey int primary key, a int) engine=cassandra
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family='cf1';
|
||||
create table t2 like t1;
|
||||
|
||||
set global query_cache_size=1024*1024;
|
||||
|
||||
select * from t1;
|
||||
insert into t2 values (1,1);
|
||||
|
||||
select * from t1;
|
||||
select sql_no_cache * from t1;
|
||||
|
||||
drop table t1,t2;
|
||||
set global QUERY_CACHE_SIZE=0;
|
|
@ -1,16 +0,0 @@
|
|||
#
|
||||
# MDEV-4403 Attempting to use cassandra storage engine causes "service 'my_snprintf_service' interface version mismatch"
|
||||
#
|
||||
if (!$HA_CASSANDRA_SO) {
|
||||
skip No Cassandra engine;
|
||||
}
|
||||
|
||||
install soname 'ha_cassandra';
|
||||
select plugin_name,plugin_status,plugin_library from information_schema.plugins where plugin_name = 'cassandra';
|
||||
uninstall plugin cassandra;
|
||||
select plugin_name,plugin_status,plugin_library from information_schema.plugins where plugin_name = 'cassandra';
|
||||
install soname 'ha_cassandra';
|
||||
select plugin_name,plugin_status,plugin_library from information_schema.plugins where plugin_name = 'cassandra';
|
||||
uninstall plugin cassandra;
|
||||
select plugin_name,plugin_status,plugin_library from information_schema.plugins where plugin_name = 'cassandra';
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
# use the first path that has Thrift.h included, if found
|
||||
|
||||
FIND_PATH(Thrift_INCLUDE_DIRS Thrift.h PATHS
|
||||
$ENV{THRIFT_INCLUDE} # environment variable to be used optionally
|
||||
${Thrift_INCLUDE_DIR} # this may be set
|
||||
/usr/local/include/thrift # list of additional directories to look from
|
||||
/opt/local/include/thrift
|
||||
/usr/include/thrift
|
||||
/opt/include/thrift
|
||||
)
|
||||
|
||||
# Verify that thrift linking library is found
|
||||
SET(Thrift_LIB_PATHS ${Thrift_LIB_PATHS} /usr/local/lib /opt/local/lib /opt/lib)
|
||||
FIND_LIBRARY(Thrift_LIBS NAMES thrift PATHS ${Thrift_LIB_PATHS} ${Thrift_LIB})
|
||||
|
||||
MARK_AS_ADVANCED(Thrift_LIBS Thrift_INCLUDE_DIRS)
|
||||
|
||||
IF(EXISTS ${Thrift_LIBS})
|
||||
GET_FILENAME_COMPONENT(LINK_DIR ${Thrift_LIBS} PATH ABSOLUTE)
|
||||
INCLUDE_DIRECTORIES(AFTER ${Thrift_INCLUDE_DIRS}/..)
|
||||
SET(CMAKE_REQUIRED_INCLUDES ${Thrift_INCLUDE_DIRS})
|
||||
|
||||
STRING(REPLACE "-fno-exceptions" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
|
||||
SET(CMAKE_REQUIRED_INCLUDES "${Thrift_INCLUDE_DIRS}/..")
|
||||
CHECK_CXX_SOURCE_COMPILES(
|
||||
"
|
||||
#include <thrift/Thrift.h>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
int main() {
|
||||
boost::shared_ptr<char> p(new char(10));
|
||||
return 0;
|
||||
}
|
||||
" CASSANDRASE_OK)
|
||||
ENDIF()
|
||||
|
||||
SET(cassandra_sources
|
||||
ha_cassandra.cc
|
||||
ha_cassandra.h
|
||||
cassandra_se.h
|
||||
cassandra_se.cc
|
||||
gen-cpp/Cassandra.cpp
|
||||
gen-cpp/cassandra_types.h
|
||||
gen-cpp/cassandra_types.cpp
|
||||
gen-cpp/cassandra_constants.h
|
||||
gen-cpp/cassandra_constants.cpp
|
||||
gen-cpp/Cassandra.h)
|
||||
|
||||
LINK_DIRECTORIES(${LINK_DIR})
|
||||
|
||||
IF(CASSANDRASE_OK)
|
||||
MYSQL_ADD_PLUGIN(cassandra ${cassandra_sources} STORAGE_ENGINE
|
||||
MODULE_ONLY LINK_LIBRARIES thrift COMPONENT cassandra-engine DISABLED)
|
||||
ENDIF(CASSANDRASE_OK)
|
|
@ -1,863 +0,0 @@
|
|||
|
||||
// Cassandra includes:
|
||||
#include <inttypes.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "thrift/Thrift.h"
|
||||
#include "thrift/transport/TSocket.h"
|
||||
#include "thrift/transport/TTransport.h"
|
||||
#include "thrift/transport/TBufferTransports.h"
|
||||
#include "thrift/protocol/TProtocol.h"
|
||||
#include "thrift/protocol/TBinaryProtocol.h"
|
||||
#include "gen-cpp/Cassandra.h"
|
||||
// cassandra includes end
|
||||
|
||||
#include "cassandra_se.h"
|
||||
|
||||
struct st_mysql_lex_string
|
||||
{
|
||||
char *str;
|
||||
size_t length;
|
||||
};
|
||||
|
||||
using namespace std;
|
||||
using namespace apache::thrift;
|
||||
using namespace apache::thrift::transport;
|
||||
using namespace apache::thrift::protocol;
|
||||
using namespace org::apache::cassandra;
|
||||
|
||||
|
||||
/*
|
||||
Implementation of connection to one Cassandra column family (ie., table)
|
||||
*/
|
||||
class Cassandra_se_impl: public Cassandra_se_interface
|
||||
{
|
||||
CassandraClient *cass; /* Connection to cassandra */
|
||||
|
||||
std::string column_family;
|
||||
std::string keyspace;
|
||||
|
||||
ConsistencyLevel::type write_consistency;
|
||||
ConsistencyLevel::type read_consistency;
|
||||
|
||||
/* Connection data */
|
||||
std::string host;
|
||||
int port;
|
||||
/* How many times to retry an operation before giving up */
|
||||
int thrift_call_retries_to_do;
|
||||
|
||||
bool inside_try_operation;
|
||||
|
||||
/* DDL data */
|
||||
KsDef ks_def; /* KeySpace we're using (TODO: put this in table->share) */
|
||||
CfDef cf_def; /* Column family we're using (TODO: put in table->share)*/
|
||||
std::vector<ColumnDef>::iterator column_ddl_it;
|
||||
|
||||
/* The list that was returned by the last key lookup */
|
||||
std::vector<ColumnOrSuperColumn> column_data_vec;
|
||||
std::vector<ColumnOrSuperColumn>::iterator column_data_it;
|
||||
|
||||
/* Insert preparation */
|
||||
typedef std::map<std::string, std::vector<Mutation> > ColumnFamilyToMutation;
|
||||
typedef std::map<std::string, ColumnFamilyToMutation> KeyToCfMutationMap;
|
||||
|
||||
KeyToCfMutationMap batch_mutation; /* Prepare operation here */
|
||||
int64_t insert_timestamp;
|
||||
std::vector<Mutation>* insert_list;
|
||||
|
||||
/* Resultset we're reading */
|
||||
std::vector<KeySlice> key_slice_vec;
|
||||
std::vector<KeySlice>::iterator key_slice_it;
|
||||
|
||||
std::string rowkey; /* key of the record we're returning now */
|
||||
|
||||
SlicePredicate slice_pred;
|
||||
SliceRange slice_pred_sr;
|
||||
bool get_slices_returned_less;
|
||||
bool get_slice_found_rows;
|
||||
|
||||
bool reconnect();
|
||||
public:
|
||||
Cassandra_se_impl() : cass(NULL),
|
||||
write_consistency(ConsistencyLevel::ONE),
|
||||
read_consistency(ConsistencyLevel::ONE),
|
||||
thrift_call_retries_to_do(1),
|
||||
inside_try_operation(false)
|
||||
{}
|
||||
virtual ~Cassandra_se_impl(){ delete cass; }
|
||||
|
||||
/* Connection and DDL checks */
|
||||
bool connect(const char *host_arg, int port_arg, const char *keyspace);
|
||||
void set_column_family(const char *cfname) { column_family.assign(cfname); }
|
||||
|
||||
bool setup_ddl_checks();
|
||||
void first_ddl_column();
|
||||
bool next_ddl_column(char **name, int *name_len, char **value, int *value_len);
|
||||
void get_rowkey_type(char **name, char **type);
|
||||
size_t get_ddl_size();
|
||||
const char* get_default_validator();
|
||||
|
||||
/* Settings */
|
||||
void set_consistency_levels(unsigned long read_cons_level, unsigned long write_cons_level);
|
||||
virtual void set_n_retries(uint retries_arg) {
|
||||
thrift_call_retries_to_do= retries_arg;
|
||||
}
|
||||
|
||||
/* Writes */
|
||||
void clear_insert_buffer();
|
||||
void start_row_insert(const char *key, int key_len);
|
||||
void add_insert_column(const char *name, int name_len,
|
||||
const char *value, int value_len);
|
||||
void add_insert_delete_column(const char *name, int name_len);
|
||||
void add_row_deletion(const char *key, int key_len,
|
||||
Column_name_enumerator *col_names,
|
||||
LEX_STRING *names, uint nnames);
|
||||
|
||||
bool do_insert();
|
||||
|
||||
/* Reads, point lookups */
|
||||
bool get_slice(char *key, size_t key_len, bool *found);
|
||||
bool get_next_read_column(char **name, int *name_len,
|
||||
char **value, int *value_len );
|
||||
void get_read_rowkey(char **value, int *value_len);
|
||||
|
||||
/* Reads, multi-row scans */
|
||||
private:
|
||||
bool have_rowkey_to_skip;
|
||||
std::string rowkey_to_skip;
|
||||
|
||||
bool get_range_slices_param_last_key_as_start_key;
|
||||
public:
|
||||
bool get_range_slices(bool last_key_as_start_key);
|
||||
void finish_reading_range_slices();
|
||||
bool get_next_range_slice_row(bool *eof);
|
||||
|
||||
/* Setup that's necessary before a multi-row read. (todo: use it before point lookups, too) */
|
||||
void clear_read_columns();
|
||||
void clear_read_all_columns();
|
||||
void add_read_column(const char *name);
|
||||
|
||||
/* Reads, MRR scans */
|
||||
void new_lookup_keys();
|
||||
int add_lookup_key(const char *key, size_t key_len);
|
||||
bool multiget_slice();
|
||||
|
||||
bool get_next_multiget_row();
|
||||
|
||||
bool truncate();
|
||||
|
||||
bool remove_row();
|
||||
|
||||
private:
|
||||
bool retryable_truncate();
|
||||
bool retryable_do_insert();
|
||||
bool retryable_remove_row();
|
||||
bool retryable_setup_ddl_checks();
|
||||
bool retryable_multiget_slice();
|
||||
bool retryable_get_range_slices();
|
||||
bool retryable_get_slice();
|
||||
|
||||
std::vector<std::string> mrr_keys; /* can we use allocator to put these into MRR buffer? */
|
||||
std::map<std::string, std::vector<ColumnOrSuperColumn> > mrr_result;
|
||||
std::map<std::string, std::vector<ColumnOrSuperColumn> >::iterator mrr_result_it;
|
||||
|
||||
/* Non-inherited utility functions: */
|
||||
int64_t get_i64_timestamp();
|
||||
|
||||
typedef bool (Cassandra_se_impl::*retryable_func_t)();
|
||||
bool try_operation(retryable_func_t func);
|
||||
};
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Connection and setup
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
Cassandra_se_interface *create_cassandra_se()
|
||||
{
|
||||
return new Cassandra_se_impl;
|
||||
}
|
||||
|
||||
|
||||
bool Cassandra_se_impl::connect(const char *host_arg, int port_arg, const char *keyspace_arg)
|
||||
{
|
||||
keyspace.assign(keyspace_arg);
|
||||
host.assign(host_arg);
|
||||
port= port_arg;
|
||||
return reconnect();
|
||||
}
|
||||
|
||||
|
||||
bool Cassandra_se_impl::reconnect()
|
||||
{
|
||||
|
||||
delete cass;
|
||||
cass= NULL;
|
||||
|
||||
bool res= true;
|
||||
try {
|
||||
boost::shared_ptr<TTransport> socket =
|
||||
boost::shared_ptr<TSocket>(new TSocket(host.c_str(), port));
|
||||
boost::shared_ptr<TTransport> tr =
|
||||
boost::shared_ptr<TFramedTransport>(new TFramedTransport (socket));
|
||||
boost::shared_ptr<TProtocol> p =
|
||||
boost::shared_ptr<TBinaryProtocol>(new TBinaryProtocol(tr));
|
||||
|
||||
cass= new CassandraClient(p);
|
||||
tr->open();
|
||||
cass->set_keyspace(keyspace.c_str());
|
||||
|
||||
res= false; // success
|
||||
}catch(TTransportException te){
|
||||
print_error("%s [%d]", te.what(), te.getType());
|
||||
}catch(InvalidRequestException ire){
|
||||
print_error("%s [%s]", ire.what(), ire.why.c_str());
|
||||
}catch(NotFoundException nfe){
|
||||
print_error("%s", nfe.what());
|
||||
}catch(TException e){
|
||||
print_error("Thrift exception: %s", e.what());
|
||||
}catch (...) {
|
||||
print_error("Unknown exception");
|
||||
}
|
||||
|
||||
if (!res && setup_ddl_checks())
|
||||
res= true;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void Cassandra_se_impl::set_consistency_levels(unsigned long read_cons_level,
|
||||
unsigned long write_cons_level)
|
||||
{
|
||||
write_consistency= (ConsistencyLevel::type)(write_cons_level + 1);
|
||||
read_consistency= (ConsistencyLevel::type)(read_cons_level + 1);
|
||||
}
|
||||
|
||||
|
||||
bool Cassandra_se_impl::retryable_setup_ddl_checks()
|
||||
{
|
||||
try {
|
||||
|
||||
cass->describe_keyspace(ks_def, keyspace);
|
||||
|
||||
} catch (NotFoundException nfe) {
|
||||
print_error("keyspace `%s` not found: %s", keyspace.c_str(), nfe.what());
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<CfDef>::iterator it;
|
||||
for (it= ks_def.cf_defs.begin(); it < ks_def.cf_defs.end(); it++)
|
||||
{
|
||||
cf_def= *it;
|
||||
if (!cf_def.name.compare(column_family))
|
||||
return false;
|
||||
}
|
||||
|
||||
print_error("Column family %s not found in keyspace %s",
|
||||
column_family.c_str(),
|
||||
keyspace.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Cassandra_se_impl::setup_ddl_checks()
|
||||
{
|
||||
return try_operation(&Cassandra_se_impl::retryable_setup_ddl_checks);
|
||||
}
|
||||
|
||||
|
||||
void Cassandra_se_impl::first_ddl_column()
|
||||
{
|
||||
column_ddl_it= cf_def.column_metadata.begin();
|
||||
}
|
||||
|
||||
|
||||
bool Cassandra_se_impl::next_ddl_column(char **name, int *name_len,
|
||||
char **type, int *type_len)
|
||||
{
|
||||
if (column_ddl_it == cf_def.column_metadata.end())
|
||||
return true;
|
||||
|
||||
*name= (char*)(*column_ddl_it).name.c_str();
|
||||
*name_len= (*column_ddl_it).name.length();
|
||||
|
||||
*type= (char*)(*column_ddl_it).validation_class.c_str();
|
||||
*type_len= (*column_ddl_it).validation_class.length();
|
||||
|
||||
column_ddl_it++;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void Cassandra_se_impl::get_rowkey_type(char **name, char **type)
|
||||
{
|
||||
if (cf_def.__isset.key_validation_class)
|
||||
*type= (char*)cf_def.key_validation_class.c_str();
|
||||
else
|
||||
*type= NULL;
|
||||
|
||||
if (cf_def.__isset.key_alias)
|
||||
*name= (char*)cf_def.key_alias.c_str();
|
||||
else
|
||||
*name= NULL;
|
||||
}
|
||||
|
||||
size_t Cassandra_se_impl::get_ddl_size()
|
||||
{
|
||||
return cf_def.column_metadata.size();
|
||||
}
|
||||
|
||||
const char* Cassandra_se_impl::get_default_validator()
|
||||
{
|
||||
return cf_def.default_validation_class.c_str();
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Data writes
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
int64_t Cassandra_se_impl::get_i64_timestamp()
|
||||
{
|
||||
struct timeval td;
|
||||
gettimeofday(&td, NULL);
|
||||
int64_t ms = td.tv_sec;
|
||||
ms = ms * 1000;
|
||||
int64_t usec = td.tv_usec;
|
||||
usec = usec / 1000;
|
||||
ms += usec;
|
||||
|
||||
return ms;
|
||||
}
|
||||
|
||||
|
||||
void Cassandra_se_impl::clear_insert_buffer()
|
||||
{
|
||||
batch_mutation.clear();
|
||||
}
|
||||
|
||||
|
||||
void Cassandra_se_impl::start_row_insert(const char *key, int key_len)
|
||||
{
|
||||
std::string key_to_insert;
|
||||
key_to_insert.assign(key, key_len);
|
||||
batch_mutation[key_to_insert]= ColumnFamilyToMutation();
|
||||
ColumnFamilyToMutation& cf_mut= batch_mutation[key_to_insert];
|
||||
|
||||
cf_mut[column_family]= std::vector<Mutation>();
|
||||
insert_list= &cf_mut[column_family];
|
||||
|
||||
insert_timestamp= get_i64_timestamp();
|
||||
}
|
||||
|
||||
|
||||
void Cassandra_se_impl::add_row_deletion(const char *key, int key_len,
|
||||
Column_name_enumerator *col_names,
|
||||
LEX_STRING *names, uint nnames)
|
||||
{
|
||||
std::string key_to_delete;
|
||||
key_to_delete.assign(key, key_len);
|
||||
|
||||
batch_mutation[key_to_delete]= ColumnFamilyToMutation();
|
||||
ColumnFamilyToMutation& cf_mut= batch_mutation[key_to_delete];
|
||||
|
||||
cf_mut[column_family]= std::vector<Mutation>();
|
||||
std::vector<Mutation> &mutation_list= cf_mut[column_family];
|
||||
|
||||
Mutation mut;
|
||||
mut.__isset.deletion= true;
|
||||
mut.deletion.__isset.timestamp= true;
|
||||
mut.deletion.timestamp= get_i64_timestamp();
|
||||
mut.deletion.__isset.predicate= true;
|
||||
|
||||
/*
|
||||
Attempting to delete columns with SliceRange causes exception with message
|
||||
"Deletion does not yet support SliceRange predicates".
|
||||
|
||||
Delete all columns individually.
|
||||
*/
|
||||
SlicePredicate slice_pred;
|
||||
slice_pred.__isset.column_names= true;
|
||||
const char *col_name;
|
||||
while ((col_name= col_names->get_next_name()))
|
||||
slice_pred.column_names.push_back(std::string(col_name));
|
||||
for (uint i= 0; i < nnames; i++)
|
||||
slice_pred.column_names.push_back(std::string(names[i].str,
|
||||
names[i].length));
|
||||
|
||||
mut.deletion.predicate= slice_pred;
|
||||
|
||||
mutation_list.push_back(mut);
|
||||
}
|
||||
|
||||
|
||||
void Cassandra_se_impl::add_insert_column(const char *name,
|
||||
int name_len,
|
||||
const char *value,
|
||||
int value_len)
|
||||
{
|
||||
Mutation mut;
|
||||
mut.__isset.column_or_supercolumn= true;
|
||||
mut.column_or_supercolumn.__isset.column= true;
|
||||
|
||||
Column& col=mut.column_or_supercolumn.column;
|
||||
if (name_len)
|
||||
col.name.assign(name, name_len);
|
||||
else
|
||||
col.name.assign(name);
|
||||
col.value.assign(value, value_len);
|
||||
col.timestamp= insert_timestamp;
|
||||
col.__isset.value= true;
|
||||
col.__isset.timestamp= true;
|
||||
insert_list->push_back(mut);
|
||||
}
|
||||
|
||||
void Cassandra_se_impl::add_insert_delete_column(const char *name,
|
||||
int name_len)
|
||||
{
|
||||
Mutation mut;
|
||||
mut.__isset.deletion= true;
|
||||
mut.deletion.__isset.timestamp= true;
|
||||
mut.deletion.timestamp= insert_timestamp;
|
||||
mut.deletion.__isset.predicate= true;
|
||||
|
||||
SlicePredicate slice_pred;
|
||||
slice_pred.__isset.column_names= true;
|
||||
slice_pred.column_names.push_back(std::string(name, name_len));
|
||||
mut.deletion.predicate= slice_pred;
|
||||
|
||||
insert_list->push_back(mut);
|
||||
}
|
||||
|
||||
|
||||
bool Cassandra_se_impl::retryable_do_insert()
|
||||
{
|
||||
cass->batch_mutate(batch_mutation, write_consistency);
|
||||
|
||||
cassandra_counters.row_inserts+= batch_mutation.size();
|
||||
cassandra_counters.row_insert_batches++;
|
||||
|
||||
clear_insert_buffer();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool Cassandra_se_impl::do_insert()
|
||||
{
|
||||
/*
|
||||
zero-size mutations are allowed by Cassandra's batch_mutate but lets not
|
||||
do them (we may attempt to do it if there is a bulk insert that stores
|
||||
exactly @@cassandra_insert_batch_size*n elements.
|
||||
*/
|
||||
if (batch_mutation.empty())
|
||||
return false;
|
||||
|
||||
return try_operation(&Cassandra_se_impl::retryable_do_insert);
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Reading data
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
Make one key lookup. If the record is found, the result is stored locally and
|
||||
the caller should iterate over it.
|
||||
*/
|
||||
|
||||
bool Cassandra_se_impl::get_slice(char *key, size_t key_len, bool *found)
|
||||
{
|
||||
bool res;
|
||||
rowkey.assign(key, key_len);
|
||||
|
||||
if (!(res= try_operation(&Cassandra_se_impl::retryable_get_slice)))
|
||||
*found= get_slice_found_rows;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
bool Cassandra_se_impl::retryable_get_slice()
|
||||
{
|
||||
ColumnParent cparent;
|
||||
cparent.column_family= column_family;
|
||||
|
||||
SlicePredicate slice_pred;
|
||||
SliceRange sr;
|
||||
sr.start = "";
|
||||
sr.finish = "";
|
||||
slice_pred.__set_slice_range(sr);
|
||||
|
||||
cass->get_slice(column_data_vec, rowkey, cparent, slice_pred,
|
||||
read_consistency);
|
||||
|
||||
if (column_data_vec.size() == 0)
|
||||
{
|
||||
/*
|
||||
No columns found. Cassandra doesn't allow records without any column =>
|
||||
this means the seach key doesn't exist
|
||||
*/
|
||||
get_slice_found_rows= false;
|
||||
return false;
|
||||
}
|
||||
get_slice_found_rows= true;
|
||||
|
||||
column_data_it= column_data_vec.begin();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Cassandra_se_impl::get_next_read_column(char **name, int *name_len,
|
||||
char **value, int *value_len)
|
||||
{
|
||||
bool use_counter=false;
|
||||
while (1)
|
||||
{
|
||||
if (column_data_it == column_data_vec.end())
|
||||
return true;
|
||||
|
||||
if ((*column_data_it).__isset.column)
|
||||
break; /* Ok it's a real column. Should be always the case. */
|
||||
|
||||
if ((*column_data_it).__isset.counter_column)
|
||||
{
|
||||
use_counter= true;
|
||||
break;
|
||||
}
|
||||
|
||||
column_data_it++;
|
||||
}
|
||||
|
||||
ColumnOrSuperColumn& cs= *column_data_it;
|
||||
if (use_counter)
|
||||
{
|
||||
*name_len= cs.counter_column.name.size();
|
||||
*name= (char*)cs.counter_column.name.c_str();
|
||||
*value= (char*)&cs.counter_column.value;
|
||||
*value_len= sizeof(cs.counter_column.value);
|
||||
}
|
||||
else
|
||||
{
|
||||
*name_len= cs.column.name.size();
|
||||
*name= (char*)cs.column.name.c_str();
|
||||
*value= (char*)cs.column.value.c_str();
|
||||
*value_len= cs.column.value.length();
|
||||
}
|
||||
|
||||
column_data_it++;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* Return the rowkey for the record that was read */
|
||||
|
||||
void Cassandra_se_impl::get_read_rowkey(char **value, int *value_len)
|
||||
{
|
||||
*value= (char*)rowkey.c_str();
|
||||
*value_len= rowkey.length();
|
||||
}
|
||||
|
||||
|
||||
bool Cassandra_se_impl::get_range_slices(bool last_key_as_start_key)
|
||||
{
|
||||
get_range_slices_param_last_key_as_start_key= last_key_as_start_key;
|
||||
|
||||
return try_operation(&Cassandra_se_impl::retryable_get_range_slices);
|
||||
}
|
||||
|
||||
|
||||
bool Cassandra_se_impl::retryable_get_range_slices()
|
||||
{
|
||||
bool last_key_as_start_key= get_range_slices_param_last_key_as_start_key;
|
||||
|
||||
ColumnParent cparent;
|
||||
cparent.column_family= column_family;
|
||||
|
||||
/* SlicePredicate can be used to limit columns we will retrieve */
|
||||
|
||||
KeyRange key_range;
|
||||
key_range.__isset.start_key= true;
|
||||
key_range.__isset.end_key= true;
|
||||
|
||||
if (last_key_as_start_key)
|
||||
{
|
||||
key_range.start_key= rowkey;
|
||||
|
||||
have_rowkey_to_skip= true;
|
||||
rowkey_to_skip= rowkey;
|
||||
}
|
||||
else
|
||||
{
|
||||
have_rowkey_to_skip= false;
|
||||
key_range.start_key.assign("", 0);
|
||||
}
|
||||
|
||||
key_range.end_key.assign("", 0);
|
||||
key_range.count= read_batch_size;
|
||||
|
||||
cass->get_range_slices(key_slice_vec, cparent, slice_pred, key_range,
|
||||
read_consistency);
|
||||
|
||||
if (key_slice_vec.size() < (uint)read_batch_size)
|
||||
get_slices_returned_less= true;
|
||||
else
|
||||
get_slices_returned_less= false;
|
||||
|
||||
key_slice_it= key_slice_vec.begin();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* Switch to next row. This may produce an error */
|
||||
bool Cassandra_se_impl::get_next_range_slice_row(bool *eof)
|
||||
{
|
||||
restart:
|
||||
if (key_slice_it == key_slice_vec.end())
|
||||
{
|
||||
if (get_slices_returned_less)
|
||||
{
|
||||
*eof= true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
We have read through all columns in this batch. Try getting the next
|
||||
batch.
|
||||
*/
|
||||
if (get_range_slices(true))
|
||||
return true;
|
||||
|
||||
if (key_slice_vec.empty())
|
||||
{
|
||||
*eof= true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
(1) - skip the last row that we have read in the previous batch.
|
||||
(2) - Rows that were deleted show up as rows without any columns. Skip
|
||||
them, like CQL does.
|
||||
*/
|
||||
if ((have_rowkey_to_skip && !rowkey_to_skip.compare(key_slice_it->key)) || // (1)
|
||||
key_slice_it->columns.size() == 0) // (2)
|
||||
{
|
||||
key_slice_it++;
|
||||
goto restart;
|
||||
}
|
||||
|
||||
*eof= false;
|
||||
column_data_vec= key_slice_it->columns;
|
||||
rowkey= key_slice_it->key;
|
||||
column_data_it= column_data_vec.begin();
|
||||
key_slice_it++;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void Cassandra_se_impl::finish_reading_range_slices()
|
||||
{
|
||||
key_slice_vec.clear();
|
||||
}
|
||||
|
||||
|
||||
void Cassandra_se_impl::clear_read_columns()
|
||||
{
|
||||
slice_pred.column_names.clear();
|
||||
}
|
||||
|
||||
void Cassandra_se_impl::clear_read_all_columns()
|
||||
{
|
||||
slice_pred_sr.start = "";
|
||||
slice_pred_sr.finish = "";
|
||||
slice_pred.__set_slice_range(slice_pred_sr);
|
||||
}
|
||||
|
||||
|
||||
void Cassandra_se_impl::add_read_column(const char *name_arg)
|
||||
{
|
||||
std::string name(name_arg);
|
||||
slice_pred.__isset.column_names= true;
|
||||
slice_pred.column_names.push_back(name);
|
||||
}
|
||||
|
||||
|
||||
bool Cassandra_se_impl::truncate()
|
||||
{
|
||||
return try_operation(&Cassandra_se_impl::retryable_truncate);
|
||||
}
|
||||
|
||||
|
||||
bool Cassandra_se_impl::retryable_truncate()
|
||||
{
|
||||
cass->truncate(column_family);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool Cassandra_se_impl::remove_row()
|
||||
{
|
||||
return try_operation(&Cassandra_se_impl::retryable_remove_row);
|
||||
}
|
||||
|
||||
|
||||
bool Cassandra_se_impl::retryable_remove_row()
|
||||
{
|
||||
ColumnPath column_path;
|
||||
column_path.column_family= column_family;
|
||||
cass->remove(rowkey, column_path, get_i64_timestamp(), write_consistency);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Try calling a function, catching possible Cassandra errors, and re-trying
|
||||
for "transient" errors.
|
||||
*/
|
||||
bool Cassandra_se_impl::try_operation(retryable_func_t func_to_call)
|
||||
{
|
||||
bool res;
|
||||
int n_attempts= thrift_call_retries_to_do;
|
||||
|
||||
bool was_inside_try_operation= inside_try_operation;
|
||||
inside_try_operation= true;
|
||||
|
||||
do
|
||||
{
|
||||
res= true;
|
||||
|
||||
try {
|
||||
|
||||
if ((res= (this->*func_to_call)()))
|
||||
{
|
||||
/*
|
||||
The function call was made successfully (without timeouts, etc),
|
||||
but something inside it returned 'true'.
|
||||
This is supposedly a failure (or "not found" or other negative
|
||||
result). We need to return this to the caller.
|
||||
*/
|
||||
n_attempts= 0;
|
||||
}
|
||||
|
||||
} catch (InvalidRequestException ire) {
|
||||
n_attempts= 0; /* there is no point in retrying this operation */
|
||||
print_error("%s [%s]", ire.what(), ire.why.c_str());
|
||||
} catch (UnavailableException ue) {
|
||||
cassandra_counters.unavailable_exceptions++;
|
||||
if (!--n_attempts)
|
||||
print_error("UnavailableException: %s", ue.what());
|
||||
} catch (TimedOutException te) {
|
||||
/*
|
||||
Note: this is a timeout generated *inside Cassandra cluster*.
|
||||
Connection between us and the cluster is ok, but something went wrong
|
||||
within the cluster.
|
||||
*/
|
||||
cassandra_counters.timeout_exceptions++;
|
||||
if (!--n_attempts)
|
||||
print_error("TimedOutException: %s", te.what());
|
||||
} catch (TTransportException tte) {
|
||||
/* Something went wrong in communication between us and Cassandra */
|
||||
cassandra_counters.network_exceptions++;
|
||||
|
||||
switch (tte.getType())
|
||||
{
|
||||
case TTransportException::NOT_OPEN:
|
||||
case TTransportException::TIMED_OUT:
|
||||
case TTransportException::END_OF_FILE:
|
||||
case TTransportException::INTERRUPTED:
|
||||
{
|
||||
if (!was_inside_try_operation && reconnect())
|
||||
{
|
||||
/* Failed to reconnect, no point to retry the operation */
|
||||
n_attempts= 0;
|
||||
print_error("%s", tte.what());
|
||||
}
|
||||
else
|
||||
{
|
||||
n_attempts--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
/*
|
||||
We assume it doesn't make sense to retry for
|
||||
unknown kinds of TTransportException-s
|
||||
*/
|
||||
n_attempts= 0;
|
||||
print_error("%s", tte.what());
|
||||
}
|
||||
}
|
||||
}catch(TException e){
|
||||
/* todo: we may use retry for certain kinds of Thrift errors */
|
||||
n_attempts= 0;
|
||||
print_error("Thrift exception: %s", e.what());
|
||||
} catch (...) {
|
||||
n_attempts= 0; /* Don't retry */
|
||||
print_error("Unknown exception");
|
||||
}
|
||||
|
||||
} while (res && n_attempts > 0);
|
||||
|
||||
inside_try_operation= was_inside_try_operation;
|
||||
return res;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// MRR reads
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Cassandra_se_impl::new_lookup_keys()
|
||||
{
|
||||
mrr_keys.clear();
|
||||
}
|
||||
|
||||
|
||||
int Cassandra_se_impl::add_lookup_key(const char *key, size_t key_len)
|
||||
{
|
||||
mrr_keys.push_back(std::string(key, key_len));
|
||||
return mrr_keys.size();
|
||||
}
|
||||
|
||||
bool Cassandra_se_impl::multiget_slice()
|
||||
{
|
||||
return try_operation(&Cassandra_se_impl::retryable_multiget_slice);
|
||||
}
|
||||
|
||||
|
||||
bool Cassandra_se_impl::retryable_multiget_slice()
|
||||
{
|
||||
ColumnParent cparent;
|
||||
cparent.column_family= column_family;
|
||||
|
||||
SlicePredicate slice_pred;
|
||||
SliceRange sr;
|
||||
sr.start = "";
|
||||
sr.finish = "";
|
||||
slice_pred.__set_slice_range(sr);
|
||||
|
||||
cassandra_counters.multiget_reads++;
|
||||
cassandra_counters.multiget_keys_scanned += mrr_keys.size();
|
||||
cass->multiget_slice(mrr_result, mrr_keys, cparent, slice_pred,
|
||||
read_consistency);
|
||||
|
||||
cassandra_counters.multiget_rows_read += mrr_result.size();
|
||||
mrr_result_it= mrr_result.begin();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Cassandra_se_impl::get_next_multiget_row()
|
||||
{
|
||||
if (mrr_result_it == mrr_result.end())
|
||||
return true; /* EOF */
|
||||
|
||||
column_data_vec= mrr_result_it->second;
|
||||
rowkey= mrr_result_it->first;
|
||||
|
||||
column_data_it= column_data_vec.begin();
|
||||
mrr_result_it++;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,125 +0,0 @@
|
|||
|
||||
/*
|
||||
This file is a "bridge" interface between cassandra+Thrift and MariaDB.
|
||||
|
||||
It is #included by both sides, so it must itself include neither (including
|
||||
both together causes compile errors due to conflicts).
|
||||
*/
|
||||
|
||||
struct st_mysql_lex_string;
|
||||
typedef struct st_mysql_lex_string LEX_STRING;
|
||||
|
||||
/* We need to define this here so that ha_cassandra.cc also has access to it */
|
||||
typedef enum
|
||||
{
|
||||
ONE = 1-1,
|
||||
QUORUM = 2-1,
|
||||
LOCAL_QUORUM = 3-1,
|
||||
EACH_QUORUM = 4-1,
|
||||
ALL = 5-1,
|
||||
ANY = 6-1,
|
||||
TWO = 7-1,
|
||||
THREE = 8-1,
|
||||
} enum_cassandra_consistency_level;
|
||||
|
||||
|
||||
class Column_name_enumerator
|
||||
{
|
||||
public:
|
||||
virtual const char* get_next_name()=0;
|
||||
virtual ~Column_name_enumerator(){}
|
||||
};
|
||||
|
||||
/*
|
||||
Interface to one cassandra column family, i.e. one 'table'
|
||||
*/
|
||||
class Cassandra_se_interface
|
||||
{
|
||||
public:
|
||||
Cassandra_se_interface() { err_buffer[0]=0; }
|
||||
|
||||
virtual ~Cassandra_se_interface(){};
|
||||
/* Init */
|
||||
virtual bool connect(const char *host, int port, const char *keyspace)=0;
|
||||
virtual void set_column_family(const char *cfname) = 0;
|
||||
|
||||
/* Settings */
|
||||
virtual void set_consistency_levels(unsigned long read_cons_level, unsigned long write_cons_level)=0;
|
||||
virtual void set_n_retries(uint retries_arg)=0;
|
||||
|
||||
/* Check underlying DDL */
|
||||
virtual bool setup_ddl_checks()=0;
|
||||
virtual void first_ddl_column()=0;
|
||||
virtual bool next_ddl_column(char **name, int *name_len, char **value,
|
||||
int *value_len)=0;
|
||||
virtual void get_rowkey_type(char **name, char **type)=0;
|
||||
virtual size_t get_ddl_size()=0;
|
||||
virtual const char* get_default_validator()=0;
|
||||
|
||||
/* Writes */
|
||||
virtual void clear_insert_buffer()=0;
|
||||
virtual void add_row_deletion(const char *key, int key_len,
|
||||
Column_name_enumerator *col_names,
|
||||
LEX_STRING *names, uint nnames)=0;
|
||||
virtual void start_row_insert(const char *key, int key_len)=0;
|
||||
virtual void add_insert_delete_column(const char *name, int name_len)= 0;
|
||||
virtual void add_insert_column(const char *name, int name_len,
|
||||
const char *value,
|
||||
int value_len)=0;
|
||||
virtual bool do_insert()=0;
|
||||
|
||||
/* Reads */
|
||||
virtual bool get_slice(char *key, size_t key_len, bool *found)=0 ;
|
||||
virtual bool get_next_read_column(char **name, int *name_len,
|
||||
char **value, int *value_len)=0;
|
||||
virtual void get_read_rowkey(char **value, int *value_len)=0;
|
||||
|
||||
/* Reads, multi-row scans */
|
||||
int read_batch_size;
|
||||
virtual bool get_range_slices(bool last_key_as_start_key)=0;
|
||||
virtual void finish_reading_range_slices()=0;
|
||||
virtual bool get_next_range_slice_row(bool *eof)=0;
|
||||
|
||||
/* Reads, MRR scans */
|
||||
virtual void new_lookup_keys()=0;
|
||||
virtual int add_lookup_key(const char *key, size_t key_len)=0;
|
||||
virtual bool multiget_slice()=0;
|
||||
virtual bool get_next_multiget_row()=0;
|
||||
|
||||
/* read_set setup */
|
||||
virtual void clear_read_columns()=0;
|
||||
virtual void clear_read_all_columns()=0;
|
||||
virtual void add_read_column(const char *name)=0;
|
||||
|
||||
virtual bool truncate()=0;
|
||||
virtual bool remove_row()=0;
|
||||
|
||||
/* Passing error messages up to ha_cassandra */
|
||||
char err_buffer[512];
|
||||
const char *error_str() { return err_buffer; }
|
||||
void print_error(const char *format, ...);
|
||||
};
|
||||
|
||||
|
||||
/* A structure with global counters */
|
||||
class Cassandra_status_vars
|
||||
{
|
||||
public:
|
||||
unsigned long row_inserts;
|
||||
unsigned long row_insert_batches;
|
||||
|
||||
unsigned long multiget_reads;
|
||||
unsigned long multiget_keys_scanned;
|
||||
unsigned long multiget_rows_read;
|
||||
|
||||
unsigned long timeout_exceptions;
|
||||
unsigned long unavailable_exceptions;
|
||||
unsigned long network_exceptions;
|
||||
};
|
||||
|
||||
|
||||
extern Cassandra_status_vars cassandra_counters;
|
||||
|
||||
|
||||
Cassandra_se_interface *create_cassandra_se();
|
||||
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,219 +0,0 @@
|
|||
// This autogenerated skeleton file illustrates how to build a server.
|
||||
// You should copy it to another filename to avoid overwriting it.
|
||||
|
||||
#include "Cassandra.h"
|
||||
#include <protocol/TBinaryProtocol.h>
|
||||
#include <server/TSimpleServer.h>
|
||||
#include <transport/TServerSocket.h>
|
||||
#include <transport/TBufferTransports.h>
|
||||
|
||||
using namespace ::apache::thrift;
|
||||
using namespace ::apache::thrift::protocol;
|
||||
using namespace ::apache::thrift::transport;
|
||||
using namespace ::apache::thrift::server;
|
||||
|
||||
using boost::shared_ptr;
|
||||
|
||||
using namespace ::org::apache::cassandra;
|
||||
|
||||
class CassandraHandler : virtual public CassandraIf {
|
||||
public:
|
||||
CassandraHandler() {
|
||||
// Your initialization goes here
|
||||
}
|
||||
|
||||
void login(const AuthenticationRequest& auth_request) {
|
||||
// Your implementation goes here
|
||||
printf("login\n");
|
||||
}
|
||||
|
||||
void set_keyspace(const std::string& keyspace) {
|
||||
// Your implementation goes here
|
||||
printf("set_keyspace\n");
|
||||
}
|
||||
|
||||
void get(ColumnOrSuperColumn& _return, const std::string& key, const ColumnPath& column_path, const ConsistencyLevel::type consistency_level) {
|
||||
// Your implementation goes here
|
||||
printf("get\n");
|
||||
}
|
||||
|
||||
void get_slice(std::vector<ColumnOrSuperColumn> & _return, const std::string& key, const ColumnParent& column_parent, const SlicePredicate& predicate, const ConsistencyLevel::type consistency_level) {
|
||||
// Your implementation goes here
|
||||
printf("get_slice\n");
|
||||
}
|
||||
|
||||
int32_t get_count(const std::string& key, const ColumnParent& column_parent, const SlicePredicate& predicate, const ConsistencyLevel::type consistency_level) {
|
||||
// Your implementation goes here
|
||||
printf("get_count\n");
|
||||
}
|
||||
|
||||
void multiget_slice(std::map<std::string, std::vector<ColumnOrSuperColumn> > & _return, const std::vector<std::string> & keys, const ColumnParent& column_parent, const SlicePredicate& predicate, const ConsistencyLevel::type consistency_level) {
|
||||
// Your implementation goes here
|
||||
printf("multiget_slice\n");
|
||||
}
|
||||
|
||||
void multiget_count(std::map<std::string, int32_t> & _return, const std::vector<std::string> & keys, const ColumnParent& column_parent, const SlicePredicate& predicate, const ConsistencyLevel::type consistency_level) {
|
||||
// Your implementation goes here
|
||||
printf("multiget_count\n");
|
||||
}
|
||||
|
||||
void get_range_slices(std::vector<KeySlice> & _return, const ColumnParent& column_parent, const SlicePredicate& predicate, const KeyRange& range, const ConsistencyLevel::type consistency_level) {
|
||||
// Your implementation goes here
|
||||
printf("get_range_slices\n");
|
||||
}
|
||||
|
||||
void get_paged_slice(std::vector<KeySlice> & _return, const std::string& column_family, const KeyRange& range, const std::string& start_column, const ConsistencyLevel::type consistency_level) {
|
||||
// Your implementation goes here
|
||||
printf("get_paged_slice\n");
|
||||
}
|
||||
|
||||
void get_indexed_slices(std::vector<KeySlice> & _return, const ColumnParent& column_parent, const IndexClause& index_clause, const SlicePredicate& column_predicate, const ConsistencyLevel::type consistency_level) {
|
||||
// Your implementation goes here
|
||||
printf("get_indexed_slices\n");
|
||||
}
|
||||
|
||||
void insert(const std::string& key, const ColumnParent& column_parent, const Column& column, const ConsistencyLevel::type consistency_level) {
|
||||
// Your implementation goes here
|
||||
printf("insert\n");
|
||||
}
|
||||
|
||||
void add(const std::string& key, const ColumnParent& column_parent, const CounterColumn& column, const ConsistencyLevel::type consistency_level) {
|
||||
// Your implementation goes here
|
||||
printf("add\n");
|
||||
}
|
||||
|
||||
void remove(const std::string& key, const ColumnPath& column_path, const int64_t timestamp, const ConsistencyLevel::type consistency_level) {
|
||||
// Your implementation goes here
|
||||
printf("remove\n");
|
||||
}
|
||||
|
||||
void remove_counter(const std::string& key, const ColumnPath& path, const ConsistencyLevel::type consistency_level) {
|
||||
// Your implementation goes here
|
||||
printf("remove_counter\n");
|
||||
}
|
||||
|
||||
void batch_mutate(const std::map<std::string, std::map<std::string, std::vector<Mutation> > > & mutation_map, const ConsistencyLevel::type consistency_level) {
|
||||
// Your implementation goes here
|
||||
printf("batch_mutate\n");
|
||||
}
|
||||
|
||||
void truncate(const std::string& cfname) {
|
||||
// Your implementation goes here
|
||||
printf("truncate\n");
|
||||
}
|
||||
|
||||
void describe_schema_versions(std::map<std::string, std::vector<std::string> > & _return) {
|
||||
// Your implementation goes here
|
||||
printf("describe_schema_versions\n");
|
||||
}
|
||||
|
||||
void describe_keyspaces(std::vector<KsDef> & _return) {
|
||||
// Your implementation goes here
|
||||
printf("describe_keyspaces\n");
|
||||
}
|
||||
|
||||
void describe_cluster_name(std::string& _return) {
|
||||
// Your implementation goes here
|
||||
printf("describe_cluster_name\n");
|
||||
}
|
||||
|
||||
void describe_version(std::string& _return) {
|
||||
// Your implementation goes here
|
||||
printf("describe_version\n");
|
||||
}
|
||||
|
||||
void describe_ring(std::vector<TokenRange> & _return, const std::string& keyspace) {
|
||||
// Your implementation goes here
|
||||
printf("describe_ring\n");
|
||||
}
|
||||
|
||||
void describe_token_map(std::map<std::string, std::string> & _return) {
|
||||
// Your implementation goes here
|
||||
printf("describe_token_map\n");
|
||||
}
|
||||
|
||||
void describe_partitioner(std::string& _return) {
|
||||
// Your implementation goes here
|
||||
printf("describe_partitioner\n");
|
||||
}
|
||||
|
||||
void describe_snitch(std::string& _return) {
|
||||
// Your implementation goes here
|
||||
printf("describe_snitch\n");
|
||||
}
|
||||
|
||||
void describe_keyspace(KsDef& _return, const std::string& keyspace) {
|
||||
// Your implementation goes here
|
||||
printf("describe_keyspace\n");
|
||||
}
|
||||
|
||||
void describe_splits(std::vector<std::string> & _return, const std::string& cfName, const std::string& start_token, const std::string& end_token, const int32_t keys_per_split) {
|
||||
// Your implementation goes here
|
||||
printf("describe_splits\n");
|
||||
}
|
||||
|
||||
void system_add_column_family(std::string& _return, const CfDef& cf_def) {
|
||||
// Your implementation goes here
|
||||
printf("system_add_column_family\n");
|
||||
}
|
||||
|
||||
void system_drop_column_family(std::string& _return, const std::string& column_family) {
|
||||
// Your implementation goes here
|
||||
printf("system_drop_column_family\n");
|
||||
}
|
||||
|
||||
void system_add_keyspace(std::string& _return, const KsDef& ks_def) {
|
||||
// Your implementation goes here
|
||||
printf("system_add_keyspace\n");
|
||||
}
|
||||
|
||||
void system_drop_keyspace(std::string& _return, const std::string& keyspace) {
|
||||
// Your implementation goes here
|
||||
printf("system_drop_keyspace\n");
|
||||
}
|
||||
|
||||
void system_update_keyspace(std::string& _return, const KsDef& ks_def) {
|
||||
// Your implementation goes here
|
||||
printf("system_update_keyspace\n");
|
||||
}
|
||||
|
||||
void system_update_column_family(std::string& _return, const CfDef& cf_def) {
|
||||
// Your implementation goes here
|
||||
printf("system_update_column_family\n");
|
||||
}
|
||||
|
||||
void execute_cql_query(CqlResult& _return, const std::string& query, const Compression::type compression) {
|
||||
// Your implementation goes here
|
||||
printf("execute_cql_query\n");
|
||||
}
|
||||
|
||||
void prepare_cql_query(CqlPreparedResult& _return, const std::string& query, const Compression::type compression) {
|
||||
// Your implementation goes here
|
||||
printf("prepare_cql_query\n");
|
||||
}
|
||||
|
||||
void execute_prepared_cql_query(CqlResult& _return, const int32_t itemId, const std::vector<std::string> & values) {
|
||||
// Your implementation goes here
|
||||
printf("execute_prepared_cql_query\n");
|
||||
}
|
||||
|
||||
void set_cql_version(const std::string& version) {
|
||||
// Your implementation goes here
|
||||
printf("set_cql_version\n");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int port = 9090;
|
||||
shared_ptr<CassandraHandler> handler(new CassandraHandler());
|
||||
shared_ptr<TProcessor> processor(new CassandraProcessor(handler));
|
||||
shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
|
||||
shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
|
||||
shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
|
||||
|
||||
TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);
|
||||
server.serve();
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
/**
|
||||
* Autogenerated by Thrift Compiler (0.8.0)
|
||||
*
|
||||
* DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||
* @generated
|
||||
*/
|
||||
#include "cassandra_constants.h"
|
||||
|
||||
namespace org { namespace apache { namespace cassandra {
|
||||
|
||||
const cassandraConstants g_cassandra_constants;
|
||||
|
||||
cassandraConstants::cassandraConstants() {
|
||||
cassandra_const_VERSION = (char *)"19.32.0";
|
||||
}
|
||||
|
||||
}}} // namespace
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
/**
|
||||
* Autogenerated by Thrift Compiler (0.8.0)
|
||||
*
|
||||
* DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||
* @generated
|
||||
*/
|
||||
#ifndef cassandra_CONSTANTS_H
|
||||
#define cassandra_CONSTANTS_H
|
||||
|
||||
#include "cassandra_types.h"
|
||||
|
||||
namespace org { namespace apache { namespace cassandra {
|
||||
|
||||
class cassandraConstants {
|
||||
public:
|
||||
cassandraConstants();
|
||||
|
||||
// std::string VERSION;
|
||||
char* cassandra_const_VERSION;
|
||||
};
|
||||
|
||||
extern const cassandraConstants g_cassandra_constants;
|
||||
|
||||
}}} // namespace
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,293 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2012, 2020, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
|
||||
#ifdef USE_PRAGMA_INTERFACE
|
||||
#pragma interface /* gcc class implementation */
|
||||
#endif
|
||||
|
||||
|
||||
#include "my_global.h" /* ulonglong */
|
||||
#include "thr_lock.h" /* THR_LOCK, THR_LOCK_DATA */
|
||||
#include "handler.h" /* handler */
|
||||
#include "my_base.h" /* ha_rows */
|
||||
|
||||
#include "cassandra_se.h"
|
||||
|
||||
/** @brief
|
||||
CASSANDRA_SHARE is a structure that will be shared among all open handlers.
|
||||
This example implements the minimum of what you will probably need.
|
||||
*/
|
||||
typedef struct st_cassandra_share {
|
||||
char *table_name;
|
||||
uint table_name_length,use_count;
|
||||
mysql_mutex_t mutex;
|
||||
THR_LOCK lock;
|
||||
} CASSANDRA_SHARE;
|
||||
|
||||
class ColumnDataConverter;
|
||||
struct st_dynamic_column_value;
|
||||
typedef struct st_dynamic_column_value DYNAMIC_COLUMN_VALUE;
|
||||
|
||||
struct ha_table_option_struct;
|
||||
|
||||
|
||||
struct st_dynamic_column_value;
|
||||
|
||||
typedef bool (* CAS2DYN_CONVERTER)(const char *cass_data,
|
||||
int cass_data_len,
|
||||
struct st_dynamic_column_value *value,
|
||||
MEM_ROOT *mem_root);
|
||||
typedef bool (* DYN2CAS_CONVERTER)(struct st_dynamic_column_value *value,
|
||||
char **cass_data,
|
||||
int *cass_data_len,
|
||||
void *buf, void **freemem);
|
||||
struct cassandra_type_def
|
||||
{
|
||||
const char *name;
|
||||
CAS2DYN_CONVERTER cassandra_to_dynamic;
|
||||
DYN2CAS_CONVERTER dynamic_to_cassandra;
|
||||
};
|
||||
|
||||
typedef struct cassandra_type_def CASSANDRA_TYPE_DEF;
|
||||
|
||||
enum cassandtra_type_enum {CT_BIGINT, CT_INT, CT_COUNTER, CT_FLOAT, CT_DOUBLE,
|
||||
CT_BLOB, CT_ASCII, CT_TEXT, CT_TIMESTAMP, CT_UUID, CT_BOOLEAN, CT_VARINT,
|
||||
CT_DECIMAL};
|
||||
|
||||
typedef enum cassandtra_type_enum CASSANDRA_TYPE;
|
||||
|
||||
|
||||
|
||||
/** @brief
|
||||
Class definition for the storage engine
|
||||
*/
|
||||
class ha_cassandra: public handler
|
||||
{
|
||||
friend class Column_name_enumerator_impl;
|
||||
THR_LOCK_DATA lock; ///< MySQL lock
|
||||
CASSANDRA_SHARE *share; ///< Shared lock info
|
||||
|
||||
Cassandra_se_interface *se;
|
||||
|
||||
/* description of static part of the table definition */
|
||||
ColumnDataConverter **field_converters;
|
||||
uint n_field_converters;
|
||||
|
||||
CASSANDRA_TYPE_DEF *default_type_def;
|
||||
/* description of dynamic columns part */
|
||||
CASSANDRA_TYPE_DEF *special_type_field_converters;
|
||||
LEX_STRING *special_type_field_names;
|
||||
uint n_special_type_fields;
|
||||
DYNAMIC_ARRAY dynamic_values, dynamic_names;
|
||||
DYNAMIC_STRING dynamic_rec;
|
||||
|
||||
ColumnDataConverter *rowkey_converter;
|
||||
|
||||
bool setup_field_converters(Field **field, uint n_fields);
|
||||
void free_field_converters();
|
||||
|
||||
int read_cassandra_columns(bool unpack_pk);
|
||||
int check_table_options(struct ha_table_option_struct* options);
|
||||
|
||||
bool doing_insert_batch;
|
||||
ha_rows insert_rows_batched;
|
||||
|
||||
uint dyncol_field;
|
||||
bool dyncol_set;
|
||||
|
||||
/* Used to produce 'wrong column %s at row %lu' warnings */
|
||||
ha_rows insert_lineno;
|
||||
void print_conversion_error(const char *field_name,
|
||||
char *cass_value, int cass_value_len);
|
||||
int connect_and_check_options(TABLE *table_arg);
|
||||
public:
|
||||
ha_cassandra(handlerton *hton, TABLE_SHARE *table_arg);
|
||||
~ha_cassandra()
|
||||
{
|
||||
free_field_converters();
|
||||
delete se;
|
||||
}
|
||||
|
||||
/** @brief
|
||||
The name that will be used for display purposes.
|
||||
*/
|
||||
const char *table_type() const { return "CASSANDRA"; }
|
||||
|
||||
/** @brief
|
||||
The name of the index type that will be used for display.
|
||||
Don't implement this method unless you really have indexes.
|
||||
*/
|
||||
const char *index_type(uint) override { return "HASH"; }
|
||||
|
||||
/** @brief
|
||||
This is a list of flags that indicate what functionality the storage engine
|
||||
implements. The current table flags are documented in handler.h
|
||||
*/
|
||||
ulonglong table_flags() const override
|
||||
{
|
||||
return HA_BINLOG_STMT_CAPABLE |
|
||||
HA_REC_NOT_IN_SEQ |
|
||||
HA_NO_TRANSACTIONS |
|
||||
HA_REQUIRE_PRIMARY_KEY |
|
||||
HA_PRIMARY_KEY_IN_READ_INDEX |
|
||||
HA_PRIMARY_KEY_REQUIRED_FOR_POSITION |
|
||||
HA_NO_AUTO_INCREMENT |
|
||||
HA_TABLE_SCAN_ON_INDEX;
|
||||
}
|
||||
|
||||
/** @brief
|
||||
This is a bitmap of flags that indicates how the storage engine
|
||||
implements indexes. The current index flags are documented in
|
||||
handler.h. If you do not implement indexes, just return zero here.
|
||||
|
||||
@details
|
||||
part is the key part to check. First key part is 0.
|
||||
If all_parts is set, MySQL wants to know the flags for the combined
|
||||
index, up to and including 'part'.
|
||||
*/
|
||||
ulong index_flags(uint, uint, bool) const override
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @brief
|
||||
unireg.cc will call max_supported_record_length(), max_supported_keys(),
|
||||
max_supported_key_parts(), uint max_supported_key_length()
|
||||
to make sure that the storage engine can handle the data it is about to
|
||||
send. Return *real* limits of your storage engine here; MySQL will do
|
||||
min(your_limits, MySQL_limits) automatically.
|
||||
*/
|
||||
uint max_supported_record_length() const override {return HA_MAX_REC_LENGTH;}
|
||||
|
||||
/* Support only one Primary Key, for now */
|
||||
uint max_supported_keys() const override { return 1; }
|
||||
uint max_supported_key_parts() const override { return 1; }
|
||||
|
||||
/** @brief
|
||||
unireg.cc will call this to make sure that the storage engine can handle
|
||||
the data it is about to send. Return *real* limits of your storage engine
|
||||
here; MySQL will do min(your_limits, MySQL_limits) automatically.
|
||||
|
||||
@details
|
||||
There is no need to implement ..._key_... methods if your engine doesn't
|
||||
support indexes.
|
||||
*/
|
||||
uint max_supported_key_length() const override
|
||||
{ return 16*1024; /* just to return something*/ }
|
||||
|
||||
int index_init(uint idx, bool sorted) override;
|
||||
|
||||
int index_read_map(uchar * buf, const uchar * key,
|
||||
key_part_map keypart_map,
|
||||
enum ha_rkey_function find_flag) override;
|
||||
|
||||
/** @brief
|
||||
Called in test_quick_select to determine if indexes should be used.
|
||||
*/
|
||||
double scan_time() override
|
||||
{ return (double) (stats.records+stats.deleted) / 20.0+10; }
|
||||
|
||||
/** @brief
|
||||
This method will never be called if you do not implement indexes.
|
||||
*/
|
||||
double read_time(uint, uint, ha_rows rows) override
|
||||
{ return (double) rows / 20.0+1; }
|
||||
|
||||
void start_bulk_insert(ha_rows rows, uint flags) override;
|
||||
int end_bulk_insert() override;
|
||||
|
||||
int reset() override;
|
||||
|
||||
|
||||
int multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param,
|
||||
uint n_ranges, uint mode, HANDLER_BUFFER *buf)
|
||||
override;
|
||||
int multi_range_read_next(range_id_t *range_info) override;
|
||||
ha_rows multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
|
||||
void *seq_init_param,
|
||||
uint n_ranges, uint *bufsz,
|
||||
uint *flags, Cost_estimate *cost)
|
||||
override;
|
||||
ha_rows multi_range_read_info(uint keyno, uint n_ranges, uint keys,
|
||||
uint key_parts, uint *bufsz,
|
||||
uint *flags, Cost_estimate *cost)
|
||||
override;
|
||||
int multi_range_read_explain_info(uint mrr_mode, char *str, size_t size)
|
||||
override;
|
||||
|
||||
private:
|
||||
bool source_exhausted;
|
||||
bool mrr_start_read();
|
||||
int check_field_options(Field **fields);
|
||||
int read_dyncol(uint *count,
|
||||
DYNAMIC_COLUMN_VALUE **vals, LEX_STRING **names,
|
||||
String *valcol);
|
||||
int write_dynamic_row(uint count,
|
||||
DYNAMIC_COLUMN_VALUE *vals,
|
||||
LEX_STRING *names);
|
||||
void static free_dynamic_row(DYNAMIC_COLUMN_VALUE **vals,
|
||||
LEX_STRING **names);
|
||||
CASSANDRA_TYPE_DEF * get_cassandra_field_def(char *cass_name,
|
||||
int cass_name_length);
|
||||
public:
|
||||
int open(const char *name, int mode, uint test_if_locked) override;
|
||||
int close() override;
|
||||
|
||||
int write_row(const uchar *buf) override;
|
||||
int update_row(const uchar *old_data, const uchar *new_data) override;
|
||||
int delete_row(const uchar *buf) override;
|
||||
|
||||
/** @brief
|
||||
Unlike index_init(), rnd_init() can be called two consecutive times
|
||||
without rnd_end() in between (it only makes sense if scan=1). In this
|
||||
case, the second call should prepare for the new table scan (e.g if
|
||||
rnd_init() allocates the cursor, the second call should position the
|
||||
cursor to the start of the table; no need to deallocate and allocate
|
||||
it again. This is a required method.
|
||||
*/
|
||||
int rnd_init(bool scan) override;
|
||||
int rnd_end() override;
|
||||
int rnd_next(uchar *buf) override;
|
||||
int rnd_pos(uchar *buf, uchar *pos) override;
|
||||
void position(const uchar *record) override;
|
||||
int info(uint) override;
|
||||
int delete_all_rows() override;
|
||||
ha_rows records_in_range(uint, const key_range *min_key,
|
||||
const key_range *max_key,
|
||||
page_range *res) override
|
||||
{ return HA_POS_ERROR; /* Range scans are not supported */ }
|
||||
|
||||
int create(const char *name, TABLE *form,
|
||||
HA_CREATE_INFO *create_info) override;
|
||||
bool check_if_incompatible_data(HA_CREATE_INFO *info,
|
||||
uint table_changes) override;
|
||||
|
||||
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
|
||||
enum thr_lock_type lock_type) override;
|
||||
|
||||
my_bool register_query_cache_table(THD *thd, const char *table_key,
|
||||
uint key_length,
|
||||
qc_engine_callback
|
||||
*engine_callback,
|
||||
ulonglong *engine_data) override
|
||||
{
|
||||
/*
|
||||
Do not put data from Cassandra tables into query cache (because there
|
||||
is no way to tell whether the data in cassandra cluster has changed or
|
||||
not)
|
||||
*/
|
||||
return FALSE;
|
||||
}
|
||||
};
|
|
@ -31,7 +31,6 @@ build_script:
|
|||
-DCMAKE_BUILD_TYPE=Debug
|
||||
-DPLUGIN_ARCHIVE=NO
|
||||
-DPLUGIN_BLACKHOLE=NO
|
||||
-DPLUGIN_CASSANDRA=NO
|
||||
-DPLUGIN_CONNECT=NO
|
||||
-DPLUGIN_CSV=NO
|
||||
-DPLUGIN_EXAMPLE=NO
|
||||
|
|
|
@ -24,7 +24,6 @@ if [ "${MROONGA_BUNDLED}" = "yes" ]; then
|
|||
cmake_args=("${cmake_args[@]}" -DWITH_EMBEDDED_SERVER=TRUE)
|
||||
cmake_args=("${cmake_args[@]}" -DWITHOUT_ARCHIVE=TRUE)
|
||||
cmake_args=("${cmake_args[@]}" -DWITHOUT_BLACKHOLE=TRUE)
|
||||
cmake_args=("${cmake_args[@]}" -DWITHOUT_CASSANDRA=TRUE)
|
||||
cmake_args=("${cmake_args[@]}" -DWITHOUT_CONNECT=TRUE)
|
||||
cmake_args=("${cmake_args[@]}" -DWITHOUT_CSV=TRUE)
|
||||
cmake_args=("${cmake_args[@]}" -DWITHOUT_EXAMPLE=TRUE)
|
||||
|
|
|
@ -173,13 +173,6 @@ set(LIBS ${ROCKSDB_LIBS} ${THIRDPARTY_LIBS} ${SYSTEM_LIBS})
|
|||
# Unit tests themselves:
|
||||
# - *_test.cc
|
||||
# - *_bench.cc
|
||||
#
|
||||
# - table/mock_table.cc
|
||||
# - utilities/cassandra/cassandra_compaction_filter.cc
|
||||
# - utilities/cassandra/format.cc
|
||||
# - utilities/cassandra/merge_operator.cc
|
||||
# - utilities/cassandra/test_utils.cc
|
||||
#
|
||||
set(ROCKSDB_SOURCES
|
||||
cache/clock_cache.cc
|
||||
cache/lru_cache.cc
|
||||
|
|
Loading…
Add table
Reference in a new issue