Skip to content

Commit 5383b5d

Browse files
committed
Okay, I have some new code in place that hopefully should work better. I
couldn't produce a full patch using cvs diff -c this time since I have created new files and anonymous cvs usage doesn't allow you to adds. I'm supplying the modified src/interfaces/jdbc as a tarball at : http://www.candleweb.no/~gunnar/projects/pgsql/postgres-jdbc-2000-10-05.tgz The new files that should be added are : ? org/postgresql/PGStatement.java ? org/postgresql/ObjectPool.java ? org/postgresql/ObjectPoolFactory.java There is now a global static pool of free byte arrays and used byte arrays connected to a statement object. This is the role of the new PGStatement class. Access to the global free array is synchronized, while we rely on the PG_Stream synchronization for the used array. My measurements show that the perfomance boost on this code is not quite as big as my last shot, but it is still an improvement. Maybe some of the difference is due to the new synchronization on the global array. I think I will look into choosing between on a connection level and global level. I have also started experimented with improving the performance of the various conversions. The problem here is ofcourse related handle the various encodings. One thing I found to speed up ResultSet.getInt() a lot was to do custom conversion on the byte array into int instead of going through the getString() to do the conversion. But I'm unsure if this is portable, can we assume that a digit never can be represented by more than one byte ? It works fine in my iso-latin-8859-1 environment, but what about other environments ? Maybe we could provide different ResultSet implementations depending on the encoding used or delegate some methods of the result set to an "converter class". Check the org/postgresql/jdbc2/FastResultSet.java in the tarball above to see the modified getInt() method. Regards, Gunnar
1 parent 52cba15 commit 5383b5d

File tree

13 files changed

+412
-84
lines changed

13 files changed

+412
-84
lines changed

src/interfaces/jdbc/org/postgresql/Connection.java

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import org.postgresql.util.*;
1111

