src.com.ibm.as400.access.DBStorage Maven / Gradle / Ivy
Show all versions of jt400-jdk8 Show documentation
///////////////////////////////////////////////////////////////////////////////
//
// JTOpen (IBM Toolbox for Java - OSS version)
//
// Filename: DBStorage.java
//
// The source code contained herein is licensed under the IBM Public License
// Version 1.0, which has been approved by the Open Source Initiative.
// Copyright (C) 1997-2001 International Business Machines Corporation and
// others. All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////
package com.ibm.as400.access;
import java.io.PrintWriter;
import java.io.StringWriter;
/**
This class manages a large byte arrays for use
in creating request datastreams. This enables reuse of
the byte array, so that it does not have to be reallocated
repeatedly.
**/
final class DBStorage //@P0C
{
public final static int DEFAULT_SIZE = 1024;
private byte[] data_ = new byte[DEFAULT_SIZE]; //@P0C
private int id_; // @B5A
private DBStoragePool pool_; // @B5A
private boolean inUse_ = false; //@P0A
private Exception allocatedLocation; // @B5A
/**
Constructs a DBStorage object.
@param id an id assigned by the pool. This is -1 if the storage does not belong to the pool.
@param pool pool that this object belongs to
**/
// @B5A
DBStorage(int id, DBStoragePool pool) {
id_ = id;
pool_ = pool;
}
/**
Constructs a DBStorage object.
@param id an id assigned by the pool.
**/
//@P0D DBStorage (int id)
//@P0D {
// Initialize to 63 KB. This used to be 64K
// The IBM i JVM adds 24 bytes of
// overhead to each object so a 64K byte array really
// takes 64K + 24 bytes. The IBM i JVM has a boundary
// at 64K. Objects 64K or smaller go into the 64K
// segment pool. Objects 64K + 1 byte or larger go into the
// 1 meg pool. We used to allocate a 64K byte array
// but that ended up in the 1 meg pool because of the
// added JVM overhead. This wasted a lot of heap because
// 1 meg was allocated but only 64K + 24 was used. Making
// the buffer smaller puts us back into the 64K segment
// greatly reducing heap loss. This object automatically
// increases the size of the byte array if necessary so if any
// caller really needs 64K the byte array will grow to that size.
//@P0 - The data is initialized to 1K now, so this isn't an issue.
// The data streams rarely need as much as 64K, so it's worth the
// memory savings.
//@P0D data_ = new byte[64512]; // @D1C
//@P0D id_ = id;
//@P0D }
/**
Checks the size of the array and resizes the storage if needed.
@param size size that is needed.
@return true if the storage was resize; false otherwise.
**/
final synchronized boolean checkSize(final int size) //@P0C
{
if (size > data_.length)
{
// Double the size each time, until the size is greater then 4 meg.
// Then just go up 4 meg at a time to avoid excessive storage consumption @A8A
int increment = data_.length;
//
// Limiting the increment to 4 meg caused performance problems with applications
// creating huge batches.
// if (increment > 4096 * 1024 ) increment = 4096 * 1024;
byte[] newdata = new byte[Math.max(data_.length + increment, size)]; // @C1C
System.arraycopy(data_, 0, newdata, 0, data_.length);
data_ = newdata;
return true;
}
return false;
}
/**
* Reduce the size of the allocated buffer if needed. @A8A
* @param length size to reduce the buffer to
*/
public synchronized void reclaim(int length) {
if(data_.length>length && length >= DEFAULT_SIZE ) {
// System.out.println("Reclaiming to "+length+" from "+data_.length);
byte[] oldData = data_;
data_ = new byte[length];
// The two byte client server ID is only set in the constructor, NOT in initialize.
// This caused a failure unless those 2 bytes are preserved
System.arraycopy(oldData, 6, data_, 6, 2);
}
}
/**
* Set the inUse_ flags so that the storage can be returned to the pool
*/
public void returnToPool() {
// Fill the array with garbage before it is reused.
// This is to catch the case where the array is still being
// used but has been returned to the pool.
// if (data_ != null) {
// Arrays.fill(data_, (byte) 0xeb);
// }
// Don't hold the lock when returning to the pool. The return to the pool
// is just to adjust the hints. If we hold the lock, then there is a possibility for
// deadlock, with the stacks looking like the following. @C9
//
// "WebContainer : 1935" (TID:0x000000012C8CFF00, sys_thread_t:0x00000001240C7E48, state:B, native ID:0x00000000002B20C7) prio=5
// at com/ibm/as400/access/DBStorage.canUse(DBStorage.java:148(Compiled Code))
// at com/ibm/as400/access/DBStoragePool.getUnusedStorage(DBStoragePool.java:142(Compiled Code))
// at com/ibm/as400/access/DBBaseRequestDS.write(DBBaseRequestDS.java:958(Compiled Code))
// at com/ibm/as400/access/AS400ThreadedServer.send(AS400ThreadedServer.java:446(Compiled Code))
// at com/ibm/as400/access/AS400ThreadedServer.sendAndReceive(AS400ThreadedServer.java:480(Compiled Code))
// at com/ibm/as400/access/AS400JDBCConnection.sendAndReceive(AS400JDBCConnection.java:2903(Compiled Code))
// at com/ibm/as400/access/AS400JDBCStatement.commonExecute(AS400JDBCStatement.java:902(Compiled Code))
// at com/ibm/as400/access/AS400JDBCPreparedStatement.executeUpdate(AS400JDBCPreparedStatement.java:1406(Compiled Code))
//
// "WebContainer : 1946" (TID:0x000000013E411700, sys_thread_t:0x00000001277E8F28, state:B, native ID:0x00000000001AC079) prio=5
// at com/ibm/as400/access/DBStoragePool.returned(DBStoragePool.java:181(Compiled Code))
// at com/ibm/as400/access/DBStorage.returnToPool(DBStorage.java:132(Compiled Code))
// at com/ibm/as400/access/DBBaseRequestDS.write(DBBaseRequestDS.java:1007(Compiled Code))
// at com/ibm/as400/access/AS400ThreadedServer.send(AS400ThreadedServer.java:446(Compiled Code))
// at com/ibm/as400/access/AS400ThreadedServer.sendAndReceive(AS400ThreadedServer.java:480(Compiled Code))
// at com/ibm/as400/access/AS400JDBCConnection.sendAndReceive(AS400JDBCConnection.java:2903(Compiled Code))
// at com/ibm/as400/access/AS400JDBCStatement.commonExecute(AS400JDBCStatement.java:902(Compiled Code))
// at com/ibm/as400/access/AS400JDBCPreparedStatement.executeUpdate(AS400JDBCPreparedStatement.java:1406(Compiled Code))
//
synchronized (this) {
inUse_ = false;
}
if (id_>= 0) {
pool_.returned(id_); //@B5A
}
}
/**
* Can this be used. If not, false is returned.
* If it can be used, then inUse_ is set to return and true is returned.
* Note: We first check unsynchronized. Then check after synchronizing.
* @return true if this can be used
*/
public boolean canUse() {
if (inUse_) {
return false;
} else {
synchronized(this) {
if (inUse_) {
return false;
} else {
inUse_ = true;
return true;
}
}
}
}
/**
* get the data buffer
* @return the data buffer
*/
public synchronized byte[] getData() {
// if (!inUse_) {
// Error case for now just trace it
// Debugging code.
// if (! DataStream.traceOpened) {
// SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmm");
// try {
// Trace.setFileName("/tmp/toolboxTrace."+sdf.format(new Date())+".txt");
// } catch (Exception e) {
//
// }
// DataStream.traceOpened=true;
//}
//boolean traceTurnedOn = false;
//if (!Trace.traceOn_) {
// traceTurnedOn = true;
// Trace.setTraceAllOn(true);
// Trace.setTraceOn(true);
//}
// Exception e = new Exception("getData() called when inUse_ = "+inUse_);
// Trace.log(Trace.ERROR, "Debug0601: DBStorage.getData() called when DBStorage not in use", e);
// if (traceTurnedOn) {
// Trace.setTraceAllOn(false);
// Trace.setTraceOn(false);
//}
// }
return data_;
}
/**
Clears the contents of the storage.
**/
//@P0D void clear ()
//@P0D {
// No-op.
//@P0D }
public void setAllocatedLocation() {
allocatedLocation = new Exception("location");
}
String getAllocatedLocation() {
if (allocatedLocation == null) {
return "NONE";
} else {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
allocatedLocation.printStackTrace(pw);
String result = sw.toString();
result = result.replace('\n', ' ');
return result;
}
}
/**
Returns the id.
@return id
**/
//@P0D int getId ()
//@P0D {
//@P0D return id_;
//@P0D }
/**
Returns a reference to the enclosed byte array.
@return a reference to the byte array.
**/
//@P0D byte[] getReference ()
//@P0D {
//@P0D return data_;
//@P0D }
}