ソースを参照

New Connection Factory

Re-Implemented C3P0 connection pool.
- Updated C3P0 library to version 0.9.5.1.
Implemented HikariCP connection pool (fast lock-free connection pool).
- Added libraries:
	- HikariCP 2.3.8
	- SLF4J-API 1.7.12
	- SLF4J-JDK14 1.7.12
	- Javassit 3.20.0-GA
Replaced PreparedStatement without parameters with Statement.
Zoey76 9 年 前
コミット
71d4cb78d5

+ 2 - 1
L2J_Server/.classpath

@@ -2,7 +2,8 @@
 <classpath>
 	<classpathentry kind="src" path="java" />
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8" />
-	<classpathentry kind="lib" path="dist/libs/c3p0-0.9.5.jar" />
+	<classpathentry kind="lib" path="dist/libs/c3p0-0.9.5.1.jar" />
+	<classpathentry kind="lib" path="dist/libs/HikariCP-2.3.8.jar" />
 	<classpathentry kind="lib" path="dist/libs/jython.jar" />
 	<classpathentry kind="lib" path="dist/libs/jython-engine-2.2.1.jar" />
 	<classpathentry kind="lib" path="dist/libs/L2J_GeoDriver.jar" />

+ 1 - 1
L2J_Server/build.gradle