1212
/**
13-
* $Id: Connection.java,v 1.6 2000/09/12 05:09:54 momjian Exp $
13+
* $Id: Connection.java,v 1.7 2000/10/08 19:37:54 momjian Exp $
1414
*
1515
* This abstract class is used by org.postgresql.Driver to open either the JDBC1 or
1616
* JDBC2 versions of the Connection class.
@@ -81,6 +81,11 @@ public abstract class Connection
8181
// The PID an cancellation key we get from the backend process
8282
public int pid;
8383
public int ckey;
84+
85+
// This receive_sbuf should be used by the different methods
86+
// that call pg_stream.ReceiveString() in this Connection, so
87+
// so we avoid uneccesary new allocations.
88+
byte receive_sbuf[] = new byte[8192];
8489

8590
/**
8691
* This is called by Class.forName() from within org.postgresql.Driver
@@ -164,8 +169,9 @@ protected void openConnection(String host, int port, Properties info, String dat
164169
// The most common one to be thrown here is:
165170
// "User authentication failed"
166171
//
167-
throw new SQLException(pg_stream.ReceiveString
168-
(4096, getEncoding()));
172+
String msg = pg_stream.ReceiveString(receive_sbuf, 4096,
173+
getEncoding());
174+
throw new SQLException(msg);
169175

170176
case 'R':
171177
// Get the type of request
@@ -236,7 +242,7 @@ protected void openConnection(String host, int port, Properties info, String dat
236242
case 'E':
237243
case 'N':
238244
throw new SQLException(pg_stream.ReceiveString
239-
(4096, getEncoding()));
245+
(receive_sbuf, 4096, getEncoding()));
240246
default:
241247
throw new PSQLException("postgresql.con.setup");
242248
}
@@ -248,7 +254,7 @@ protected void openConnection(String host, int port, Properties info, String dat
248254
break;
249255
case 'E':
250256
case 'N':
251-
throw new SQLException(pg_stream.ReceiveString(4096));
257+
throw new SQLException(pg_stream.ReceiveString(receive_sbuf, 4096, getEncoding()));
252258
default:
253259
throw new PSQLException("postgresql.con.setup");
254260
}
@@ -263,7 +269,7 @@ protected void openConnection(String host, int port, Properties info, String dat
263269
//
264270
firstWarning = null;
265271

266-
ExecSQL("set datestyle to 'ISO'");
272+
ExecSQL(null, "set datestyle to 'ISO'");
267273

268274
// Initialise object handling
269275
initObjectTypes();
@@ -306,23 +312,27 @@ public void addWarning(String msg)
306312
//currentDateStyle=i+1; // this is the index of the format
307313
//}
308314
}
309-
315+
316+
310317
/**
311318
* Send a query to the backend. Returns one of the ResultSet
312319
* objects.
313320
*
314321
* <B>Note:</B> there does not seem to be any method currently
315322
* in existance to return the update count.
316323
*
324+
* @param stmt The statment object.
317325
* @param sql the SQL statement to be executed
318326
* @return a ResultSet holding the results
319327
* @exception SQLException if a database error occurs
320328
*/
321-
public java.sql.ResultSet ExecSQL(String sql) throws SQLException
329+
public java.sql.ResultSet ExecSQL(PGStatement stmt,
330+
String sql) throws SQLException
322331
{
323332
// added Oct 7 1998 to give us thread safety.
324333
synchronized(pg_stream) {
325-
334+
pg_stream.setExecutingStatement(stmt);
335+
326336
Field[] fields = null;
327337
Vector tuples = new Vector();
328338
byte[] buf = null;
@@ -352,8 +362,7 @@ public java.sql.ResultSet ExecSQL(String sql) throws SQLException
352362
try
353363
{
354364
pg_stream.SendChar('Q');
355-
buf = sql.getBytes();
356-
pg_stream.Send(buf);
365+
pg_stream.Send(sql.getBytes());
357366
pg_stream.SendChar(0);
358367
pg_stream.flush();
359368
} catch (IOException e) {
@@ -370,7 +379,8 @@ public java.sql.ResultSet ExecSQL(String sql) throws SQLException
370379
{
371380
case 'A': // Asynchronous Notify
372381
pid = pg_stream.ReceiveInteger(4);
373-
msg = pg_stream.ReceiveString(8192);
382+
msg = pg_stream.ReceiveString(receive_sbuf, 8192,
383+
getEncoding());
374384
break;
375385
case 'B': // Binary Data Transfer
376386
if (fields == null)
@@ -381,7 +391,9 @@ public java.sql.ResultSet ExecSQL(String sql) throws SQLException
381391
tuples.addElement(tup);
382392
break;
383393
case 'C': // Command Status
384-
recv_status = pg_stream.ReceiveString(8192);
394+
recv_status =
395+
pg_stream.ReceiveString(receive_sbuf, 8192,
396+
getEncoding());
385397

386398
// Now handle the update count correctly.
387399
if(recv_status.startsWith("INSERT") || recv_status.startsWith("UPDATE") || recv_status.startsWith("DELETE")) {
@@ -423,7 +435,8 @@ public java.sql.ResultSet ExecSQL(String sql) throws SQLException
423435
tuples.addElement(tup);
424436
break;
425437
case 'E': // Error Message
426-
msg = pg_stream.ReceiveString(4096);
438+
msg = pg_stream.ReceiveString(receive_sbuf, 4096,
439+
getEncoding());
427440
final_error = new SQLException(msg);
428441
hfr = true;
429442
break;
@@ -438,10 +451,14 @@ public java.sql.ResultSet ExecSQL(String sql) throws SQLException
438451
hfr = true;
439452
break;
440453
case 'N': // Error Notification
441-
addWarning(pg_stream.ReceiveString(4096));
454+
addWarning(pg_stream.ReceiveString(receive_sbuf,
455+
4096,
456+
getEncoding()));
442457
break;
443458
case 'P': // Portal Name
444-
String pname = pg_stream.ReceiveString(8192);
459+
String pname =
460+
pg_stream.ReceiveString(receive_sbuf, 8192,
461+
getEncoding());
445462
break;
446463
case 'T': // MetaData Field Description
447464
if (fields != null)
@@ -461,6 +478,8 @@ public java.sql.ResultSet ExecSQL(String sql) throws SQLException
461478
}
462479
}
463480

481+
482+
464483
/**
465484
* Receive the field descriptions from the back end
466485
*
@@ -474,7 +493,8 @@ private Field[] ReceiveFields() throws SQLException
474493

475494
for (i = 0 ; i < nf ; ++i)
476495
{
477-
String typname = pg_stream.ReceiveString(8192);
496+
String typname = pg_stream.ReceiveString(receive_sbuf, 8192,
497+
getEncoding());
478498
int typid = pg_stream.ReceiveIntegerR(4);
479499
int typlen = pg_stream.ReceiveIntegerR(2);
480500
int typmod = pg_stream.ReceiveIntegerR(4);

src/interfaces/jdbc/org/postgresql/Field.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,9 @@ public int getSQLType() throws SQLException
7676
// it's not in the cache, so perform a query, and add the result to
7777
// the cache
7878
if(type_name==null) {
79-
ResultSet result = (org.postgresql.ResultSet)conn.ExecSQL("select typname from pg_type where oid = " + oid);
79+
ResultSet result = (org.postgresql.ResultSet)
80+
conn.ExecSQL(null, "select typname from pg_type where oid = "
81+
+ oid);
8082
if (result.getColumnCount() != 1 || result.getTupleCount() != 1)
8183
throw new PSQLException("postgresql.unexpected");
8284
result.next();
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package org.postgresql;
2+
3+
/**
4+
* A simple and fast object pool implementation that can pool objects
5+
* of any type. This implementation is not thread safe, it is up to the users
6+
* of this class to assure thread safety.
7+
*/
8+
public class ObjectPool {
9+
int cursize = 0;
10+
int maxsize = 8;
11+
Object arr[] = new Object[8];
12+
13+
/**
14+
* Add object to the pool.
15+
* @param o The object to add.
16+
*/
17+
public void add(Object o){
18+
if(cursize >= maxsize){
19+
Object newarr[] = new Object[maxsize*2];
20+
System.arraycopy(arr, 0, newarr, 0, maxsize);
21+
maxsize = maxsize * 2;
22+
arr = newarr;
23+
}
24+
arr[cursize++] = o;
25+
}
26+
27+
/**
28+
* Remove an object from the pool. If the pool is empty
29+
* ArrayIndexOutOfBoundsException will be thrown.
30+
* @return Returns the removed object.
31+
* @exception If the pool is empty
32+
* ArrayIndexOutOfBoundsException will be thrown.
33+
*/
34+
public Object remove(){
35+
Object o = arr[cursize-1];
36+
// This have to be here, so we don't decrease the counter when
37+
// cursize == 0;
38+
cursize--;
39+
return o;
40+
}
41+
42+
/**
43+
* Check if pool is empty.
44+
* @return true if pool is empty, false otherwise.
45+
*/
46+
public boolean isEmpty(){
47+
return cursize == 0;
48+
}
49+
50+
/**
51+
* Get the size of the pool.
52+
* @return Returns the number of objects in the pool.
53+
*/
54+
public int size(){
55+
return cursize;
56+
}
57+
/**
58+
* Add all the objects from another pool to this pool.
59+
* @pool The pool to add the objects from.
60+
*/
61+
public void addAll(ObjectPool pool){
62+
int srcsize = pool.size();
63+
if(srcsize == 0)
64+
return;
65+
int totalsize = srcsize + cursize;
66+
if(totalsize > maxsize){
67+
Object newarr[] = new Object[totalsize*2];
68+
System.arraycopy(arr, 0, newarr, 0, cursize);
69+
maxsize = maxsize = totalsize * 2;
70+
arr = newarr;
71+
}
72+
System.arraycopy(pool.arr, 0, arr, cursize, srcsize);
73+
cursize = totalsize;
74+
}
75+
76+
/**
77+
* Clear the elements from this pool.
78+
* The method is lazy, so it just resets the index counter without
79+
* removing references to pooled objects. This could possibly
80+
* be an issue with garbage collection, depending on how the
81+
* pool is used.
82+
*/
83+
public void clear(){
84+
cursize = 0;
85+
}
86+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package org.postgresql;
2+
3+
import java.util.Hashtable;
4+
5+
/**
6+
* Just a factory class for creating and reusing
7+
* ObjectPool arrays of different sizes.
8+
*/
9+
public class ObjectPoolFactory {
10+
private static Hashtable instances = new Hashtable();
11+
12+
ObjectPool pool = new ObjectPool();
13+
int maxsize;
14+
15+
public static ObjectPoolFactory getInstance(int size){
16+
Integer s = new Integer(size);
17+
ObjectPoolFactory poolFactory = (ObjectPoolFactory) instances.get(s);
18+
if(poolFactory == null){
19+
synchronized(instances) {
20+
poolFactory = (ObjectPoolFactory) instances.get(s);
21+
if(poolFactory == null){
22+
poolFactory = new ObjectPoolFactory(size);
23+
instances.put(s, poolFactory);
24+
}
25+
}
26+
}
27+
return poolFactory;
28+
}
29+
30+
private ObjectPoolFactory(int maxsize){
31+
this.maxsize = maxsize;
32+
}
33+
34+
public ObjectPool[] getObjectPoolArr(){
35+
ObjectPool p[] = null;
36+
synchronized(pool){
37+
if(pool.size() > 0)
38+
p = (ObjectPool []) pool.remove();
39+
}
40+
if(p == null) {
41+
p = new ObjectPool[maxsize];
42+
for(int i = 0; i < maxsize; i++){
43+
p[i] = new ObjectPool();
44+
}
45+
}
46+
return p;
47+
}
48+
49+
public void releaseObjectPoolArr(ObjectPool p[]){
50+
synchronized(pool){
51+
pool.add(p);
52+
for(int i = 0; i < maxsize; i++){
53+
p[i].clear();
54+
}
55+
}
56+
}
57+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package org.postgresql;
2+
3+
import java.sql.Statement;
4+
import java.sql.SQLException;
5+
6+
public abstract class PGStatement implements Statement {
7+
public ObjectPool inusemap_dim1[];
8+
public ObjectPool inusemap_dim2[];
9+
protected Connection connection;
10+
11+
public PGStatement(Connection connection){
12+
this.connection = connection;
13+
inusemap_dim1 = connection.pg_stream.factory_dim1.getObjectPoolArr();
14+
inusemap_dim2 = connection.pg_stream.factory_dim2.getObjectPoolArr();
15+
}
16+
17+
public void deallocate(){
18+
connection.pg_stream.deallocate(this);
19+
}
20+
21+
public void close() throws SQLException {
22+
deallocate();
23+
connection.pg_stream.factory_dim1.releaseObjectPoolArr(inusemap_dim1);
24+
connection.pg_stream.factory_dim2.releaseObjectPoolArr(inusemap_dim2);
25+
}
26+
}

0 commit comments

Comments
 (0)