org.firebirdsql.management.FBMaintenanceManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jaybird-jdk15 Show documentation
Show all versions of jaybird-jdk15 Show documentation
JDBC Driver for the Firebird RDBMS
/*
* Firebird Open Source J2EE Connector - JDBC Driver
*
* Copyright (C) All Rights Reserved.
*
* This file was created by members of the firebird development team.
* All individual contributions remain the Copyright (C) of those
* individuals. Contributors to this file are either listed here or
* can be obtained from a CVS history command.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* - Neither the name of the firebird development team nor the names
* of its contributors may be used to endorse or promote products
* derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
package org.firebirdsql.management;
import java.sql.SQLException;
import java.util.StringTokenizer;
import org.firebirdsql.gds.ISCConstants;
import org.firebirdsql.gds.ServiceRequestBuffer;
import org.firebirdsql.gds.impl.GDSType;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.ByteArrayOutputStream;
/**
* The FBMaintenanceManager
class is responsible for replicating
* the functionality provided by the gfix
command-line tool.
* Among the responsibilities of this class are:
*
* - Database shutdown
*
- Extended database shutdown/online modes new with Firebird 2.5
*
- Changing database mode to read-only or read-write
*
- Enabling or disabling forced writes in the database
*
- Changing the dialect of the database
*
- Setting the cache size at database-level
*
- Mending databases and making minor repairs
*
- Sweeping databases
*
- Activating and killing shadow files
*
- Displaying, committing, or recovering limbo transactions
*
*
* @author Gabriel Reid
* @author Thomas Steinmaurer
*/
public class FBMaintenanceManager extends FBServiceManager
implements MaintenanceManager {
/**
* Create a new instance of FBMaintenanceManager
based on
* the default GDSType.
*/
public FBMaintenanceManager()
{
super();
}
/**
* Create a new instance of FBMaintenanceManager
based on
* a given GDSType.
*
* @param gdsType type must be PURE_JAVA, EMBEDDED, or NATIVE
*/
public FBMaintenanceManager(String gdsType)
{
super(gdsType);
}
/**
* Create a new instance of FBMaintenanceManager
based on
* a given GDSType.
*
* @param gdsType The GDS implementation type to use
*/
public FBMaintenanceManager(GDSType gdsType){
super(gdsType);
}
/**
* Set the database to have read-write or read-only access.
*
* @param mode Must be either ACCESS_MODE_READ_WRITE
* or ACCESS_MODE_READ_ONLY
* @throws SQLException if a database access error occurs
*/
public void setDatabaseAccessMode(int mode) throws SQLException {
if (mode != ACCESS_MODE_READ_WRITE && mode != ACCESS_MODE_READ_ONLY){
throw new IllegalArgumentException("mode must be one of "
+ "ACCESS_MODE_READ_WRITE or ACCESS_MODE_READ_ONLY");
}
ServiceRequestBuffer srb = createDefaultPropertiesSRB();
srb.addArgument(ISCConstants.isc_spb_prp_access_mode, (byte)mode);
executeServicesOperation(srb);
}
/**
* Set the database's dialect.
*
* @param dialect The database dialect, must be either 1 or 3
* @throws SQLException if a database access error occurs
*/
public void setDatabaseDialect(int dialect) throws SQLException {
if (dialect != 1 && dialect != 3){
throw new IllegalArgumentException("dialect must be either "
+ "1 or 3");
}
ServiceRequestBuffer srb = createDefaultPropertiesSRB();
srb.addArgument(ISCConstants.isc_spb_prp_set_sql_dialect, dialect);
executeServicesOperation(srb);
}
/**
* Set the default page-buffer count to be cached in the database. The
* Firebird default is 2048.
*
* @param pageCount The number of pages to be cached, must be positive
* @throws SQLException If the given page count cannot be set, or a
* database access error occurs
*/
public void setDefaultCacheBuffer(int pageCount) throws SQLException {
if (pageCount < 1){
throw new IllegalArgumentException("page count must be positive");
}
ServiceRequestBuffer srb = createDefaultPropertiesSRB();
srb.addArgument(ISCConstants.isc_spb_prp_page_buffers, pageCount);
executeServicesOperation(srb);
}
/**
* Enable or disable forced (synchronous) writes in the database.
* Note, it is considered to be a very bad idea to use buffered
* writing on Windows platforms.
*
* @param forced If true
, forced writes will be used in the
* database, otherwise buffered writes will be used.
* @throws SQLException if a database access error occurs
*/
public void setForcedWrites(boolean forced) throws SQLException {
ServiceRequestBuffer srb = createDefaultPropertiesSRB();
srb.addArgument(ISCConstants.isc_spb_prp_write_mode,
(byte) (forced ? ISCConstants.isc_spb_prp_wm_sync
: ISCConstants.isc_spb_prp_wm_async));
executeServicesOperation(srb);
}
/**
* Set the page fill strategy for when inserting records.
* pageFill
can be one of:
*
* PAGE_FILL_FULL
Fully fill database pages
* PAGE_FILL_RESERVE
Reserve 20% of page space for
* later record deltas
*
*
* @param pageFill The page-filling strategy, either
* PAGE_FILL_FULL
or PAGE_FILL_RESERVE
* @throws SQLException if a database access error occurs
*/
public void setPageFill(int pageFill) throws SQLException {
if (pageFill != PAGE_FILL_FULL && pageFill != PAGE_FILL_RESERVE){
throw new IllegalArgumentException( "Page fill must be either "
+ "PAGE_FILL_FULL or PAGE_FILL_RESERVE");
}
ServiceRequestBuffer srb = createDefaultPropertiesSRB();
srb.addArgument(ISCConstants.isc_spb_prp_reserve_space,
(byte)pageFill);
executeServicesOperation(srb);
}
//----------- Database Shutdown -------------------
/**
* Shutdown the current database.
* Shutdown can be done in three modes:
*
* SHUTDOWN_ATTACH
- No new non-owner connections
* will be allowed to the database during the shutdown, and shutdown
* is cancelled if there are still processes connected at the end
* of the timeout.
*
* SHUTDOWN_TRANSACTIONAL
- No new transactions can
* be started during the timeout period, and shutdown is cancelled
* if there are still active transactions at the end of the timeout.
*
* SHUTDOWN_FORCE
- Forcefully shuts down the
* database at the end of the timeout.
*
*
* @param shutdownMode One of SHUTDOWN_ATTACH
,
* SHUTDOWN_TRANSACTIONAL
,
* or SHUTDOWN_FORCE
.
* @param timeout The maximum amount of time allocated for the operation,
* in seconds
* @throws SQLException if the requested operation cannot be completed
* within the given timeout, or a database access error occurs
*/
public void shutdownDatabase(int shutdownMode, int timeout)
throws SQLException {
if (shutdownMode != SHUTDOWN_ATTACH
&& shutdownMode != SHUTDOWN_TRANSACTIONAL
&& shutdownMode != SHUTDOWN_FORCE){
throw new IllegalArgumentException("Shutdown mode must be "
+ "one of: SHUTDOWN_ATTACH, SHUTDOWN_TRANSACTIONAL, "
+ "SHUTDOWN_FORCE");
}
if (timeout < 0){
throw new IllegalArgumentException(
"Timeout must be >= 0");
}
ServiceRequestBuffer srb = createDefaultPropertiesSRB();
srb.addArgument(shutdownMode, timeout);
executeServicesOperation(srb);
}
public void shutdownDatabase(byte operationMode, int shutdownModeEx, int timeout) throws SQLException {
if (
operationMode != OPERATION_MODE_MULTI
&& operationMode != OPERATION_MODE_SINGLE
&& operationMode != OPERATION_MODE_FULL_SHUTDOWN
) {
throw new IllegalArgumentException("Operation mode must be "
+ "one of: OPERATION_MODE_MULTI, "
+ "OPERATION_MODE_SINGLE, OPERATION_MODE_FULL_SHUTDOWN");
}
if (
shutdownModeEx != SHUTDOWNEX_FORCE
&& shutdownModeEx != SHUTDOWNEX_ATTACHMENTS
&& shutdownModeEx != SHUTDOWNEX_TRANSACTIONS
) {
throw new IllegalArgumentException("Extended shutdown mode must be "
+ "one of: SHUTDOWNEX_FORCE, SHUTDOWNEX_ATTACHMENTS, "
+ "SHUTDOWNEX_TRANSACTIONS");
}
if (timeout < 0) {
throw new IllegalArgumentException("Timeout must be >= 0");
}
ServiceRequestBuffer srb = createDefaultPropertiesSRB();
srb.addArgument(ISCConstants.isc_spb_prp_shutdown_mode, operationMode);
srb.addArgument(shutdownModeEx, timeout);
executeServicesOperation(srb);
}
/**
* Bring a shutdown database online.
*
* @throws SQLException if a database access error occurs
*/
public void bringDatabaseOnline() throws SQLException {
executePropertiesOperation(ISCConstants.isc_spb_prp_db_online);
}
/**
* Bring a shutdown database online with enhanced operation modes
* new since Firebird 2.5.
*
* @throws SQLException if a database access error occurs
*/
public void bringDatabaseOnline(byte operationMode) throws SQLException {
if (
operationMode != OPERATION_MODE_NORMAL
&& operationMode != OPERATION_MODE_MULTI
&& operationMode != OPERATION_MODE_SINGLE
) {
throw new IllegalArgumentException("Operation mode must be "
+ "one of: OPERATION_MODE_NORMAL, OPERATION_MODE_MULTI, "
+ "OPERATION_MODE_SINGLE");
}
ServiceRequestBuffer srb = createDefaultPropertiesSRB();
srb.addArgument(ISCConstants.isc_spb_prp_online_mode, operationMode);
executeServicesOperation(srb);
}
//-------------- Database Repair ----------------------
/**
* Mark corrupt records in the database as unavailable.
* This operation ensures that the corrupt records are skipped (for
* example, during a subsequent backup). This method is the equivalent
* of gfix -mend
.
*
* @throws SQLException if a database access error occurs
*/
public void markCorruptRecords() throws SQLException {
executeRepairOperation(ISCConstants.isc_spb_rpr_mend_db);
}
/**
* Locate and release database pages that are allocated but unassigned
* to any data structures. This method also reports corrupt structures.
*
* @throws SQLException if a database access error occurs
*/
public void validateDatabase() throws SQLException {
executeRepairOperation(ISCConstants.isc_spb_rpr_validate_db);
}
/**
* Locate and release database pages that are allocated but unassigned
* to any data structures. This method also reports corrupt structures.
* The value supplied for options
must be one of the
* following:
*
* - 0 - Simple validation
*
VALIDATE_READ_ONLY
- read-only validation,
* no repair
* VALIDATE_FULL
- full validation and repair
*
*
* The value for options
can additionally be combined in
* a bitmask with VALIDATE_IGNORE_CHECKSUM
to ignore
* checksums while performing validation.
*
* @param options Either 0, VALIDATE_READ_ONLY
, or
* VALIDATE_FULL
* @throws SQLException if a database access error occurs
*/
public void validateDatabase(int options) throws SQLException {
if (options < 0
|| options != 0 && options != VALIDATE_IGNORE_CHECKSUM
&& (options & ~VALIDATE_IGNORE_CHECKSUM) != VALIDATE_READ_ONLY
&& (options & ~VALIDATE_IGNORE_CHECKSUM) != VALIDATE_FULL
&& (options |
(VALIDATE_READ_ONLY | VALIDATE_IGNORE_CHECKSUM)) != options
&& (options |
(VALIDATE_FULL | VALIDATE_IGNORE_CHECKSUM)) != options) {
throw new IllegalArgumentException("options must be either 0, "
+ "VALIDATE_READ_ONLY, or VALIDATE_FULL, optionally "
+ "combined with VALIDATE_IGNORE_CHECKSUM");
}
ServiceRequestBuffer srb = createRepairSRB(
options | ISCConstants.isc_spb_rpr_validate_db);
executeServicesOperation(srb);
}
//----------- Sweeping -------------------------
/**
* Set the database automatic sweep interval to a given number of
* transactions. The Firebird default value is 20,000. If
* transactions
is 0, automatic sweeping is disabled.
*
* @param transactions The interval of transactions between automatic
* sweeps of the database. Can be set to 0, which disables
* automatic sweeping of the database.
* @throws SQLException if a database access error occurs
*/
public void setSweepThreshold(int transactions) throws SQLException {
if (transactions < 0){
throw new IllegalArgumentException("transactions must be >= 0");
}
ServiceRequestBuffer srb = createDefaultPropertiesSRB();
srb.addArgument(ISCConstants.isc_spb_prp_sweep_interval, transactions);
executeServicesOperation(srb);
}
/**
* Perform an immediate sweep of the database.
*
* @throws SQLException if a database access error occurs
*/
public void sweepDatabase() throws SQLException {
executeRepairOperation(ISCConstants.isc_spb_rpr_sweep_db);
}
//----------- Shadow Files ------------------------------------
/**
* Activate a database shadow file to be used as the actual database.
* This method is the equivalent of gfix -activate
.
*
* @throws SQLException if a database access error occurs
*/
public void activateShadowFile() throws SQLException {
executePropertiesOperation(ISCConstants.isc_spb_prp_activate);
}
/**
* Remove references to unavailable shadow files. This method is the
* equivalent of gfix -kill
.
*
* @throws SQLException if a database access error occurs
*/
public void killUnavailableShadows() throws SQLException {
executeRepairOperation(ISCConstants.isc_spb_rpr_kill_shadows);
}
//----------- Transaction Management ----------------------------
/**
* Retrieve the ID of each limbo transaction. The output of this method
* is written to the logger.
*
* @throws SQLException if a database access error occurs
*/
public void listLimboTransactions() throws SQLException {
OutputStream saveOut = getLogger();
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(saveOut);
setLogger(out);
executeRepairOperation(ISCConstants.isc_spb_rpr_list_limbo_trans);
byte output[] = out.toByteArray();
int trId = 0, shift = 0;
for (int i = 0; i < output.length; i++){
if (output[i] == ISCConstants.isc_spb_single_tra_id){
trId = 0;
shift = 0;
} else if (output[i] == 0 && shift != -1){
ps.print(trId + "\n");
shift = -1;
} else if (shift != -1) {
trId += ((output[i] & 0xff) << shift);
shift += 8;
}
}
} finally {
setLogger(saveOut);
}
}
public int[] getLimboTransactions() throws SQLException
{
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
setLogger(byteOut);
listLimboTransactions();
StringTokenizer limboTransactions = new StringTokenizer(byteOut.toString(),"\n");
int[] trans = new int[limboTransactions.countTokens()];
int count = 0;
while(limboTransactions.hasMoreTokens())
trans[count++] = Integer.parseInt(limboTransactions.nextToken().trim());
return trans;
}
/**
* Commit a limbo transaction based on its ID.
*
* @param transactionId The ID of the limbo transaction to be committed
* @throws SQLException if a database access error occurs or the
* given transaction ID is not valid
*/
public void commitTransaction(int transactionId) throws SQLException {
ServiceRequestBuffer srb = createDefaultRepairSRB();
srb.addArgument(ISCConstants.isc_spb_rpr_commit_trans, transactionId);
executeServicesOperation(srb);
}
/**
* Rollback a limbo transaction based on its ID.
*
* @param transactionId The ID of the limbo transaction to be rolled back
* @throws SQLException if a database access error occurs or the
* given transaction ID is not valid
*/
public void rollbackTransaction(int transactionId) throws SQLException {
ServiceRequestBuffer srb = createDefaultRepairSRB();
srb.addArgument(
ISCConstants.isc_spb_rpr_rollback_trans,
transactionId);
executeServicesOperation(srb);
}
//----------- Private imlementation methods --------------------
/**
* Execute a isc_spb_rpr_* (repair) services operation.
*
* @param operation The identifier for the operation to be executed
* @throws SQLException if a database access error occurs
*/
private void executeRepairOperation(int operation) throws SQLException {
ServiceRequestBuffer srb = createRepairSRB(operation);
executeServicesOperation(srb);
}
/**
* Execute a isc_spb_prp_* (properties) services operation.
*
* @param operation The identifier for the operation to be executed
* @throws SQLException if a database access error occurs
*/
private void executePropertiesOperation(int operation)
throws SQLException {
ServiceRequestBuffer srb = createPropertiesSRB(operation);
executeServicesOperation(srb);
}
/**
* Get a mostly empty properties-operation buffer that can be filled in as
* needed. The buffer created by this method cannot have the options
* bitmask set on it.
*/
private ServiceRequestBuffer createDefaultPropertiesSRB(){
return createPropertiesSRB(0);
}
/**
* Get a mostly empty repair-operation buffer that can be filled in as
* needed. The buffer created by this method cannot have the options
* bitmask set on it.
*/
private ServiceRequestBuffer createDefaultRepairSRB(){
return createRepairSRB(0);
}
/**
* Get a mostly-empty properties-operation request buffer that can be
* filled as needed.
*
* @param options The options bitmask for the request buffer
*/
private ServiceRequestBuffer createPropertiesSRB(int options){
return createRequestBuffer(
ISCConstants.isc_action_svc_properties,
options);
}
/**
* Get a mostly-empty repair-operation request buffer that can be
* filled as needed.
*
* @param options The options bitmask for the request buffer
*/
private ServiceRequestBuffer createRepairSRB(int options){
return createRequestBuffer(ISCConstants.isc_action_svc_repair, options);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy