diff --git a/lealone-bootstrap/src/main/java/org/lealone/bootstrap/Lealone.java b/lealone-bootstrap/src/main/java/org/lealone/bootstrap/Lealone.java index 91c9decc3..183477bf9 100644 --- a/lealone-bootstrap/src/main/java/org/lealone/bootstrap/Lealone.java +++ b/lealone-bootstrap/src/main/java/org/lealone/bootstrap/Lealone.java @@ -27,11 +27,11 @@ import org.lealone.cluster.utils.Utils; import org.lealone.cluster.utils.WrappedRunnable; import org.lealone.command.router.Router; +import org.lealone.command.router.TransactionalRouter; import org.lealone.engine.Session; import org.lealone.engine.SysProperties; import org.lealone.server.PgServer; import org.lealone.server.TcpServer; -import org.lealone.transaction.TransactionalRouter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/lealone-client/src/main/java/org/lealone/engine/FrontendSession.java b/lealone-client/src/main/java/org/lealone/engine/FrontendSession.java index 580df724f..f735b33cd 100644 --- a/lealone-client/src/main/java/org/lealone/engine/FrontendSession.java +++ b/lealone-client/src/main/java/org/lealone/engine/FrontendSession.java @@ -21,7 +21,10 @@ import org.lealone.message.JdbcSQLException; import org.lealone.message.Trace; import org.lealone.message.TraceSystem; -import org.lealone.transaction.TransactionInterface; +import org.lealone.storage.FileStore; +import org.lealone.storage.FrontendLobStorage; +import org.lealone.storage.LobStorage; +import org.lealone.transaction.Transaction; import org.lealone.util.MathUtils; import org.lealone.util.NetUtils; import org.lealone.util.SmallLRUCache; @@ -93,8 +96,8 @@ public class FrontendSession extends SessionWithState implements DataHandler { private int lastReconnect; private SessionInterface embedded; //private DatabaseEventListener eventListener; - private LobStorageInterface lobStorage; - private TransactionInterface transaction; + private LobStorage lobStorage; + private Transaction transaction; public FrontendSession(ConnectionInfo ci) { this.connectionInfo = ci; @@ -601,7 +604,7 @@ public void afterWriting() { } @Override - public LobStorageInterface getLobStorage() { + public LobStorage getLobStorage() { if (lobStorage == null) { lobStorage = new FrontendLobStorage(this); } @@ -688,11 +691,11 @@ public synchronized boolean validateTransaction(String localTransactionName) { } } - public void setTransaction(TransactionInterface transaction) { + public void setTransaction(Transaction transaction) { this.transaction = transaction; } - public TransactionInterface getTransaction() { + public Transaction getTransaction() { return transaction; } diff --git a/lealone-client/src/main/java/org/lealone/engine/FrontendLobStorage.java b/lealone-client/src/main/java/org/lealone/storage/FrontendLobStorage.java similarity index 96% rename from lealone-client/src/main/java/org/lealone/engine/FrontendLobStorage.java rename to lealone-client/src/main/java/org/lealone/storage/FrontendLobStorage.java index f5aae2ed1..842362f48 100644 --- a/lealone-client/src/main/java/org/lealone/engine/FrontendLobStorage.java +++ b/lealone-client/src/main/java/org/lealone/storage/FrontendLobStorage.java @@ -3,14 +3,16 @@ * and the EPL 1.0 (http://h2database.com/html/license.html). * Initial Developer: H2 Group */ -package org.lealone.engine; +package org.lealone.storage; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.io.Reader; +import org.lealone.engine.DataHandler; import org.lealone.message.DbException; +import org.lealone.storage.LobStorage; import org.lealone.value.Value; import org.lealone.value.ValueLobDb; @@ -18,7 +20,7 @@ * This factory creates in-memory objects and temporary files. It is used on the * client side. */ -public class FrontendLobStorage implements LobStorageInterface { +public class FrontendLobStorage implements LobStorage { private final DataHandler handler; diff --git a/lealone-common/src/main/java/org/lealone/engine/DataHandler.java b/lealone-common/src/main/java/org/lealone/engine/DataHandler.java index ca3f061ec..0cb7e1325 100644 --- a/lealone-common/src/main/java/org/lealone/engine/DataHandler.java +++ b/lealone-common/src/main/java/org/lealone/engine/DataHandler.java @@ -9,6 +9,8 @@ import java.sql.Connection; import org.lealone.message.DbException; +import org.lealone.storage.FileStore; +import org.lealone.storage.LobStorage; import org.lealone.util.SmallLRUCache; import org.lealone.util.TempFileDeleter; @@ -91,7 +93,7 @@ public interface DataHandler { * * @return the lob storage mechanism */ - LobStorageInterface getLobStorage(); + LobStorage getLobStorage(); /** * Get a database connection to be used for LOB access. diff --git a/lealone-common/src/main/java/org/lealone/security/SecureFileStore.java b/lealone-common/src/main/java/org/lealone/security/SecureFileStore.java index 309b8e21c..08e327b15 100644 --- a/lealone-common/src/main/java/org/lealone/security/SecureFileStore.java +++ b/lealone-common/src/main/java/org/lealone/security/SecureFileStore.java @@ -8,7 +8,7 @@ import org.lealone.engine.Constants; import org.lealone.engine.DataHandler; -import org.lealone.engine.FileStore; +import org.lealone.storage.FileStore; import org.lealone.util.MathUtils; /** diff --git a/lealone-common/src/main/java/org/lealone/engine/FileStore.java b/lealone-common/src/main/java/org/lealone/storage/FileStore.java similarity index 99% rename from lealone-common/src/main/java/org/lealone/engine/FileStore.java rename to lealone-common/src/main/java/org/lealone/storage/FileStore.java index 4cc2d1a98..7f685bfb2 100644 --- a/lealone-common/src/main/java/org/lealone/engine/FileStore.java +++ b/lealone-common/src/main/java/org/lealone/storage/FileStore.java @@ -4,7 +4,7 @@ * (http://h2database.com/html/license.html). * Initial Developer: H2 Group */ -package org.lealone.engine; +package org.lealone.storage; import java.io.IOException; import java.lang.ref.Reference; @@ -13,6 +13,9 @@ import java.util.Arrays; import org.lealone.api.ErrorCode; +import org.lealone.engine.Constants; +import org.lealone.engine.DataHandler; +import org.lealone.engine.SysProperties; import org.lealone.fs.FileUtils; import org.lealone.message.DbException; import org.lealone.security.SecureFileStore; diff --git a/lealone-common/src/main/java/org/lealone/engine/FileStoreInputStream.java b/lealone-common/src/main/java/org/lealone/storage/FileStoreInputStream.java similarity index 96% rename from lealone-common/src/main/java/org/lealone/engine/FileStoreInputStream.java rename to lealone-common/src/main/java/org/lealone/storage/FileStoreInputStream.java index bffed1b5b..9b477869f 100644 --- a/lealone-common/src/main/java/org/lealone/engine/FileStoreInputStream.java +++ b/lealone-common/src/main/java/org/lealone/storage/FileStoreInputStream.java @@ -4,12 +4,15 @@ * (http://h2database.com/html/license.html). * Initial Developer: H2 Group */ -package org.lealone.engine; +package org.lealone.storage; import java.io.IOException; import java.io.InputStream; import org.lealone.compress.CompressTool; +import org.lealone.engine.Constants; +import org.lealone.engine.Data; +import org.lealone.engine.DataHandler; import org.lealone.message.DbException; import org.lealone.util.DataUtils; diff --git a/lealone-common/src/main/java/org/lealone/engine/FileStoreOutputStream.java b/lealone-common/src/main/java/org/lealone/storage/FileStoreOutputStream.java similarity index 94% rename from lealone-common/src/main/java/org/lealone/engine/FileStoreOutputStream.java rename to lealone-common/src/main/java/org/lealone/storage/FileStoreOutputStream.java index b6b35efbb..32e15cba7 100644 --- a/lealone-common/src/main/java/org/lealone/engine/FileStoreOutputStream.java +++ b/lealone-common/src/main/java/org/lealone/storage/FileStoreOutputStream.java @@ -4,11 +4,14 @@ * (http://h2database.com/html/license.html). * Initial Developer: H2 Group */ -package org.lealone.engine; +package org.lealone.storage; import java.io.OutputStream; import org.lealone.compress.CompressTool; +import org.lealone.engine.Constants; +import org.lealone.engine.Data; +import org.lealone.engine.DataHandler; /** * An output stream that is backed by a file store. diff --git a/lealone-common/src/main/java/org/lealone/engine/LobStorageInterface.java b/lealone-common/src/main/java/org/lealone/storage/LobStorage.java similarity index 97% rename from lealone-common/src/main/java/org/lealone/engine/LobStorageInterface.java rename to lealone-common/src/main/java/org/lealone/storage/LobStorage.java index b64c64e07..f2804f786 100644 --- a/lealone-common/src/main/java/org/lealone/engine/LobStorageInterface.java +++ b/lealone-common/src/main/java/org/lealone/storage/LobStorage.java @@ -3,7 +3,7 @@ * and the EPL 1.0 (http://h2database.com/html/license.html). * Initial Developer: H2 Group */ -package org.lealone.engine; +package org.lealone.storage; import java.io.IOException; import java.io.InputStream; @@ -15,7 +15,7 @@ /** * A mechanism to store and retrieve lob data. */ -public interface LobStorageInterface { +public interface LobStorage { /** * The name of the lob data table. If this table exists, then lob storage is diff --git a/lealone-common/src/main/java/org/lealone/engine/StorageMap.java b/lealone-common/src/main/java/org/lealone/storage/StorageMap.java similarity index 99% rename from lealone-common/src/main/java/org/lealone/engine/StorageMap.java rename to lealone-common/src/main/java/org/lealone/storage/StorageMap.java index 36b908dae..a65c5aa1e 100644 --- a/lealone-common/src/main/java/org/lealone/engine/StorageMap.java +++ b/lealone-common/src/main/java/org/lealone/storage/StorageMap.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.lealone.engine; +package org.lealone.storage; import java.util.Iterator; import java.util.Map; @@ -32,6 +32,8 @@ public interface Builder { StorageMap openMap(String name, DataType valueType); StorageMap openMap(String name, DataType keyType, DataType valueType); + + String getMapName(int id); } public abstract class BuilderBase implements Builder { diff --git a/lealone-common/src/main/java/org/lealone/transaction/TransactionInterface.java b/lealone-common/src/main/java/org/lealone/transaction/Transaction.java similarity index 61% rename from lealone-common/src/main/java/org/lealone/transaction/TransactionInterface.java rename to lealone-common/src/main/java/org/lealone/transaction/Transaction.java index 3c19c965a..d4cfa2c4a 100644 --- a/lealone-common/src/main/java/org/lealone/transaction/TransactionInterface.java +++ b/lealone-common/src/main/java/org/lealone/transaction/Transaction.java @@ -17,28 +17,57 @@ */ package org.lealone.transaction; -public interface TransactionInterface { - long getTransactionId(); +import org.lealone.type.DataType; - long getCommitTimestamp(); +public interface Transaction { + + //long getTransactionId(); + + //long getCommitTimestamp(); boolean isAutoCommit(); + void setAutoCommit(boolean autoCommit); + + void setLocal(boolean local); + void addLocalTransactionNames(String localTransactionNames); String getLocalTransactionNames(); + void setValidator(Validator validator); + + void addParticipant(Participant participant); + + TransactionMap openMap(String name); + + TransactionMap openMap(String name, DataType keyType, DataType valueType); + + void addSavepoint(String name); + + long getSavepointId(); + void commit(); void commit(String allLocalTransactionNames); void rollback(); - void addSavepoint(String name); - void rollbackToSavepoint(String name); - long getSavepointId(); - void rollbackToSavepoint(long savepointId); + + interface Participant { + void addSavepoint(String name); + + void rollbackToSavepoint(String name); + + void commitTransaction(String localTransactionName); + + void rollbackTransaction(); + } + + interface Validator { + boolean validateTransaction(String localTransactionName); + } } diff --git a/lealone-transaction/src/main/java/org/lealone/transaction/TransactionEngine.java b/lealone-common/src/main/java/org/lealone/transaction/TransactionEngine.java similarity index 87% rename from lealone-transaction/src/main/java/org/lealone/transaction/TransactionEngine.java rename to lealone-common/src/main/java/org/lealone/transaction/TransactionEngine.java index 85263d602..6252b2078 100644 --- a/lealone-transaction/src/main/java/org/lealone/transaction/TransactionEngine.java +++ b/lealone-common/src/main/java/org/lealone/transaction/TransactionEngine.java @@ -17,8 +17,10 @@ */ package org.lealone.transaction; -import org.lealone.transaction.TransactionInterface; - public interface TransactionEngine { - TransactionInterface beginTransaction(); + Transaction beginTransaction(boolean autoCommit); + + void close(); + + boolean isValid(String localTransactionName); } diff --git a/lealone-mvdb/src/main/java/org/lealone/engine/TransactionMap.java b/lealone-common/src/main/java/org/lealone/transaction/TransactionMap.java similarity index 96% rename from lealone-mvdb/src/main/java/org/lealone/engine/TransactionMap.java rename to lealone-common/src/main/java/org/lealone/transaction/TransactionMap.java index 6d0d28019..48649eb9c 100644 --- a/lealone-mvdb/src/main/java/org/lealone/engine/TransactionMap.java +++ b/lealone-common/src/main/java/org/lealone/transaction/TransactionMap.java @@ -16,12 +16,11 @@ * specific language governing permissions and limitations * under the License. */ -package org.lealone.engine; +package org.lealone.transaction; import java.util.Iterator; import java.util.Map.Entry; -import org.lealone.engine.Session; import org.lealone.type.DataType; public interface TransactionMap { @@ -54,7 +53,7 @@ public interface TransactionMap { * @param savepoint the savepoint * @return the map */ - public TransactionMap getInstance(Session session, long savepoint); + public TransactionMap getInstance(Transaction transaction, long savepoint); /** * Get the most recent value for the given key. @@ -111,7 +110,7 @@ public interface TransactionMap { */ public boolean isClosed(); - public void removeMap(Session session); + public void removeMap(); /** * Clear the map. diff --git a/lealone-common/src/main/java/org/lealone/value/ValueLob.java b/lealone-common/src/main/java/org/lealone/value/ValueLob.java index 0728ed26c..a33cf68cb 100644 --- a/lealone-common/src/main/java/org/lealone/value/ValueLob.java +++ b/lealone-common/src/main/java/org/lealone/value/ValueLob.java @@ -16,12 +16,12 @@ import org.lealone.engine.Constants; import org.lealone.engine.DataHandler; -import org.lealone.engine.FileStore; -import org.lealone.engine.FileStoreInputStream; -import org.lealone.engine.FileStoreOutputStream; import org.lealone.engine.SysProperties; import org.lealone.fs.FileUtils; import org.lealone.message.DbException; +import org.lealone.storage.FileStore; +import org.lealone.storage.FileStoreInputStream; +import org.lealone.storage.FileStoreOutputStream; import org.lealone.util.DataUtils; import org.lealone.util.IOUtils; import org.lealone.util.MathUtils; diff --git a/lealone-common/src/main/java/org/lealone/value/ValueLobDb.java b/lealone-common/src/main/java/org/lealone/value/ValueLobDb.java index a05b03927..c99a39e8c 100644 --- a/lealone-common/src/main/java/org/lealone/value/ValueLobDb.java +++ b/lealone-common/src/main/java/org/lealone/value/ValueLobDb.java @@ -16,13 +16,13 @@ import org.lealone.engine.Constants; import org.lealone.engine.DataHandler; -import org.lealone.engine.FileStore; -import org.lealone.engine.FileStoreInputStream; -import org.lealone.engine.FileStoreOutputStream; -import org.lealone.engine.LobStorageInterface; import org.lealone.engine.SysProperties; import org.lealone.fs.FileUtils; import org.lealone.message.DbException; +import org.lealone.storage.FileStore; +import org.lealone.storage.FileStoreInputStream; +import org.lealone.storage.FileStoreOutputStream; +import org.lealone.storage.LobStorage; import org.lealone.util.DataUtils; import org.lealone.util.IOUtils; import org.lealone.util.MathUtils; @@ -195,7 +195,7 @@ public Value convertTo(int t) { @Override public boolean isLinked() { - return tableId != LobStorageInterface.TABLE_ID_SESSION_VARIABLE && small == null; + return tableId != LobStorage.TABLE_ID_SESSION_VARIABLE && small == null; } public boolean isStored() { @@ -221,23 +221,23 @@ public void close() { @Override public void unlink(DataHandler database) { - if (small == null && tableId != LobStorageInterface.TABLE_ID_SESSION_VARIABLE) { - database.getLobStorage().setTable(this, LobStorageInterface.TABLE_ID_SESSION_VARIABLE); - tableId = LobStorageInterface.TABLE_ID_SESSION_VARIABLE; + if (small == null && tableId != LobStorage.TABLE_ID_SESSION_VARIABLE) { + database.getLobStorage().setTable(this, LobStorage.TABLE_ID_SESSION_VARIABLE); + tableId = LobStorage.TABLE_ID_SESSION_VARIABLE; } } @Override public Value link(DataHandler database, int tabId) { if (small == null) { - if (tableId == LobStorageInterface.TABLE_TEMP) { + if (tableId == LobStorage.TABLE_TEMP) { database.getLobStorage().setTable(this, tabId); this.tableId = tabId; } else { return handler.getLobStorage().copyLob(this, tabId, getPrecision()); } } else if (small.length > database.getMaxLengthInplaceLob()) { - LobStorageInterface s = database.getLobStorage(); + LobStorage s = database.getLobStorage(); Value v; if (type == Value.BLOB) { v = s.createBlob(getInputStream(), getPrecision()); @@ -473,11 +473,11 @@ public ValueLobDb copyToResult() { if (handler == null) { return this; } - LobStorageInterface s = handler.getLobStorage(); + LobStorage s = handler.getLobStorage(); if (s.isReadOnly()) { return this; } - return s.copyLob(this, LobStorageInterface.TABLE_RESULT, getPrecision()); + return s.copyLob(this, LobStorage.TABLE_RESULT, getPrecision()); } public long getLobId() { diff --git a/lealone-mvdb/src/main/java/org/lealone/dbobject/index/MVPrimaryIndex.java b/lealone-mvdb/src/main/java/org/lealone/dbobject/index/MVPrimaryIndex.java index 7827d6e30..2492a702d 100644 --- a/lealone-mvdb/src/main/java/org/lealone/dbobject/index/MVPrimaryIndex.java +++ b/lealone-mvdb/src/main/java/org/lealone/dbobject/index/MVPrimaryIndex.java @@ -21,12 +21,12 @@ import org.lealone.engine.Constants; import org.lealone.engine.Database; import org.lealone.engine.Session; -import org.lealone.engine.TransactionMap; -import org.lealone.engine.TransactionStorageEngine; import org.lealone.message.DbException; import org.lealone.result.Row; import org.lealone.result.SearchRow; import org.lealone.result.SortOrder; +import org.lealone.storage.TransactionStorageEngine; +import org.lealone.transaction.TransactionMap; import org.lealone.util.DataUtils; import org.lealone.value.Value; import org.lealone.value.ValueArray; @@ -247,7 +247,7 @@ public int getColumnIndex(Column col) { public void remove(Session session) { TransactionMap map = getMap(session); if (!map.isClosed()) { - map.removeMap(session); + map.removeMap(); } } @@ -373,7 +373,7 @@ TransactionMap getMap(Session session) { if (session == null) { return dataMap; } - return dataMap.getInstance(session, Long.MAX_VALUE); + return dataMap.getInstance(session.getTransaction(), Long.MAX_VALUE); } /** diff --git a/lealone-mvdb/src/main/java/org/lealone/dbobject/index/MVSecondaryIndex.java b/lealone-mvdb/src/main/java/org/lealone/dbobject/index/MVSecondaryIndex.java index 9694124ad..d8f10d2b9 100644 --- a/lealone-mvdb/src/main/java/org/lealone/dbobject/index/MVSecondaryIndex.java +++ b/lealone-mvdb/src/main/java/org/lealone/dbobject/index/MVSecondaryIndex.java @@ -20,12 +20,12 @@ import org.lealone.dbobject.table.MVTable; import org.lealone.engine.Database; import org.lealone.engine.Session; -import org.lealone.engine.TransactionMap; -import org.lealone.engine.TransactionStorageEngine; import org.lealone.message.DbException; import org.lealone.result.Row; import org.lealone.result.SearchRow; import org.lealone.result.SortOrder; +import org.lealone.storage.TransactionStorageEngine; +import org.lealone.transaction.TransactionMap; import org.lealone.util.New; import org.lealone.value.CompareMode; import org.lealone.value.Value; @@ -151,8 +151,7 @@ public int compareTo(Source o) { } finally { for (String tempMapName : mapNames) { TransactionMap map = openMap(tempMapName); - //map.getStore().removeMap(map); - map.removeMap(null); + map.removeMap(); } } } @@ -371,7 +370,7 @@ public double getCost(Session session, int[] masks, SortOrder sortOrder) { public void remove(Session session) { TransactionMap map = getMap(session); if (!map.isClosed()) { - map.removeMap(session); + map.removeMap(); } } @@ -461,7 +460,7 @@ TransactionMap getMap(Session session) { if (session == null) { return dataMap; } - return dataMap.getInstance(session, Long.MAX_VALUE); + return dataMap.getInstance(session.getTransaction(), Long.MAX_VALUE); } /** diff --git a/lealone-mvdb/src/main/java/org/lealone/dbobject/table/MVTable.java b/lealone-mvdb/src/main/java/org/lealone/dbobject/table/MVTable.java index 834a74471..9c0e9ba7d 100644 --- a/lealone-mvdb/src/main/java/org/lealone/dbobject/table/MVTable.java +++ b/lealone-mvdb/src/main/java/org/lealone/dbobject/table/MVTable.java @@ -36,11 +36,11 @@ import org.lealone.engine.Constants; import org.lealone.engine.Session; import org.lealone.engine.SysProperties; -import org.lealone.engine.TransactionStorageEngine; import org.lealone.message.DbException; import org.lealone.message.Trace; import org.lealone.result.Row; import org.lealone.result.SortOrder; +import org.lealone.storage.TransactionStorageEngine; import org.lealone.util.MathUtils; import org.lealone.util.New; import org.lealone.value.DataType; diff --git a/lealone-mvdb/src/main/java/org/lealone/engine/TransactionStorageEngine.java b/lealone-mvdb/src/main/java/org/lealone/storage/TransactionStorageEngine.java similarity index 95% rename from lealone-mvdb/src/main/java/org/lealone/engine/TransactionStorageEngine.java rename to lealone-mvdb/src/main/java/org/lealone/storage/TransactionStorageEngine.java index 8e746d676..1e077b819 100644 --- a/lealone-mvdb/src/main/java/org/lealone/engine/TransactionStorageEngine.java +++ b/lealone-mvdb/src/main/java/org/lealone/storage/TransactionStorageEngine.java @@ -16,11 +16,12 @@ * specific language governing permissions and limitations * under the License. */ -package org.lealone.engine; +package org.lealone.storage; import org.lealone.dbobject.table.MVTable; import org.lealone.engine.Database; import org.lealone.engine.Session; +import org.lealone.transaction.TransactionMap; import org.lealone.type.DataType; public interface TransactionStorageEngine { diff --git a/lealone-server/pom.xml b/lealone-server/pom.xml index a08e7b588..faa549c46 100644 --- a/lealone-server/pom.xml +++ b/lealone-server/pom.xml @@ -31,7 +31,7 @@ org.lealone - lealone-transaction + lealone-sql ${project.version} diff --git a/lealone-server/src/main/java/org/lealone/server/TcpServer.java b/lealone-server/src/main/java/org/lealone/server/TcpServer.java index 734174b0b..98ce623bf 100644 --- a/lealone-server/src/main/java/org/lealone/server/TcpServer.java +++ b/lealone-server/src/main/java/org/lealone/server/TcpServer.java @@ -23,12 +23,14 @@ import java.util.Set; import org.lealone.api.ErrorCode; +import org.lealone.command.router.Router; +import org.lealone.command.router.TransactionalRouter; import org.lealone.engine.Constants; import org.lealone.engine.DatabaseEngine; +import org.lealone.engine.Session; import org.lealone.jdbc.Driver; import org.lealone.message.DbException; import org.lealone.message.TraceSystem; -import org.lealone.transaction.TransactionManager; import org.lealone.util.JdbcUtils; import org.lealone.util.NetUtils; import org.lealone.util.New; @@ -206,8 +208,11 @@ public void init(String... args) { } Driver.load(); - TransactionManager.init(baseDir, listenAddress, port); - DatabaseEngine.init(baseDir); + Router r = Session.getRouter(); + if (!(r instanceof TransactionalRouter)) { + Session.setRouter(new TransactionalRouter(r)); + } + DatabaseEngine.init(baseDir, listenAddress, port); } @Override diff --git a/lealone-server/src/main/java/org/lealone/server/TcpServerThread.java b/lealone-server/src/main/java/org/lealone/server/TcpServerThread.java index b759cab78..ba95c0fe5 100644 --- a/lealone-server/src/main/java/org/lealone/server/TcpServerThread.java +++ b/lealone-server/src/main/java/org/lealone/server/TcpServerThread.java @@ -24,7 +24,6 @@ import org.lealone.engine.ConnectionInfo; import org.lealone.engine.Constants; import org.lealone.engine.FrontendSession; -import org.lealone.engine.LobStorageInterface; import org.lealone.engine.Session; import org.lealone.engine.SysProperties; import org.lealone.expression.Parameter; @@ -32,7 +31,7 @@ import org.lealone.message.JdbcSQLException; import org.lealone.result.ResultColumn; import org.lealone.result.ResultInterface; -import org.lealone.transaction.TransactionStatusTable; +import org.lealone.storage.LobStorage; import org.lealone.util.IOUtils; import org.lealone.util.New; import org.lealone.util.SmallLRUCache; @@ -482,7 +481,7 @@ private void process() throws IOException { } case FrontendSession.COMMAND_EXECUTE_TRANSACTION_VALIDATE: { int old = session.getModificationId(); - boolean isValid = TransactionStatusTable.isValid(transfer.readString()); + boolean isValid = session.getDatabase().getTransactionEngine().isValid(transfer.readString()); int status; if (session.isClosed()) { status = FrontendSession.STATUS_CLOSED; @@ -590,7 +589,7 @@ private void process() throws IOException { int length = transfer.readInt(); transfer.verifyLobMac(hmac, lobId); if (in.getPos() != offset) { - LobStorageInterface lobStorage = session.getDataHandler().getLobStorage(); + LobStorage lobStorage = session.getDataHandler().getLobStorage(); // only the lob id is used ValueLobDb lob = ValueLobDb.create(Value.BLOB, null, -1, lobId, hmac, -1); InputStream lobIn = lobStorage.getInputStream(lob, hmac, -1); diff --git a/lealone-sql/src/main/java/org/lealone/command/dml/ScriptBase.java b/lealone-sql/src/main/java/org/lealone/command/dml/ScriptBase.java index 87353b9e9..bb9ed1b9f 100644 --- a/lealone-sql/src/main/java/org/lealone/command/dml/ScriptBase.java +++ b/lealone-sql/src/main/java/org/lealone/command/dml/ScriptBase.java @@ -19,16 +19,16 @@ import org.lealone.engine.Constants; import org.lealone.engine.DataHandler; import org.lealone.engine.Database; -import org.lealone.engine.FileStore; -import org.lealone.engine.FileStoreInputStream; -import org.lealone.engine.FileStoreOutputStream; -import org.lealone.engine.LobStorageInterface; import org.lealone.engine.Session; import org.lealone.engine.SysProperties; import org.lealone.expression.Expression; import org.lealone.fs.FileUtils; import org.lealone.message.DbException; import org.lealone.security.SHA256; +import org.lealone.storage.FileStore; +import org.lealone.storage.FileStoreInputStream; +import org.lealone.storage.FileStoreOutputStream; +import org.lealone.storage.LobStorage; import org.lealone.util.IOUtils; import org.lealone.util.SmallLRUCache; import org.lealone.util.TempFileDeleter; @@ -245,7 +245,7 @@ public SmallLRUCache getLobFileListCache() { } @Override - public LobStorageInterface getLobStorage() { + public LobStorage getLobStorage() { return null; } diff --git a/lealone-transaction/src/main/java/org/lealone/transaction/TransactionalRouter.java b/lealone-sql/src/main/java/org/lealone/command/router/TransactionalRouter.java similarity index 98% rename from lealone-transaction/src/main/java/org/lealone/transaction/TransactionalRouter.java rename to lealone-sql/src/main/java/org/lealone/command/router/TransactionalRouter.java index 0e2d7c617..029e54d6e 100644 --- a/lealone-transaction/src/main/java/org/lealone/transaction/TransactionalRouter.java +++ b/lealone-sql/src/main/java/org/lealone/command/router/TransactionalRouter.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.lealone.transaction; +package org.lealone.command.router; import org.lealone.command.CommandInterface; import org.lealone.command.Prepared; @@ -26,7 +26,6 @@ import org.lealone.command.dml.Select; import org.lealone.command.dml.TransactionCommand; import org.lealone.command.dml.Update; -import org.lealone.command.router.Router; import org.lealone.engine.Session; import org.lealone.message.DbException; import org.lealone.result.ResultInterface; diff --git a/lealone-sql/src/main/java/org/lealone/dbobject/Schema.java b/lealone-sql/src/main/java/org/lealone/dbobject/Schema.java index 272df95ca..964b2be63 100644 --- a/lealone-sql/src/main/java/org/lealone/dbobject/Schema.java +++ b/lealone-sql/src/main/java/org/lealone/dbobject/Schema.java @@ -17,11 +17,11 @@ import org.lealone.dbobject.table.Table; import org.lealone.engine.Database; import org.lealone.engine.Session; -import org.lealone.engine.StorageEngine; import org.lealone.engine.SysProperties; -import org.lealone.engine.StorageEngineManager; import org.lealone.message.DbException; import org.lealone.message.Trace; +import org.lealone.storage.StorageEngine; +import org.lealone.storage.StorageEngineManager; import org.lealone.util.New; import org.lealone.util.Utils; diff --git a/lealone-sql/src/main/java/org/lealone/engine/Database.java b/lealone-sql/src/main/java/org/lealone/engine/Database.java index 26177fdf3..47689e20d 100644 --- a/lealone-sql/src/main/java/org/lealone/engine/Database.java +++ b/lealone-sql/src/main/java/org/lealone/engine/Database.java @@ -48,6 +48,10 @@ import org.lealone.message.TraceSystem; import org.lealone.result.Row; import org.lealone.result.SearchRow; +import org.lealone.storage.FileStore; +import org.lealone.storage.LobStorage; +import org.lealone.storage.StorageEngine; +import org.lealone.transaction.TransactionEngine; import org.lealone.util.BitField; import org.lealone.util.MathUtils; import org.lealone.util.New; @@ -156,7 +160,7 @@ public class Database implements DataHandler { private int compactMode; private SourceCompiler compiler; private volatile boolean metaTablesInitialized; - private LobStorageInterface lobStorage; + private LobStorage lobStorage; private int pageSize; private int defaultTableType = Table.TYPE_CACHED; private DbSettings dbSettings; @@ -956,11 +960,11 @@ protected synchronized void close(boolean fromShutdownHook) { } // remove all session variables if (persistent) { - boolean lobStorageIsUsed = infoSchema.findTableOrView(systemSession, LobStorageInterface.LOB_DATA_TABLE) != null; + boolean lobStorageIsUsed = infoSchema.findTableOrView(systemSession, LobStorage.LOB_DATA_TABLE) != null; if (lobStorageIsUsed) { try { getLobStorage(); - lobStorage.removeAllForTable(LobStorageInterface.TABLE_ID_SESSION_VARIABLE); + lobStorage.removeAllForTable(LobStorage.TABLE_ID_SESSION_VARIABLE); } catch (DbException e) { trace.error(e, "close"); } @@ -1948,11 +1952,11 @@ public SourceCompiler getCompiler() { } @Override - public LobStorageInterface getLobStorage() { + public LobStorage getLobStorage() { return lobStorage; } - public void setLobStorage(LobStorageInterface lobStorage) { + public void setLobStorage(LobStorage lobStorage) { if (lobStorage == null) { this.lobStorage = lobStorage; } diff --git a/lealone-sql/src/main/java/org/lealone/engine/DatabaseEngine.java b/lealone-sql/src/main/java/org/lealone/engine/DatabaseEngine.java index e3d9623e8..daa395307 100644 --- a/lealone-sql/src/main/java/org/lealone/engine/DatabaseEngine.java +++ b/lealone-sql/src/main/java/org/lealone/engine/DatabaseEngine.java @@ -26,6 +26,7 @@ import org.lealone.command.Parser; import org.lealone.dbobject.User; import org.lealone.message.DbException; +import org.lealone.storage.StorageEngineManager; import org.lealone.util.MathUtils; import org.lealone.util.New; @@ -38,11 +39,19 @@ public class DatabaseEngine implements SessionFactory { private static final HashMap DATABASES = New.hashMap(); private static final DatabaseEngine INSTANCE = new DatabaseEngine(); + private static String hostAndPort; + + public static String getHostAndPort() { + return hostAndPort; + } + public static DatabaseEngine getInstance() { return INSTANCE; } - public static synchronized void init(String baseDir) { + public static synchronized void init(String baseDir, String host, int port) { + hostAndPort = host + ":" + port; + StorageEngineManager.initStorageEngines(); SystemDatabase.init(baseDir); diff --git a/lealone-sql/src/main/java/org/lealone/engine/Session.java b/lealone-sql/src/main/java/org/lealone/engine/Session.java index 1aecbdc22..15a7de321 100644 --- a/lealone-sql/src/main/java/org/lealone/engine/Session.java +++ b/lealone-sql/src/main/java/org/lealone/engine/Session.java @@ -38,7 +38,8 @@ import org.lealone.result.ResultInterface; import org.lealone.result.Row; import org.lealone.result.SubqueryResult; -import org.lealone.transaction.TransactionInterface; +import org.lealone.storage.LobStorage; +import org.lealone.transaction.Transaction; import org.lealone.util.New; import org.lealone.util.SmallLRUCache; import org.lealone.value.Value; @@ -149,7 +150,7 @@ public void setVariable(String name, Value value) { old = variables.remove(name); } else { // link LOB values, to make sure we have our own object - value = value.link(database, LobStorageInterface.TABLE_ID_SESSION_VARIABLE); + value = value.link(database, LobStorage.TABLE_ID_SESSION_VARIABLE); old = variables.put(name, value); } if (old != null) { @@ -496,7 +497,7 @@ public void commit(boolean ddl, String allLocalTransactionNames) { // } // } //避免重复commit - TransactionInterface transaction = this.transaction; + Transaction transaction = this.transaction; this.transaction = null; if (allLocalTransactionNames == null) transaction.commit(); @@ -543,7 +544,7 @@ public void rollback() { checkCommitRollback(); currentTransactionName = null; if (transaction != null) { - TransactionInterface transaction = this.transaction; + Transaction transaction = this.transaction; this.transaction = null; transaction.rollback(); } @@ -1343,11 +1344,11 @@ public String getURL(InetAddress host) { return buff.toString(); } - private volatile TransactionInterface transaction; + private volatile Transaction transaction; - public TransactionInterface getTransaction() { + public Transaction getTransaction() { if (transaction == null) { - transaction = database.getTransactionEngine().beginTransaction(this); + transaction = database.getTransactionEngine().beginTransaction(autoCommit); } return transaction; } diff --git a/lealone-sql/src/main/java/org/lealone/engine/TransactionEngine.java b/lealone-sql/src/main/java/org/lealone/engine/TransactionEngine.java deleted file mode 100644 index 83304cce5..000000000 --- a/lealone-sql/src/main/java/org/lealone/engine/TransactionEngine.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.lealone.engine; - -import org.lealone.transaction.TransactionInterface; - -public interface TransactionEngine { - TransactionInterface beginTransaction(Session session); -} diff --git a/lealone-sql/src/main/java/org/lealone/result/ResultDiskBuffer.java b/lealone-sql/src/main/java/org/lealone/result/ResultDiskBuffer.java index 08995fc14..3e7651256 100644 --- a/lealone-sql/src/main/java/org/lealone/result/ResultDiskBuffer.java +++ b/lealone-sql/src/main/java/org/lealone/result/ResultDiskBuffer.java @@ -12,9 +12,9 @@ import org.lealone.engine.Constants; import org.lealone.engine.Data; import org.lealone.engine.Database; -import org.lealone.engine.FileStore; import org.lealone.engine.Session; import org.lealone.message.DbException; +import org.lealone.storage.FileStore; import org.lealone.util.New; import org.lealone.value.Value; diff --git a/lealone-sql/src/main/java/org/lealone/result/RowList.java b/lealone-sql/src/main/java/org/lealone/result/RowList.java index 9e92ba284..5dbf76ffe 100644 --- a/lealone-sql/src/main/java/org/lealone/result/RowList.java +++ b/lealone-sql/src/main/java/org/lealone/result/RowList.java @@ -11,8 +11,8 @@ import org.lealone.engine.Constants; import org.lealone.engine.Data; import org.lealone.engine.Database; -import org.lealone.engine.FileStore; import org.lealone.engine.Session; +import org.lealone.storage.FileStore; import org.lealone.util.New; import org.lealone.value.Value; diff --git a/lealone-sql/src/main/java/org/lealone/engine/StorageEngine.java b/lealone-sql/src/main/java/org/lealone/storage/StorageEngine.java similarity index 87% rename from lealone-sql/src/main/java/org/lealone/engine/StorageEngine.java rename to lealone-sql/src/main/java/org/lealone/storage/StorageEngine.java index bfa41ac25..f45e0323e 100644 --- a/lealone-sql/src/main/java/org/lealone/engine/StorageEngine.java +++ b/lealone-sql/src/main/java/org/lealone/storage/StorageEngine.java @@ -4,10 +4,11 @@ * (http://h2database.com/html/license.html). * Initial Developer: H2 Group */ -package org.lealone.engine; +package org.lealone.storage; import org.lealone.command.ddl.CreateTableData; import org.lealone.dbobject.table.Table; +import org.lealone.engine.Database; /** * A class that implements this interface can create custom table @@ -27,7 +28,7 @@ public interface StorageEngine { String getName(); - LobStorageInterface getLobStorage(); + LobStorage getLobStorage(); void close(Database db); } diff --git a/lealone-sql/src/main/java/org/lealone/engine/StorageEngineBase.java b/lealone-sql/src/main/java/org/lealone/storage/StorageEngineBase.java similarity index 92% rename from lealone-sql/src/main/java/org/lealone/engine/StorageEngineBase.java rename to lealone-sql/src/main/java/org/lealone/storage/StorageEngineBase.java index 922f577f1..d2e67ae17 100644 --- a/lealone-sql/src/main/java/org/lealone/engine/StorageEngineBase.java +++ b/lealone-sql/src/main/java/org/lealone/storage/StorageEngineBase.java @@ -15,13 +15,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.lealone.engine; +package org.lealone.storage; import org.lealone.message.DbException; public abstract class StorageEngineBase implements StorageEngine { @Override - public LobStorageInterface getLobStorage() { + public LobStorage getLobStorage() { throw DbException.getUnsupportedException("getLobStorage()"); } } diff --git a/lealone-sql/src/main/java/org/lealone/engine/StorageEngineManager.java b/lealone-sql/src/main/java/org/lealone/storage/StorageEngineManager.java similarity index 97% rename from lealone-sql/src/main/java/org/lealone/engine/StorageEngineManager.java rename to lealone-sql/src/main/java/org/lealone/storage/StorageEngineManager.java index 31429517f..4c2d23cbc 100644 --- a/lealone-sql/src/main/java/org/lealone/engine/StorageEngineManager.java +++ b/lealone-sql/src/main/java/org/lealone/storage/StorageEngineManager.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.lealone.engine; +package org.lealone.storage; import java.security.AccessController; import java.security.PrivilegedAction; @@ -24,6 +24,7 @@ import java.util.ServiceLoader; import java.util.concurrent.ConcurrentHashMap; +import org.lealone.engine.DbSettings; import org.lealone.message.DbException; public class StorageEngineManager { diff --git a/lealone-storage/engine/pom.xml b/lealone-storage/engine/pom.xml index 385afe1c6..6a496d8aa 100644 --- a/lealone-storage/engine/pom.xml +++ b/lealone-storage/engine/pom.xml @@ -34,6 +34,16 @@ org.lealone lealone-transaction ${project.version} + + + org.lealone + lealone-mvdb + ${project.version} + + + org.lealone + lealone-storage-mvstore + ${project.version} org.lealone diff --git a/lealone-storage/engine/src/main/java/org/lealone/engine/LobStorageMap.java b/lealone-storage/engine/src/main/java/org/lealone/storage/LobStorageMap.java similarity index 96% rename from lealone-storage/engine/src/main/java/org/lealone/engine/LobStorageMap.java rename to lealone-storage/engine/src/main/java/org/lealone/storage/LobStorageMap.java index a32cd1829..f1703e54e 100644 --- a/lealone-storage/engine/src/main/java/org/lealone/engine/LobStorageMap.java +++ b/lealone-storage/engine/src/main/java/org/lealone/storage/LobStorageMap.java @@ -3,7 +3,7 @@ * and the EPL 1.0 (http://h2database.com/html/license.html). * Initial Developer: H2 Group */ -package org.lealone.engine; +package org.lealone.storage; import java.io.BufferedInputStream; import java.io.BufferedReader; @@ -21,12 +21,11 @@ import org.lealone.api.ErrorCode; import org.lealone.engine.Constants; import org.lealone.engine.Database; -import org.lealone.engine.LobStorageInterface; -import org.lealone.engine.MVStorageEngine.Store; import org.lealone.message.DbException; import org.lealone.mvstore.MVMap; import org.lealone.mvstore.MVStore; import org.lealone.mvstore.StreamStore; +import org.lealone.storage.MVStorageEngine.Store; import org.lealone.util.IOUtils; import org.lealone.util.New; import org.lealone.value.Value; @@ -36,7 +35,7 @@ * This class stores LOB objects in the database, in maps. This is the back-end * i.e. the server side of the LOB storage. */ -public class LobStorageMap implements LobStorageInterface { +public class LobStorageMap implements LobStorage { private static final boolean TRACE = false; @@ -206,7 +205,7 @@ private ValueLobDb createLob(InputStream in, int type) throws IOException { } long lobId = generateLobId(); long length = streamStore.length(streamStoreId); - int tableId = LobStorageInterface.TABLE_TEMP; + int tableId = LobStorage.TABLE_TEMP; Object[] value = new Object[] { streamStoreId, tableId, length, 0 }; lobMap.put(lobId, value); Object[] key = new Object[] { streamStoreId, lobId }; @@ -299,9 +298,9 @@ public void removeAllForTable(int tableId) { for (long lobId : list) { removeLob(tableId, lobId); } - if (tableId == LobStorageInterface.TABLE_ID_SESSION_VARIABLE) { - removeAllForTable(LobStorageInterface.TABLE_TEMP); - removeAllForTable(LobStorageInterface.TABLE_RESULT); + if (tableId == LobStorage.TABLE_ID_SESSION_VARIABLE) { + removeAllForTable(LobStorage.TABLE_TEMP); + removeAllForTable(LobStorage.TABLE_RESULT); } } diff --git a/lealone-storage/engine/src/main/java/org/lealone/engine/MVMapBuilder.java b/lealone-storage/engine/src/main/java/org/lealone/storage/MVMapBuilder.java similarity index 91% rename from lealone-storage/engine/src/main/java/org/lealone/engine/MVMapBuilder.java rename to lealone-storage/engine/src/main/java/org/lealone/storage/MVMapBuilder.java index 8a292f315..d7a6df45a 100644 --- a/lealone-storage/engine/src/main/java/org/lealone/engine/MVMapBuilder.java +++ b/lealone-storage/engine/src/main/java/org/lealone/storage/MVMapBuilder.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.lealone.engine; +package org.lealone.storage; import org.lealone.mvstore.MVMap; import org.lealone.mvstore.MVStore; @@ -33,4 +33,9 @@ public StorageMap openMap(String name, DataType keyType, DataType v MVMap.Builder builder = new MVMap.Builder().keyType(keyType).valueType(valueType); return store.openMap(name, builder); } + + @Override + public String getMapName(int id) { + return store.getMapName(id); + } } diff --git a/lealone-storage/engine/src/main/java/org/lealone/engine/MVStorageEngine.java b/lealone-storage/engine/src/main/java/org/lealone/storage/MVStorageEngine.java similarity index 90% rename from lealone-storage/engine/src/main/java/org/lealone/engine/MVStorageEngine.java rename to lealone-storage/engine/src/main/java/org/lealone/storage/MVStorageEngine.java index 513be7375..9d54b86c8 100644 --- a/lealone-storage/engine/src/main/java/org/lealone/engine/MVStorageEngine.java +++ b/lealone-storage/engine/src/main/java/org/lealone/storage/MVStorageEngine.java @@ -3,7 +3,7 @@ * and the EPL 1.0 (http://h2database.com/html/license.html). * Initial Developer: H2 Group */ -package org.lealone.engine; +package org.lealone.storage; import java.io.InputStream; import java.lang.Thread.UncaughtExceptionHandler; @@ -19,15 +19,21 @@ import org.lealone.dbobject.index.ValueDataType; import org.lealone.dbobject.table.MVTable; import org.lealone.dbobject.table.Table; +import org.lealone.engine.Constants; +import org.lealone.engine.Database; +import org.lealone.engine.DatabaseEngine; +import org.lealone.engine.InDoubtTransaction; +import org.lealone.engine.Session; import org.lealone.fs.FileChannelInputStream; import org.lealone.fs.FileUtils; import org.lealone.message.DbException; import org.lealone.mvstore.MVMap; import org.lealone.mvstore.MVStore; import org.lealone.mvstore.MVStoreTool; -import org.lealone.transaction.DefaultTransactionEngine; -import org.lealone.transaction.DefaultTransactionMap; -import org.lealone.transaction.Transaction; +import org.lealone.transaction.MVCCTransaction; +import org.lealone.transaction.MVCCTransactionEngine; +import org.lealone.transaction.MVCCTransactionMap; +import org.lealone.transaction.TransactionMap; import org.lealone.type.DataType; import org.lealone.util.BitField; import org.lealone.util.DataUtils; @@ -189,25 +195,23 @@ public static class Store { /** * The transaction engine. */ - private final DefaultTransactionEngine transactionEngine; + private final MVCCTransactionEngine transactionEngine; private long statisticsStart; private int temporaryMapId; - private final Database db; - public Store(Database db, MVStore.Builder builder) { this(db, builder, null); } public Store(Database db, MVStore.Builder builder, StorageMap.Builder mapBuilder) { - this.db = db; this.store = builder.open(); if (mapBuilder == null) mapBuilder = new MVMapBuilder(store); - this.transactionEngine = new DefaultTransactionEngine(store, new ValueDataType(null, db, null), mapBuilder); - transactionEngine.init(); + this.transactionEngine = new MVCCTransactionEngine(new ValueDataType(null, db, null), mapBuilder, + DatabaseEngine.getHostAndPort()); + transactionEngine.init(store.getMapNames()); initTransactions(); } @@ -215,7 +219,7 @@ public MVStore getStore() { return store; } - public DefaultTransactionEngine getTransactionEngine() { + public MVCCTransactionEngine getTransactionEngine() { return transactionEngine; } @@ -260,11 +264,11 @@ public void closeImmediately() { * rollback all open transactions. */ public void initTransactions() { - List list = transactionEngine.getOpenTransactions(db.getSystemSession()); - for (Transaction t : list) { - if (t.getStatus() == Transaction.STATUS_COMMITTING) { + List list = transactionEngine.getOpenTransactions(); + for (MVCCTransaction t : list) { + if (t.getStatus() == MVCCTransaction.STATUS_COMMITTING) { t.commit(); - } else if (t.getStatus() != Transaction.STATUS_PREPARED) { + } else if (t.getStatus() != MVCCTransaction.STATUS_PREPARED) { t.rollback(); } } @@ -285,8 +289,8 @@ public void removeTemporaryMaps(BitField objectIds) { if (!objectIds.get(id)) { ValueDataType keyType = new ValueDataType(null, null, null); ValueDataType valueType = new ValueDataType(null, null, null); - Transaction t = transactionEngine.beginTransaction(db.getSystemSession()); - DefaultTransactionMap m = t.openMap(mapName, keyType, valueType); + MVCCTransaction t = transactionEngine.beginTransaction(false); + MVCCTransactionMap m = t.openMap(mapName, keyType, valueType); transactionEngine.removeMap(m); t.commit(); } @@ -310,17 +314,17 @@ public synchronized String nextTemporaryMapName() { * @param transactionName the transaction name (may be null) */ public void prepareCommit(Session session, String transactionName) { - Transaction t = (Transaction) session.getTransaction(); + MVCCTransaction t = (MVCCTransaction) session.getTransaction(); t.setName(transactionName); t.prepare(); store.commit(); } public ArrayList getInDoubtTransactions() { - List list = transactionEngine.getOpenTransactions(db.getSystemSession()); + List list = transactionEngine.getOpenTransactions(); ArrayList result = New.arrayList(); - for (Transaction t : list) { - if (t.getStatus() == Transaction.STATUS_PREPARED) { + for (MVCCTransaction t : list) { + if (t.getStatus() == MVCCTransaction.STATUS_PREPARED) { result.add(new MVInDoubtTransaction(store, t)); } } @@ -439,10 +443,10 @@ public Map statisticsEnd() { private static class MVInDoubtTransaction implements InDoubtTransaction { private final MVStore store; - private final Transaction transaction; + private final MVCCTransaction transaction; private int state = InDoubtTransaction.IN_DOUBT; - MVInDoubtTransaction(MVStore store, Transaction transaction) { + MVInDoubtTransaction(MVStore store, MVCCTransaction transaction) { this.store = store; this.transaction = transaction; } @@ -501,7 +505,7 @@ public String nextTemporaryMapName(Database db) { @Override public TransactionMap openMap(Session session, String name, DataType keyType, DataType valueType) { - return ((Transaction) session.getTransaction()).openMap(name, keyType, valueType); + return ((MVCCTransaction) session.getTransaction()).openMap(name, keyType, valueType); } } diff --git a/lealone-storage/engine/src/main/java/org/lealone/engine/WTCursor.java b/lealone-storage/engine/src/main/java/org/lealone/storage/WTCursor.java similarity index 95% rename from lealone-storage/engine/src/main/java/org/lealone/engine/WTCursor.java rename to lealone-storage/engine/src/main/java/org/lealone/storage/WTCursor.java index 7ac40efe9..a2f2e6f1e 100644 --- a/lealone-storage/engine/src/main/java/org/lealone/engine/WTCursor.java +++ b/lealone-storage/engine/src/main/java/org/lealone/storage/WTCursor.java @@ -16,12 +16,12 @@ * specific language governing permissions and limitations * under the License. */ -package org.lealone.engine; +package org.lealone.storage; import org.lealone.util.DataUtils; @SuppressWarnings("unchecked") -public class WTCursor implements org.lealone.engine.StorageMap.Cursor { +public class WTCursor implements org.lealone.storage.StorageMap.Cursor { private final com.wiredtiger.db.Cursor wtCursor; private final WTMap map; diff --git a/lealone-storage/engine/src/main/java/org/lealone/engine/WTMap.java b/lealone-storage/engine/src/main/java/org/lealone/storage/WTMap.java similarity index 99% rename from lealone-storage/engine/src/main/java/org/lealone/engine/WTMap.java rename to lealone-storage/engine/src/main/java/org/lealone/storage/WTMap.java index c2abd98ec..1f91194e7 100644 --- a/lealone-storage/engine/src/main/java/org/lealone/engine/WTMap.java +++ b/lealone-storage/engine/src/main/java/org/lealone/storage/WTMap.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.lealone.engine; +package org.lealone.storage; import java.nio.ByteBuffer; import java.util.AbstractSet; @@ -24,7 +24,6 @@ import java.util.Map.Entry; import java.util.Set; -import org.lealone.engine.StorageMap; import org.lealone.type.DataType; import org.lealone.type.ObjectDataType; import org.lealone.type.WriteBuffer; diff --git a/lealone-storage/engine/src/main/java/org/lealone/engine/WTMapBuilder.java b/lealone-storage/engine/src/main/java/org/lealone/storage/WTMapBuilder.java similarity index 85% rename from lealone-storage/engine/src/main/java/org/lealone/engine/WTMapBuilder.java rename to lealone-storage/engine/src/main/java/org/lealone/storage/WTMapBuilder.java index 20679dcfe..161288007 100644 --- a/lealone-storage/engine/src/main/java/org/lealone/engine/WTMapBuilder.java +++ b/lealone-storage/engine/src/main/java/org/lealone/storage/WTMapBuilder.java @@ -15,8 +15,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.lealone.engine; +package org.lealone.storage; +import org.lealone.message.DbException; import org.lealone.type.DataType; public class WTMapBuilder extends StorageMap.BuilderBase { @@ -30,4 +31,10 @@ public WTMapBuilder(com.wiredtiger.db.Session wtSession) { public StorageMap openMap(String name, DataType keyType, DataType valueType) { return new WTMap(wtSession, name, keyType, valueType); } + + @Override + public String getMapName(int id) { + //TODO + throw DbException.getUnsupportedException("getMapName"); + } } diff --git a/lealone-storage/engine/src/main/java/org/lealone/engine/WTStorageEngine.java b/lealone-storage/engine/src/main/java/org/lealone/storage/WTStorageEngine.java similarity index 95% rename from lealone-storage/engine/src/main/java/org/lealone/engine/WTStorageEngine.java rename to lealone-storage/engine/src/main/java/org/lealone/storage/WTStorageEngine.java index 1e4d6010c..59fba52bd 100644 --- a/lealone-storage/engine/src/main/java/org/lealone/engine/WTStorageEngine.java +++ b/lealone-storage/engine/src/main/java/org/lealone/storage/WTStorageEngine.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.lealone.engine; +package org.lealone.storage; import java.io.File; import java.util.HashMap; @@ -24,8 +24,6 @@ import org.lealone.dbobject.table.MVTable; import org.lealone.dbobject.table.Table; import org.lealone.engine.Database; -import org.lealone.engine.StorageEngineManager; -import org.lealone.engine.TransactionStorageEngine; import com.wiredtiger.db.Connection; import com.wiredtiger.db.wiredtiger; diff --git a/lealone-storage/engine/src/main/resources/META-INF/services/org.lealone.engine.StorageEngine b/lealone-storage/engine/src/main/resources/META-INF/services/org.lealone.engine.StorageEngine deleted file mode 100644 index 8ec49ecc3..000000000 --- a/lealone-storage/engine/src/main/resources/META-INF/services/org.lealone.engine.StorageEngine +++ /dev/null @@ -1,2 +0,0 @@ -org.lealone.engine.MVStorageEngine -org.lealone.engine.WTStorageEngine diff --git a/lealone-storage/engine/src/main/resources/META-INF/services/org.lealone.storage.StorageEngine b/lealone-storage/engine/src/main/resources/META-INF/services/org.lealone.storage.StorageEngine new file mode 100644 index 000000000..614b56640 --- /dev/null +++ b/lealone-storage/engine/src/main/resources/META-INF/services/org.lealone.storage.StorageEngine @@ -0,0 +1,2 @@ +org.lealone.storage.MVStorageEngine +org.lealone.storage.WTStorageEngine diff --git a/lealone-storage/mvstore/src/main/java/org/lealone/mvstore/Cursor.java b/lealone-storage/mvstore/src/main/java/org/lealone/mvstore/Cursor.java index 5b5e0b297..95b08086d 100644 --- a/lealone-storage/mvstore/src/main/java/org/lealone/mvstore/Cursor.java +++ b/lealone-storage/mvstore/src/main/java/org/lealone/mvstore/Cursor.java @@ -7,7 +7,7 @@ import java.util.Iterator; -import org.lealone.engine.StorageMap; +import org.lealone.storage.StorageMap; import org.lealone.util.DataUtils; /** diff --git a/lealone-storage/mvstore/src/main/java/org/lealone/mvstore/MVMap.java b/lealone-storage/mvstore/src/main/java/org/lealone/mvstore/MVMap.java index 7e00fc8e8..4121fdadf 100644 --- a/lealone-storage/mvstore/src/main/java/org/lealone/mvstore/MVMap.java +++ b/lealone-storage/mvstore/src/main/java/org/lealone/mvstore/MVMap.java @@ -15,7 +15,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentMap; -import org.lealone.engine.StorageMap; +import org.lealone.storage.StorageMap; import org.lealone.type.DataType; import org.lealone.type.ObjectDataType; import org.lealone.util.DataUtils; diff --git a/lealone-storage/mvstore/src/main/java/org/lealone/mvstore/MVStore.java b/lealone-storage/mvstore/src/main/java/org/lealone/mvstore/MVStore.java index 01899b12c..fe884ca3c 100644 --- a/lealone-storage/mvstore/src/main/java/org/lealone/mvstore/MVStore.java +++ b/lealone-storage/mvstore/src/main/java/org/lealone/mvstore/MVStore.java @@ -22,9 +22,9 @@ import org.lealone.compress.CompressDeflate; import org.lealone.compress.CompressLZF; import org.lealone.compress.Compressor; -import org.lealone.engine.StorageMap; import org.lealone.mvstore.Page.PageChildren; import org.lealone.mvstore.cache.CacheLongKeyLIRS; +import org.lealone.storage.StorageMap; import org.lealone.type.StringDataType; import org.lealone.type.WriteBuffer; import org.lealone.util.DataUtils; @@ -1185,7 +1185,7 @@ private Set collectReferencedChunks() { DataUtils.checkArgument(testVersion > 0, "Collect references on version 0"); long readCount = getFileStore().readCount; Set referenced = New.hashSet(); - for (org.lealone.engine.StorageMap.Cursor c = meta.cursor("root."); c.hasNext();) { + for (org.lealone.storage.StorageMap.Cursor c = meta.cursor("root."); c.hasNext();) { String key = c.next(); if (!key.startsWith("root.")) { break; diff --git a/lealone-test/src/test/java/org/lealone/test/misc/WiredTigerExample.java b/lealone-test/src/test/java/org/lealone/test/misc/WiredTigerExample.java index 2b4d69195..c4a645bc2 100644 --- a/lealone-test/src/test/java/org/lealone/test/misc/WiredTigerExample.java +++ b/lealone-test/src/test/java/org/lealone/test/misc/WiredTigerExample.java @@ -21,7 +21,7 @@ import java.sql.ResultSet; import java.sql.Statement; -import org.lealone.engine.WTStorageEngine; +import org.lealone.storage.WTStorageEngine; import org.lealone.test.TestBase; public class WiredTigerExample { diff --git a/lealone-test/src/test/java/org/lealone/test/storage/MemoryStorageEngine.java b/lealone-test/src/test/java/org/lealone/test/storage/MemoryStorageEngine.java index 74b7fe262..c8bc8babd 100644 --- a/lealone-test/src/test/java/org/lealone/test/storage/MemoryStorageEngine.java +++ b/lealone-test/src/test/java/org/lealone/test/storage/MemoryStorageEngine.java @@ -20,12 +20,13 @@ import java.util.Iterator; import java.util.Map.Entry; import java.util.NoSuchElementException; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentSkipListMap; import java.util.concurrent.atomic.AtomicInteger; -import org.lealone.engine.MVStorageEngine; -import org.lealone.engine.StorageEngineManager; -import org.lealone.engine.StorageMap; +import org.lealone.storage.MVStorageEngine; +import org.lealone.storage.StorageEngineManager; +import org.lealone.storage.StorageMap; import org.lealone.test.TestBase; import org.lealone.test.misc.CRUDExample; import org.lealone.type.DataType; @@ -44,7 +45,7 @@ public static void main(String[] args) throws Exception { CRUDExample.main(args); } - //如果配置了META-INF/services/org.lealone.engine.StorageEngine + //如果配置了META-INF/services/org.lealone.storage.StorageEngine //就不需要调用这个方法了,会自动注册 public static void register() { StorageEngineManager.registerStorageEngine(new MemoryStorageEngine()); @@ -59,11 +60,18 @@ public String getName() { return NAME; } - static class MemoryMapBuilder extends StorageMap.BuilderBase { + private static ConcurrentHashMap mapNames = new ConcurrentHashMap<>(); + + public static class MemoryMapBuilder extends StorageMap.BuilderBase { @Override public StorageMap openMap(String name, DataType keyType, DataType valueType) { return new MemoryMap(name, keyType, valueType); } + + @Override + public String getMapName(int id) { + return mapNames.get(id); + } } static class MemoryCursor implements StorageMap.Cursor { @@ -135,6 +143,8 @@ public MemoryMap(String name, DataType keyType, DataType valueType) { this.keyType = keyType; this.valueType = valueType; id = counter.incrementAndGet(); + + mapNames.put(id, name); } @Override diff --git a/lealone-test/src/test/java/org/lealone/test/storage/WTMapTest.java b/lealone-test/src/test/java/org/lealone/test/storage/WTMapTest.java index 0a3746c93..a805aa4d2 100644 --- a/lealone-test/src/test/java/org/lealone/test/storage/WTMapTest.java +++ b/lealone-test/src/test/java/org/lealone/test/storage/WTMapTest.java @@ -21,7 +21,7 @@ import java.util.Map.Entry; import org.junit.Assert; -import org.lealone.engine.WTMap; +import org.lealone.storage.WTMap; import com.wiredtiger.db.Connection; import com.wiredtiger.db.Session; @@ -97,7 +97,7 @@ public void run() { Assert.assertTrue(map.areValuesEqual("a", "a")); Assert.assertFalse(map.areValuesEqual("a", "b")); - org.lealone.engine.StorageMap.Cursor cursor = map.cursor(2); + org.lealone.storage.StorageMap.Cursor cursor = map.cursor(2); Assert.assertTrue(cursor.hasNext()); key = cursor.next(); Assert.assertEquals(2, (int) key); diff --git a/lealone-test/src/test/java/org/lealone/test/transaction/TransactionTest.java b/lealone-test/src/test/java/org/lealone/test/transaction/TransactionTest.java new file mode 100644 index 000000000..26b3002c8 --- /dev/null +++ b/lealone-test/src/test/java/org/lealone/test/transaction/TransactionTest.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.lealone.test.transaction; + +import org.junit.Assert; +import org.lealone.storage.StorageMap; +import org.lealone.test.TestBase; +import org.lealone.test.storage.MemoryStorageEngine; +import org.lealone.transaction.MVCCTransactionEngine; +import org.lealone.transaction.TransactionEngine; +import org.lealone.transaction.Transaction; +import org.lealone.transaction.TransactionMap; +import org.lealone.type.ObjectDataType; + +public class TransactionTest { + public static void main(String[] args) { + StorageMap.Builder mapBuilder = new MemoryStorageEngine.MemoryMapBuilder(); + String hostAndPort = TestBase.getHost() + ":" + TestBase.getPort(); + MVCCTransactionEngine e = new MVCCTransactionEngine(new ObjectDataType(), mapBuilder, hostAndPort); + e.init(null); + TransactionEngine te = e; + + Transaction t = te.beginTransaction(false); + TransactionMap map = t.openMap("test"); + map.put("1", "a"); + map.put("2", "b"); + Assert.assertEquals("a", map.get("1")); + Assert.assertEquals("b", map.get("2")); + + t.rollback(); + + t = te.beginTransaction(false); + + Assert.assertNull(map.get("1")); + Assert.assertNull(map.get("2")); + map = map.getInstance(t, Long.MAX_VALUE); + map.put("1", "a"); + map.put("2", "b"); + t.commit(); + + Assert.assertEquals(2, map.sizeAsLong()); + } +} diff --git a/lealone-test/src/test/resources/META-INF/services/org.lealone.engine.StorageEngine b/lealone-test/src/test/resources/META-INF/services/org.lealone.storage.StorageEngine similarity index 100% rename from lealone-test/src/test/resources/META-INF/services/org.lealone.engine.StorageEngine rename to lealone-test/src/test/resources/META-INF/services/org.lealone.storage.StorageEngine diff --git a/lealone-transaction/pom.xml b/lealone-transaction/pom.xml index 5f8f9de87..fb5cb28f5 100644 --- a/lealone-transaction/pom.xml +++ b/lealone-transaction/pom.xml @@ -29,14 +29,9 @@ 1.0.0-SNAPSHOT - + org.lealone - lealone-mvdb - ${project.version} - - - org.lealone - lealone-storage-mvstore + lealone-common ${project.version} diff --git a/lealone-transaction/src/main/java/org/lealone/transaction/MVCCTransaction.java b/lealone-transaction/src/main/java/org/lealone/transaction/MVCCTransaction.java new file mode 100644 index 000000000..987f30633 --- /dev/null +++ b/lealone-transaction/src/main/java/org/lealone/transaction/MVCCTransaction.java @@ -0,0 +1,475 @@ +/* + * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0, + * and the EPL 1.0 (http://h2database.com/html/license.html). + * Initial Developer: H2 Group + */ +package org.lealone.transaction; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentSkipListSet; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import org.lealone.api.ErrorCode; +import org.lealone.message.DbException; +import org.lealone.storage.StorageMap; +import org.lealone.type.DataType; +import org.lealone.util.DataUtils; +import org.lealone.util.New; + +/** + * A transaction. + */ +public class MVCCTransaction implements Transaction { + + /** + * The status of a closed transaction (committed or rolled back). + */ + public static final int STATUS_CLOSED = 0; + + /** + * The status of an open transaction. + */ + public static final int STATUS_OPEN = 1; + + /** + * The status of a prepared transaction. + */ + public static final int STATUS_PREPARED = 2; + + /** + * The status of a transaction that is being committed, but possibly not + * yet finished. A transactions can go into this state when the store is + * closed while the transaction is committing. When opening a store, + * such transactions should be committed. + */ + public static final int STATUS_COMMITTING = 3; + + private static final ExecutorService executorService = Executors.newCachedThreadPool(); + + final MVCCTransactionEngine transactionEngine; + final int transactionId; + final String transactionName; + + /** + * The log id of the last entry in the undo log map. + */ + long logId; + + Validator validator; + + private String name; //用于2pc的事务名,未来会考虑删除,目前实际使用的是Lealone的分布式事务模型 + private int status; + private boolean autoCommit; + private boolean local = true; //默认是true,如果是分布式事务才设为false + + private long commitTimestamp; + + private HashMap savepoints; + + //协调者或参与者自身的本地事务名 + private StringBuilder localTransactionNamesBuilder; + //如果本事务是协调者中的事务,那么在此字段中存放其他参与者的本地事务名 + private ConcurrentSkipListSet participantLocalTransactionNames; + private List participants; + + MVCCTransaction(MVCCTransactionEngine engine, int tid, int status, String name, long logId) { + transactionEngine = engine; + transactionId = tid; + transactionName = getTransactionName(engine.hostAndPort, tid); + + this.status = status; + this.name = name; + this.logId = logId; + } + + @Override + public boolean isAutoCommit() { + return autoCommit; + } + + @Override + public void setAutoCommit(boolean autoCommit) { + this.autoCommit = autoCommit; + } + + @Override + public void setLocal(boolean local) { + this.local = local; + } + + /** + * 假设有RS1、RS2、RS3,Client启动的一个事务涉及这三个RS, + * 第一个接收到Client读写请求的RS即是协调者也是参与者,之后Client的任何读写请求都只会跟协调者打交道, + * 假设这里的协调者是RS1,当读写由RS1转发到RS2时,RS2在完成读写请求后会把它的本地事务名(可能有多个(嵌套事务)发回来, + * 此时协调者必须记下所有其他参与者的本地事务名。

+ * + * 如果本地事务名是null,代表参与者执行完读写请求后发现跟上次的本地事务名一样,为了减少网络传输就不再重发。 + */ + @Override + public void addLocalTransactionNames(String localTransactionNames) { + if (localTransactionNames != null) { + if (participantLocalTransactionNames == null) + participantLocalTransactionNames = new ConcurrentSkipListSet<>(); + for (String name : localTransactionNames.split(",")) + participantLocalTransactionNames.add(name.trim()); + } + } + + @Override + public String getLocalTransactionNames() { + StringBuilder buff = new StringBuilder(transactionName); + + if (participantLocalTransactionNames != null) { + for (String name : participantLocalTransactionNames) { + buff.append(','); + buff.append(name); + } + } + + if (localTransactionNamesBuilder != null && localTransactionNamesBuilder.equals(buff)) + return null; + localTransactionNamesBuilder = buff; + return buff.toString(); + } + + @Override + public void setValidator(Validator validator) { + this.validator = validator; + } + + @Override + public void addParticipant(Participant participant) { + if (participants == null) + participants = new ArrayList<>(); + participants.add(participant); + } + + /** + * Open a data map. + * + * @param the key type + * @param the value type + * @param name the name of the map + * @return the transaction map + */ + @Override + public MVCCTransactionMap openMap(String name) { + return openMap(name, null, null); + } + + /** + * Open the map to store the data. + * + * @param the key type + * @param the value type + * @param name the name of the map + * @param keyType the key data type + * @param valueType the value data type + * @return the transaction map + */ + @Override + public MVCCTransactionMap openMap(String name, DataType keyType, DataType valueType) { + checkNotClosed(); + StorageMap map = transactionEngine.openMap(name, keyType, valueType); + int mapId = map.getId(); + return new MVCCTransactionMap(this, map, mapId); + } + + @Override + public void addSavepoint(String name) { + if (savepoints == null) + savepoints = new HashMap<>(); + + savepoints.put(name, getSavepointId()); + + if (!isAutoCommit() && participants != null) + parallelSavepoint(true, name); + } + + @Override + public long getSavepointId() { + return logId; + } + + /** + * Commit the transaction. Afterwards, this transaction is closed. + */ + @Override + public void commit() { + if (local) + commitLocal(); + else + commit(null); + } + + @Override + public void commit(String allLocalTransactionNames) { + try { + if (allLocalTransactionNames == null) + allLocalTransactionNames = getAllLocalTransactionNames(); + List> futures = null; + if (!isAutoCommit() && participants != null) + futures = parallelCommitOrRollback(allLocalTransactionNames); + + commitLocalAndTransactionStatusTable(allLocalTransactionNames); + if (futures != null) + waitFutures(futures); + } finally { + endTransaction(); + } + } + + private void commitLocal() { + checkNotClosed(); + transactionEngine.commit(this, logId); + } + + private void commitLocalAndTransactionStatusTable(String allLocalTransactionNames) { + commitLocal(); + transactionEngine.commitTransactionStatusTable(this, allLocalTransactionNames); + } + + private void waitFutures(List> futures) { + try { + for (int i = 0, size = futures.size(); i < size; i++) { + futures.get(i).get(); + } + } catch (Exception e) { + throw DbException.convert(e); + } + } + + /** + * Roll the transaction back. Afterwards, this transaction is closed. + */ + @Override + public void rollback() { + try { + checkNotClosed(); + transactionEngine.rollbackTo(this, logId, 0); + transactionEngine.endTransaction(this); + } finally { + endTransaction(); + } + } + + @Override + public void rollbackToSavepoint(String name) { + if (savepoints == null) { + throw DbException.get(ErrorCode.SAVEPOINT_IS_INVALID_1, name); + } + + Long savepointId = savepoints.get(name); + if (savepointId == null) { + throw DbException.get(ErrorCode.SAVEPOINT_IS_INVALID_1, name); + } + long i = savepointId.longValue(); + rollbackToSavepoint(i); + + if (savepoints != null) { + String[] names = new String[savepoints.size()]; + savepoints.keySet().toArray(names); + for (String n : names) { + savepointId = savepoints.get(n); + if (savepointId.longValue() >= i) { + savepoints.remove(n); + } + } + } + + if (!isAutoCommit() && participants != null) + parallelSavepoint(false, name); + } + + /** + * Roll back to the given savepoint. This is only allowed if the + * transaction is open. + * + * @param savepointId the savepoint id + */ + @Override + public void rollbackToSavepoint(long savepointId) { + checkNotClosed(); + transactionEngine.rollbackTo(this, logId, savepointId); + logId = savepointId; + } + + public int getStatus() { + return status; + } + + void setStatus(int status) { + this.status = status; + } + + public void setName(String name) { + checkNotClosed(); + this.name = name; + transactionEngine.storeTransaction(this); + } + + public String getName() { + return name; + } + + long getCommitTimestamp() { + return commitTimestamp; + } + + void setCommitTimestamp(long commitTimestamp) { + this.commitTimestamp = commitTimestamp; + } + + /** + * Create a new savepoint. + * + * @return the savepoint id + */ + public long setSavepoint() { + return logId; + } + + /** + * Add a log entry. + * + * @param mapId the map id + * @param key the key + * @param oldValue the old value + */ + void log(int mapId, Object key, Object oldValue) { + transactionEngine.log(this, logId, mapId, key, oldValue); + // only increment the log id if logging was successful + logId++; + } + + /** + * Remove the last log entry. + */ + void logUndo() { + transactionEngine.logUndo(this, --logId); + } + + /** + * Prepare the transaction. Afterwards, the transaction can only be + * committed or rolled back. + */ + public void prepare() { + checkNotClosed(); + status = STATUS_PREPARED; + transactionEngine.storeTransaction(this); + } + + /** + * Get the list of changes, starting with the latest change, up to the + * given savepoint (in reverse order than they occurred). The value of + * the change is the value before the change was applied. + * + * @param savepointId the savepoint id, 0 meaning the beginning of the + * transaction + * @return the changes + */ + public Iterator getChanges(long savepointId) { + return transactionEngine.getChanges(this, logId, savepointId); + } + + /** + * Check whether this transaction is open or prepared. + */ + void checkNotClosed() { + if (status == STATUS_CLOSED) { + throw DataUtils.newIllegalStateException(DataUtils.ERROR_CLOSED, "Transaction is closed"); + } + } + + /** + * Remove the map. + * + * @param map the map + */ + public void removeMap(MVCCTransactionMap map) { + transactionEngine.removeMap(map); + } + + @Override + public String toString() { + return "" + transactionId; + } + + private void parallelSavepoint(final boolean add, final String name) { + int size = participants.size(); + List> futures = New.arrayList(size); + for (final Participant participant : participants) { + futures.add(executorService.submit(new Callable() { + @Override + public Void call() throws Exception { + if (add) + participant.addSavepoint(name); + else + participant.rollbackToSavepoint(name); + return null; + } + })); + } + try { + for (int i = 0; i < size; i++) { + futures.get(i).get(); + } + } catch (Exception e) { + throw DbException.convert(e); + } + } + + private String getAllLocalTransactionNames() { + getLocalTransactionNames(); + return localTransactionNamesBuilder.toString(); + } + + private void endTransaction() { + savepoints = null; + + // if (!session.getFrontendSessionCache().isEmpty()) { + // for (FrontendSession fs : session.getFrontendSessionCache().values()) { + // fs.setTransaction(null); + // FrontendSessionPool.release(fs); + // } + // + // session.getFrontendSessionCache().clear(); + // } + // + // if (!session.isRoot()) + // session.setAutoCommit(true); + } + + private List> parallelCommitOrRollback(final String allLocalTransactionNames) { + int size = participants.size(); + List> futures = New.arrayList(size); + for (final Participant participant : participants) { + futures.add(executorService.submit(new Callable() { + @Override + public Void call() throws Exception { + if (allLocalTransactionNames != null) + participant.commitTransaction(allLocalTransactionNames); + else + participant.rollbackTransaction(); + return null; + } + })); + } + return futures; + } + + static String getTransactionName(String hostAndPort, long tid) { + if (hostAndPort == null) + hostAndPort = "0:0"; + StringBuilder buff = new StringBuilder(hostAndPort); + buff.append(':'); + buff.append(tid); + return buff.toString(); + } +} \ No newline at end of file diff --git a/lealone-transaction/src/main/java/org/lealone/transaction/DefaultTransactionEngine.java b/lealone-transaction/src/main/java/org/lealone/transaction/MVCCTransactionEngine.java similarity index 76% rename from lealone-transaction/src/main/java/org/lealone/transaction/DefaultTransactionEngine.java rename to lealone-transaction/src/main/java/org/lealone/transaction/MVCCTransactionEngine.java index 3083943ef..46c0a27a3 100644 --- a/lealone-transaction/src/main/java/org/lealone/transaction/DefaultTransactionEngine.java +++ b/lealone-transaction/src/main/java/org/lealone/transaction/MVCCTransactionEngine.java @@ -9,26 +9,24 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; -import org.lealone.engine.Session; -import org.lealone.engine.StorageMap; -import org.lealone.engine.TransactionEngine; -import org.lealone.mvstore.MVStore; +import org.lealone.storage.StorageMap; import org.lealone.type.DataType; import org.lealone.type.ObjectDataType; import org.lealone.util.DataUtils; import org.lealone.util.New; /** - * The default transaction engine that supports concurrent MVCC read-committed transactions. + * The transaction engine that supports concurrent MVCC read-committed transactions. */ -public class DefaultTransactionEngine implements TransactionEngine { +public class MVCCTransactionEngine implements TransactionEngine { /** * The store. */ - public final MVStore store; + //public final MVStore store; /** * The persisted map of prepared transactions. @@ -68,16 +66,25 @@ public class DefaultTransactionEngine implements TransactionEngine { private final StorageMap.Builder mapBuilder; + final String hostAndPort; + + private final boolean isClusterMode; + /** * Create a new transaction engine. * - * @param store the store * @param dataType the data type for map keys and values */ - public DefaultTransactionEngine(MVStore store, DataType dataType, StorageMap.Builder mapBuilder) { - this.store = store; + public MVCCTransactionEngine(DataType dataType, StorageMap.Builder mapBuilder, String hostAndPort) { + this(dataType, mapBuilder, hostAndPort, false); + } + + public MVCCTransactionEngine(DataType dataType, StorageMap.Builder mapBuilder, String hostAndPort, + boolean isClusterMode) { this.dataType = dataType; this.mapBuilder = mapBuilder; + this.hostAndPort = hostAndPort; + this.isClusterMode = isClusterMode; preparedTransactions = mapBuilder.openMap("openTransactions"); VersionedValueType oldValueType = new VersionedValueType(dataType); @@ -87,6 +94,7 @@ public DefaultTransactionEngine(MVStore store, DataType dataType, StorageMap.Bui throw DataUtils.newIllegalStateException(DataUtils.ERROR_TRANSACTION_CORRUPT, "Undo map open with a different value type"); } + } /** @@ -94,14 +102,16 @@ public DefaultTransactionEngine(MVStore store, DataType dataType, StorageMap.Bui * If the transaction store is corrupt, this method can throw an exception, * in which case the store can only be used for reading. */ - public synchronized void init() { + public synchronized void init(Set storageMapNames) { init = true; // remove all temporary maps - for (String mapName : store.getMapNames()) { - if (mapName.startsWith("temp.")) { - StorageMap temp = openTempMap(mapName); - store.removeMap(temp); + if (storageMapNames != null) { + for (String mapName : storageMapNames) { + if (mapName.startsWith("temp.")) { + StorageMap temp = openTempMap(mapName); + temp.remove(); + } } } synchronized (undoLog) { @@ -110,6 +120,11 @@ public synchronized void init() { lastTransactionId.set(getTransactionId(key)); } } + + TransactionStatusTable.init(mapBuilder); + + if (isClusterMode) + TransactionValidator.getInstance().start(); } /** @@ -162,9 +177,9 @@ static long getLogId(long operationId) { * * @return the list of transactions (sorted by id) */ - public List getOpenTransactions(Session session) { + public List getOpenTransactions() { synchronized (undoLog) { - ArrayList list = New.arrayList(); + ArrayList list = New.arrayList(); Long key = undoLog.firstKey(); while (key != null) { int transactionId = getTransactionId(key); @@ -175,16 +190,16 @@ public List getOpenTransactions(Session session) { String name; if (data == null) { if (undoLog.containsKey(getOperationId(transactionId, 0))) { - status = Transaction.STATUS_OPEN; + status = MVCCTransaction.STATUS_OPEN; } else { - status = Transaction.STATUS_COMMITTING; + status = MVCCTransaction.STATUS_COMMITTING; } name = null; } else { status = (Integer) data[0]; name = (String) data[1]; } - Transaction t = new Transaction(session, this, transactionId, status, name, logId); + MVCCTransaction t = new MVCCTransaction(this, transactionId, status, name, logId); list.add(t); key = undoLog.ceilingKey(getOperationId(transactionId + 1, 0)); } @@ -192,16 +207,9 @@ public List getOpenTransactions(Session session) { } } - /** - * Close the transaction store. - */ - public synchronized void close() { - store.commit(); - } - - private int nextTransactionId(Session session) { + private int nextTransactionId(boolean autoCommit) { //分布式事务使用奇数的事务ID - if (!session.isAutoCommit() && Session.isClusterMode()) { + if (!autoCommit && isClusterMode) { return nextOddTransactionId(); } @@ -254,11 +262,21 @@ private int nextEvenTransactionId() { * @return the transaction */ @Override - public Transaction beginTransaction(Session session) { + public MVCCTransaction beginTransaction(boolean autoCommit) { if (!init) { throw DataUtils.newIllegalStateException(DataUtils.ERROR_TRANSACTION_ILLEGAL_STATE, "Not initialized"); } - return new Transaction(session, this, nextTransactionId(session), Transaction.STATUS_OPEN, null, 0); + int tid = nextTransactionId(autoCommit); + MVCCTransaction t = new MVCCTransaction(this, tid, MVCCTransaction.STATUS_OPEN, null, 0); + t.setAutoCommit(autoCommit); + return t; + } + + @Override + public void close() { + //store.commit(); + if (isClusterMode) + TransactionValidator.getInstance().close(); } /** @@ -266,10 +284,10 @@ public Transaction beginTransaction(Session session) { * * @param t the transaction */ - synchronized void storeTransaction(Transaction t) { - if (t.getStatus() == Transaction.STATUS_PREPARED || t.getName() != null) { + synchronized void storeTransaction(MVCCTransaction t) { + if (t.getStatus() == MVCCTransaction.STATUS_PREPARED || t.getName() != null) { Object[] v = { t.getStatus(), t.getName() }; - preparedTransactions.put(t.getId(), v); + preparedTransactions.put(t.transactionId, v); } } @@ -282,14 +300,14 @@ synchronized void storeTransaction(Transaction t) { * @param key the key * @param oldValue the old value */ - void log(Transaction t, long logId, int mapId, Object key, Object oldValue) { - Long undoKey = getOperationId(t.getId(), logId); + void log(MVCCTransaction t, long logId, int mapId, Object key, Object oldValue) { + Long undoKey = getOperationId(t.transactionId, logId); Object[] log = new Object[] { mapId, key, oldValue }; synchronized (undoLog) { if (logId == 0) { if (undoLog.containsKey(undoKey)) { throw DataUtils.newIllegalStateException(DataUtils.ERROR_TRANSACTION_STILL_OPEN, - "An old transaction with the same id " + "is still open: {0}", t.getId()); + "An old transaction with the same id " + "is still open: {0}", t.transactionId); } } undoLog.put(undoKey, log); @@ -302,13 +320,13 @@ void log(Transaction t, long logId, int mapId, Object key, Object oldValue) { * @param t the transaction * @param logId the log id */ - public void logUndo(Transaction t, long logId) { - Long undoKey = getOperationId(t.getId(), logId); + public void logUndo(MVCCTransaction t, long logId) { + Long undoKey = getOperationId(t.transactionId, logId); synchronized (undoLog) { Object[] old = undoLog.remove(undoKey); if (old == null) { throw DataUtils.newIllegalStateException(DataUtils.ERROR_TRANSACTION_ILLEGAL_STATE, - "Transaction {0} was concurrently rolled back", t.getId()); + "Transaction {0} was concurrently rolled back", t.transactionId); } } } @@ -320,9 +338,10 @@ public void logUndo(Transaction t, long logId) { * @param the value type * @param map the map */ - public synchronized void removeMap(DefaultTransactionMap map) { + public synchronized void removeMap(MVCCTransactionMap map) { maps.remove(map.mapId); - store.removeMap(map.map); + map.removeMap(); + //store.removeMap(map.map); } /** @@ -331,23 +350,23 @@ public synchronized void removeMap(DefaultTransactionMap map) { * @param t the transaction * @param maxLogId the last log id */ - void commit(Transaction t, long maxLogId) { - if (store.isClosed()) { - return; - } + void commit(MVCCTransaction t, long maxLogId) { + // if (store.isClosed()) { + // return; + // } //分布式事务推迟删除undoLog if (t.transactionId % 2 == 0) { - removeUndoLog(t.getId(), maxLogId); + removeUndoLog(t.transactionId, maxLogId); } endTransaction(t); } public void commitAfterValidate(int tid) { - if (store.isClosed()) { - return; - } + // if (store.isClosed()) { + // return; + // } removeUndoLog(tid, Long.MAX_VALUE); } @@ -428,7 +447,7 @@ synchronized StorageMap openMap(int mapId) { if (map != null) { return map; } - String mapName = store.getMapName(mapId); + String mapName = mapBuilder.getMapName(mapId); if (mapName == null) { // the map was removed later on return null; @@ -464,26 +483,26 @@ StorageMap openTempMap(String mapName) { * * @param t the transaction */ - synchronized void endTransaction(Transaction t) { - if (t.getStatus() == Transaction.STATUS_PREPARED) { - preparedTransactions.remove(t.getId()); - } - t.setStatus(Transaction.STATUS_CLOSED); - if (store.getAutoCommitDelay() == 0) { - store.commit(); - return; - } - // to avoid having to store the transaction log, - // if there is no open transaction, - // and if there have been many changes, store them now - if (undoLog.isEmpty()) { - int unsaved = store.getUnsavedMemory(); - int max = store.getAutoCommitMemory(); - // save at 3/4 capacity - if (unsaved * 4 > max * 3) { - store.commit(); - } + synchronized void endTransaction(MVCCTransaction t) { + if (t.getStatus() == MVCCTransaction.STATUS_PREPARED) { + preparedTransactions.remove(t.transactionId); } + t.setStatus(MVCCTransaction.STATUS_CLOSED); + // if (store.getAutoCommitDelay() == 0) { + // store.commit(); + // return; + // } + // // to avoid having to store the transaction log, + // // if there is no open transaction, + // // and if there have been many changes, store them now + // if (undoLog.isEmpty()) { + // int unsaved = store.getUnsavedMemory(); + // int max = store.getAutoCommitMemory(); + // // save at 3/4 capacity + // if (unsaved * 4 > max * 3) { + // store.commit(); + // } + // } } /** @@ -493,16 +512,16 @@ synchronized void endTransaction(Transaction t) { * @param maxLogId the last log id * @param toLogId the log id to roll back to */ - void rollbackTo(Transaction t, long maxLogId, long toLogId) { + void rollbackTo(MVCCTransaction t, long maxLogId, long toLogId) { // TODO could synchronize on blocks (100 at a time or so) synchronized (undoLog) { for (long logId = maxLogId - 1; logId >= toLogId; logId--) { - Long undoKey = getOperationId(t.getId(), logId); + Long undoKey = getOperationId(t.transactionId, logId); Object[] op = undoLog.get(undoKey); if (op == null) { // partially rolled back: load previous undoKey = undoLog.floorKey(undoKey); - if (undoKey == null || getTransactionId(undoKey) != t.getId()) { + if (undoKey == null || getTransactionId(undoKey) != t.transactionId) { break; } logId = getLogId(undoKey) + 1; @@ -535,7 +554,7 @@ void rollbackTo(Transaction t, long maxLogId, long toLogId) { * @param toLogId the minimum log id * @return the changes */ - Iterator getChanges(final Transaction t, final long maxLogId, final long toLogId) { + Iterator getChanges(final MVCCTransaction t, final long maxLogId, final long toLogId) { return new Iterator() { private long logId = maxLogId - 1; @@ -548,13 +567,13 @@ Iterator getChanges(final Transaction t, final long maxLogId, final long private void fetchNext() { synchronized (undoLog) { while (logId >= toLogId) { - Long undoKey = getOperationId(t.getId(), logId); + Long undoKey = getOperationId(t.transactionId, logId); Object[] op = undoLog.get(undoKey); logId--; if (op == null) { // partially rolled back: load previous undoKey = undoLog.floorKey(undoKey); - if (undoKey == null || getTransactionId(undoKey) != t.getId()) { + if (undoKey == null || getTransactionId(undoKey) != t.transactionId) { break; } logId = getLogId(undoKey); @@ -600,16 +619,18 @@ public void remove() { }; } - void commitTransactionStatusTable(Transaction t, String allLocalTransactionNames) { + void commitTransactionStatusTable(MVCCTransaction t, String allLocalTransactionNames) { t.setCommitTimestamp(nextOddTransactionId()); TransactionStatusTable.commit(t, allLocalTransactionNames); + TransactionValidator.getInstance().enqueue(this, t, allLocalTransactionNames); + } - Session s = t.getSession(); - TransactionValidator.getInstance().enqueue(s.getDatabase().getShortName(), this, t.getId(), - s.getOriginalProperties(), allLocalTransactionNames); + boolean validateTransaction(Transaction.Validator validator, int tid, MVCCTransaction currentTransaction) { + return TransactionStatusTable.isValid(validator, hostAndPort, tid, currentTransaction); } - boolean validateTransaction(Session session, int tid, Transaction currentTransaction) { - return TransactionStatusTable.isValid(session, TransactionManager.getHostAndPort(), tid, currentTransaction); + @Override + public boolean isValid(String localTransactionName) { + return TransactionStatusTable.isValid(localTransactionName); } } diff --git a/lealone-transaction/src/main/java/org/lealone/transaction/DefaultTransactionMap.java b/lealone-transaction/src/main/java/org/lealone/transaction/MVCCTransactionMap.java similarity index 92% rename from lealone-transaction/src/main/java/org/lealone/transaction/DefaultTransactionMap.java rename to lealone-transaction/src/main/java/org/lealone/transaction/MVCCTransactionMap.java index cdfe22701..afcb79c65 100644 --- a/lealone-transaction/src/main/java/org/lealone/transaction/DefaultTransactionMap.java +++ b/lealone-transaction/src/main/java/org/lealone/transaction/MVCCTransactionMap.java @@ -8,9 +8,7 @@ import java.util.Iterator; import java.util.Map.Entry; -import org.lealone.engine.Session; -import org.lealone.engine.StorageMap; -import org.lealone.engine.TransactionMap; +import org.lealone.storage.StorageMap; import org.lealone.type.DataType; import org.lealone.util.DataUtils; @@ -20,7 +18,7 @@ * @param the key type * @param the value type */ -public class DefaultTransactionMap implements TransactionMap { +public class MVCCTransactionMap implements TransactionMap { /** * The map id. @@ -43,9 +41,9 @@ public class DefaultTransactionMap implements TransactionMap { */ public final StorageMap map; - private final Transaction transaction; + private final MVCCTransaction transaction; - DefaultTransactionMap(Transaction transaction, StorageMap map, int mapId) { + MVCCTransactionMap(MVCCTransaction transaction, StorageMap map, int mapId) { this.transaction = transaction; this.map = map; this.mapId = mapId; @@ -68,8 +66,9 @@ public void setSavepoint(long savepoint) { * @param savepoint the savepoint * @return the map */ - public DefaultTransactionMap getInstance(Transaction transaction, long savepoint) { - DefaultTransactionMap m = new DefaultTransactionMap(transaction, map, mapId); + @Override + public TransactionMap getInstance(Transaction transaction, long savepoint) { + MVCCTransactionMap m = new MVCCTransactionMap((MVCCTransaction) transaction, map, mapId); m.setSavepoint(savepoint); return m; } @@ -105,7 +104,7 @@ public long sizeAsLong() { // the undo log is larger than the map - // count the entries of the map long size = 0; - org.lealone.engine.StorageMap.Cursor cursor = map.cursor(null); + org.lealone.storage.StorageMap.Cursor cursor = map.cursor(null); while (cursor.hasNext()) { K key = cursor.next(); VersionedValue data = cursor.getValue(); @@ -142,7 +141,8 @@ public long sizeAsLong() { } } } finally { - transaction.transactionEngine.store.removeMap(temp); + //transaction.transactionEngine.store.removeMap(temp); + temp.remove(); } return size; } @@ -251,7 +251,7 @@ public boolean trySet(K key, V value, boolean onlyIfUnchanged) { if (onlyIfUnchanged) { VersionedValue old = getValue(key, readLogId); if (!map.areValuesEqual(old, current)) { - long tx = DefaultTransactionEngine.getTransactionId(current.operationId); + long tx = MVCCTransactionEngine.getTransactionId(current.operationId); if (tx == transaction.transactionId) { if (value == null) { // ignore removing an entry @@ -270,7 +270,7 @@ public boolean trySet(K key, V value, boolean onlyIfUnchanged) { } } VersionedValue newValue = new VersionedValue(); - newValue.operationId = DefaultTransactionEngine.getOperationId(transaction.transactionId, transaction.logId); + newValue.operationId = MVCCTransactionEngine.getOperationId(transaction.transactionId, transaction.logId); newValue.value = value; if (current == null) { // a new value @@ -295,7 +295,7 @@ public boolean trySet(K key, V value, boolean onlyIfUnchanged) { } return true; } - int tx = DefaultTransactionEngine.getTransactionId(current.operationId); + int tx = MVCCTransactionEngine.getTransactionId(current.operationId); if (tx == transaction.transactionId) { // added or updated by this transaction transaction.log(mapId, key, current); @@ -309,8 +309,7 @@ public boolean trySet(K key, V value, boolean onlyIfUnchanged) { } if (tx % 2 == 1) { - boolean isValid = transaction.transactionEngine.validateTransaction(transaction.getSession(), tx, - transaction); + boolean isValid = transaction.transactionEngine.validateTransaction(transaction.validator, tx, transaction); if (isValid) { transaction.transactionEngine.commitAfterValidate(tx); return trySet(key, value, onlyIfUnchanged); @@ -379,7 +378,7 @@ public boolean isSameTransaction(K key) { // doesn't exist or deleted by a committed transaction return false; } - int tx = DefaultTransactionEngine.getTransactionId(data.operationId); + int tx = MVCCTransactionEngine.getTransactionId(data.operationId); return tx == transaction.transactionId; } @@ -407,16 +406,16 @@ VersionedValue getValue(K key, long maxLog, VersionedValue data) { // it is committed return data; } - int tx = DefaultTransactionEngine.getTransactionId(id); + int tx = MVCCTransactionEngine.getTransactionId(id); if (tx == transaction.transactionId) { // added by this transaction - if (DefaultTransactionEngine.getLogId(id) < maxLog) { + if (MVCCTransactionEngine.getLogId(id) < maxLog) { return data; } } if (tx % 2 == 1) { - boolean isValid = transaction.transactionEngine.validateTransaction(transaction.getSession(), tx, + boolean isValid = transaction.transactionEngine.validateTransaction(transaction.validator, tx, transaction); if (isValid) { transaction.transactionEngine.commitAfterValidate(tx); @@ -571,7 +570,7 @@ public Iterator keyIterator(K from) { public Iterator keyIterator(final K from, final boolean includeUncommitted) { return new Iterator() { private K currentKey = from; - private org.lealone.engine.StorageMap.Cursor cursor = map.cursor(currentKey); + private org.lealone.storage.StorageMap.Cursor cursor = map.cursor(currentKey); { fetchNext(); @@ -641,7 +640,7 @@ public Iterator> entryIterator(final K from) { return new Iterator>() { private Entry current; private K currentKey = from; - private org.lealone.engine.StorageMap.Cursor cursor = map.cursor(currentKey); + private org.lealone.storage.StorageMap.Cursor cursor = map.cursor(currentKey); { fetchNext(); @@ -765,13 +764,7 @@ public void setVolatile(boolean isVolatile) { } @Override - public TransactionMap getInstance(Session session, long savepoint) { - return getInstance((Transaction) session.getTransaction(), savepoint); - } - - @Override - public void removeMap(Session session) { + public void removeMap() { map.remove(); } - -} \ No newline at end of file +} diff --git a/lealone-transaction/src/main/java/org/lealone/transaction/Transaction.java b/lealone-transaction/src/main/java/org/lealone/transaction/Transaction.java deleted file mode 100644 index ad2bb66c9..000000000 --- a/lealone-transaction/src/main/java/org/lealone/transaction/Transaction.java +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0, - * and the EPL 1.0 (http://h2database.com/html/license.html). - * Initial Developer: H2 Group - */ -package org.lealone.transaction; - -import java.util.Iterator; - -import org.lealone.engine.Session; -import org.lealone.engine.StorageMap; -import org.lealone.type.DataType; -import org.lealone.util.DataUtils; - -/** - * A transaction. - */ -public class Transaction extends TransactionBase { - - /** - * The status of a closed transaction (committed or rolled back). - */ - public static final int STATUS_CLOSED = 0; - - /** - * The status of an open transaction. - */ - public static final int STATUS_OPEN = 1; - - /** - * The status of a prepared transaction. - */ - public static final int STATUS_PREPARED = 2; - - /** - * The status of a transaction that is being committed, but possibly not - * yet finished. A transactions can go into this state when the store is - * closed while the transaction is committing. When opening a store, - * such transactions should be committed. - */ - public static final int STATUS_COMMITTING = 3; - - /** - * The transaction engine. - */ - final DefaultTransactionEngine transactionEngine; - - /** - * The transaction id. - */ - final int transactionId; - - /** - * The log id of the last entry in the undo log map. - */ - long logId; - - private int status; - - private String name; - - Transaction(Session session, DefaultTransactionEngine engine, int tid, int status, String name, long logId) { - super(session); - this.transactionEngine = engine; - this.transactionId = tid; - this.status = status; - this.name = name; - this.logId = logId; - - super.transactionId = tid; - transactionName = getTransactionName(TransactionManager.getHostAndPort(), transactionId); - } - - public int getId() { - return transactionId; - } - - public int getStatus() { - return status; - } - - void setStatus(int status) { - this.status = status; - } - - public void setName(String name) { - checkNotClosed(); - this.name = name; - transactionEngine.storeTransaction(this); - } - - public String getName() { - return name; - } - - /** - * Create a new savepoint. - * - * @return the savepoint id - */ - public long setSavepoint() { - return logId; - } - - /** - * Add a log entry. - * - * @param mapId the map id - * @param key the key - * @param oldValue the old value - */ - void log(int mapId, Object key, Object oldValue) { - transactionEngine.log(this, logId, mapId, key, oldValue); - // only increment the log id if logging was successful - logId++; - } - - /** - * Remove the last log entry. - */ - void logUndo() { - transactionEngine.logUndo(this, --logId); - } - - /** - * Open a data map. - * - * @param the key type - * @param the value type - * @param name the name of the map - * @return the transaction map - */ - public DefaultTransactionMap openMap(String name) { - return openMap(name, null, null); - } - - /** - * Open the map to store the data. - * - * @param the key type - * @param the value type - * @param name the name of the map - * @param keyType the key data type - * @param valueType the value data type - * @return the transaction map - */ - public DefaultTransactionMap openMap(String name, DataType keyType, DataType valueType) { - checkNotClosed(); - StorageMap map = transactionEngine.openMap(name, keyType, valueType); - int mapId = map.getId(); - return new DefaultTransactionMap(this, map, mapId); - } - - /** - * Open the transactional version of the given map. - * - * @param the key type - * @param the value type - * @param map the base map - * @return the transactional map - */ - public DefaultTransactionMap openMap(StorageMap map) { - checkNotClosed(); - int mapId = map.getId(); - return new DefaultTransactionMap(this, map, mapId); - } - - /** - * Prepare the transaction. Afterwards, the transaction can only be - * committed or rolled back. - */ - public void prepare() { - checkNotClosed(); - status = STATUS_PREPARED; - transactionEngine.storeTransaction(this); - } - - /** - * Get the list of changes, starting with the latest change, up to the - * given savepoint (in reverse order than they occurred). The value of - * the change is the value before the change was applied. - * - * @param savepointId the savepoint id, 0 meaning the beginning of the - * transaction - * @return the changes - */ - public Iterator getChanges(long savepointId) { - return transactionEngine.getChanges(this, logId, savepointId); - } - - /** - * Check whether this transaction is open or prepared. - */ - void checkNotClosed() { - if (status == STATUS_CLOSED) { - throw DataUtils.newIllegalStateException(DataUtils.ERROR_CLOSED, "Transaction is closed"); - } - } - - /** - * Remove the map. - * - * @param map the map - */ - public void removeMap(DefaultTransactionMap map) { - transactionEngine.removeMap(map); - } - - @Override - public String toString() { - return "" + transactionId; - } - - /** - * Commit the transaction. Afterwards, this transaction is closed. - */ - @Override - public void commit() { - if (session.isLocal()) - commit0(); - else - commit(null); - } - - private void commit0() { - checkNotClosed(); - transactionEngine.commit(this, logId); - } - - @Override - protected void commitLocal(String allLocalTransactionNames) { - commit0(); - transactionEngine.commitTransactionStatusTable(this, allLocalTransactionNames); - } - - @Override - public long getSavepointId() { - return logId; - } - - /** - * Roll back to the given savepoint. This is only allowed if the - * transaction is open. - * - * @param savepointId the savepoint id - */ - @Override - public void rollbackToSavepoint(long savepointId) { - checkNotClosed(); - transactionEngine.rollbackTo(this, logId, savepointId); - logId = savepointId; - } - - /** - * Roll the transaction back. Afterwards, this transaction is closed. - */ - @Override - public void rollback() { - try { - checkNotClosed(); - transactionEngine.rollbackTo(this, logId, 0); - transactionEngine.endTransaction(this); - } finally { - endTransaction(); - } - } -} \ No newline at end of file diff --git a/lealone-transaction/src/main/java/org/lealone/transaction/TransactionBase.java b/lealone-transaction/src/main/java/org/lealone/transaction/TransactionBase.java deleted file mode 100644 index 50e02651f..000000000 --- a/lealone-transaction/src/main/java/org/lealone/transaction/TransactionBase.java +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.lealone.transaction; - -import java.util.HashMap; -import java.util.List; -import java.util.concurrent.Callable; -import java.util.concurrent.ConcurrentSkipListSet; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; - -import org.lealone.api.ErrorCode; -import org.lealone.command.router.FrontendSessionPool; -import org.lealone.engine.FrontendSession; -import org.lealone.engine.Session; -import org.lealone.message.DbException; -import org.lealone.transaction.TransactionInterface; -import org.lealone.util.New; - -public abstract class TransactionBase implements TransactionInterface { - - protected static final ExecutorService executorService = Executors.newCachedThreadPool(); - - protected final Session session; - protected final boolean autoCommit; - - protected long transactionId; - protected String transactionName; - protected long commitTimestamp; - protected HashMap savepoints; - - //协调者或参与者自身的本地事务名 - protected StringBuilder localTransactionNamesBuilder; - //如果本事务是协调者中的事务,那么在此字段中存放其他参与者的本地事务名 - protected final ConcurrentSkipListSet participantLocalTransactionNames = new ConcurrentSkipListSet<>(); - - protected TransactionBase(Session session) { - this.session = session; - autoCommit = session.isAutoCommit(); - } - - public Session getSession() { - return session; - } - - @Override - public long getTransactionId() { - return transactionId; - } - - @Override - public long getCommitTimestamp() { - return commitTimestamp; - } - - public void setCommitTimestamp(long commitTimestamp) { - this.commitTimestamp = commitTimestamp; - } - - @Override - public boolean isAutoCommit() { - return autoCommit; - } - - @Override - public void addSavepoint(String name) { - if (savepoints == null) - savepoints = session.getDatabase().newStringMap(); - - savepoints.put(name, getSavepointId()); - - if (!isAutoCommit() && session.getFrontendSessionCache().size() > 0) - parallelSavepoint(true, name); - } - - @Override - public void rollbackToSavepoint(String name) { - if (savepoints == null) { - throw DbException.get(ErrorCode.SAVEPOINT_IS_INVALID_1, name); - } - - Long savepointId = savepoints.get(name); - if (savepointId == null) { - throw DbException.get(ErrorCode.SAVEPOINT_IS_INVALID_1, name); - } - long i = savepointId.longValue(); - rollbackToSavepoint(i); - - if (savepoints != null) { - String[] names = new String[savepoints.size()]; - savepoints.keySet().toArray(names); - for (String n : names) { - savepointId = savepoints.get(n); - if (savepointId.longValue() >= i) { - savepoints.remove(n); - } - } - } - - if (!isAutoCommit() && session.getFrontendSessionCache().size() > 0) - parallelSavepoint(false, name); - } - - private void parallelSavepoint(final boolean add, final String name) { - int size = session.getFrontendSessionCache().size(); - List> futures = New.arrayList(size); - for (final FrontendSession fs : session.getFrontendSessionCache().values()) { - futures.add(executorService.submit(new Callable() { - @Override - public Void call() throws Exception { - if (add) - fs.addSavepoint(name); - else - fs.rollbackToSavepoint(name); - return null; - } - })); - } - try { - for (int i = 0; i < size; i++) { - futures.get(i).get(); - } - } catch (Exception e) { - throw DbException.convert(e); - } - } - - public String getTransactionName() { - return transactionName; - } - - public String getAllLocalTransactionNames() { - getLocalTransactionNames(); - return localTransactionNamesBuilder.toString(); - } - - /** - * 假设有RS1、RS2、RS3,Client启动的一个事务涉及这三个RS, - * 第一个接收到Client读写请求的RS即是协调者也是参与者,之后Client的任何读写请求都只会跟协调者打交道, - * 假设这里的协调者是RS1,当读写由RS1转发到RS2时,RS2在完成读写请求后会把它的本地事务名(可能有多个(嵌套事务)发回来, - * 此时协调者必须记下所有其他参与者的本地事务名。

- * - * 如果本地事务名是null,代表参与者执行完读写请求后发现跟上次的本地事务名一样,为了减少网络传输就不再重发。 - */ - @Override - public void addLocalTransactionNames(String localTransactionNames) { - if (localTransactionNames != null) { - for (String name : localTransactionNames.split(",")) - participantLocalTransactionNames.add(name.trim()); - } - } - - @Override - public String getLocalTransactionNames() { - if (transactionName == null) - transactionName = TransactionManager.getHostAndPort() + ":" + transactionId; - StringBuilder buff = new StringBuilder(transactionName); - - if (!participantLocalTransactionNames.isEmpty()) { - for (String name : participantLocalTransactionNames) { - buff.append(','); - buff.append(name); - } - } - - if (localTransactionNamesBuilder != null && localTransactionNamesBuilder.equals(buff)) - return null; - localTransactionNamesBuilder = buff; - return buff.toString(); - } - - protected void endTransaction() { - savepoints = null; - - if (!session.getFrontendSessionCache().isEmpty()) { - for (FrontendSession fs : session.getFrontendSessionCache().values()) { - fs.setTransaction(null); - FrontendSessionPool.release(fs); - } - - session.getFrontendSessionCache().clear(); - } - - if (!session.isRoot()) - session.setAutoCommit(true); - } - - protected List> parallelCommitOrRollback(final String allLocalTransactionNames) { - int size = session.getFrontendSessionCache().size(); - List> futures = New.arrayList(size); - for (final FrontendSession fs : session.getFrontendSessionCache().values()) { - futures.add(executorService.submit(new Callable() { - @Override - public Void call() throws Exception { - if (allLocalTransactionNames != null) - fs.commitTransaction(allLocalTransactionNames); - else - fs.rollbackTransaction(); - return null; - } - })); - } - return futures; - } - - protected void waitFutures(List> futures) { - try { - for (int i = 0, size = futures.size(); i < size; i++) { - futures.get(i).get(); - } - } catch (Exception e) { - throw DbException.convert(e); - } - } - - @Override - public void commit() { - commit(null); - } - - @Override - public void commit(String allLocalTransactionNames) { - try { - if (allLocalTransactionNames == null) - allLocalTransactionNames = getAllLocalTransactionNames(); - List> futures = null; - if (!isAutoCommit() && session.getFrontendSessionCache().size() > 0) - futures = parallelCommitOrRollback(allLocalTransactionNames); - - commitLocal(allLocalTransactionNames); - if (futures != null) - waitFutures(futures); - } finally { - endTransaction(); - } - } - - protected abstract void commitLocal(String allLocalTransactionNames); - - public static String getTransactionName(String hostAndPort, long tid) { - if (hostAndPort == null) - hostAndPort = "0:0"; - StringBuilder buff = new StringBuilder(hostAndPort); - buff.append(':'); - buff.append(tid); - return buff.toString(); - } -} diff --git a/lealone-transaction/src/main/java/org/lealone/transaction/TransactionManager.java b/lealone-transaction/src/main/java/org/lealone/transaction/TransactionManager.java deleted file mode 100644 index ad745fae5..000000000 --- a/lealone-transaction/src/main/java/org/lealone/transaction/TransactionManager.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.lealone.transaction; - -import java.lang.Thread.UncaughtExceptionHandler; - -import org.lealone.command.router.Router; -import org.lealone.engine.Constants; -import org.lealone.engine.Session; -import org.lealone.engine.SysProperties; -import org.lealone.engine.SystemDatabase; -import org.lealone.fs.FileUtils; -import org.lealone.mvstore.MVStore; -import org.lealone.mvstore.MVStoreCache; -import org.lealone.mvstore.MVStoreTool; - -public class TransactionManager { - private static MVStore store; - private static String hostAndPort; - - public static String getHostAndPort() { - return hostAndPort; - } - - public static synchronized void init(String baseDir, String host, int port) { - if (store != null) - return; - - hostAndPort = host + ":" + port; - - Router r = Session.getRouter(); - if (!(r instanceof TransactionalRouter)) { - Session.setRouter(new TransactionalRouter(r)); - } - - initStore(baseDir); - - TransactionStatusTable.init(store); - if (Session.isClusterMode()) { - TransactionValidator.getInstance().start(); - } - } - - public static synchronized void close() { - if (store == null) - return; - - store = null; - hostAndPort = null; - if (Session.isClusterMode()) { - TransactionValidator.getInstance().close(); - } - store.close(); - } - - private static void initStore(String baseDir) { - if (baseDir == null) { - baseDir = SysProperties.getBaseDir(); - - if (baseDir == null) - baseDir = "."; - } - - String fileName = FileUtils.toRealPath(baseDir + "/" + SystemDatabase.NAME) + Constants.SUFFIX_MV_FILE; - - if (MVStoreCache.getMVStore(fileName) != null) { - store = MVStoreCache.getMVStore(fileName); - return; - } - MVStoreTool.compactCleanUp(fileName); - MVStore.Builder builder = new MVStore.Builder(); - builder.fileName(fileName); - - // possibly create the directory - boolean exists = FileUtils.exists(fileName); - if (exists && !FileUtils.canWrite(fileName)) { - // read only - } else { - String dir = FileUtils.getParent(fileName); - FileUtils.createDirectories(dir); - } - builder.backgroundExceptionHandler(new UncaughtExceptionHandler() { - @Override - public void uncaughtException(Thread t, Throwable e) { - //TODO - } - }); - - store = builder.open(); - } -} diff --git a/lealone-transaction/src/main/java/org/lealone/transaction/TransactionStatusTable.java b/lealone-transaction/src/main/java/org/lealone/transaction/TransactionStatusTable.java index abfb9edbd..769a3de60 100644 --- a/lealone-transaction/src/main/java/org/lealone/transaction/TransactionStatusTable.java +++ b/lealone-transaction/src/main/java/org/lealone/transaction/TransactionStatusTable.java @@ -19,15 +19,10 @@ import java.util.Map; -import org.lealone.command.router.FrontendSessionPool; -import org.lealone.engine.FrontendSession; -import org.lealone.engine.Session; -import org.lealone.message.DbException; -import org.lealone.mvstore.MVMap; -import org.lealone.mvstore.MVStore; +import org.lealone.storage.StorageMap; import org.lealone.util.New; -public class TransactionStatusTable { +class TransactionStatusTable { private TransactionStatusTable() { } @@ -39,17 +34,17 @@ private TransactionStatusTable() { * The persisted map of transactionStatusTable. * Key: transaction_name, value: [ all_local_transaction_names, commit_timestamp ]. */ - private static MVMap map; + private static StorageMap map; - synchronized static void init(MVStore store) { + synchronized static void init(StorageMap.Builder mapBuilder) { if (map != null) return; - map = store.openMap("transactionStatusTable", new MVMap.Builder()); + map = mapBuilder.openMap("transactionStatusTable"); } - public static void commit(TransactionBase transaction, String allLocalTransactionNames) { + public static void commit(MVCCTransaction transaction, String allLocalTransactionNames) { Object[] v = { allLocalTransactionNames, transaction.getCommitTimestamp() }; - map.put(transaction.getTransactionName(), v); + map.put(transaction.transactionName, v); } private static TransactionStatusCache newCache(String hostAndPort) { @@ -72,8 +67,8 @@ private static TransactionStatusCache newCache(String hostAndPort) { * @param currentTransaction 当前事务 * @return true 有效 */ - public static boolean isValid(Session session, String hostAndPort, long oldTid, - TransactionInterface currentTransaction) { + public static boolean isValid(Transaction.Validator validator, String hostAndPort, long oldTid, + MVCCTransaction currentTransaction) { TransactionStatusCache cache = hostAndPortMap.get(hostAndPort); if (cache == null) { cache = newCache(hostAndPort); @@ -84,9 +79,9 @@ public static boolean isValid(Session session, String hostAndPort, long oldTid, return false; //2. 是有效的事务记录,再进一步判断是否小于等于当前事务的开始时间戳 if (commitTimestamp != -1) - return commitTimestamp <= currentTransaction.getTransactionId(); + return commitTimestamp <= currentTransaction.transactionId; - String oldTransactionName = TransactionBase.getTransactionName(hostAndPort, oldTid); + String oldTransactionName = MVCCTransaction.getTransactionName(hostAndPort, oldTid); Object[] v = map.get(oldTransactionName); @@ -96,7 +91,7 @@ public static boolean isValid(Session session, String hostAndPort, long oldTid, for (String localTransactionName : allLocalTransactionNames) { if (!oldTransactionName.equals(localTransactionName)) { - if (!validate(session, localTransactionName)) { + if (!validate(validator, localTransactionName)) { isFullSuccessful = false; break; } @@ -113,20 +108,22 @@ public static boolean isValid(Session session, String hostAndPort, long oldTid, } } - private static boolean validate(Session session, String localTransactionName) { - String[] a = localTransactionName.split(":"); - - FrontendSession fs = null; - try { - String dbName = session.getDatabase().getShortName(); - String url = TransactionValidator.createURL(dbName, a[0], a[1]); - fs = FrontendSessionPool.getFrontendSession(session.getOriginalProperties(), url); - return fs.validateTransaction(localTransactionName); - } catch (Exception e) { - throw DbException.convert(e); - } finally { - FrontendSessionPool.release(fs); - } + private static boolean validate(Transaction.Validator validator, String localTransactionName) { + // String[] a = localTransactionName.split(":"); + // + // FrontendSession fs = null; + // try { + // String dbName = session.getDatabase().getShortName(); + // String url = TransactionValidator.createURL(dbName, a[0], a[1]); + // fs = FrontendSessionPool.getFrontendSession(session.getOriginalProperties(), url); + // return fs.validateTransaction(localTransactionName); + // } catch (Exception e) { + // throw DbException.convert(e); + // } finally { + // FrontendSessionPool.release(fs); + // } + + return validator.validateTransaction(localTransactionName); } public static boolean isValid(String localTransactionName) { diff --git a/lealone-transaction/src/main/java/org/lealone/transaction/TransactionValidator.java b/lealone-transaction/src/main/java/org/lealone/transaction/TransactionValidator.java index d73da2af6..4602e9004 100644 --- a/lealone-transaction/src/main/java/org/lealone/transaction/TransactionValidator.java +++ b/lealone-transaction/src/main/java/org/lealone/transaction/TransactionValidator.java @@ -19,18 +19,14 @@ import java.util.ArrayList; import java.util.List; -import java.util.Properties; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; -import org.lealone.command.router.FrontendSessionPool; import org.lealone.engine.Constants; -import org.lealone.engine.FrontendSession; -import org.lealone.message.DbException; class TransactionValidator extends Thread { - private static final QueuedMessage CLOSE_SENTINEL = new QueuedMessage(null, null, 0, null, null); + private static final QueuedMessage CLOSE_SENTINEL = new QueuedMessage(null, null, null); private static final TransactionValidator INSTANCE = new TransactionValidator(); @@ -83,8 +79,8 @@ private void validateTransaction(QueuedMessage qm) { boolean isFullSuccessful = true; for (String localTransactionName : allLocalTransactionNames) { - if (!localTransactionName.startsWith(TransactionManager.getHostAndPort())) { - if (!validate(qm.dbName, qm.properties, localTransactionName)) { + if (!localTransactionName.startsWith(qm.transactionEngine.hostAndPort)) { + if (!qm.t.validator.validateTransaction(localTransactionName)) { isFullSuccessful = false; break; } @@ -92,50 +88,30 @@ private void validateTransaction(QueuedMessage qm) { } if (isFullSuccessful) { - qm.transactionEngine.commitAfterValidate(qm.tid); + qm.transactionEngine.commitAfterValidate(qm.t.transactionId); } } - public void enqueue(String dbName, DefaultTransactionEngine transactionEngine, int tid, Properties properties, - String allLocalTransactionNames) { + public void enqueue(MVCCTransactionEngine transactionEngine, MVCCTransaction t, String allLocalTransactionNames) { try { - backlog.put(new QueuedMessage(dbName, transactionEngine, tid, properties, allLocalTransactionNames)); + backlog.put(new QueuedMessage(transactionEngine, t, allLocalTransactionNames)); } catch (InterruptedException e) { throw new AssertionError(e); } } private static class QueuedMessage { - final DefaultTransactionEngine transactionEngine; - final String dbName; - final int tid; - final Properties properties; + final MVCCTransactionEngine transactionEngine; + final MVCCTransaction t; final String allLocalTransactionNames; - QueuedMessage(String dbName, DefaultTransactionEngine transactionEngine, int tid, Properties properties, - String allLocalTransactionNames) { - this.dbName = dbName; + QueuedMessage(MVCCTransactionEngine transactionEngine, MVCCTransaction t, String allLocalTransactionNames) { this.transactionEngine = transactionEngine; - this.tid = tid; - this.properties = properties; + this.t = t; this.allLocalTransactionNames = allLocalTransactionNames; } } - private static boolean validate(String dbName, Properties properties, String localTransactionName) { - String[] a = localTransactionName.split(":"); - - FrontendSession fs = null; - try { - fs = FrontendSessionPool.getFrontendSession(properties, createURL(dbName, a[0], a[1])); - return fs.validateTransaction(localTransactionName); - } catch (Exception e) { - throw DbException.convert(e); - } finally { - FrontendSessionPool.release(fs); - } - } - static String createURL(String dbName, String host, String port) { StringBuilder url = new StringBuilder(100); url.append(Constants.URL_PREFIX).append(Constants.URL_TCP).append("//"); diff --git a/lealone-transaction/src/main/java/org/lealone/transaction/VersionedValue.java b/lealone-transaction/src/main/java/org/lealone/transaction/VersionedValue.java index accd5f26f..3d7613f41 100644 --- a/lealone-transaction/src/main/java/org/lealone/transaction/VersionedValue.java +++ b/lealone-transaction/src/main/java/org/lealone/transaction/VersionedValue.java @@ -27,8 +27,8 @@ public String toString() { buff.append(", operationId = ").append(operationId); if (operationId != 0) { - buff.append(", transactionId = ").append(DefaultTransactionEngine.getTransactionId(operationId)); - buff.append(", logId = ").append(DefaultTransactionEngine.getLogId(operationId)); + buff.append(", transactionId = ").append(MVCCTransactionEngine.getTransactionId(operationId)); + buff.append(", logId = ").append(MVCCTransactionEngine.getLogId(operationId)); } buff.append("]"); diff --git a/lealone-transaction/src/main/java/org/lealone/transaction/VersionedValueType.java b/lealone-transaction/src/main/java/org/lealone/transaction/VersionedValueType.java index c589a4c01..d43eb2dac 100644 --- a/lealone-transaction/src/main/java/org/lealone/transaction/VersionedValueType.java +++ b/lealone-transaction/src/main/java/org/lealone/transaction/VersionedValueType.java @@ -105,5 +105,4 @@ public void write(WriteBuffer buff, Object obj) { valueType.write(buff, v.value); } } - -} \ No newline at end of file +}