@@ -64,7 +64,7 @@ task configuratorJar(type: Jar, dependsOn: classes) {
 	exclude('**/status/**')
 	exclude('**/util/**')
 	exclude('**/Config/**')
-	exclude('**/L2DatabaseFactory/**')
+	exclude('**/ConnectionFactory/**')
 	exclude('**/Server/**')
 	manifest {
 		from(generalManifest)

+ 3 - 3
L2J_Server/build.xml

@@ -90,7 +90,7 @@
 				<attribute name="Built-By" value="${user.name}" />
 				<attribute name="Built-Date" value="${time.stamp}" />
 				<attribute name="Implementation-URL" value="http://www.l2jserver.com/" />
-				<attribute name="Class-Path" value="../libs/c3p0-0.9.5.jar ../libs/mail-1.5.2.jar ../libs/mmocore.jar ../libs/mysql-connector-java-5.1.34-bin.jar ../libs/weupnp-0.1.3.jar" />
+				<attribute name="Class-Path" value="${manifest.libs}" />
 				<attribute name="Main-Class" value="com.l2jserver.loginserver.L2LoginServer" />
 			</manifest>
 		</jar>
@@ -108,7 +108,7 @@
 				<exclude name="**/status/**" />
 				<exclude name="**/util/**" />
 				<exclude name="**/Config/**" />
-				<exclude name="**/L2DatabaseFactory/**" />
+				<exclude name="**/ConnectionFactory/**" />
 				<exclude name="**/Server/**" />
 			</fileset>
 			<manifest>
@@ -148,7 +148,7 @@
 				<exclude name="**/status/**" />
 				<exclude name="**/util/**" />
 				<exclude name="**/Config/**" />
-				<exclude name="**/L2DatabaseFactory/**" />
+				<exclude name="**/ConnectionFactory/**" />
 				<exclude name="**/Server/**" />
 			</fileset>
 			<manifest>

+ 5 - 0
L2J_Server/dist/game/config/Server.properties

@@ -57,6 +57,11 @@ Login = root
 # Database connection password
 Password = 
 
+# Database Connection Pool
+# Default: C3P0
+# Available: C3P0, HikariCP
+ConnectionPool = HikariCP
+
 # Default: 100
 MaximumDbConnections = 100
 

BIN
L2J_Server/dist/libs/HikariCP-2.3.8.jar


BIN
L2J_Server/dist/libs/c3p0-0.9.5.1.jar


BIN
L2J_Server/dist/libs/c3p0-0.9.5.jar


BIN
L2J_Server/dist/libs/javassist-3.20.0.jar


BIN
L2J_Server/dist/libs/mchange-commons-java-0.2.10.jar


BIN
L2J_Server/dist/libs/mchange-commons-java-0.2.9.jar


BIN
L2J_Server/dist/libs/slf4j-api-1.7.12.jar


BIN
L2J_Server/dist/libs/slf4j-jdk14-1.7.12.jar


+ 5 - 0
L2J_Server/dist/login/config/LoginServer.properties

@@ -87,6 +87,11 @@ Login = root
 # Database connection password
 Password = 
 
+# Database Connection Pool
+# Default: C3P0
+# Available: C3P0, HikariCP
+ConnectionPool = HikariCP
+
 # Default: 10
 MaximumDbConnections = 10
 

+ 3 - 0
L2J_Server/java/com/l2jserver/Config.java

@@ -926,6 +926,7 @@ public final class Config
 	public static String DATABASE_URL;
 	public static String DATABASE_LOGIN;
 	public static String DATABASE_PASSWORD;
+	public static String DATABASE_CONNECTION_POOL;
 	public static int DATABASE_MAX_CONNECTIONS;
 	public static int DATABASE_MAX_IDLE_TIME;
 	public static int MAXIMUM_ONLINE_USERS;
@@ -1148,6 +1149,7 @@ public final class Config
 			DATABASE_URL = serverSettings.getString("URL", "jdbc:mysql://localhost/l2jgs");
 			DATABASE_LOGIN = serverSettings.getString("Login", "root");
 			DATABASE_PASSWORD = serverSettings.getString("Password", "");
+			DATABASE_CONNECTION_POOL = serverSettings.getString("ConnectionPool", "C3P0");
 			DATABASE_MAX_CONNECTIONS = serverSettings.getInt("MaximumDbConnections", 10);
 			DATABASE_MAX_IDLE_TIME = serverSettings.getInt("MaximumDbIdleTime", 0);
 			
@@ -2739,6 +2741,7 @@ public final class Config
 			DATABASE_URL = ServerSettings.getString("URL", "jdbc:mysql://localhost/l2jls");
 			DATABASE_LOGIN = ServerSettings.getString("Login", "root");
 			DATABASE_PASSWORD = ServerSettings.getString("Password", "");
+			DATABASE_CONNECTION_POOL = ServerSettings.getString("ConnectionPool", "C3P0");
 			DATABASE_MAX_CONNECTIONS = ServerSettings.getInt("MaximumDbConnections", 10);
 			DATABASE_MAX_IDLE_TIME = ServerSettings.getInt("MaximumDbIdleTime", 0);
 			CONNECTION_CLOSE_TIME = ServerSettings.getLong("ConnectionCloseTime", 60000);

+ 51 - 0
L2J_Server/java/com/l2jserver/commons/database/pool/AbstractConnectionFactory.java

@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2004-2015 L2J Server
+ * 
+ * This file is part of L2J Server.
+ * 
+ * L2J Server is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * L2J Server is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.l2jserver.commons.database.pool;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.logging.Logger;
+
+/**
+ * Abstract Connection Factory.
+ * @author Zoey76
+ */
+public abstract class AbstractConnectionFactory implements IConnectionFactory
+{
+	/** The logger. */
+	protected static final Logger LOG = Logger.getLogger(AbstractConnectionFactory.class.getName());
+	
+	@Override
+	public Connection getConnection()
+	{
+		Connection con = null;
+		while (con == null)
+		{
+			try
+			{
+				con = getDataSource().getConnection();
+			}
+			catch (SQLException e)
+			{
+				LOG.warning(getClass().getSimpleName() + ": Unable to get a connection: " + e.getMessage());
+			}
+		}
+		return con;
+	}
+}

+ 48 - 0
L2J_Server/java/com/l2jserver/commons/database/pool/IConnectionFactory.java

@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2004-2015 L2J Server
+ * 
+ * This file is part of L2J Server.
+ * 
+ * L2J Server is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * L2J Server is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.l2jserver.commons.database.pool;
+
+import java.sql.Connection;
+
+import javax.sql.DataSource;
+
+/**
+ * Connection Factory interface.
+ * @author Zoey76
+ */
+public interface IConnectionFactory
+{
+	/**
+	 * Gets the data source.
+	 * @return the data source
+	 */
+	DataSource getDataSource();
+	
+	/**
+	 * Gets a connection from the pool.
+	 * @return a connection
+	 */
+	Connection getConnection();
+	
+	/**
+	 * Closes the data source.<br>
+	 * <i>Same as shutdown.</i>
+	 */
+	void close();
+}

+ 62 - 0
L2J_Server/java/com/l2jserver/commons/database/pool/impl/BoneCPConnectionFactory.java

@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2004-2015 L2J Server
+ * 
+ * This file is part of L2J Server.
+ * 
+ * L2J Server is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * L2J Server is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.l2jserver.commons.database.pool.impl;
+
+import javax.sql.DataSource;
+
+import com.l2jserver.commons.database.pool.AbstractConnectionFactory;
+import com.l2jserver.commons.database.pool.IConnectionFactory;
+
+/**
+ * BoneCP Connection Factory implementation.<br>
+ * <b>Note that this class is not public to prevent external initialization.</b><br>
+ * <b>Access it through {@link ConnectionFactory} and proper configuration.</b>
+ * @author Zoey76
+ */
+final class BoneCPConnectionFactory extends AbstractConnectionFactory
+{
+	private final DataSource _dataSource = null;
+	
+	public BoneCPConnectionFactory()
+	{
+		LOG.severe("BoneCP is not supported yet, nothing is going to work!");
+	}
+	
+	@Override
+	public void close()
+	{
+		throw new UnsupportedOperationException("BoneCP is not supported yet!");
+	}
+	
+	@Override
+	public DataSource getDataSource()
+	{
+		return _dataSource;
+	}
+	
+	public static IConnectionFactory getInstance()
+	{
+		return SingletonHolder.INSTANCE;
+	}
+	
+	private static class SingletonHolder
+	{
+		protected static final IConnectionFactory INSTANCE = new BoneCPConnectionFactory();
+	}
+}

+ 143 - 0
L2J_Server/java/com/l2jserver/commons/database/pool/impl/C3P0ConnectionFactory.java

@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2004-2015 L2J Server
+ * 
+ * This file is part of L2J Server.
+ * 
+ * L2J Server is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * L2J Server is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.l2jserver.commons.database.pool.impl;
+
+import java.beans.PropertyVetoException;
+import java.sql.SQLException;
+
+import javax.sql.DataSource;
+
+import com.l2jserver.Config;
+import com.l2jserver.commons.database.pool.AbstractConnectionFactory;
+import com.l2jserver.commons.database.pool.IConnectionFactory;
+import com.mchange.v2.c3p0.ComboPooledDataSource;
+
+/**
+ * C3P0 Connection Factory implementation.<br>
+ * <b>Note that this class is not public to prevent external initialization.</b><br>
+ * <b>Access it through {@link ConnectionFactory} and proper configuration.</b>
+ * @author Zoey76
+ */
+final class C3P0ConnectionFactory extends AbstractConnectionFactory
+{
+	private final ComboPooledDataSource _dataSource;
+	
+	public C3P0ConnectionFactory()
+	{
+		if (Config.DATABASE_MAX_CONNECTIONS < 2)
+		{
+			Config.DATABASE_MAX_CONNECTIONS = 2;
+			LOG.warning("A minimum of " + Config.DATABASE_MAX_CONNECTIONS + " db connections are required.");
+		}
+		
+		_dataSource = new ComboPooledDataSource();
+		_dataSource.setAutoCommitOnClose(true);
+		
+		_dataSource.setInitialPoolSize(10);
+		_dataSource.setMinPoolSize(10);
+		_dataSource.setMaxPoolSize(Math.max(10, Config.DATABASE_MAX_CONNECTIONS));
+		
+		_dataSource.setAcquireRetryAttempts(0); // try to obtain connections indefinitely (0 = never quit)
+		_dataSource.setAcquireRetryDelay(500); // 500 milliseconds wait before try to acquire connection again
+		_dataSource.setCheckoutTimeout(0); // 0 = wait indefinitely for new connection if pool is exhausted
+		_dataSource.setAcquireIncrement(5); // if pool is exhausted, get 5 more connections at a time
+		// cause there is a "long" delay on acquire connection
+		// so taking more than one connection at once will make connection pooling
+		// more effective.
+		
+		// this "connection_test_table" is automatically created if not already there
+		_dataSource.setAutomaticTestTable("connection_test_table");
+		_dataSource.setTestConnectionOnCheckin(false);
+		
+		// testing OnCheckin used with IdleConnectionTestPeriod is faster than testing on checkout
+		
+		_dataSource.setIdleConnectionTestPeriod(3600); // test idle connection every 60 sec
+		_dataSource.setMaxIdleTime(Config.DATABASE_MAX_IDLE_TIME); // 0 = idle connections never expire
+		// *THANKS* to connection testing configured above
+		// but I prefer to disconnect all connections not used
+		// for more than 1 hour
+		
+		// enables statement caching, there is a "semi-bug" in c3p0 0.9.0 but in 0.9.0.2 and later it's fixed
+		_dataSource.setMaxStatementsPerConnection(100);
+		
+		_dataSource.setBreakAfterAcquireFailure(false); // never fail if any way possible
+		// setting this to true will make
+		// c3p0 "crash" and refuse to work
+		// till restart thus making acquire
+		// errors "FATAL" ... we don't want that
+		// it should be possible to recover
+		try
+		{
+			_dataSource.setDriverClass(Config.DATABASE_DRIVER);
+		}
+		catch (PropertyVetoException e)
+		{
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		_dataSource.setJdbcUrl(Config.DATABASE_URL);
+		_dataSource.setUser(Config.DATABASE_LOGIN);
+		_dataSource.setPassword(Config.DATABASE_PASSWORD);
+		
+		/* Test the connection */
+		try
+		{
+			_dataSource.getConnection().close();
+		}
+		catch (SQLException e)
+		{
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		
+		if (Config.DEBUG)
+		{
+			LOG.fine("Database Connection Working");
+		}
+	}
+	
+	@Override
+	public void close()
+	{
+		try
+		{
+			_dataSource.close();
+		}
+		catch (Exception e)
+		{
+			LOG.info(e.getMessage());
+		}
+	}
+	
+	@Override
+	public DataSource getDataSource()
+	{
+		return _dataSource;
+	}
+	
+	public static IConnectionFactory getInstance()
+	{
+		return SingletonHolder.INSTANCE;
+	}
+	
+	private static class SingletonHolder
+	{
+		protected static final IConnectionFactory INSTANCE = new C3P0ConnectionFactory();
+	}
+}

+ 62 - 0
L2J_Server/java/com/l2jserver/commons/database/pool/impl/ConnectionFactory.java

@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2004-2015 L2J Server
+ * 
+ * This file is part of L2J Server.
+ * 
+ * L2J Server is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * L2J Server is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.l2jserver.commons.database.pool.impl;
+
+import com.l2jserver.Config;
+import com.l2jserver.commons.database.pool.IConnectionFactory;
+
+/**
+ * Connection Factory implementation.
+ * @author Zoey76
+ */
+public class ConnectionFactory
+{
+	public static IConnectionFactory getInstance()
+	{
+		return SingletonHolder.INSTANCE;
+	}
+	
+	private static class SingletonHolder
+	{
+		protected static final IConnectionFactory INSTANCE;
+		
+		static
+		{
+			switch (Config.DATABASE_CONNECTION_POOL)
+			{
+				default:
+				case "C3P0":
+				{
+					INSTANCE = new C3P0ConnectionFactory();
+					break;
+				}
+				case "HikariCP":
+				{
+					INSTANCE = new HikariCPConnectionFactory();
+					break;
+				}
+				case "BoneCP":
+				{
+					INSTANCE = new BoneCPConnectionFactory();
+					break;
+				}
+			}
+		}
+	}
+}

+ 76 - 0
L2J_Server/java/com/l2jserver/commons/database/pool/impl/HikariCPConnectionFactory.java

@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2004-2015 L2J Server
+ * 
+ * This file is part of L2J Server.
+ * 
+ * L2J Server is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * L2J Server is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.l2jserver.commons.database.pool.impl;
+
+import javax.sql.DataSource;
+
+import com.l2jserver.Config;
+import com.l2jserver.commons.database.pool.AbstractConnectionFactory;
+import com.l2jserver.commons.database.pool.IConnectionFactory;
+import com.zaxxer.hikari.HikariDataSource;
+
+/**
+ * HikariCP Connection Factory implementation.<br>
+ * <b>Note that this class is not public to prevent external initialization.</b><br>
+ * <b>Access it through {@link ConnectionFactory} and proper configuration.</b><br>
+ * <b><font color="RED" size="3">Totally BETA and untested feature!</font></b>
+ * @author Zoey76
+ */
+final class HikariCPConnectionFactory extends AbstractConnectionFactory
+{
+	private final HikariDataSource _dataSource;
+	
+	public HikariCPConnectionFactory()
+	{
+		_dataSource = new HikariDataSource();
+		_dataSource.setJdbcUrl(Config.DATABASE_URL);
+		_dataSource.setUsername(Config.DATABASE_LOGIN);
+		_dataSource.setPassword(Config.DATABASE_PASSWORD);
+		_dataSource.setMaximumPoolSize(Config.DATABASE_MAX_CONNECTIONS);
+	}
+	
+	@Override
+	public void close()
+	{
+		try
+		{
+			_dataSource.close();
+		}
+		catch (Exception e)
+		{
+			LOG.info(e.getMessage());
+		}
+	}
+	
+	@Override
+	public DataSource getDataSource()
+	{
+		return _dataSource;
+	}
+	
+	public static IConnectionFactory getInstance()
+	{
+		return SingletonHolder.INSTANCE;
+	}
+	
+	private static class SingletonHolder
+	{
+		protected static final IConnectionFactory INSTANCE = new HikariCPConnectionFactory();
+	}
+}