package com.alibaba.doris.dataserver.store.mysql; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Iterator; import java.util.List; import javax.sql.DataSource; import com.alibaba.doris.common.data.CompareStatus; import com.alibaba.doris.common.data.Key; import com.alibaba.doris.common.data.Pair; import com.alibaba.doris.common.data.Value; import com.alibaba.doris.dataserver.store.BaseStorage; import com.alibaba.doris.dataserver.store.StorageType; import com.alibaba.doris.dataserver.store.mysql.util.MysqlUtils; import com.alibaba.doris.dataserver.store.serialize.KeyValueSerializerFactory; /** * @author ajun Email:jack.yuj@alibaba-inc.com */ public class MysqlDatabase extends BaseStorage { public MysqlDatabase(String databaseName, DataSource datasource) { this.datasource = datasource; this.databaseName = databaseName; } public void close() { } public void destroy() { // execute("drop table if exists " + getDatabaseName()); } private void createTable() { // execute("create table " + getDatabaseName() + " (key_ varbinary(200) not null, " // + " value_ blob, primary key(key_)) engine = InnoDB"); } private void createTable(Key key) { execute("create table " + getDatabaseName(key) + " (key_ varbinary(200) not null, " + " value_ blob, primary key(key_)) engine = InnoDB"); } private void execute(String query) { Connection conn = null; PreparedStatement stmt = null; try { conn = datasource.getConnection(); stmt = conn.prepareStatement(query); stmt.executeUpdate(); } catch (SQLException e) { throw new MysqlStorageException("SQLException while performing operation.", e); } finally { MysqlUtils.close(stmt); MysqlUtils.close(conn); } } // private String getDatabaseName() { // return databaseName; // } private String getDatabaseName(Key key) { return databaseName + "_" + key.getVNode(); } private boolean checkTableExists() { // Connection conn = null; // PreparedStatement stmt = null; // ResultSet rs = null; // String select = "show tables like '" + getDatabaseName() + "'"; // try { // conn = this.datasource.getConnection(); // stmt = conn.prepareStatement(select); // rs = stmt.executeQuery(); // return rs.next(); // } catch (SQLException e) { // throw new MysqlStorageException("SQLException while checking for table existence!", e); // } finally { // MysqlUtils.close(rs); // MysqlUtils.close(stmt); // MysqlUtils.close(conn); // } return true; } public void open() { if (!checkTableExists()) { createTable(); } } public boolean delete(Key key) { String delete = "delete from " + getDatabaseName(key) + " where key_ = ?"; Connection conn = null; PreparedStatement deleteStmt = null; try { conn = datasource.getConnection(); deleteStmt = conn.prepareStatement(delete); deleteStmt.setBytes(1, serializerFactory.encode(key).copyBytes()); return deleteStmt.executeUpdate() > 0; } catch (SQLException e) { throw new MysqlStorageException("Sql exception on delete!" + key.getKey(), e); } finally { MysqlUtils.close(deleteStmt); MysqlUtils.close(conn); } } public boolean delete(Key key, Value value) { // TODO Auto-generated method stub return false; } public boolean delete(List<Integer> vnodeList) { return false; } public Value get(Key key) { Connection conn = null; PreparedStatement stmt = null; ResultSet rs = null; String select = "select value_ from " + getDatabaseName(key) + " where key_ = ?"; try { conn = datasource.getConnection(); stmt = conn.prepareStatement(select); stmt.setBytes(1, serializerFactory.encode(key).copyBytes()); rs = stmt.executeQuery(); while (rs.next()) { byte[] valueBytes = rs.getBytes("value_"); return serializerFactory.decodeValue(valueBytes); } } catch (SQLException e) { throw new MysqlStorageException("Sql exception!", e); } finally { MysqlUtils.close(rs); MysqlUtils.close(stmt); MysqlUtils.close(conn); } return null; } public void set(Key key, Value value) { boolean doCommit = false; Connection conn = null; PreparedStatement insert = null; PreparedStatement select = null; ResultSet results = null; String insertSql = "insert into " + getDatabaseName(key) + " (key_, value_) values (?, ?) ON DUPLICATE KEY UPDATE value_= ? "; try { conn = datasource.getConnection(); conn.setAutoCommit(false); byte[] keyBytes = serializerFactory.encode(key).copyBytes(); byte[] valueBytes = serializerFactory.encode(value).copyBytes(); insert = conn.prepareStatement(insertSql); insert.setBytes(1, keyBytes); insert.setBytes(2, valueBytes); insert.setBytes(3, valueBytes); insert.executeUpdate(); doCommit = true; } catch (SQLException e) { throw new MysqlStorageException("Fix me!" + key, e); } finally { if (conn != null) { if (doCommit) { MysqlUtils.commit(conn); } else { MysqlUtils.rollback(conn); } } MysqlUtils.close(results); MysqlUtils.close(insert); MysqlUtils.close(select); MysqlUtils.close(conn); } } public void set(Key key, Value value, boolean isSetWithCompareVersion) { boolean doCommit = false; Connection conn = null; PreparedStatement insert = null; PreparedStatement select = null; ResultSet results = null; String insertSql = "insert into " + getDatabaseName(key) + " (key_, value_) values (?, ?)"; String selectSql = "select value_ from " + getDatabaseName(key) + " where key_ = ?"; try { conn = datasource.getConnection(); conn.setAutoCommit(false); byte[] keyBytes = serializerFactory.encode(key).copyBytes(); byte[] valueBytes = serializerFactory.encode(value).copyBytes(); // check for superior versions select = conn.prepareStatement(selectSql); select.setBytes(1, keyBytes); results = select.executeQuery(); Value oldValue = null; while (results.next()) { serializerFactory.decodeValue(results.getBytes("value_")); if (!CompareStatus.AFTER.equals(value.compareVersion(oldValue))) { return; } else { delete(key); } } // Okay, cool, now put the value insert = conn.prepareStatement(insertSql); insert.setBytes(1, keyBytes); insert.setBytes(2, valueBytes); insert.executeUpdate(); doCommit = true; } catch (SQLException e) { if (e.getErrorCode() == MYSQL_ERR_DUP_KEY || e.getErrorCode() == MYSQL_ERR_DUP_ENTRY) { throw new MysqlStorageException("Key or value already used."); } else { throw new MysqlStorageException("Fix me!", e); } } finally { if (conn != null) { if (doCommit) { MysqlUtils.commit(conn); } else { MysqlUtils.rollback(conn); } } MysqlUtils.close(results); MysqlUtils.close(insert); MysqlUtils.close(select); MysqlUtils.close(conn); } } public StorageType getType() { return MysqlStorageType.MYSQL; } public Iterator<Pair> iterator() { return null; } public Iterator<Pair> iterator(List<Integer> vnodeList) { return null; } private DataSource datasource; private MysqlStorageConfigure config; private String databaseName; private static int MYSQL_ERR_DUP_KEY = 1022; private static int MYSQL_ERR_DUP_ENTRY = 1062; private static final KeyValueSerializerFactory serializerFactory = KeyValueSerializerFactory.getInstance(); }