In previous version of jaybird (2.2) I was able to execute Services API to Firebird server to get active transaction markers: OIT, OAT, Next, etc.
In version 3.0, I can't find out how to do it properly. There are only ISC-constants (like isc_info_oldest_snapshot) but no methods.
So, I see one way to do that: Get query of database header by StatisticsManager
. But it is not so easy, because it will return text that needs to be parsed:
StatisticsManager SM = new FBStatisticsManager(); //"PURE_JAVA", "NATIVE", "EMBEDDED"
SM.setHost("localhost");
SM.setUser("sysdba");
SM.setPort(3053);
SM.setPassword("masterkey");
SM.setDatabase("c:\\Firebird\\3.0.2\\examples\\empbuild\\EMPLOYEE.FDB");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
SM.setLogger(baos);
SM.getHeaderPage();
String outputstr2 = new String( baos.toByteArray(), java.nio.charset.StandardCharsets.UTF_8 );
and now I need to parse the text:
Database "C:\FIREBIRD\3.0.2\EXAMPLES\EMPBUILD\EMPLOYEE.FDB"
Database header page information:
Flags 0
Generation 806
System Change Number 12
Page size 8192
ODS version 12.0
Oldest transaction 520
Oldest active 521
Oldest snapshot 521
Next transaction 521
Sequence number 0
Next attachment ID 857
Implementation HW=AMD/Intel/x64 little-endian OS=Windows CC=MSVC
Shadow count 0
Page buffers 0
Next header page 0
Database dialect 3
Creation date Apr 15, 2016 17:38:34
Attributes
Variable header data:
Database backup GUID: {6F41E937-76D5-4C67-6CAE-F8556AD27BEE}
Database GUID: {EE5B2713-7B17-43B0-0CB3-0616B4B8A63D}
*END*
May be it is possible to get direct values?
upd: Old version of code was:
/** [ActiveCount, OAT, OST, OIT, Next] */
public static int[] getTxInfo( final GDS gds,
final String host,
final int port,
final String databasePath,
final String user,
final String password ) throws Exception {
final byte[] queryItems = {
ISCConstants.isc_info_oldest_transaction,
ISCConstants.isc_info_oldest_active,
ISCConstants.isc_info_oldest_snapshot,
ISCConstants.isc_info_next_transaction,
ISCConstants.isc_info_active_transactions,
ISCConstants.isc_info_end
};
byte[] response = queryDB(
gds, host, port, databasePath, user, password,
queryItems, DEFAULT_BUFFER_SIZE
);
int i = 0;
final int[] result = new int[5];
while ( response[i] != ISCConstants.isc_info_end ) {
final byte code = response[i++];
switch ( code ) {
case ISCConstants.isc_info_active_transactions: {
//здесь идет столько блоков isc_info_active_transactions, сколько
//реально активных транзакций в данный момент
final int valueLen = gds.iscVaxInteger( response, i, LENGTH_LEN );
i += LENGTH_LEN;
//final int res = gds.iscVaxInteger( response, i, valueLen );
i += valueLen;
result[0]++;
break;
}
case ISCConstants.isc_info_oldest_active: {
final int valueLen = gds.iscVaxInteger( response, i, LENGTH_LEN );
i += LENGTH_LEN;
final int res = gds.iscVaxInteger( response, i, valueLen );
i += valueLen;
result[1] = res;
break;
}
case ISCConstants.isc_info_oldest_snapshot: {
final int valueLen = gds.iscVaxInteger( response, i, LENGTH_LEN );
i += LENGTH_LEN;
final int res = gds.iscVaxInteger( response, i, valueLen );
i += valueLen;
result[2] = res;
break;
}
case ISCConstants.isc_info_oldest_transaction: {
final int valueLen = gds.iscVaxInteger( response, i, LENGTH_LEN );
i += LENGTH_LEN;
final int res = gds.iscVaxInteger( response, i, valueLen );
i += valueLen;
result[3] = res;
break;
}
case ISCConstants.isc_info_next_transaction: {
final int valueLen = gds.iscVaxInteger( response, i, LENGTH_LEN );
i += LENGTH_LEN;
final int res = gds.iscVaxInteger( response, i, valueLen );
i += valueLen;
result[4] = res;
break;
}
case ISCConstants.isc_info_truncated: {
//этот код означает "буфер слишком маленький, дайте больше"
//обычно это бывает когда слишком много активных транзакций
//сначала пробуем увеличить буфер
if ( response.length == DEFAULT_BUFFER_SIZE ) {
response = queryDB(
gds, host, port, databasePath, user, password,
queryItems, 32 * DEFAULT_BUFFER_SIZE
);
result[0] = 0;//на всякий случай
//начинаем разбор заново
i = 0;
} else {
//32Кб буфера оказалось тоже недостаточно -- пичалька. Но
//делать нечего -- просто обойдемся без числа активных транзакций
response = queryDB(
gds, host, port, databasePath, user, password,
new byte[]{
ISCConstants.isc_info_oldest_transaction,
ISCConstants.isc_info_oldest_active,
ISCConstants.isc_info_oldest_snapshot,
ISCConstants.isc_info_next_transaction,
ISCConstants.isc_info_end
}, DEFAULT_BUFFER_SIZE
);
result[0] = -1;
//начинаем разбор заново
i = 0;
}
break;
}
default:
throw new FBSQLException( "Unrecognized response code: " + code + " (response=" + Arrays.toString( result ) + ")" );
}
}
return result;
}
where
public static byte[] queryDB( final GDS gds,
final String host,
final int port,
final String databasePath,
final String user,
final String password,
final byte[] queryItems,
final int bufferLength ) throws Exception {
return doWithDB(
gds, host, port, databasePath, user, password,
new DBOperation<byte[]>() {
public byte[] doWithDB( final GDS gds,
final IscDbHandle db ) throws GDSException {
return gds.iscDatabaseInfo(
db,
queryItems,
bufferLength
);
}
}
);
}
Is it enough?
I have added the functionality to Jaybird 3.0.0, see this commit.
I have added two ways to get this information:
Using StatisticsManager
:
StatisticsManager statsMan = new FBStatisticsManager();
statsMan.setHost("localhost");
statsMan.setDatabase("/path/to/your.fdb");
statsMan.setUser("youruser");
statsMan.setPassword("yourpassword");
DatabaseTransactionInfo info = statsMan.getDatabaseTransactionInfo();
A convenience method to use an existing Connection
to get this information:
try (Connection connection = dataSource.getConnection()) {
DatabaseTransactionInfo info = FBStatisticsManager
.getDatabaseTransactionInfo(connection);
}
The only requirement is that the connection instance unwraps to the FirebirdConnection
interface.
If you are using Maven, you can try the latest Jaybird snapshot from the Sonatype OSS snapshot repository: https://oss.sonatype.org/content/repositories/snapshots (you need to add this snapshot repository to your maven config).
<dependency>
<groupId>org.firebirdsql.jdbc</groupId>
<artifactId>jaybird-jdk18</artifactId>
<version>3.0.0-SNAPSHOT</version>
</dependency>
Otherwise you can download the snapshot using:
For a future version I will consider if I can expose the database information query facility in a more general way so it is not necessary to use the internal FbDatabase
interface.