summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Vasu Nori <vnori@google.com> 2010-07-07 12:17:14 -0700
committer Vasu Nori <vnori@google.com> 2010-07-07 14:26:10 -0700
commit6ac21d30be06c1c6d5ef04a88cf5171a446633f1 (patch)
treeaa4a885763414125c6ed5bb0c4c4fd6ef1a4faa2
parent8cb6240125068da07cbcc10a210014f600a953da (diff)
unittests for DatabaseConnectionPool (and fix bugs)
Change-Id: I6f251b4bdd472bd840ea1be6497660f8c31cd3e3
-rw-r--r--core/java/android/database/sqlite/DatabaseConnectionPool.java118
-rw-r--r--core/tests/coretests/src/android/database/sqlite/DatabaseConnectionPoolTest.java364
2 files changed, 449 insertions, 33 deletions
diff --git a/core/java/android/database/sqlite/DatabaseConnectionPool.java b/core/java/android/database/sqlite/DatabaseConnectionPool.java
index 3f7018fe14ff..50b291949974 100644
--- a/core/java/android/database/sqlite/DatabaseConnectionPool.java
+++ b/core/java/android/database/sqlite/DatabaseConnectionPool.java
@@ -48,6 +48,9 @@ import java.util.Random;
/** the main database connection to which this connection pool is attached */
private final SQLiteDatabase mParentDbObj;
+ /** Random number generator used to pick a free connection out of the pool */
+ private Random rand; // lazily initialized
+
/* package */ DatabaseConnectionPool(SQLiteDatabase db) {
this.mParentDbObj = db;
if (Log.isLoggable(TAG, Log.DEBUG)) {
@@ -75,50 +78,67 @@ import java.util.Random;
* @return the Database connection that the caller can use
*/
/* package */ SQLiteDatabase get(String sql) {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- doAsserts();
- }
-
SQLiteDatabase db = null;
PoolObj poolObj = null;
synchronized(mParentDbObj) {
+ int poolSize = mPool.size();
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ assert sql != null;
+ doAsserts();
+ }
if (getFreePoolSize() == 0) {
- if (mMaxPoolSize == mPool.size()) {
+ // no free ( = available) connections
+ if (mMaxPoolSize == poolSize) {
// maxed out. can't open any more connections.
// let the caller wait on one of the pooled connections
+ // preferably a connection caching the pre-compiled statement of the given SQL
if (mMaxPoolSize == 1) {
poolObj = mPool.get(0);
} else {
- // get a random number between 0 and (mMaxPoolSize-1)
- poolObj = mPool.get(
- new Random(SystemClock.elapsedRealtime()).nextInt(mMaxPoolSize-1));
+ for (int i = 0; i < mMaxPoolSize; i++) {
+ if (mPool.get(i).mDb.isSqlInStatementCache(sql)) {
+ poolObj = mPool.get(i);
+ break;
+ }
+ }
+ if (poolObj == null) {
+ // there are no database connections with the given SQL pre-compiled.
+ // ok to return any of the connections.
+ if (rand == null) {
+ rand = new Random(SystemClock.elapsedRealtime());
+ }
+ poolObj = mPool.get(rand.nextInt(mMaxPoolSize));
+ }
}
db = poolObj.mDb;
} else {
// create a new connection and add it to the pool, since we haven't reached
// max pool size allowed
- int poolSize = getPoolSize();
db = mParentDbObj.createPoolConnection((short)(poolSize + 1));
poolObj = new PoolObj(db);
mPool.add(poolSize, poolObj);
}
} else {
// there are free connections available. pick one
- for (int i = mPool.size() - 1; i >= 0; i--) {
- poolObj = mPool.get(i);
- if (!poolObj.isFree()) {
- continue;
- }
- // it is free - but does its database object already have the given sql in its
- // statement-cache?
- db = poolObj.mDb;
- if (sql == null || db.isSqlInStatementCache(sql)) {
- // found a free connection we can use
+ // preferably a connection caching the pre-compiled statement of the given SQL
+ for (int i = 0; i < poolSize; i++) {
+ if (mPool.get(i).isFree() && mPool.get(i).mDb.isSqlInStatementCache(sql)) {
+ poolObj = mPool.get(i);
break;
}
- // haven't found a database object which has the given sql in its
- // statement-cache
}
+ if (poolObj == null) {
+ // didn't find a free database connection with the given SQL already
+ // pre-compiled. return a free connection (this means, the same SQL could be
+ // pre-compiled on more than one database connection. potential wasted memory.)
+ for (int i = 0; i < poolSize; i++) {
+ if (mPool.get(i).isFree()) {
+ poolObj = mPool.get(i);
+ break;
+ }
+ }
+ }
+ db = poolObj.mDb;
}
assert poolObj != null;
@@ -181,13 +201,10 @@ import java.util.Random;
return list;
}
- /* package */ int getPoolSize() {
- synchronized(mParentDbObj) {
- return mPool.size();
- }
- }
-
- private int getFreePoolSize() {
+ /**
+ * package level access for testing purposes only. otherwise, private should be sufficient.
+ */
+ /* package */ int getFreePoolSize() {
int count = 0;
for (int i = mPool.size() - 1; i >= 0; i--) {
if (mPool.get(i).isFree()) {
@@ -197,12 +214,29 @@ import java.util.Random;
return count++;
}
+ /**
+ * only for testing purposes
+ */
+ /* package */ ArrayList<PoolObj> getPool() {
+ return mPool;
+ }
+
@Override
public String toString() {
- return "db: " + mParentDbObj.getPath() +
- ", threadid = " + Thread.currentThread().getId() +
- ", totalsize = " + mPool.size() + ", #free = " + getFreePoolSize() +
- ", maxpoolsize = " + mMaxPoolSize;
+ StringBuilder buff = new StringBuilder();
+ buff.append("db: ");
+ buff.append(mParentDbObj.getPath());
+ buff.append(", totalsize = ");
+ buff.append(mPool.size());
+ buff.append(", #free = ");
+ buff.append(getFreePoolSize());
+ buff.append(", maxpoolsize = ");
+ buff.append(mMaxPoolSize);
+ for (PoolObj p : mPool) {
+ buff.append("\n");
+ buff.append(p.toString());
+ }
+ return buff.toString();
}
private void doAsserts() {
@@ -224,10 +258,21 @@ import java.util.Random;
}
}
+ /** only used for testing purposes. */
+ /* package */ boolean isDatabaseObjFree(SQLiteDatabase db) {
+ return mPool.get(db.mConnectionNum - 1).isFree();
+ }
+
+ /** only used for testing purposes. */
+ /* package */ int getSize() {
+ return mPool.size();
+ }
+
/**
* represents objects in the connection pool.
+ * package-level access for testing purposes only.
*/
- private static class PoolObj {
+ /* package */ static class PoolObj {
private final SQLiteDatabase mDb;
private boolean mFreeBusyFlag = FREE;
@@ -289,6 +334,13 @@ import java.util.Random;
}
}
+ /**
+ * only for testing purposes
+ */
+ /* package */ synchronized int getNumHolders() {
+ return mNumHolders;
+ }
+
@Override
public String toString() {
StringBuilder buff = new StringBuilder();
diff --git a/core/tests/coretests/src/android/database/sqlite/DatabaseConnectionPoolTest.java b/core/tests/coretests/src/android/database/sqlite/DatabaseConnectionPoolTest.java
new file mode 100644
index 000000000000..bb5e02465501
--- /dev/null
+++ b/core/tests/coretests/src/android/database/sqlite/DatabaseConnectionPoolTest.java
@@ -0,0 +1,364 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed 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 android.database.sqlite;
+
+import android.content.Context;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+public class DatabaseConnectionPoolTest extends AndroidTestCase {
+ private static final String TAG = "DatabaseConnectionPoolTest";
+
+ private static final int MAX_CONN = 5;
+ private static final String TEST_SQL = "select * from test where i = ? AND j = 1";
+ private static final String[] TEST_SQLS = new String[] {
+ TEST_SQL, TEST_SQL + 1, TEST_SQL + 2, TEST_SQL + 3, TEST_SQL + 4
+ };
+
+ private SQLiteDatabase mDatabase;
+ private File mDatabaseFile;
+ private DatabaseConnectionPool mTestPool;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ File dbDir = getContext().getDir(this.getClass().getName(), Context.MODE_PRIVATE);
+ mDatabaseFile = new File(dbDir, "database_test.db");
+ if (mDatabaseFile.exists()) {
+ mDatabaseFile.delete();
+ }
+ mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null);
+ assertNotNull(mDatabase);
+ mDatabase.execSQL("create table test (i int, j int);");
+ mTestPool = new DatabaseConnectionPool(mDatabase);
+ assertNotNull(mTestPool);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ mTestPool.close();
+ mDatabase.close();
+ mDatabaseFile.delete();
+ super.tearDown();
+ }
+
+ @SmallTest
+ public void testGetAndRelease() {
+ mTestPool.setMaxPoolSize(MAX_CONN);
+ // connections should be lazily created.
+ assertEquals(0, mTestPool.getSize());
+ // MAX pool size should be set to MAX_CONN
+ assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
+ // get a connection
+ SQLiteDatabase db = mTestPool.get(TEST_SQL);
+ // pool size should be one - since only one should be allocated for the above get()
+ assertEquals(1, mTestPool.getSize());
+ // no free connections should be available
+ assertEquals(0, mTestPool.getFreePoolSize());
+ assertFalse(mTestPool.isDatabaseObjFree(db));
+ // release the connection
+ mTestPool.release(db);
+ assertEquals(1, mTestPool.getFreePoolSize());
+ assertEquals(1, mTestPool.getSize());
+ assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
+ assertTrue(mTestPool.isDatabaseObjFree(db));
+ // release the same object again and expect IllegalStateException
+ try {
+ mTestPool.release(db);
+ fail("illegalStateException expected");
+ } catch (IllegalStateException e ) {
+ // expected.
+ }
+ }
+
+ /**
+ * get all connections from the pool and ask for one more.
+ * should get one of the connections already got so far.
+ */
+ @SmallTest
+ public void testGetAllConnAndOneMore() {
+ mTestPool.setMaxPoolSize(MAX_CONN);
+ assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
+ ArrayList<SQLiteDatabase> dbObjs = new ArrayList<SQLiteDatabase>();
+ for (int i = 0; i < MAX_CONN; i++) {
+ SQLiteDatabase db = mTestPool.get(TEST_SQL);
+ assertFalse(dbObjs.contains(db));
+ dbObjs.add(db);
+ }
+ assertEquals(0, mTestPool.getFreePoolSize());
+ assertEquals(MAX_CONN, mTestPool.getSize());
+ assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
+ // pool is maxed out and no free connections. ask for one more connection
+ SQLiteDatabase db1 = mTestPool.get(TEST_SQL);
+ // make sure db1 is one of the existing ones
+ assertTrue(dbObjs.contains(db1));
+ // pool size should remain at MAX_CONN
+ assertEquals(0, mTestPool.getFreePoolSize());
+ assertEquals(MAX_CONN, mTestPool.getSize());
+ assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
+ // release db1 but since it is allocated 2 times, it should still remain 'busy'
+ mTestPool.release(db1);
+ assertFalse(mTestPool.isDatabaseObjFree(db1));
+ assertEquals(0, mTestPool.getFreePoolSize());
+ assertEquals(MAX_CONN, mTestPool.getSize());
+ assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
+ // release all connections
+ for (int i = 0; i < MAX_CONN; i++) {
+ mTestPool.release(dbObjs.get(i));
+ }
+ // all objects in the pool should be freed now
+ assertEquals(MAX_CONN, mTestPool.getFreePoolSize());
+ assertEquals(MAX_CONN, mTestPool.getSize());
+ assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
+ }
+
+ /**
+ * same as above except that each connection has different SQL statement associated with it.
+ */
+ @SmallTest
+ public void testConnRetrievalForPreviouslySeenSql() {
+ mTestPool.setMaxPoolSize(MAX_CONN);
+ assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
+
+ HashMap<String, SQLiteDatabase> dbObjs = new HashMap<String, SQLiteDatabase>();
+ for (int i = 0; i < MAX_CONN; i++) {
+ SQLiteDatabase db = mTestPool.get(TEST_SQLS[i]);
+ executeSqlOnDatabaseConn(db, TEST_SQLS[i]);
+ assertFalse(dbObjs.values().contains(db));
+ dbObjs.put(TEST_SQLS[i], db);
+ }
+ assertEquals(0, mTestPool.getFreePoolSize());
+ assertEquals(MAX_CONN, mTestPool.getSize());
+ assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
+ // pool is maxed out and no free connections. ask for one more connection
+ // use a previously seen SQL statement
+ String testSql = TEST_SQLS[MAX_CONN - 1];
+ SQLiteDatabase db1 = mTestPool.get(testSql);
+ assertEquals(0, mTestPool.getFreePoolSize());
+ assertEquals(MAX_CONN, mTestPool.getSize());
+ assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
+ // make sure db1 is one of the existing ones
+ assertTrue(dbObjs.values().contains(db1));
+ assertEquals(db1, dbObjs.get(testSql));
+ // do the same again
+ SQLiteDatabase db2 = mTestPool.get(testSql);
+ // make sure db1 is one of the existing ones
+ assertEquals(db2, dbObjs.get(testSql));
+
+ // pool size should remain at MAX_CONN
+ assertEquals(0, mTestPool.getFreePoolSize());
+ assertEquals(MAX_CONN, mTestPool.getSize());
+ assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
+
+ // release db1 but since the same connection is allocated 3 times,
+ // it should still remain 'busy'
+ mTestPool.release(db1);
+ assertFalse(mTestPool.isDatabaseObjFree(dbObjs.get(testSql)));
+ assertEquals(0, mTestPool.getFreePoolSize());
+ assertEquals(MAX_CONN, mTestPool.getSize());
+ assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
+
+ // release db2 but since the same connection is allocated 2 times,
+ // it should still remain 'busy'
+ mTestPool.release(db2);
+ assertFalse(mTestPool.isDatabaseObjFree(dbObjs.get(testSql)));
+ assertEquals(0, mTestPool.getFreePoolSize());
+ assertEquals(MAX_CONN, mTestPool.getSize());
+ assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
+
+ // release all connections
+ for (int i = 0; i < MAX_CONN; i++) {
+ mTestPool.release(dbObjs.get(TEST_SQLS[i]));
+ }
+ // all objects in the pool should be freed now
+ assertEquals(MAX_CONN, mTestPool.getFreePoolSize());
+ assertEquals(MAX_CONN, mTestPool.getSize());
+ assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
+ }
+
+ private void executeSqlOnDatabaseConn(SQLiteDatabase db, String sql) {
+ // execute the given SQL on the given database connection so that the prepared
+ // statement for SQL is cached by the given database connection
+ // this will help DatabaseConenctionPool figure out if a given SQL statement
+ // is already cached by a database connection.
+ db.execSQL(sql, new String[]{1+""});
+ }
+
+ /**
+ * get a connection for a SQL statement 'blah'. (connection_s)
+ * make sure the pool has at least one free connection even after this get().
+ * and get a connection for the same SQL again.
+ * this connection should be different from connection_s.
+ * even though there is a connection with the given SQL pre-compiled, since is it not free
+ * AND since the pool has free connections available, should get a new connection.
+ */
+ @SmallTest
+ public void testGetConnForTheSameSql() {
+ mTestPool.setMaxPoolSize(MAX_CONN);
+
+ SQLiteDatabase db = mTestPool.get(TEST_SQL);
+ executeSqlOnDatabaseConn(db, TEST_SQL);
+ assertEquals(0, mTestPool.getFreePoolSize());
+ assertEquals(1, mTestPool.getSize());
+ assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
+
+ assertFalse(mTestPool.isDatabaseObjFree(db));
+
+ SQLiteDatabase db1 = mTestPool.get(TEST_SQL);
+ assertEquals(0, mTestPool.getFreePoolSize());
+ assertEquals(2, mTestPool.getSize());
+ assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
+
+ assertFalse(mTestPool.isDatabaseObjFree(db1));
+ assertFalse(db1.equals(db));
+
+ mTestPool.release(db);
+ assertEquals(1, mTestPool.getFreePoolSize());
+ assertEquals(2, mTestPool.getSize());
+ assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
+
+ mTestPool.release(db1);
+ assertEquals(2, mTestPool.getFreePoolSize());
+ assertEquals(2, mTestPool.getSize());
+ assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
+ }
+
+ /**
+ * get the same connection N times and release it N times.
+ * this tests DatabaseConnectionPool.PoolObj.mNumHolders
+ */
+ @SmallTest
+ public void testGetSameConnNtimesAndReleaseItNtimes() {
+ mTestPool.setMaxPoolSize(MAX_CONN);
+ assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
+
+ HashMap<String, SQLiteDatabase> dbObjs = new HashMap<String, SQLiteDatabase>();
+ for (int i = 0; i < MAX_CONN; i++) {
+ SQLiteDatabase db = mTestPool.get(TEST_SQLS[i]);
+ executeSqlOnDatabaseConn(db, TEST_SQLS[i]);
+ assertFalse(dbObjs.values().contains(db));
+ dbObjs.put(TEST_SQLS[i], db);
+ }
+ assertEquals(0, mTestPool.getFreePoolSize());
+ assertEquals(MAX_CONN, mTestPool.getSize());
+ assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
+ // every connection in the pool should have numHolders = 1
+ for (int i = 0; i < MAX_CONN; i ++) {
+ assertEquals(1, mTestPool.getPool().get(i).getNumHolders());
+ }
+ // pool is maxed out and no free connections. ask for one more connection
+ // use a previously seen SQL statement
+ String testSql = TEST_SQLS[MAX_CONN - 1];
+ SQLiteDatabase db1 = mTestPool.get(testSql);
+ assertEquals(0, mTestPool.getFreePoolSize());
+ assertEquals(MAX_CONN, mTestPool.getSize());
+ assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
+ // make sure db1 is one of the existing ones
+ assertTrue(dbObjs.values().contains(db1));
+ assertEquals(db1, dbObjs.get(testSql));
+ assertFalse(mTestPool.isDatabaseObjFree(db1));
+ DatabaseConnectionPool.PoolObj poolObj = mTestPool.getPool().get(db1.mConnectionNum - 1);
+ int numHolders = poolObj.getNumHolders();
+ assertEquals(2, numHolders);
+ assertEquals(0, mTestPool.getFreePoolSize());
+ assertEquals(MAX_CONN, mTestPool.getSize());
+ assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
+ // get the same connection N times more
+ int N = 100;
+ for (int i = 0; i < N; i++) {
+ SQLiteDatabase db2 = mTestPool.get(testSql);
+ assertEquals(db1, db2);
+ assertFalse(mTestPool.isDatabaseObjFree(db2));
+ // numHolders for this object should be now up by 1
+ int prev = numHolders;
+ numHolders = poolObj.getNumHolders();
+ assertEquals(prev + 1, numHolders);
+ }
+ // release it N times
+ for (int i = 0; i < N; i++) {
+ mTestPool.release(db1);
+ int prev = numHolders;
+ numHolders = poolObj.getNumHolders();
+ assertEquals(prev - 1, numHolders);
+ assertFalse(mTestPool.isDatabaseObjFree(db1));
+ }
+ // the connection should still have 2 more holders
+ assertFalse(mTestPool.isDatabaseObjFree(db1));
+ assertEquals(2, poolObj.getNumHolders());
+ assertEquals(0, mTestPool.getFreePoolSize());
+ assertEquals(MAX_CONN, mTestPool.getSize());
+ assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
+ // release 2 more times
+ mTestPool.release(db1);
+ mTestPool.release(db1);
+ assertEquals(0, poolObj.getNumHolders());
+ assertEquals(1, mTestPool.getFreePoolSize());
+ assertEquals(MAX_CONN, mTestPool.getSize());
+ assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
+ assertTrue(mTestPool.isDatabaseObjFree(db1));
+ }
+
+ @SmallTest
+ public void testStressTest() {
+ mTestPool.setMaxPoolSize(MAX_CONN);
+ assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
+
+ HashMap<SQLiteDatabase, Integer> dbMap = new HashMap<SQLiteDatabase, Integer>();
+ for (int i = 0; i < MAX_CONN; i++) {
+ SQLiteDatabase db = mTestPool.get(TEST_SQLS[i]);
+ assertFalse(dbMap.containsKey(db));
+ dbMap.put(db, 1);
+ executeSqlOnDatabaseConn(db, TEST_SQLS[i]);
+ }
+ assertEquals(0, mTestPool.getFreePoolSize());
+ assertEquals(MAX_CONN, mTestPool.getSize());
+ assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
+ // ask for lot more connections but since the pool is maxed out, we should start receiving
+ // connections that we already got so far
+ for (int i = MAX_CONN; i < 1000; i++) {
+ SQLiteDatabase db = mTestPool.get(TEST_SQL + i);
+ assertTrue(dbMap.containsKey(db));
+ int k = dbMap.get(db);
+ dbMap.put(db, ++k);
+ }
+ assertEquals(0, mTestPool.getFreePoolSize());
+ assertEquals(MAX_CONN, mTestPool.getSize());
+ assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
+ // print the distribution of the database connection handles received, should be uniform.
+ for (SQLiteDatabase d : dbMap.keySet()) {
+ Log.i(TAG, "connection # " + d.mConnectionNum + ", numHolders: " + dbMap.get(d));
+ }
+ // print the pool info
+ Log.i(TAG, mTestPool.toString());
+ // release all
+ for (SQLiteDatabase d : dbMap.keySet()) {
+ int num = dbMap.get(d);
+ for (int i = 0; i < num; i++) {
+ mTestPool.release(d);
+ }
+ }
+ assertEquals(MAX_CONN, mTestPool.getFreePoolSize());
+ assertEquals(MAX_CONN, mTestPool.getSize());
+ assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
+ }
+}