package com.taobao.tddl.repo.bdb.spi; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import com.sleepycat.je.CursorConfig; import com.sleepycat.je.Database; import com.sleepycat.je.DatabaseEntry; import com.sleepycat.je.LockMode; import com.sleepycat.je.LockTimeoutException; import com.sleepycat.je.OperationStatus; import com.sleepycat.je.rep.ReplicaWriteException; import com.taobao.tddl.common.exception.TddlException; import com.taobao.tddl.common.utils.ExceptionErrorCodeUtils; import com.taobao.tddl.executor.codec.CodecFactory; import com.taobao.tddl.executor.codec.RecordCodec; import com.taobao.tddl.executor.common.ExecutionContext; import com.taobao.tddl.executor.common.TransactionConfig.Isolation; import com.taobao.tddl.executor.cursor.ISchematicCursor; import com.taobao.tddl.executor.cursor.SchematicCursor; import com.taobao.tddl.executor.record.CloneableRecord; import com.taobao.tddl.executor.spi.AbstractTable; import com.taobao.tddl.executor.spi.IRepository; import com.taobao.tddl.executor.spi.ITransaction; import com.taobao.tddl.executor.utils.ExecUtils; import com.taobao.tddl.optimizer.config.table.IndexMeta; import com.taobao.tddl.optimizer.config.table.TableMeta; import com.taobao.tddl.optimizer.core.plan.query.IQuery; /** * @author jianxing <jianxing.qx@taobao.com> */ public class JE_Table extends AbstractTable { boolean isTempTable = false; Map<String, Database> databases = new HashMap(); public Map<String, Database> getDatabases() { return databases; } public void setDatabases(Map<String, Database> databases) { this.databases = databases; } Map<String/** index **/ , KVCodec> indexCodecMap; DatabaseEntry emptyValueEntry = new DatabaseEntry(); { emptyValueEntry.setData(new byte[1]); } public JE_Table(TableMeta schema, IRepository repo){ super(schema, repo); indexCodecMap = new HashMap<String, KVCodec>(); KVCodec pkCodec = null; IndexMeta pkIndex = getSchema().getPrimaryIndex(); if (pkCodec == null) { pkCodec = new KVCodec(); pkCodec.setKey_codec(CodecFactory.getInstance(CodecFactory.FIXED_LENGTH) .getCodec((pkIndex.getKeyColumns()))); if (pkIndex.getValueColumns() != null) { pkCodec.setValue_codec(CodecFactory.getInstance(CodecFactory.FIXED_LENGTH) .getCodec((pkIndex.getValueColumns()))); } } indexCodecMap.put(pkIndex.getName(), pkCodec); for (IndexMeta secondIndex : getSchema().getSecondaryIndexes()) { KVCodec secCodec = new KVCodec(); secCodec.setKey_codec(CodecFactory.getInstance(CodecFactory.FIXED_LENGTH) .getCodec((secondIndex.getKeyColumns()))); if (secondIndex.getValueColumns() != null) { secCodec.setValue_codec(CodecFactory.getInstance(CodecFactory.FIXED_LENGTH) .getCodec((secondIndex.getValueColumns()))); } indexCodecMap.put(secondIndex.getName(), secCodec); } } public Database getDatabase(String name) { Database db = databases.get(name); if (db == null) { synchronized (this) { db = databases.get(name); if (db == null) { db = ((JE_Repository) this.repo).getDatabase(name, schema.isTmp(), schema.issortedDuplicates()); databases.put(name, db); } } } return db; } public ISchematicCursor getCursor(ITransaction txn, IndexMeta indexMeta, String isolation, String actualTableName) throws TddlException { Database db = getDatabase(actualTableName); if (db == null) { throw new TddlException("table don't contains indexName:" + actualTableName); } CursorConfig cc = CursorConfig.DEFAULT; LockMode lm = LockMode.DEFAULT; if (txn != null) { com.sleepycat.je.TransactionConfig _config = ((JE_Transaction) txn).config; if (_config.getReadUncommitted()) { cc = CursorConfig.READ_UNCOMMITTED; lm = LockMode.READ_UNCOMMITTED; } else if (_config.getReadCommitted()) { cc = CursorConfig.READ_COMMITTED; // lm = LockMode.READ_COMMITTED; } } else { if (Isolation.READ_COMMITTED.equals(isolation)) { cc = CursorConfig.READ_COMMITTED; // lm = LockMode.READ_COMMITTED;//not support } else if (Isolation.READ_UNCOMMITTED.equals(isolation)) { cc = CursorConfig.READ_UNCOMMITTED; lm = LockMode.READ_UNCOMMITTED; } else if (Isolation.REPEATABLE_READ.equals(isolation)) { // default } else if (Isolation.SERIALIZABLE.equals(isolation)) { // txn_config } } JE_Cursor je_cursor = new JE_Cursor(indexMeta, db.openCursor(txn == null ? null : ((JE_Transaction) txn).txn, cc), lm); if (txn != null) { ((JE_Transaction) txn).addCursor(je_cursor); } return new SchematicCursor(je_cursor, je_cursor.getiCursorMeta(), ExecUtils.getOrderBy(indexMeta)); } /** * todo:触发更新二级索引 * * @param key * @param value * @throws TddlException */ @Override public void put(ExecutionContext context, CloneableRecord key, CloneableRecord value, IndexMeta indexMeta, String dbName) throws TddlException { DatabaseEntry keyEntry = new DatabaseEntry(); DatabaseEntry valueEntry = new DatabaseEntry(); keyEntry.setData(indexCodecMap.get(indexMeta.getName()).getKey_codec().encode(key)); // 当临时表排序时候可能会用到临时表join,主键插入值为null // if (keyEntry.getData().length == 1 && !isTempTable) { // throw new RuntimeException("pk must not null."); // } if (value != null) { valueEntry.setData(indexCodecMap.get(indexMeta.getName()).getValue_codec().encode(value)); } else { valueEntry = emptyValueEntry; } try { ITransaction transaction = context.getTransaction(); com.sleepycat.je.Transaction txn = null; if (transaction != null && transaction instanceof JE_Transaction) { txn = ((JE_Transaction) transaction).txn; } OperationStatus operationStatus = getDatabase(dbName).put(txn, keyEntry, valueEntry); if (operationStatus.equals(OperationStatus.SUCCESS)) { return; } } catch (LockTimeoutException ex) { throw ex; } catch (ReplicaWriteException ex) { throw new TddlException(ExceptionErrorCodeUtils.Read_only, ex); } } // @Override // public long count() { // return databases.get(getSchema().getPrimaryIndex().getName()).count(); // } // // @Override // public void sync() { // for (Entry<String, Database> entry : databases.entrySet()) { // entry.getValue().sync(); // } // } @Override public void close() { for (Entry<String, Database> entry : databases.entrySet()) { entry.getValue().close(); } } @Override public void delete(ExecutionContext context, CloneableRecord key, IndexMeta indexMeta, String dbName) throws TddlException { DatabaseEntry keyEntry = new DatabaseEntry(); keyEntry.setData(indexCodecMap.get(indexMeta.getName()).getKey_codec().encode(key)); try { getDatabase(dbName).delete(context.getTransaction() == null ? null : ((JE_Transaction) context.getTransaction()).txn, keyEntry); } catch (LockTimeoutException ex) { throw ex; } catch (ReplicaWriteException ex) { throw new TddlException(ExceptionErrorCodeUtils.Read_only, ex); } } @Override public CloneableRecord get(ExecutionContext context, CloneableRecord key, IndexMeta indexMeta, String dbName) { DatabaseEntry keyEntry = new DatabaseEntry(); DatabaseEntry valueEntry = new DatabaseEntry(); keyEntry.setData(indexCodecMap.get(indexMeta.getName()).getKey_codec().encode(key)); OperationStatus status = getDatabase(dbName).get(context.getTransaction() == null ? null : ((JE_Transaction) context.getTransaction()).txn, keyEntry, valueEntry, LockMode.DEFAULT); if (OperationStatus.SUCCESS != status) { return null; } if (valueEntry.getSize() != 0) { return indexCodecMap.get(indexMeta.getName()).getValue_codec().decode(valueEntry.getData()); } else { return null; } } public void setTempTable(boolean isTempTable) { this.isTempTable = isTempTable; } @Override public ISchematicCursor getCursor(ExecutionContext executionContext, IndexMeta meta, IQuery iQuery) throws TddlException { String actualTable = iQuery.getTableName(); return getCursor(executionContext.getTransaction(), meta, executionContext.getIsolation(), actualTable); } @Override public ISchematicCursor getCursor(ExecutionContext executionContext, IndexMeta indexMeta, String actualTableName) throws TddlException { Database db = getDatabase(actualTableName); if (db == null) { throw new TddlException("table don't contains indexName:" + actualTableName); } ITransaction txn = executionContext.getTransaction(); CursorConfig cc = CursorConfig.DEFAULT; LockMode lm = LockMode.DEFAULT; if (txn != null) { com.sleepycat.je.TransactionConfig _config = ((JE_Transaction) txn).config; if (_config.getReadUncommitted()) { cc = CursorConfig.READ_UNCOMMITTED; lm = LockMode.READ_UNCOMMITTED; } else if (_config.getReadCommitted()) { cc = CursorConfig.READ_COMMITTED; // lm = LockMode.READ_COMMITTED; } } else { cc = CursorConfig.READ_COMMITTED; } JE_Cursor je_cursor = new JE_Cursor(indexMeta, db.openCursor(txn == null ? null : ((JE_Transaction) txn).txn, cc), lm); if (txn != null) { ((JE_Transaction) txn).addCursor(je_cursor); } return new SchematicCursor(je_cursor, je_cursor.getiCursorMeta(), ExecUtils.getOrderBy(indexMeta)); } } class KVCodec { RecordCodec key_codec; RecordCodec value_codec; public RecordCodec getKey_codec() { return key_codec; } public void setKey_codec(RecordCodec key_codec) { this.key_codec = key_codec; } public RecordCodec getValue_codec() { return value_codec; } public void setValue_codec(RecordCodec value_codec) { this.value_codec = value_codec; } }